From fb72ab5c8d6feb69a47b6cabf5d99e13f2f75466 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 3 Aug 2012 10:14:09 -0700 Subject: [PATCH] Add the rest of atomic op. --- llvm/_core.cpp | 2 + llvm/core.py | 10 ++++- llvm/extra.cpp | 100 ++++++++++++++++++++++++++++++++++++------------- llvm/extra.h | 6 +++ llvm/wrap.h | 26 +++++++++++++ test/atomic.py | 48 +++++++++++++++++++++--- 6 files changed, 159 insertions(+), 33 deletions(-) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index d1100ea..7b0d31a 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -743,6 +743,7 @@ _wrap_objenumobjobjstr2obj(LLVMBuildFCmp, LLVMBuilderRef, LLVMRealPredicate, LLV /* Atomics */ _wrap_objobjobjobjstrint2obj(LLVMBuildAtomicCmpXchg, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) +_wrap_objstrobjobjstrint2obj(LLVMBuildAtomicRMW, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) /* Miscellaneous instructions */ @@ -1653,6 +1654,7 @@ static PyMethodDef core_methods[] = { /* Atomics */ _method( LLVMBuildAtomicCmpXchg ) + _method( LLVMBuildAtomicRMW ) /* Miscellaneous instructions */ _method( LLVMBuildGetResult ) diff --git a/llvm/core.py b/llvm/core.py index 7ae22ea..2219aa7 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -2003,7 +2003,15 @@ class Builder(object): check_is_value(old) check_is_value(new) inst = _core.LLVMBuildAtomicCmpXchg(self.ptr, ptr.ptr, old.ptr, new.ptr, - ordering.lower(), int(bool(crossthread))) + ordering.lower(), + int(bool(crossthread))) + return _make_value(inst) + + def atomic_rmw(self, op, ptr, val, ordering, crossthread=True): + check_is_value(ptr) + check_is_value(val) + inst = _core.LLVMBuildAtomicRMW(self.ptr, op.lower(), ptr.ptr, val.ptr, + ordering.lower(), int(bool(crossthread))) return _make_value(inst) #===----------------------------------------------------------------------=== diff --git a/llvm/extra.cpp b/llvm/extra.cpp index 0d71065..e36ef99 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -110,6 +110,76 @@ char *do_print(W obj) p->print(buf); return strdup(buf.str().c_str()); } +static +llvm::AtomicOrdering atomic_ordering_from_string(const char * ordering) +{ + using namespace llvm; + + if ( strcmp(ordering, "unordered") == 0 ) + return Unordered; + else if ( strcmp(ordering, "monotonic") == 0 ) + return Monotonic; + else if ( strcmp(ordering, "acquire") == 0 ) + return Acquire; + else if ( strcmp(ordering, "release") == 0 ) + return Release; + else if ( strcmp(ordering, "acq_rel") == 0 ) + return AcquireRelease; + else if ( strcmp(ordering, "seq_cst") == 0 ) + return SequentiallyConsistent; + else + return NotAtomic; +} + +static +llvm::SynchronizationScope sync_scope_from_int(int crossthread) +{ + if( crossthread ) + return llvm::CrossThread; + else + return llvm::SingleThread; +} + +LLVMValueRef LLVMBuildAtomicRMW(LLVMBuilderRef builder, const char * opname, + LLVMValueRef ptr, LLVMValueRef val, + const char* ordering, int crossthread) +{ + using namespace llvm; + + AtomicRMWInst::BinOp op; + + if( strcmp(opname, "xchg") == 0 ) + op = AtomicRMWInst::Xchg; + else if( strcmp(opname, "add") == 0 ) + op = AtomicRMWInst::Add; + else if( strcmp(opname, "sub") == 0 ) + op = AtomicRMWInst::Sub; + else if( strcmp(opname, "and") == 0 ) + op = AtomicRMWInst::And; + else if( strcmp(opname, "nand") == 0 ) + op = AtomicRMWInst::Nand; + else if( strcmp(opname, "or") == 0 ) + op = AtomicRMWInst::Or; + else if( strcmp(opname, "xor") == 0 ) + op = AtomicRMWInst::Xor; + else if( strcmp(opname, "max") == 0 ) + op = AtomicRMWInst::Max; + else if( strcmp(opname, "min") == 0 ) + op = AtomicRMWInst::Min; + else if( strcmp(opname, "umax") == 0 ) + op = AtomicRMWInst::UMax; + else if( strcmp(opname, "umin") == 0 ) + op = AtomicRMWInst::UMin; + else + op = AtomicRMWInst::BAD_BINOP; + + AtomicOrdering atomic_order = atomic_ordering_from_string(ordering); + SynchronizationScope sync_scope = sync_scope_from_int(crossthread); + + Value * inst = unwrap(builder)->CreateAtomicRMW(op, unwrap(ptr), unwrap(val), + atomic_order, sync_scope); + return wrap(inst); +} LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp, LLVMValueRef val, @@ -117,36 +187,12 @@ LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, { 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; - } - + AtomicOrdering atomic_order = atomic_ordering_from_string(ordering); + SynchronizationScope sync_scope = sync_scope_from_int(crossthread); Value * inst = unwrap(builder)->CreateAtomicCmpXchg( unwrap(ptr), unwrap(cmp), unwrap(val), - ordering_enum, crossthread_enum); + atomic_order, sync_scope); return wrap(inst); } diff --git a/llvm/extra.h b/llvm/extra.h index b02c527..5a11d0b 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -45,6 +45,12 @@ extern "C" { #endif +/* + * Wraps IRBuilder::CreateAtomicRMW + */ +LLVMValueRef LLVMBuildAtomicRMW(LLVMBuilderRef builder, const char * op, + LLVMValueRef ptr, LLVMValueRef val, + const char* ordering, int crossthread); /* * Wraps IRBuilder::CreateAtomicCmpXchg diff --git a/llvm/wrap.h b/llvm/wrap.h index f754b02..15c90e9 100644 --- a/llvm/wrap.h +++ b/llvm/wrap.h @@ -699,6 +699,32 @@ _w ## func (PyObject *self, PyObject *args) \ return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4, arg5, arg6)); \ } +/** + * Wrap LLVM functions of the type + * outtype func(intype1 arg1, const char* arg2, intype3 arg3, intype4, const char *arg5, arg6) + */ +#define _wrap_objstrobjobjstrint2obj(func, intype1, intype3, intype4, outtype)\ +static PyObject * \ +_w ## func (PyObject *self, PyObject *args) \ +{ \ + PyObject *obj1, *obj3, *obj4; \ + intype1 arg1; \ + const char *arg2; \ + intype3 arg3; \ + intype4 arg4; \ + const char *arg5; \ + int arg6; \ + \ + if (!PyArg_ParseTuple(args, "OsOOsi", &obj1, &arg2, &obj3, &obj4, &arg5, &arg6)) \ + return NULL; \ + \ + arg1 = ( intype1 ) PyCapsule_GetPointer(obj1, 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 index 7cbbf49..5e3d9b0 100644 --- a/test/atomic.py +++ b/test/atomic.py @@ -1,7 +1,7 @@ from llvm.core import * import unittest -test_these_orderings = filter(bool, map(lambda s:s.strip(), +test_these_orderings = list(filter(bool, map(lambda s:s.strip(), ''' unordered monotonic @@ -9,10 +9,25 @@ acquire release acq_rel seq_cst -'''.splitlines())) +'''.splitlines()))) + +test_these_atomic_op = list(filter(bool, map(lambda s:s.strip(), +''' +xchg +add +sub +and +nand +or +xor +max +min +umax +umin +'''.splitlines()))) class TestAtomic(unittest.TestCase): - def test_atomic(self): + def test_atomic_cmpxchg(self): mod = Module.new('mod') functype = Type.function(Type.void(), []) func = mod.add_function(functype, name='foo') @@ -26,11 +41,34 @@ class TestAtomic(unittest.TestCase): for ordering in test_these_orderings: inst = bldr.atomic_cmpxchg(ptr, old, new, ordering) - self.assertEqual(ordering, str(inst).split(' ')[-1]) + self.assertEqual(ordering, str(inst).strip().split(' ')[-1]) inst = bldr.atomic_cmpxchg(ptr, old, new, ordering, crossthread=False) - self.assertEqual('singlethread', str(inst).split(' ')[-2]) + self.assertEqual('singlethread', str(inst).strip().split(' ')[-2]) + + def test_atomic_rmw(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) + val = Constant.int(Type.int(), 1234) + + for ordering in test_these_orderings: + inst = bldr.atomic_rmw('xchg', ptr, val, ordering) + self.assertEqual(ordering, str(inst).split(' ')[-1]) + + for op in test_these_atomic_op: + inst = bldr.atomic_rmw(op, ptr, val, ordering) + self.assertEqual(op, str(inst).strip().split(' ')[3]) + + inst = bldr.atomic_rmw('xchg', ptr, val, ordering, crossthread=False) + self.assertEqual('singlethread', str(inst).strip().split(' ')[-2]) + if __name__ == '__main__': unittest.main()