diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 765d106..14143f2 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -596,6 +596,7 @@ _wrap_obj2obj(LLVMInstIsArithmeticShift, LLVMValueRef, int) _wrap_obj2obj(LLVMInstIsAssociative, LLVMValueRef, int) _wrap_obj2obj(LLVMInstIsCommutative, LLVMValueRef, int) _wrap_obj2obj(LLVMInstIsVolatile, LLVMValueRef, int) +_wrap_objint2none(LLVMSetVolatile, LLVMValueRef) _wrap_obj2obj(LLVMInstGetOpcode, LLVMValueRef, int) _wrap_obj2str(LLVMInstGetOpcodeName, LLVMValueRef) @@ -739,6 +740,14 @@ _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) +_wrap_objstrobjobjstrint2obj(LLVMBuildAtomicRMW, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) +_wrap_objobjintstrint2obj(LLVMBuildAtomicLoad, LLVMBuilderRef, LLVMValueRef, LLVMValueRef) +_wrap_objobjobjintstrint2obj(LLVMBuildAtomicStore, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) +_wrap_objstrint2obj(LLVMBuildFence, LLVMBuilderRef, LLVMValueRef) + /* Miscellaneous instructions */ _wrap_objobjintstr2obj(LLVMBuildGetResult, LLVMBuilderRef, LLVMValueRef, LLVMValueRef) @@ -1554,6 +1563,7 @@ static PyMethodDef core_methods[] = { _method( LLVMInstIsAssociative ) _method( LLVMInstIsCommutative ) _method( LLVMInstIsVolatile ) + _method( LLVMSetVolatile ) _method( LLVMInstGetOpcode ) _method( LLVMInstGetOpcodeName ) @@ -1645,6 +1655,13 @@ static PyMethodDef core_methods[] = { _method( LLVMBuildICmp ) _method( LLVMBuildFCmp ) + /* Atomics */ + _method( LLVMBuildAtomicCmpXchg ) + _method( LLVMBuildAtomicRMW ) + _method( LLVMBuildAtomicLoad ) + _method( LLVMBuildAtomicStore ) + _method( LLVMBuildFence ) + /* Miscellaneous instructions */ _method( LLVMBuildGetResult ) _method( LLVMBuildPhi ) diff --git a/llvm/core.py b/llvm/core.py index f4c75bf..47b3b8a 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -1458,6 +1458,9 @@ class Instruction(User): """True if this is a volatile load or store.""" return _core.LLVMInstIsVolatile(self.ptr) != 0 + def set_volatile(self, flag): + return _core.LLVMSetVolatile(self.ptr, int(bool(flag))) + @property def opcode(self): return _core.LLVMInstGetOpcode(self.ptr) @@ -1827,14 +1830,20 @@ class Builder(object): check_is_value(ptr) return _make_value(_core.LLVMBuildFree(self.ptr, ptr.ptr)) - def load(self, ptr, name=""): + def load(self, ptr, name="", volatile=False): check_is_value(ptr) - return _make_value(_core.LLVMBuildLoad(self.ptr, ptr.ptr, name)) + inst = _make_value(_core.LLVMBuildLoad(self.ptr, ptr.ptr, name)) + if volatile: + inst.set_volatile(volatile) + return inst - def store(self, value, ptr): + def store(self, value, ptr, volatile=False): check_is_value(value) check_is_value(ptr) - return _make_value(_core.LLVMBuildStore(self.ptr, value.ptr, ptr.ptr)) + inst = _make_value(_core.LLVMBuildStore(self.ptr, value.ptr, ptr.ptr)) + if volatile: + inst.set_volatile(volatile) + return inst def gep(self, ptr, indices, name=""): check_is_value(ptr) @@ -1987,6 +1996,85 @@ 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) + + 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) + + def atomic_xchg(self, *args, **kwargs): + return self.atomic_rmw('xchg', *args, **kwargs) + + def atomic_add(self, *args, **kwargs): + return self.atomic_rmw('add', *args, **kwargs) + + def atomic_sub(self, *args, **kwargs): + return self.atomic_rmw('sub', *args, **kwargs) + + def atomic_and(self, *args, **kwargs): + return self.atomic_rmw('and', *args, **kwargs) + + def atomic_nand(self, *args, **kwargs): + return self.atomic_rmw('nand', *args, **kwargs) + + def atomic_or(self, *args, **kwargs): + return self.atomic_rmw('or', *args, **kwargs) + + def atomic_xor(self, *args, **kwargs): + return self.atomic_rmw('xor', *args, **kwargs) + + def atomic_max(self, *args, **kwargs): + return self.atomic_rmw('max', *args, **kwargs) + + def atomic_min(self, *args, **kwargs): + return self.atomic_rmw('min', *args, **kwargs) + + def atomic_umax(self, *args, **kwargs): + return self.atomic_rmw('umax', *args, **kwargs) + + def atomic_umin(self, *args, **kwargs): + return self.atomic_rmw('umin', *args, **kwargs) + + + def atomic_load(self, ptr, ordering, align=1, crossthread=True, + volatile=False, name=""): + check_is_value(ptr) + inst = _make_value(_core.LLVMBuildAtomicLoad( + self.ptr, ptr.ptr, int(align), + ordering.lower(), int(bool(crossthread)))) + if volatile: + inst.set_volatile(volatile) + if inst: + inst.name = name + return inst + + def atomic_store(self, value, ptr, ordering, align=1, crossthread=True, + volatile=False): + check_is_value(value) + check_is_value(ptr) + inst = _make_value(_core.LLVMBuildAtomicStore( + self.ptr, ptr.ptr, value.ptr, int(align), + ordering.lower(), int(bool(crossthread)))) + if volatile: + inst.set_volatile(volatile) + return inst + + def fence(self, ordering, crossthread=True): + inst = _make_value(_core.LLVMBuildFence(self.ptr, ordering.lower(), + int(bool(crossthread)))) + return inst #===----------------------------------------------------------------------=== # Memory buffer diff --git a/llvm/extra.cpp b/llvm/extra.cpp index 858fbcf..122d387 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -110,6 +110,135 @@ 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 LLVMBuildFence(LLVMBuilderRef builder, const char* ordering, + int crossthread) +{ + using namespace llvm; + AtomicOrdering atomic_order = atomic_ordering_from_string(ordering); + SynchronizationScope sync_scope = sync_scope_from_int(crossthread); + + Value * inst = unwrap(builder)->CreateFence(atomic_order, sync_scope); + return wrap(inst); +} + +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 LLVMBuildAtomicLoad(LLVMBuilderRef builder, LLVMValueRef ptr, + unsigned align, const char* ordering, + int crossthread) +{ + using namespace llvm; + AtomicOrdering atomic_order = atomic_ordering_from_string(ordering); + SynchronizationScope sync_scope = sync_scope_from_int(crossthread); + + LoadInst * inst = unwrap(builder)->CreateLoad(unwrap(ptr)); + + inst->setAtomic(atomic_order, sync_scope); + inst->setAlignment(align); + + return wrap(inst); +} + +LLVMValueRef LLVMBuildAtomicStore(LLVMBuilderRef builder, + LLVMValueRef ptr, LLVMValueRef val, + unsigned align, const char* ordering, + int crossthread) +{ + using namespace llvm; + AtomicOrdering atomic_order = atomic_ordering_from_string(ordering); + SynchronizationScope sync_scope = sync_scope_from_int(crossthread); + + StoreInst * inst = unwrap(builder)->CreateStore(unwrap(val), unwrap(ptr)); + + inst->setAtomic(atomic_order, sync_scope); + inst->setAlignment(align); + + return wrap(inst); +} + +LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, + LLVMValueRef cmp, LLVMValueRef val, + const char* ordering, int crossthread) +{ + using namespace llvm; + + 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), + atomic_order, sync_scope); + return wrap(inst); +} LLVMEngineBuilderRef LLVMCreateEngineBuilder(LLVMModuleRef mod) { diff --git a/llvm/extra.h b/llvm/extra.h index b0bacc8..b13c80f 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -45,6 +45,41 @@ extern "C" { #endif + +/* + * Wraps IRBuilder::CreateFence + */ +LLVMValueRef LLVMBuildFence(LLVMBuilderRef builder, const char* ordering, + int crossthread); + +/* + * Wraps IRBuilder::CreateLoad, LoadInst::setAtomic + */ +LLVMValueRef LLVMBuildAtomicLoad(LLVMBuilderRef builder, LLVMValueRef ptr, + unsigned align, const char* ordering, + int crossthread); +/* + * Wraps IRBuilder::CreateStore, StoreInst::setAtomic + */ +LLVMValueRef LLVMBuildAtomicStore(LLVMBuilderRef builder, + LLVMValueRef ptr, LLVMValueRef val, + unsigned align, const char* ordering, + int crossthread); + +/* + * Wraps IRBuilder::CreateAtomicRMW + */ +LLVMValueRef LLVMBuildAtomicRMW(LLVMBuilderRef builder, const char * op, + LLVMValueRef ptr, LLVMValueRef val, + const char* ordering, int crossthread); + +/* + * 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..bceca87 100644 --- a/llvm/wrap.h +++ b/llvm/wrap.h @@ -671,6 +671,185 @@ _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, const char *arg3, arg4) + */ +#define _wrap_objobjstrint2obj(func, intype1, intype2, outtype)\ +static PyObject * \ +_w ## func (PyObject *self, PyObject *args) \ +{ \ + PyObject *obj1, *obj2; \ + intype1 arg1; \ + intype2 arg2; \ + const char *arg3; \ + int arg4; \ + \ + if (!PyArg_ParseTuple(args, "OOsi", &obj1, &obj2, &arg3, &arg4)) \ + return NULL; \ + \ + arg1 = ( intype1 ) PyCapsule_GetPointer(obj1, NULL); \ + arg2 = ( intype2 ) PyCapsule_GetPointer(obj2, NULL); \ + \ + return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4)); \ +} + + + +/** + * Wrap LLVM functions of the type + * outtype func(intype1 arg1, intype2 arg2, arg3, const char *arg4, arg5) + */ +#define _wrap_objobjintstrint2obj(func, intype1, intype2, outtype)\ +static PyObject * \ +_w ## func (PyObject *self, PyObject *args) \ +{ \ + PyObject *obj1, *obj2; \ + intype1 arg1; \ + intype2 arg2; \ + int arg3; \ + const char *arg4; \ + int arg5; \ + \ + if (!PyArg_ParseTuple(args, "OOisi", &obj1, &obj2, &arg3, &arg4, &arg5)) \ + return NULL; \ + \ + arg1 = ( intype1 ) PyCapsule_GetPointer(obj1, NULL); \ + arg2 = ( intype2 ) PyCapsule_GetPointer(obj2, NULL); \ + \ + return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4, arg5)); \ +} + +/** + * Wrap LLVM functions of the type + * outtype func(intype1 arg1, const char *arg2, arg3) + */ +#define _wrap_objstrint2obj(func, intype1, outtype)\ +static PyObject * \ +_w ## func (PyObject *self, PyObject *args) \ +{ \ + PyObject *obj1; \ + intype1 arg1; \ + const char *arg2; \ + int arg3; \ + \ + if (!PyArg_ParseTuple(args, "Osi", &obj1, &arg2, &arg3)) \ + return NULL; \ + \ + arg1 = ( intype1 ) PyCapsule_GetPointer(obj1, NULL); \ + \ + return ctor_ ## outtype ( func (arg1, arg2, arg3)); \ +} + + +/** + * Wrap LLVM functions of the type + * outtype func(intype1 arg1, intype2 arg2, intype3, const char *arg4, arg5) + */ +#define _wrap_objobjobjstrint2obj(func, intype1, intype2, intype3, outtype)\ +static PyObject * \ +_w ## func (PyObject *self, PyObject *args) \ +{ \ + PyObject *obj1, *obj2, *obj3; \ + intype1 arg1; \ + intype2 arg2; \ + intype3 arg3; \ + const char *arg4; \ + int arg5; \ + \ + if (!PyArg_ParseTuple(args, "OOOsi", &obj1, &obj2, &obj3, &arg4, &arg5)) \ + return NULL; \ + \ + arg1 = ( intype1 ) PyCapsule_GetPointer(obj1, NULL); \ + arg2 = ( intype2 ) PyCapsule_GetPointer(obj2, NULL); \ + arg3 = ( intype3 ) PyCapsule_GetPointer(obj3, NULL); \ + \ + return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4, arg5)); \ +} + + + + +/** + * Wrap LLVM functions of the type + * outtype func(intype1 arg1, intype2 arg2, intype3, arg4, const char *arg5, arg6) + */ +#define _wrap_objobjobjintstrint2obj(func, intype1, intype2, intype3, outtype)\ +static PyObject * \ +_w ## func (PyObject *self, PyObject *args) \ +{ \ + PyObject *obj1, *obj2, *obj3; \ + intype1 arg1; \ + intype2 arg2; \ + intype3 arg3; \ + int arg4; \ + const char *arg5; \ + int arg6; \ + \ + if (!PyArg_ParseTuple(args, "OOOisi", &obj1, &obj2, &obj3, &arg4, &arg5, &arg6)) \ + return NULL; \ + \ + arg1 = ( intype1 ) PyCapsule_GetPointer(obj1, NULL); \ + arg2 = ( intype2 ) PyCapsule_GetPointer(obj2, NULL); \ + arg3 = ( intype3 ) PyCapsule_GetPointer(obj3, 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, 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, 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 new file mode 100644 index 0000000..fd565cc --- /dev/null +++ b/test/atomic.py @@ -0,0 +1,108 @@ +from llvm.core import * +import unittest + +test_these_orderings = list(filter(bool, map(lambda s:s.strip(), +''' +unordered +monotonic +acquire +release +acq_rel +seq_cst +'''.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_cmpxchg(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).strip().split(' ')[-1]) + + + inst = bldr.atomic_cmpxchg(ptr, old, new, ordering, crossthread=False) + 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]) + + + for op in test_these_atomic_op: + atomic_op = getattr(bldr, 'atomic_%s' % op) + inst = atomic_op(ptr, val, ordering) + self.assertEqual(op, str(inst).strip().split(' ')[3]) + + def test_atomic_ldst(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()) + + val = Constant.int(Type.int(), 1234) + + for ordering in test_these_orderings: + loaded = bldr.atomic_load(ptr, ordering) + self.assertIn('load atomic', str(loaded)) + self.assertEqual(ordering, + str(loaded).strip().split(' ')[-3].rstrip(',')) + self.assertIn('align 1', str(loaded)) + + stored = bldr.atomic_store(loaded, ptr, ordering) + self.assertIn('store atomic', str(stored)) + self.assertEqual(ordering, + str(stored).strip().split(' ')[-3].rstrip(',')) + self.assertIn('align 1', str(stored)) + + fenced = bldr.fence(ordering) + self.assertEqual(['fence', ordering], str(fenced).strip().split(' ')) + +if __name__ == '__main__': + unittest.main() + + diff --git a/test/testall.py b/test/testall.py index acf330b..ed7a8a1 100755 --- a/test/testall.py +++ b/test/testall.py @@ -610,7 +610,7 @@ def do_functionpassmanager(): b.ret(Constant.int(ti, 42)) fpm = FunctionPassManager.new(m) fpm.add(TargetData.new('')) - fpm.add(PASS_AGGRESSIVE_DCE) + fpm.add(PASS_ADCE) fpm.initialize() fpm.run(f) fpm.finalize() diff --git a/test/uses.py b/test/uses.py index 97040fa..1b13aa6 100755 --- a/test/uses.py +++ b/test/uses.py @@ -21,7 +21,7 @@ class TestUses(unittest.TestCase): logging.debug(m) logging.debug("-"*60) - logging.debug("Testing use count ..", end=' ') + logging.debug("Testing use count ..") self.assertEqual(f.args[0].use_count, 1) self.assertEqual(f.args[1].use_count, 1) self.assertEqual(f.args[2].use_count, 1) @@ -29,7 +29,7 @@ class TestUses(unittest.TestCase): self.assertEqual(tmp2.use_count, 0) self.assertEqual(tmp3.use_count, 1) - logging.debug("Testing uses ..", end=' ') + logging.debug("Testing uses ..") self.assertIs(f.args[0].uses[0], tmp1) self.assertEqual(len(f.args[0].uses), 1) self.assertIs(f.args[1].uses[0], tmp2) diff --git a/test/volatile.py b/test/volatile.py new file mode 100644 index 0000000..e567a80 --- /dev/null +++ b/test/volatile.py @@ -0,0 +1,55 @@ +from llvm.core import * +import unittest + +class TestVolatile(unittest.TestCase): + def test_volatile(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()) + + # test load inst + val = bldr.load(ptr) + self.assertFalse(val.is_volatile, "default must be non-volatile") + val.set_volatile(True) + self.assertTrue(val.is_volatile, "fail to set volatile") + val.set_volatile(False) + self.assertFalse(val.is_volatile, "fail to unset volatile") + + # test store inst + store_inst = bldr.store(val, ptr) + self.assertFalse(store_inst.is_volatile, "default must be non-volatile") + store_inst.set_volatile(True) + self.assertTrue(store_inst.is_volatile, "fail to set volatile") + store_inst.set_volatile(False) + self.assertFalse(store_inst.is_volatile, "fail to unset volatile") + + def test_volatile_another(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()) + + # test load inst + val = bldr.load(ptr, volatile=True) + self.assertTrue(val.is_volatile, "volatile kwarg does not work") + val.set_volatile(False) + self.assertFalse(val.is_volatile, "fail to unset volatile") + val.set_volatile(True) + self.assertTrue(val.is_volatile, "fail to set volatile") + + # test store inst + store_inst = bldr.store(val, ptr, volatile=True) + self.assertTrue(store_inst.is_volatile, "volatile kwarg does not work") + store_inst.set_volatile(False) + self.assertFalse(store_inst.is_volatile, "fail to unset volatile") + store_inst.set_volatile(True) + self.assertTrue(store_inst.is_volatile, "fail to set volatile") + + +if __name__ == '__main__': + unittest.main()