diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 821537e..d1100ea 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -740,6 +740,10 @@ _wrap_objobjobjstr2obj(LLVMBuildBitCast, LLVMBuilderRef, LLVMValueRef, LLVMTypeR _wrap_objenumobjobjstr2obj(LLVMBuildICmp, LLVMBuilderRef, LLVMIntPredicate, LLVMValueRef, LLVMValueRef, LLVMValueRef) _wrap_objenumobjobjstr2obj(LLVMBuildFCmp, LLVMBuilderRef, LLVMRealPredicate, LLVMValueRef, LLVMValueRef, LLVMValueRef) + +/* Atomics */ +_wrap_objobjobjobjstrint2obj(LLVMBuildAtomicCmpXchg, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) + /* Miscellaneous instructions */ _wrap_objobjintstr2obj(LLVMBuildGetResult, LLVMBuilderRef, LLVMValueRef, LLVMValueRef) @@ -1647,6 +1651,9 @@ static PyMethodDef core_methods[] = { _method( LLVMBuildICmp ) _method( LLVMBuildFCmp ) + /* Atomics */ + _method( LLVMBuildAtomicCmpXchg ) + /* Miscellaneous instructions */ _method( LLVMBuildGetResult ) _method( LLVMBuildPhi ) diff --git a/llvm/core.py b/llvm/core.py index f1cade7..7ae22ea 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -1996,6 +1996,15 @@ class Builder(object): _core.LLVMBuildShuffleVector(self.ptr, vecA.ptr, vecB.ptr, mask.ptr, name)) + # atomics + + def atomic_cmpxchg(self, ptr, old, new, ordering, crossthread=True): + check_is_value(ptr) + check_is_value(old) + check_is_value(new) + inst = _core.LLVMBuildAtomicCmpXchg(self.ptr, ptr.ptr, old.ptr, new.ptr, + ordering.lower(), int(bool(crossthread))) + return _make_value(inst) #===----------------------------------------------------------------------=== # Memory buffer diff --git a/llvm/extra.cpp b/llvm/extra.cpp index 858fbcf..0d71065 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -111,6 +111,45 @@ char *do_print(W obj) return strdup(buf.str().c_str()); } +LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, + LLVMValueRef cmp, LLVMValueRef val, + const char* ordering, int crossthread) +{ + using namespace llvm; + + AtomicOrdering ordering_enum; + + if ( strcmp(ordering, "unordered") == 0 ) + ordering_enum = Unordered; + else if ( strcmp(ordering, "monotonic") == 0 ) + ordering_enum = Monotonic; + else if ( strcmp(ordering, "acquire") == 0 ) + ordering_enum = Acquire; + else if ( strcmp(ordering, "release") == 0 ) + ordering_enum = Release; + else if ( strcmp(ordering, "acq_rel") == 0 ) + ordering_enum = AcquireRelease; + else if ( strcmp(ordering, "seq_cst") == 0 ) + ordering_enum = SequentiallyConsistent; + else + ordering_enum = NotAtomic; + + SynchronizationScope crossthread_enum; + switch( crossthread ){ + case 0: + crossthread_enum = SingleThread; + break; + default: + crossthread_enum = CrossThread; + } + + + Value * inst = unwrap(builder)->CreateAtomicCmpXchg( + unwrap(ptr), unwrap(cmp), unwrap(val), + ordering_enum, crossthread_enum); + return wrap(inst); +} + LLVMEngineBuilderRef LLVMCreateEngineBuilder(LLVMModuleRef mod) { using namespace llvm; diff --git a/llvm/extra.h b/llvm/extra.h index b0bacc8..b02c527 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -45,6 +45,14 @@ extern "C" { #endif + +/* + * Wraps IRBuilder::CreateAtomicCmpXchg + */ +LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, + LLVMValueRef cmp, LLVMValueRef val, + const char* ordering, int crossthread); + /* * Wraps new EngineBuilder */ diff --git a/llvm/wrap.h b/llvm/wrap.h index 754d9d0..f754b02 100644 --- a/llvm/wrap.h +++ b/llvm/wrap.h @@ -671,6 +671,34 @@ _w ## func (PyObject *self, PyObject *args) \ return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4)); \ } + +/** + * Wrap LLVM functions of the type + * outtype func(intype1 arg1, intype2 arg2, intype3 arg3, intype4, const char *arg5, arg6) + */ +#define _wrap_objobjobjobjstrint2obj(func, intype1, intype2, intype3, intype4, outtype)\ +static PyObject * \ +_w ## func (PyObject *self, PyObject *args) \ +{ \ + PyObject *obj1, *obj2, *obj3, *obj4; \ + intype1 arg1; \ + intype2 arg2; \ + intype3 arg3; \ + intype4 arg4; \ + const char *arg5; \ + int arg6; \ + \ + if (!PyArg_ParseTuple(args, "OOOOsi", &obj1, &obj2, &obj3, &obj4, &arg5, &arg6)) \ + return NULL; \ + \ + arg1 = ( intype1 ) PyCapsule_GetPointer(obj1, NULL); \ + arg2 = ( intype2 ) PyCapsule_GetPointer(obj2, NULL); \ + arg3 = ( intype3 ) PyCapsule_GetPointer(obj3, NULL); \ + arg4 = ( intype4 ) PyCapsule_GetPointer(obj4, NULL); \ + \ + return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4, arg5, arg6)); \ +} + /** * Wrap LLVM functions of the type * outtype func(intype1 arg1, intype2 arg2, intype3 arg3, arg4) diff --git a/test/atomic.py b/test/atomic.py new file mode 100644 index 0000000..7cbbf49 --- /dev/null +++ b/test/atomic.py @@ -0,0 +1,36 @@ +from llvm.core import * +import unittest + +test_these_orderings = filter(bool, map(lambda s:s.strip(), +''' +unordered +monotonic +acquire +release +acq_rel +seq_cst +'''.splitlines())) + +class TestAtomic(unittest.TestCase): + def test_atomic(self): + mod = Module.new('mod') + functype = Type.function(Type.void(), []) + func = mod.add_function(functype, name='foo') + bb = func.append_basic_block('entry') + bldr = Builder.new(bb) + ptr = bldr.alloca(Type.int()) + + old = bldr.load(ptr) + new = Constant.int(Type.int(), 1234) + + + for ordering in test_these_orderings: + inst = bldr.atomic_cmpxchg(ptr, old, new, ordering) + self.assertEqual(ordering, str(inst).split(' ')[-1]) + + + inst = bldr.atomic_cmpxchg(ptr, old, new, ordering, crossthread=False) + self.assertEqual('singlethread', str(inst).split(' ')[-2]) + +if __name__ == '__main__': + unittest.main()