Add the rest of atomic op.
This commit is contained in:
parent
acad5c9d8b
commit
fb72ab5c8d
6 changed files with 159 additions and 33 deletions
|
|
@ -743,6 +743,7 @@ _wrap_objenumobjobjstr2obj(LLVMBuildFCmp, LLVMBuilderRef, LLVMRealPredicate, LLV
|
||||||
|
|
||||||
/* Atomics */
|
/* Atomics */
|
||||||
_wrap_objobjobjobjstrint2obj(LLVMBuildAtomicCmpXchg, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef, LLVMValueRef)
|
_wrap_objobjobjobjstrint2obj(LLVMBuildAtomicCmpXchg, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef, LLVMValueRef)
|
||||||
|
_wrap_objstrobjobjstrint2obj(LLVMBuildAtomicRMW, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef)
|
||||||
|
|
||||||
/* Miscellaneous instructions */
|
/* Miscellaneous instructions */
|
||||||
|
|
||||||
|
|
@ -1653,6 +1654,7 @@ static PyMethodDef core_methods[] = {
|
||||||
|
|
||||||
/* Atomics */
|
/* Atomics */
|
||||||
_method( LLVMBuildAtomicCmpXchg )
|
_method( LLVMBuildAtomicCmpXchg )
|
||||||
|
_method( LLVMBuildAtomicRMW )
|
||||||
|
|
||||||
/* Miscellaneous instructions */
|
/* Miscellaneous instructions */
|
||||||
_method( LLVMBuildGetResult )
|
_method( LLVMBuildGetResult )
|
||||||
|
|
|
||||||
10
llvm/core.py
10
llvm/core.py
|
|
@ -2003,7 +2003,15 @@ class Builder(object):
|
||||||
check_is_value(old)
|
check_is_value(old)
|
||||||
check_is_value(new)
|
check_is_value(new)
|
||||||
inst = _core.LLVMBuildAtomicCmpXchg(self.ptr, ptr.ptr, old.ptr, new.ptr,
|
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)
|
return _make_value(inst)
|
||||||
|
|
||||||
#===----------------------------------------------------------------------===
|
#===----------------------------------------------------------------------===
|
||||||
|
|
|
||||||
100
llvm/extra.cpp
100
llvm/extra.cpp
|
|
@ -110,6 +110,76 @@ char *do_print(W obj)
|
||||||
p->print(buf);
|
p->print(buf);
|
||||||
return strdup(buf.str().c_str());
|
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 LLVMBuildAtomicCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr,
|
||||||
LLVMValueRef cmp, LLVMValueRef val,
|
LLVMValueRef cmp, LLVMValueRef val,
|
||||||
|
|
@ -117,36 +187,12 @@ LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr,
|
||||||
{
|
{
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
AtomicOrdering ordering_enum;
|
AtomicOrdering atomic_order = atomic_ordering_from_string(ordering);
|
||||||
|
SynchronizationScope sync_scope = sync_scope_from_int(crossthread);
|
||||||
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(
|
Value * inst = unwrap(builder)->CreateAtomicCmpXchg(
|
||||||
unwrap(ptr), unwrap(cmp), unwrap(val),
|
unwrap(ptr), unwrap(cmp), unwrap(val),
|
||||||
ordering_enum, crossthread_enum);
|
atomic_order, sync_scope);
|
||||||
return wrap(inst);
|
return wrap(inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,12 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wraps IRBuilder::CreateAtomicRMW
|
||||||
|
*/
|
||||||
|
LLVMValueRef LLVMBuildAtomicRMW(LLVMBuilderRef builder, const char * op,
|
||||||
|
LLVMValueRef ptr, LLVMValueRef val,
|
||||||
|
const char* ordering, int crossthread);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wraps IRBuilder::CreateAtomicCmpXchg
|
* Wraps IRBuilder::CreateAtomicCmpXchg
|
||||||
|
|
|
||||||
26
llvm/wrap.h
26
llvm/wrap.h
|
|
@ -699,6 +699,32 @@ _w ## func (PyObject *self, PyObject *args) \
|
||||||
return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4, arg5, arg6)); \
|
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, <unsigned/signed int> 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
|
* Wrap LLVM functions of the type
|
||||||
* outtype func(intype1 arg1, intype2 arg2, intype3 arg3, <unsigned/signed int> arg4)
|
* outtype func(intype1 arg1, intype2 arg2, intype3 arg3, <unsigned/signed int> arg4)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
from llvm.core import *
|
from llvm.core import *
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
test_these_orderings = filter(bool, map(lambda s:s.strip(),
|
test_these_orderings = list(filter(bool, map(lambda s:s.strip(),
|
||||||
'''
|
'''
|
||||||
unordered
|
unordered
|
||||||
monotonic
|
monotonic
|
||||||
|
|
@ -9,10 +9,25 @@ acquire
|
||||||
release
|
release
|
||||||
acq_rel
|
acq_rel
|
||||||
seq_cst
|
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):
|
class TestAtomic(unittest.TestCase):
|
||||||
def test_atomic(self):
|
def test_atomic_cmpxchg(self):
|
||||||
mod = Module.new('mod')
|
mod = Module.new('mod')
|
||||||
functype = Type.function(Type.void(), [])
|
functype = Type.function(Type.void(), [])
|
||||||
func = mod.add_function(functype, name='foo')
|
func = mod.add_function(functype, name='foo')
|
||||||
|
|
@ -26,11 +41,34 @@ class TestAtomic(unittest.TestCase):
|
||||||
|
|
||||||
for ordering in test_these_orderings:
|
for ordering in test_these_orderings:
|
||||||
inst = bldr.atomic_cmpxchg(ptr, old, new, ordering)
|
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)
|
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__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue