From fac1bc782d1283aa107cac66f1f1586007d18831 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 4 Oct 2013 14:55:56 +0800 Subject: [PATCH] Reorganize and cleanup tests --- llvm/tests/__init__.py | 26 +- llvm/tests/support.py | 34 + llvm/tests/test_arg_attr.py | 24 + llvm/tests/test_arith.py | 74 ++ llvm/tests/test_asm.py | 58 + llvm/tests/test_atomic.py | 85 ++ llvm/tests/test_attr.py | 33 + llvm/tests/test_cmp.py | 26 + llvm/tests/test_const_expr.py | 23 + llvm/tests/test_cpu_support.py | 90 ++ llvm/tests/test_engine_builder.py | 65 ++ llvm/tests/test_exact.py | 37 + llvm/tests/test_execution_engine.py | 47 + llvm/tests/test_inlining.py | 34 + llvm/tests/test_intrinsic.py | 113 ++ llvm/tests/test_intrinsic_basic.py | 99 ++ llvm/tests/test_issue_10.py | 26 + llvm/tests/test_llrt.py | 34 + llvm/tests/test_llvmpy.py | 1583 --------------------------- llvm/tests/test_mcjit.py | 73 ++ llvm/tests/test_metadata.py | 25 + llvm/tests/test_named_metadata.py | 20 + llvm/tests/test_native.py | 81 ++ llvm/tests/test_nuw_nsw.py | 48 + llvm/tests/test_obj_cache.py | 107 ++ llvm/tests/test_opaque.py | 38 + llvm/tests/test_operands.py | 66 ++ llvm/tests/test_passes.py | 143 +++ llvm/tests/test_struct.py | 15 + llvm/tests/test_struct_args.py | 12 +- llvm/tests/test_switch.py | 36 + llvm/tests/test_target_machines.py | 62 ++ llvm/tests/test_type_hash.py | 30 + llvm/tests/test_uses.py | 43 + llvm/tests/test_volatile.py | 59 + setup.py | 3 +- 36 files changed, 1780 insertions(+), 1592 deletions(-) create mode 100644 llvm/tests/support.py create mode 100644 llvm/tests/test_arg_attr.py create mode 100644 llvm/tests/test_arith.py create mode 100644 llvm/tests/test_asm.py create mode 100644 llvm/tests/test_atomic.py create mode 100644 llvm/tests/test_attr.py create mode 100644 llvm/tests/test_cmp.py create mode 100644 llvm/tests/test_const_expr.py create mode 100644 llvm/tests/test_cpu_support.py create mode 100644 llvm/tests/test_engine_builder.py create mode 100644 llvm/tests/test_exact.py create mode 100644 llvm/tests/test_execution_engine.py create mode 100644 llvm/tests/test_inlining.py create mode 100644 llvm/tests/test_intrinsic.py create mode 100644 llvm/tests/test_intrinsic_basic.py create mode 100644 llvm/tests/test_issue_10.py create mode 100644 llvm/tests/test_llrt.py delete mode 100644 llvm/tests/test_llvmpy.py create mode 100644 llvm/tests/test_mcjit.py create mode 100644 llvm/tests/test_metadata.py create mode 100644 llvm/tests/test_named_metadata.py create mode 100644 llvm/tests/test_native.py create mode 100644 llvm/tests/test_nuw_nsw.py create mode 100644 llvm/tests/test_obj_cache.py create mode 100644 llvm/tests/test_opaque.py create mode 100644 llvm/tests/test_operands.py create mode 100644 llvm/tests/test_passes.py create mode 100644 llvm/tests/test_struct.py create mode 100644 llvm/tests/test_switch.py create mode 100644 llvm/tests/test_target_machines.py create mode 100644 llvm/tests/test_type_hash.py create mode 100644 llvm/tests/test_uses.py create mode 100644 llvm/tests/test_volatile.py diff --git a/llvm/tests/__init__.py b/llvm/tests/__init__.py index e6967fe..35670d1 100644 --- a/llvm/tests/__init__.py +++ b/llvm/tests/__init__.py @@ -2,10 +2,16 @@ from __future__ import print_function import sys import os import unittest +import subprocess import llvm tests = [] +# Isolated tests +# Tests that affect process-wide settings +isolated_tests = [] + + def run(verbosity=1): print('llvmpy is installed in: ' + os.path.dirname(__file__)) print('llvmpy version: ' + llvm.__version__) @@ -24,8 +30,24 @@ def run(verbosity=1): # The default stream fails in IPython qtconsole on Windows, # so just using sys.stdout - runner = unittest.TextTestRunner(verbosity=verbosity, stream=sys.stdout) - return runner.run(suite) + + kwargs = dict(verbosity=verbosity, stream=sys.stdout) + + if sys.version_info[:2] > (2, 6): + kwargs['buffer'] = True + runner = unittest.TextTestRunner(**kwargs) + testresult = runner.run(suite) + + if testresult: + # Run isolated tests + print("run isolated tests".center(80, '-')) + + for test in isolated_tests: + print(('testing %s' % test).center(80)) + subprocess.check_call([sys.executable, '-m', test]) + + return testresult + if __name__ == '__main__': unittest.main() diff --git a/llvm/tests/support.py b/llvm/tests/support.py new file mode 100644 index 0000000..a661a85 --- /dev/null +++ b/llvm/tests/support.py @@ -0,0 +1,34 @@ +import sys +import unittest +import contextlib +from llvm.tests import tests, isolated_tests # re-expose symbol + +IS_PY3K = sys.version_info[0] >= 3 +BITS = tuple.__itemsize__ * 8 + +if sys.version_info[:2] <= (2, 6): + # create custom TestCase + class TestCase(unittest.TestCase): + def assertIn(self, item, container): + self.assertTrue(item in container) + + def assertNotIn(self, item, container): + self.assertFalse(item in container) + + def assertLess(self, a, b): + self.assertTrue(a < b) + + def assertIs(self, a, b): + self.assertTrue(a is b) + + @contextlib.contextmanager + def assertRaises(self, exc): + try: + yield + except exc: + pass + else: + raise self.failureException("Did not raise %s" % exc) + +else: + TestCase = unittest.TestCase diff --git a/llvm/tests/test_arg_attr.py b/llvm/tests/test_arg_attr.py new file mode 100644 index 0000000..c388bd4 --- /dev/null +++ b/llvm/tests/test_arg_attr.py @@ -0,0 +1,24 @@ +import unittest +from llvm.core import Module, Type +import llvm.core as lc +from .support import TestCase, tests + +class TestArgAttr(TestCase): + def test_arg_attr(self): + m = Module.new('oifjda') + vptr = Type.pointer(Type.float()) + fnty = Type.function(Type.void(), [vptr] * 5) + func = m.add_function(fnty, 'foo') + attrs = [lc.ATTR_STRUCT_RET, lc.ATTR_BY_VAL, lc.ATTR_NEST, + lc.ATTR_NO_ALIAS, lc.ATTR_NO_CAPTURE] + for i, attr in enumerate(attrs): + arg = func.args[i] + self.assertEqual(i, arg.arg_no) + arg.add_attribute(attr) + self.assertTrue(attr in func.args[i]) + +tests.append(TestArgAttr) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_arith.py b/llvm/tests/test_arith.py new file mode 100644 index 0000000..c6043ff --- /dev/null +++ b/llvm/tests/test_arith.py @@ -0,0 +1,74 @@ +import unittest +import llvm +from llvm.core import (Module, Type, Builder) +from llvm.ee import EngineBuilder +from .support import TestCase, tests, BITS + +class TestArith(TestCase): + ''' + Test basic arithmetic support with LLVM MCJIT + ''' + def func_template(self, ty, op): + m = Module.new('dofjaa') + fnty = Type.function(ty, [ty, ty]) + fn = m.add_function(fnty, 'foo') + bldr = Builder.new(fn.append_basic_block('')) + bldr.ret(getattr(bldr, op)(*fn.args)) + + engine = EngineBuilder.new(m).mcjit(True).create() + ptr = engine.get_pointer_to_function(fn) + + from ctypes import c_uint32, c_uint64, c_float, c_double, CFUNCTYPE + + maptypes = { + Type.int(32): c_uint32, + Type.int(64): c_uint64, + Type.float(): c_float, + Type.double(): c_double, + } + cty = maptypes[ty] + prototype = CFUNCTYPE(*[cty] * 3) + callee = prototype(ptr) + callee(12, 23) + + def template(self, iop, fop): + inttys = [Type.int(32), Type.int(64)] + flttys = [Type.float(), Type.double()] + + if iop: + for ty in inttys: + self.func_template(ty, iop) + if fop: + for ty in flttys: + self.func_template(ty, fop) + + def test_add(self): + self.template('add', 'fadd') + + def test_sub(self): + self.template('sub', 'fsub') + + def test_mul(self): + self.template('mul', 'fmul') + + def test_div(self): + if BITS == 32: + print('skipped test for div') + print('known failure due to unresolved external symbol __udivdi3') + return + self.template('udiv', None) # 'fdiv') + + def test_rem(self): + if BITS == 32: + print('skipped test for rem') + print('known failure due to unresolved external symbol __umoddi3') + return + self.template('urem', None) # 'frem') + +if llvm.version >= (3, 3): + # MCJIT is broken in 3.2 + tests.append(TestArith) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_asm.py b/llvm/tests/test_asm.py new file mode 100644 index 0000000..d4e02fb --- /dev/null +++ b/llvm/tests/test_asm.py @@ -0,0 +1,58 @@ +import os +import unittest +import tempfile +import shutil +from llvm.core import Module, Type +from .support import TestCase, tests + +class TestAsm(TestCase): + def setUp(self): + self.tmpdir = tempfile.mkdtemp() + + def tearDown(self): + shutil.rmtree(self.tmpdir) + + def test_asm(self): + # create a module + m = Module.new('module1') + m.add_global_variable(Type.int(), 'i') + + # write it's assembly representation to a file + asm = str(m) + + testasm_ll = os.path.join(self.tmpdir, 'testasm.ll') + with open(testasm_ll, "w") as fout: + fout.write(asm) + + # read it back into a module + with open(testasm_ll) as fin: + m2 = Module.from_assembly(fin) + # The default `m.id` is ''. + m2.id = m.id # Copy the name from `m` + + self.assertEqual(str(m2).strip(), asm.strip()) + + def test_bitcode(self): + # create a module + m = Module.new('module1') + m.add_global_variable(Type.int(), 'i') + + # write it's assembly representation to a file + asm = str(m) + + testasm_bc = os.path.join(self.tmpdir, 'testasm.bc') + with open(testasm_bc, "wb") as fout: + m.to_bitcode(fout) + + # read it back into a module + with open(testasm_bc, "rb") as fin: + m2 = Module.from_bitcode(fin) + # The default `m.id` is ''. + m2.id = m.id # Copy the name from `m` + + self.assertEqual(str(m2).strip(), asm.strip()) + +tests.append(TestAsm) + +if __name__ == '__main__': + unittest.main() diff --git a/llvm/tests/test_atomic.py b/llvm/tests/test_atomic.py new file mode 100644 index 0000000..2a2f402 --- /dev/null +++ b/llvm/tests/test_atomic.py @@ -0,0 +1,85 @@ +import unittest +from llvm.core import (Module, Type, Builder, Constant) +from .support import TestCase, tests + +class TestAtomic(TestCase): + orderings = ['unordered', 'monotonic', 'acquire', + 'release', 'acq_rel', 'seq_cst'] + + atomic_op = ['xchg', 'add', 'sub', 'and', 'nand', 'or', 'xor', + 'max', 'min', 'umax', 'umin'] + + 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 self.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()) + + val = Constant.int(Type.int(), 1234) + + for ordering in self.orderings: + inst = bldr.atomic_rmw('xchg', ptr, val, ordering) + self.assertEqual(ordering, str(inst).split(' ')[-1]) + + for op in self.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 self.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()) + + for ordering in self.orderings: + loaded = bldr.atomic_load(ptr, ordering) + self.assert_('load atomic' in str(loaded)) + self.assertEqual(ordering, + str(loaded).strip().split(' ')[-3].rstrip(',')) + self.assert_('align 1' in str(loaded)) + + stored = bldr.atomic_store(loaded, ptr, ordering) + self.assert_('store atomic' in str(stored)) + self.assertEqual(ordering, + str(stored).strip().split(' ')[-3].rstrip(',')) + self.assert_('align 1' in str(stored)) + + fenced = bldr.fence(ordering) + self.assertEqual(['fence', ordering], + str(fenced).strip().split(' ')) + +tests.append(TestAtomic) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_attr.py b/llvm/tests/test_attr.py new file mode 100644 index 0000000..d1df700 --- /dev/null +++ b/llvm/tests/test_attr.py @@ -0,0 +1,33 @@ +import unittest +try: + from StringIO import StringIO +except ImportError: + from io import StringIO + +from llvm.core import Module +from .support import TestCase, tests + +class TestAttr(TestCase): + def make_module(self): + test_module = """ + define void @sum(i32*, i32*) { + entry: + ret void + } + """ + buf = StringIO(test_module) + return Module.from_assembly(buf) + + def test_align(self): + m = self.make_module() + f = m.get_function_named('sum') + f.args[0].alignment = 16 + self.assert_("align 16" in str(f)) + self.assertEqual(f.args[0].alignment, 16) + +tests.append(TestAttr) + + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_cmp.py b/llvm/tests/test_cmp.py new file mode 100644 index 0000000..85cf1f0 --- /dev/null +++ b/llvm/tests/test_cmp.py @@ -0,0 +1,26 @@ +import unittest +from llvm.core import (Module, Type, Builder, Constant) +import llvm.core as lc +from .support import TestCase, tests + +class TestCmp(TestCase): + def test_arg_attr(self): + m = Module.new('oifjda') + fnty = Type.function(Type.void(), [Type.int()]) + func = m.add_function(fnty, 'foo') + bb = func.append_basic_block('') + bldr = Builder.new(bb) + + cmpinst = bldr.icmp(lc.ICMP_ULE, func.args[0], + Constant.int(Type.int(), 123)) + self.assertTrue(repr(cmpinst.predicate).startswith('ICMP_ULE')) + self.assertEqual(cmpinst.predicate, lc.ICMP_ULE) + bldr.ret_void() + + func.verify() + +tests.append(TestCmp) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_const_expr.py b/llvm/tests/test_const_expr.py new file mode 100644 index 0000000..c398573 --- /dev/null +++ b/llvm/tests/test_const_expr.py @@ -0,0 +1,23 @@ +import unittest +from llvm.core import (Module, Type, Builder, Constant) +import llvm.core as lc + +from .support import TestCase, tests + +class TestConstExpr(TestCase): + + def test_constexpr_opcode(self): + mod = Module.new('test_constexpr_opcode') + func = mod.add_function(Type.function(Type.void(), []), name="foo") + builder = Builder.new(func.append_basic_block('entry')) + a = builder.inttoptr(Constant.int(Type.int(), 123), + Type.pointer(Type.int())) + self.assertTrue(isinstance(a, lc.ConstantExpr)) + self.assertEqual(a.opcode, lc.OPCODE_INTTOPTR) + self.assertEqual(a.opcode_name, "inttoptr") + +tests.append(TestConstExpr) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_cpu_support.py b/llvm/tests/test_cpu_support.py new file mode 100644 index 0000000..3ec9c9c --- /dev/null +++ b/llvm/tests/test_cpu_support.py @@ -0,0 +1,90 @@ +import unittest +import math +from llvm.core import (Module, Type, Function, Builder, + Constant) +from llvm.ee import EngineBuilder +import llvm.core as lc +import llvm.ee as le +from .support import TestCase, tests + +class TestCPUSupport(TestCase): + + def _build_test_module(self): + mod = Module.new('test') + + float = Type.double() + mysinty = Type.function( float, [float] ) + mysin = mod.add_function(mysinty, "mysin") + block = mysin.append_basic_block("entry") + b = Builder.new(block) + + sqrt = Function.intrinsic(mod, lc.INTR_SQRT, [float]) + pow = Function.intrinsic(mod, lc.INTR_POWI, [float]) + cos = Function.intrinsic(mod, lc.INTR_COS, [float]) + + mysin.args[0].name = "x" + x = mysin.args[0] + one = Constant.real(float, "1") + cosx = b.call(cos, [x], "cosx") + cos2 = b.call(pow, [cosx, Constant.int(Type.int(), 2)], "cos2") + onemc2 = b.fsub(one, cos2, "onemc2") # Should use fsub + sin = b.call(sqrt, [onemc2], "sin") + b.ret(sin) + return mod, mysin + + def _template(self, mattrs): + mod, func = self._build_test_module() + ee = self._build_engine(mod, mattrs=mattrs) + arg = le.GenericValue.real(Type.double(), 1.234) + retval = ee.run_function(func, [arg]) + + golden = math.sin(1.234) + answer = retval.as_real(Type.double()) + self.assertTrue(abs(answer-golden)/golden < 1e-5) + + + def _build_engine(self, mod, mattrs): + if mattrs: + return EngineBuilder.new(mod).mattrs(mattrs).create() + else: + return EngineBuilder.new(mod).create() + + def test_cpu_support2(self): + features = 'sse3', 'sse41', 'sse42', 'avx' + mattrs = ','.join(map(lambda s: '-%s' % s, features)) + print('disable mattrs', mattrs) + self._template(mattrs) + + def test_cpu_support3(self): + features = 'sse41', 'sse42', 'avx' + mattrs = ','.join(map(lambda s: '-%s' % s, features)) + print('disable mattrs', mattrs) + self._template(mattrs) + + def test_cpu_support4(self): + features = 'sse42', 'avx' + mattrs = ','.join(map(lambda s: '-%s' % s, features)) + print('disable mattrs', mattrs) + self._template(mattrs) + + def test_cpu_support5(self): + features = 'avx', + mattrs = ','.join(map(lambda s: '-%s' % s, features)) + print('disable mattrs', mattrs) + self._template(mattrs) + + def test_cpu_support6(self): + features = [] + from llvm.workaround.avx_support import detect_avx_support + if not detect_avx_support(): + print('Skipping: no AVX') + else: + mattrs = ','.join(map(lambda s: '-%s' % s, features)) + print('disable mattrs', mattrs) + self._template(mattrs) + +tests.append(TestCPUSupport) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_engine_builder.py b/llvm/tests/test_engine_builder.py new file mode 100644 index 0000000..24037d6 --- /dev/null +++ b/llvm/tests/test_engine_builder.py @@ -0,0 +1,65 @@ +import unittest +from llvm.core import Module, Type, Builder, Constant +from llvm.ee import EngineBuilder +import llvm.ee as le +import llvmpy + +from .support import TestCase, tests + +class TestEngineBuilder(TestCase): + + def make_test_module(self): + module = Module.new("testmodule") + fnty = Type.function(Type.int(), []) + function = module.add_function(fnty, 'foo') + bb_entry = function.append_basic_block('entry') + builder = Builder.new(bb_entry) + builder.ret(Constant.int(Type.int(), 0xcafe)) + module.verify() + return module + + def run_foo(self, ee, module): + function = module.get_function_named('foo') + retval = ee.run_function(function, []) + self.assertEqual(retval.as_int(), 0xcafe) + + + def test_enginebuilder_basic(self): + module = self.make_test_module() + self.assertTrue(llvmpy.capsule.has_ownership(module._ptr._ptr)) + ee = EngineBuilder.new(module).create() + self.assertFalse(llvmpy.capsule.has_ownership(module._ptr._ptr)) + self.run_foo(ee, module) + + + def test_enginebuilder_with_tm(self): + tm = le.TargetMachine.new() + module = self.make_test_module() + self.assertTrue(llvmpy.capsule.has_ownership(module._ptr._ptr)) + ee = EngineBuilder.new(module).create(tm) + self.assertFalse(llvmpy.capsule.has_ownership(module._ptr._ptr)) + self.run_foo(ee, module) + + def test_enginebuilder_force_jit(self): + module = self.make_test_module() + ee = EngineBuilder.new(module).force_jit().create() + + self.run_foo(ee, module) +# +# def test_enginebuilder_force_interpreter(self): +# module = self.make_test_module() +# ee = EngineBuilder.new(module).force_interpreter().create() +# +# self.run_foo(ee, module) + + def test_enginebuilder_opt(self): + module = self.make_test_module() + ee = EngineBuilder.new(module).opt(3).create() + + self.run_foo(ee, module) + +tests.append(TestEngineBuilder) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_exact.py b/llvm/tests/test_exact.py new file mode 100644 index 0000000..db711a5 --- /dev/null +++ b/llvm/tests/test_exact.py @@ -0,0 +1,37 @@ +import unittest +from llvm.core import (Module, Type, Builder) +from .support import TestCase, tests + +class TestExact(TestCase): + def make_module(self): + mod = Module.new('asdfa') + fnty = Type.function(Type.void(), [Type.int()] * 2) + func = mod.add_function(fnty, 'foo') + bldr = Builder.new(func.append_basic_block('')) + return mod, func, bldr + + def has_exact(self, inst, op): + self.assertTrue(('%s exact' % op) in str(inst), "exact flag does not work") + + def _test_template(self, opf, opname): + mod, func, bldr = self.make_module() + a, b = func.args + self.has_exact(opf(bldr, a, b, exact=True), opname) + + def test_udiv_exact(self): + self._test_template(Builder.udiv, 'udiv') + + def test_sdiv_exact(self): + self._test_template(Builder.sdiv, 'sdiv') + + def test_lshr_exact(self): + self._test_template(Builder.lshr, 'lshr') + + def test_ashr_exact(self): + self._test_template(Builder.ashr, 'ashr') + +tests.append(TestExact) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_execution_engine.py b/llvm/tests/test_execution_engine.py new file mode 100644 index 0000000..446b25f --- /dev/null +++ b/llvm/tests/test_execution_engine.py @@ -0,0 +1,47 @@ +import unittest +from llvm.core import Type +import llvm.core as lc +import llvm.ee as le + +from .support import TestCase, tests + +class TestExecutionEngine(TestCase): + def test_get_pointer_to_global(self): + module = lc.Module.new(str(self)) + gvar = module.add_global_variable(Type.int(), 'hello') + X = 1234 + gvar.initializer = lc.Constant.int(Type.int(), X) + + ee = le.ExecutionEngine.new(module) + ptr = ee.get_pointer_to_global(gvar) + from ctypes import c_void_p, cast, c_int, POINTER + casted = cast(c_void_p(ptr), POINTER(c_int)) + self.assertEqual(X, casted[0]) + + def test_add_global_mapping(self): + module = lc.Module.new(str(self)) + gvar = module.add_global_variable(Type.int(), 'hello') + + fnty = lc.Type.function(Type.int(), []) + foo = module.add_function(fnty, name='foo') + bldr = lc.Builder.new(foo.append_basic_block('entry')) + bldr.ret(bldr.load(gvar)) + + ee = le.ExecutionEngine.new(module) + from ctypes import c_int, addressof, CFUNCTYPE + value = 0xABCD + value_ctype = c_int(value) + value_pointer = addressof(value_ctype) + + ee.add_global_mapping(gvar, value_pointer) + + foo_addr = ee.get_pointer_to_function(foo) + prototype = CFUNCTYPE(c_int) + foo_callable = prototype(foo_addr) + self.assertEqual(foo_callable(), value) + +tests.append(TestExecutionEngine) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_inlining.py b/llvm/tests/test_inlining.py new file mode 100644 index 0000000..3104da8 --- /dev/null +++ b/llvm/tests/test_inlining.py @@ -0,0 +1,34 @@ +import unittest +from llvm.core import (Module, Type, Builder, Constant, inline_function) +from .support import TestCase, tests + +class TestInlining(TestCase): + def test_inline_call(self): + mod = Module.new(__name__) + callee = mod.add_function(Type.function(Type.int(), [Type.int()]), + name='bar') + + builder = Builder.new(callee.append_basic_block('entry')) + builder.ret(builder.add(callee.args[0], callee.args[0])) + + caller = mod.add_function(Type.function(Type.int(), []), + name='foo') + + builder = Builder.new(caller.append_basic_block('entry')) + callinst = builder.call(callee, [Constant.int(Type.int(), 1234)]) + builder.ret(callinst) + + pre_inlining = str(caller) + self.assertIn('call', pre_inlining) + + self.assertTrue(inline_function(callinst)) + + post_inlining = str(caller) + self.assertNotIn('call', post_inlining) + self.assertIn('2468', post_inlining) + +tests.append(TestInlining) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_intrinsic.py b/llvm/tests/test_intrinsic.py new file mode 100644 index 0000000..e30bd49 --- /dev/null +++ b/llvm/tests/test_intrinsic.py @@ -0,0 +1,113 @@ +import unittest +import sys +import math +from llvm.core import (Module, Type, Function, Builder, Constant) +import llvm.core as lc +import llvm.ee as le +from .support import TestCase, tests, BITS + +class TestIntrinsic(TestCase): + def test_bswap(self): + # setup a function and a builder + mod = Module.new('test') + functy = Type.function(Type.int(), []) + func = mod.add_function(functy, "showme") + block = func.append_basic_block("entry") + b = Builder.new(block) + + # let's do bswap on a 32-bit integer using llvm.bswap + val = Constant.int(Type.int(), 0x42) + bswap = Function.intrinsic(mod, lc.INTR_BSWAP, [Type.int()]) + + bswap_res = b.call(bswap, [val]) + b.ret(bswap_res) + + # logging.debug(mod) + + # the output is: + # + # ; ModuleID = 'test' + # + # define void @showme() { + # entry: + # %0 = call i32 @llvm.bswap.i32(i32 42) + # ret i32 %0 + # } + + # let's run the function + ee = le.ExecutionEngine.new(mod) + retval = ee.run_function(func, []) + self.assertEqual(retval.as_int(), 0x42000000) + + def test_mysin(self): + if sys.platform == 'win32' and BITS == 32: + # float32 support is known to fail on 32-bit Windows + return + + # mysin(x) = sqrt(1.0 - pow(cos(x), 2)) + mod = Module.new('test') + + float = Type.float() + mysinty = Type.function( float, [float] ) + mysin = mod.add_function(mysinty, "mysin") + block = mysin.append_basic_block("entry") + b = Builder.new(block) + + sqrt = Function.intrinsic(mod, lc.INTR_SQRT, [float]) + pow = Function.intrinsic(mod, lc.INTR_POWI, [float]) + cos = Function.intrinsic(mod, lc.INTR_COS, [float]) + + mysin.args[0].name = "x" + x = mysin.args[0] + one = Constant.real(float, "1") + cosx = b.call(cos, [x], "cosx") + cos2 = b.call(pow, [cosx, Constant.int(Type.int(), 2)], "cos2") + onemc2 = b.fsub(one, cos2, "onemc2") # Should use fsub + sin = b.call(sqrt, [onemc2], "sin") + b.ret(sin) + #logging.debug(mod) + +# ; ModuleID = 'test' +# +# define void @showme() { +# entry: +# call i32 @llvm.bswap.i32( i32 42 ) ; :0 [#uses +# } +# +# declare i32 @llvm.bswap.i32(i32) nounwind readnone +# +# define float @mysin(float %x) { +# entry: +# %cosx = call float @llvm.cos.f32( float %x ) ; [#uses +# %sin = call float @llvm.sqrt.f32( float %onemc2 ) +# ret float %sin +# } +# +# declare float @llvm.sqrt.f32(float) nounwind readnone +# +# declare float @llvm.powi.f32(float, i32) nounwind readnone +# +# declare float @llvm.cos.f32(float) nounwind readnone + + # let's run the function + + from llvm.workaround.avx_support import detect_avx_support + if not detect_avx_support(): + ee = le.EngineBuilder.new(mod).mattrs("-avx").create() + else: + ee = le.EngineBuilder.new(mod).create() + + arg = le.GenericValue.real(Type.float(), 1.234) + retval = ee.run_function(mysin, [arg]) + + golden = math.sin(1.234) + answer = retval.as_real(Type.float()) + self.assertTrue(abs(answer-golden)/golden < 1e-5) + +tests.append(TestIntrinsic) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_intrinsic_basic.py b/llvm/tests/test_intrinsic_basic.py new file mode 100644 index 0000000..d89106a --- /dev/null +++ b/llvm/tests/test_intrinsic_basic.py @@ -0,0 +1,99 @@ +import unittest +import sys +import math +from llvm.core import (Module, Type, Function, Builder) +import llvm.core as lc +import llvm.ee as le +from .support import TestCase, BITS, tests + +class TestIntrinsicBasic(TestCase): + + def _build_module(self, float): + mod = Module.new('test') + functy = Type.function(float, [float]) + func = mod.add_function(functy, "mytest%s" % float) + block = func.append_basic_block("entry") + b = Builder.new(block) + return mod, func, b + + def _template(self, mod, func, pyfunc): + float = func.type.pointee.return_type + + from llvm.workaround.avx_support import detect_avx_support + if not detect_avx_support(): + ee = le.EngineBuilder.new(mod).mattrs("-avx").create() + else: + ee = le.EngineBuilder.new(mod).create() + arg = le.GenericValue.real(float, 1.234) + retval = ee.run_function(func, [arg]) + golden = pyfunc(1.234) + answer = retval.as_real(float) + self.assertTrue(abs(answer - golden) / golden < 1e-7) + + def test_sqrt_f32(self): + float = Type.float() + mod, func, b = self._build_module(float) + intr = Function.intrinsic(mod, lc.INTR_SQRT, [float]) + b.ret(b.call(intr, func.args)) + self._template(mod, func, math.sqrt) + + def test_sqrt_f64(self): + float = Type.double() + mod, func, b = self._build_module(float) + intr = Function.intrinsic(mod, lc.INTR_SQRT, [float]) + b.ret(b.call(intr, func.args)) + self._template(mod, func, math.sqrt) + + def test_cos_f32(self): + if sys.platform == 'win32' and BITS == 32: + # float32 support is known to fail on 32-bit Windows + return + float = Type.float() + mod, func, b = self._build_module(float) + intr = Function.intrinsic(mod, lc.INTR_COS, [float]) + b.ret(b.call(intr, func.args)) + self._template(mod, func, math.cos) + + def test_cos_f64(self): + float = Type.double() + mod, func, b = self._build_module(float) + intr = Function.intrinsic(mod, lc.INTR_COS, [float]) + b.ret(b.call(intr, func.args)) + self._template(mod, func, math.cos) + + def test_sin_f32(self): + if sys.platform == 'win32' and BITS == 32: + # float32 support is known to fail on 32-bit Windows + return + float = Type.float() + mod, func, b = self._build_module(float) + intr = Function.intrinsic(mod, lc.INTR_SIN, [float]) + b.ret(b.call(intr, func.args)) + self._template(mod, func, math.sin) + + def test_sin_f64(self): + float = Type.double() + mod, func, b = self._build_module(float) + intr = Function.intrinsic(mod, lc.INTR_SIN, [float]) + b.ret(b.call(intr, func.args)) + self._template(mod, func, math.sin) + + def test_powi_f32(self): + float = Type.float() + mod, func, b = self._build_module(float) + intr = Function.intrinsic(mod, lc.INTR_POWI, [float]) + b.ret(b.call(intr, [func.args[0], lc.Constant.int(Type.int(), 2)])) + self._template(mod, func, lambda x: x**2) + + def test_powi_f64(self): + float = Type.double() + mod, func, b = self._build_module(float) + intr = Function.intrinsic(mod, lc.INTR_POWI, [float]) + b.ret(b.call(intr, [func.args[0], lc.Constant.int(Type.int(), 2)])) + self._template(mod, func, lambda x: x**2) + +tests.append(TestIntrinsicBasic) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_issue_10.py b/llvm/tests/test_issue_10.py new file mode 100644 index 0000000..61b390d --- /dev/null +++ b/llvm/tests/test_issue_10.py @@ -0,0 +1,26 @@ +import unittest +from llvm.core import (Module, Type, Builder) +from .support import TestCase, tests + +class TestIssue10(TestCase): + def test_issue10(self): + m = Module.new('a') + ti = Type.int() + tf = Type.function(ti, [ti, ti]) + + f = m.add_function(tf, "func1") + + bb = f.append_basic_block('entry') + + b = Builder.new(bb) + + # There are no instructions in bb. Positioning of the + # builder at beginning (or end) should succeed (trivially). + b.position_at_end(bb) + b.position_at_beginning(bb) + +tests.append(TestIssue10) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_llrt.py b/llvm/tests/test_llrt.py new file mode 100644 index 0000000..2b220f5 --- /dev/null +++ b/llvm/tests/test_llrt.py @@ -0,0 +1,34 @@ +import unittest +import llvm.core as lc +import llvm.ee as le +from .support import TestCase, tests + +class TestLLRT(TestCase): + def test_llrt_divmod(self): + from llvm import llrt + m = lc.Module.new('testllrt') + longlong = lc.Type.int(64) + lfunc = m.add_function(lc.Type.function(longlong, [longlong, longlong]), 'foo') + bldr = lc.Builder.new(lfunc.append_basic_block('')) + bldr.ret(bldr.udiv(*lfunc.args)) + + llrt.replace_divmod64(lfunc) + + rt = llrt.LLRT() + rt.install_symbols() + + engine = le.EngineBuilder.new(m).create() + pointer = engine.get_pointer_to_function(lfunc) + + from ctypes import CFUNCTYPE, c_uint64 + func = CFUNCTYPE(c_uint64, c_uint64, c_uint64)(pointer) + a, b = 98342, 2231 + self.assertEqual(func(98342, 2231), 98342 // 2231) + + rt.uninstall_symbols() + +tests.append(TestLLRT) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_llvmpy.py b/llvm/tests/test_llvmpy.py deleted file mode 100644 index b7961e0..0000000 --- a/llvm/tests/test_llvmpy.py +++ /dev/null @@ -1,1583 +0,0 @@ -""" -LLVM tests -""" -import os -import sys -import math -import shutil -import unittest -import subprocess -import tempfile -import contextlib -from distutils.spawn import find_executable -from . import tests - -is_py3k = sys.version_info[0] >= 3 -BITS = tuple.__itemsize__ * 8 - -try: - from StringIO import StringIO -except ImportError: - from io import StringIO - - -import llvm -from llvm.core import (Module, Type, GlobalVariable, Function, Builder, - Constant, MetaData, MetaDataString, inline_function) -from llvm.ee import EngineBuilder -import llvm.core as lc -import llvm.passes as lp -import llvm.ee as le -import llvmpy - - -# --------------------------------------------------------------------------- - -if sys.version_info[:2] <= (2, 6): - # create custom TestCase - class TestCase(unittest.TestCase): - def assertIn(self, item, container): - self.assertTrue(item in container) - - def assertNotIn(self, item, container): - self.assertFalse(item in container) - - def assertLess(self, a, b): - self.assertTrue(a < b) - - def assertIs(self, a, b): - self.assertTrue(a is b) - - @contextlib.contextmanager - def assertRaises(self, exc): - try: - yield - except exc: - pass - else: - raise self.failureException("Did not raise %s" % exc) - -else: - TestCase = unittest.TestCase - - -# --------------------------------------------------------------------------- - -class TestAsm(TestCase): - def setUp(self): - self.tmpdir = tempfile.mkdtemp() - - def tearDown(self): - shutil.rmtree(self.tmpdir) - - def test_asm(self): - # create a module - m = Module.new('module1') - m.add_global_variable(Type.int(), 'i') - - # write it's assembly representation to a file - asm = str(m) - - testasm_ll = os.path.join(self.tmpdir, 'testasm.ll') - with open(testasm_ll, "w") as fout: - fout.write(asm) - - # read it back into a module - with open(testasm_ll) as fin: - m2 = Module.from_assembly(fin) - # The default `m.id` is ''. - m2.id = m.id # Copy the name from `m` - - self.assertEqual(str(m2).strip(), asm.strip()) - - def test_bitcode(self): - # create a module - m = Module.new('module1') - m.add_global_variable(Type.int(), 'i') - - # write it's assembly representation to a file - asm = str(m) - - testasm_bc = os.path.join(self.tmpdir, 'testasm.bc') - with open(testasm_bc, "wb") as fout: - m.to_bitcode(fout) - - # read it back into a module - with open(testasm_bc, "rb") as fin: - m2 = Module.from_bitcode(fin) - # The default `m.id` is ''. - m2.id = m.id # Copy the name from `m` - - self.assertEqual(str(m2).strip(), asm.strip()) - -tests.append(TestAsm) - -# --------------------------------------------------------------------------- - -class TestAttr(TestCase): - def make_module(self): - test_module = """ - define void @sum(i32*, i32*) { - entry: - ret void - } - """ - buf = StringIO(test_module) - return Module.from_assembly(buf) - - def test_align(self): - m = self.make_module() - f = m.get_function_named('sum') - f.args[0].alignment = 16 - self.assert_("align 16" in str(f)) - self.assertEqual(f.args[0].alignment, 16) - -tests.append(TestAttr) - -# --------------------------------------------------------------------------- - -class TestAtomic(TestCase): - orderings = ['unordered', 'monotonic', 'acquire', - 'release', 'acq_rel', 'seq_cst'] - - atomic_op = ['xchg', 'add', 'sub', 'and', 'nand', 'or', 'xor', - 'max', 'min', 'umax', 'umin'] - - 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 self.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 self.orderings: - inst = bldr.atomic_rmw('xchg', ptr, val, ordering) - self.assertEqual(ordering, str(inst).split(' ')[-1]) - - for op in self.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 self.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 self.orderings: - loaded = bldr.atomic_load(ptr, ordering) - self.assert_('load atomic' in str(loaded)) - self.assertEqual(ordering, - str(loaded).strip().split(' ')[-3].rstrip(',')) - self.assert_('align 1' in str(loaded)) - - stored = bldr.atomic_store(loaded, ptr, ordering) - self.assert_('store atomic' in str(stored)) - self.assertEqual(ordering, - str(stored).strip().split(' ')[-3].rstrip(',')) - self.assert_('align 1' in str(stored)) - - fenced = bldr.fence(ordering) - self.assertEqual(['fence', ordering], - str(fenced).strip().split(' ')) - -tests.append(TestAtomic) - -# --------------------------------------------------------------------------- - -class TestConstExpr(TestCase): - - def test_constexpr_opcode(self): - mod = Module.new('test_constexpr_opcode') - func = mod.add_function(Type.function(Type.void(), []), name="foo") - builder = Builder.new(func.append_basic_block('entry')) - a = builder.inttoptr(Constant.int(Type.int(), 123), - Type.pointer(Type.int())) - self.assertTrue(isinstance(a, lc.ConstantExpr)) - self.assertEqual(a.opcode, lc.OPCODE_INTTOPTR) - self.assertEqual(a.opcode_name, "inttoptr") - -tests.append(TestConstExpr) - -# --------------------------------------------------------------------------- - -class TestOperands(TestCase): - # implement a test function - test_module = """ -define i32 @prod(i32, i32) { -entry: - %2 = mul i32 %0, %1 - ret i32 %2 -} - -define i32 @test_func(i32, i32, i32) { -entry: - %tmp1 = call i32 @prod(i32 %0, i32 %1) - %tmp2 = add i32 %tmp1, %2 - %tmp3 = add i32 %tmp2, 1 - %tmp4 = add i32 %tmp3, -1 - %tmp5 = add i64 -81985529216486895, 12297829382473034410 - ret i32 %tmp4 -} -""" - def test_operands(self): - m = Module.from_assembly(StringIO(self.test_module)) - - test_func = m.get_function_named("test_func") - prod = m.get_function_named("prod") - - # test operands - i1 = test_func.basic_blocks[0].instructions[0] - i2 = test_func.basic_blocks[0].instructions[1] - i3 = test_func.basic_blocks[0].instructions[2] - i4 = test_func.basic_blocks[0].instructions[3] - i5 = test_func.basic_blocks[0].instructions[4] - - self.assertEqual(i1.operand_count, 3) - self.assertEqual(i2.operand_count, 2) - - self.assertEqual(i3.operands[1].z_ext_value, 1) - self.assertEqual(i3.operands[1].s_ext_value, 1) - self.assertEqual(i4.operands[1].z_ext_value, 0xffffffff) - self.assertEqual(i4.operands[1].s_ext_value, -1) - self.assertEqual(i5.operands[0].s_ext_value, -81985529216486895) - self.assertEqual(i5.operands[1].z_ext_value, 12297829382473034410) - - self.assert_(i1.operands[-1] is prod) - self.assert_(i1.operands[0] is test_func.args[0]) - self.assert_(i1.operands[1] is test_func.args[1]) - self.assert_(i2.operands[0] is i1) - self.assert_(i2.operands[1] is test_func.args[2]) - self.assertEqual(len(i1.operands), 3) - self.assertEqual(len(i2.operands), 2) - - self.assert_(i1.called_function is prod) - -tests.append(TestOperands) - -# --------------------------------------------------------------------------- - -class TestPasses(TestCase): - # Create a module. - asm = """ - -define i32 @test() nounwind { - ret i32 42 -} - -define i32 @test1() nounwind { -entry: - %tmp = alloca i32 - store i32 42, i32* %tmp, align 4 - %tmp1 = load i32* %tmp, align 4 - %tmp2 = call i32 @test() - %tmp3 = load i32* %tmp, align 4 - %tmp4 = load i32* %tmp, align 4 - ret i32 %tmp1 -} - -define i32 @test2() nounwind { -entry: - %tmp = call i32 @test() - ret i32 %tmp -} -""" - def test_passes(self): - m = Module.from_assembly(StringIO(self.asm)) - - fn_test1 = m.get_function_named('test1') - fn_test2 = m.get_function_named('test2') - - original_test1 = str(fn_test1) - original_test2 = str(fn_test2) - - # Let's run a module-level inlining pass. First, create a pass manager. - pm = lp.PassManager.new() - - # Add the target data as the first "pass". This is mandatory. - pm.add(le.TargetData.new('')) - - # Add the inlining pass. - pm.add(lp.PASS_INLINE) - - # Run it! - pm.run(m) - - # Done with the pass manager. - del pm - - # Make sure test2 is inlined - self.assertNotEqual(str(fn_test2).strip(), original_test2.strip()) - - bb_entry = fn_test2.basic_blocks[0] - - self.assertEqual(len(bb_entry.instructions), 1) - self.assertEqual(bb_entry.instructions[0].opcode_name, 'ret') - - # Let's run a DCE pass on the the function 'test1' now. First create a - # function pass manager. - fpm = lp.FunctionPassManager.new(m) - - # Add the target data as first "pass". This is mandatory. - fpm.add(le.TargetData.new('')) - - # Add a DCE pass - fpm.add(lp.PASS_ADCE) - - # Run the pass on the function 'test1' - fpm.run(m.get_function_named('test1')) - - # Make sure test1 is modified - self.assertNotEqual(str(fn_test1).strip(), original_test1.strip()) - - def test_passes_with_pmb(self): - m = Module.from_assembly(StringIO(self.asm)) - - fn_test1 = m.get_function_named('test1') - fn_test2 = m.get_function_named('test2') - - original_test1 = str(fn_test1) - original_test2 = str(fn_test2) - - # Try out the PassManagerBuilder - - pmb = lp.PassManagerBuilder.new() - - self.assertEqual(pmb.opt_level, 2) # ensure default is level 2 - pmb.opt_level = 3 - self.assertEqual(pmb.opt_level, 3) # make sure it works - - self.assertEqual(pmb.size_level, 0) # ensure default is level 0 - pmb.size_level = 2 - self.assertEqual(pmb.size_level, 2) # make sure it works - - self.assertFalse(pmb.vectorize) # ensure default is False - pmb.vectorize = True - self.assertTrue(pmb.vectorize) # make sure it works - - # make sure the default is False - self.assertFalse(pmb.disable_unit_at_a_time) - self.assertFalse(pmb.disable_unroll_loops) - if llvm.version <= (3, 3): - self.assertFalse(pmb.disable_simplify_lib_calls) - - pmb.disable_unit_at_a_time = True - self.assertTrue(pmb.disable_unit_at_a_time) - - # Do function pass - fpm = lp.FunctionPassManager.new(m) - pmb.populate(fpm) - fpm.run(fn_test1) - - # Make sure test1 has changed - self.assertNotEqual(str(fn_test1).strip(), original_test1.strip()) - - # Do module pass - pm = lp.PassManager.new() - pmb.populate(pm) - pm.run(m) - - # Make sure test2 has changed - self.assertNotEqual(str(fn_test2).strip(), original_test2.strip()) - - def test_dump_passes(self): - self.assertTrue(len(lp.PASSES)>0, msg="Cannot have no passes") - -tests.append(TestPasses) - -# --------------------------------------------------------------------------- - -class TestEngineBuilder(TestCase): - - def make_test_module(self): - module = Module.new("testmodule") - fnty = Type.function(Type.int(), []) - function = module.add_function(fnty, 'foo') - bb_entry = function.append_basic_block('entry') - builder = Builder.new(bb_entry) - builder.ret(Constant.int(Type.int(), 0xcafe)) - module.verify() - return module - - def run_foo(self, ee, module): - function = module.get_function_named('foo') - retval = ee.run_function(function, []) - self.assertEqual(retval.as_int(), 0xcafe) - - - def test_enginebuilder_basic(self): - module = self.make_test_module() - self.assertTrue(llvmpy.capsule.has_ownership(module._ptr._ptr)) - ee = EngineBuilder.new(module).create() - self.assertFalse(llvmpy.capsule.has_ownership(module._ptr._ptr)) - self.run_foo(ee, module) - - - def test_enginebuilder_with_tm(self): - tm = le.TargetMachine.new() - module = self.make_test_module() - self.assertTrue(llvmpy.capsule.has_ownership(module._ptr._ptr)) - ee = EngineBuilder.new(module).create(tm) - self.assertFalse(llvmpy.capsule.has_ownership(module._ptr._ptr)) - self.run_foo(ee, module) - - def test_enginebuilder_force_jit(self): - module = self.make_test_module() - ee = EngineBuilder.new(module).force_jit().create() - - self.run_foo(ee, module) -# -# def test_enginebuilder_force_interpreter(self): -# module = self.make_test_module() -# ee = EngineBuilder.new(module).force_interpreter().create() -# -# self.run_foo(ee, module) - - def test_enginebuilder_opt(self): - module = self.make_test_module() - ee = EngineBuilder.new(module).opt(3).create() - - self.run_foo(ee, module) - -tests.append(TestEngineBuilder) - -# --------------------------------------------------------------------------- - -class TestExecutionEngine(TestCase): - def test_get_pointer_to_global(self): - module = lc.Module.new(str(self)) - gvar = module.add_global_variable(Type.int(), 'hello') - X = 1234 - gvar.initializer = lc.Constant.int(Type.int(), X) - - ee = le.ExecutionEngine.new(module) - ptr = ee.get_pointer_to_global(gvar) - from ctypes import c_void_p, cast, c_int, POINTER - casted = cast(c_void_p(ptr), POINTER(c_int)) - self.assertEqual(X, casted[0]) - - def test_add_global_mapping(self): - module = lc.Module.new(str(self)) - gvar = module.add_global_variable(Type.int(), 'hello') - - fnty = lc.Type.function(Type.int(), []) - foo = module.add_function(fnty, name='foo') - bldr = lc.Builder.new(foo.append_basic_block('entry')) - bldr.ret(bldr.load(gvar)) - - ee = le.ExecutionEngine.new(module) - from ctypes import c_int, addressof, CFUNCTYPE - value = 0xABCD - value_ctype = c_int(value) - value_pointer = addressof(value_ctype) - - ee.add_global_mapping(gvar, value_pointer) - - foo_addr = ee.get_pointer_to_function(foo) - prototype = CFUNCTYPE(c_int) - foo_callable = prototype(foo_addr) - self.assertEqual(foo_callable(), value) - - - -tests.append(TestExecutionEngine) -# --------------------------------------------------------------------------- - -class TestObjCache(TestCase): - - def test_objcache(self): - # Testing module aliasing - m1 = Module.new('a') - t = Type.int() - ft = Type.function(t, [t]) - f1 = m1.add_function(ft, "func") - m2 = f1.module - self.assert_(m1 is m2) - - # Testing global vairable aliasing 1 - gv1 = GlobalVariable.new(m1, t, "gv") - gv2 = GlobalVariable.get(m1, "gv") - self.assert_(gv1 is gv2) - - # Testing global vairable aliasing 2 - gv3 = m1.global_variables[0] - self.assert_(gv1 is gv3) - - # Testing global vairable aliasing 3 - gv2 = None - gv3 = None - - gv1.delete() - - gv4 = GlobalVariable.new(m1, t, "gv") - - self.assert_(gv1 is not gv4) - - # Testing function aliasing 1 - b1 = f1.append_basic_block('entry') - f2 = b1.function - self.assert_(f1 is f2) - - # Testing function aliasing 2 - f3 = m1.get_function_named("func") - self.assert_(f1 is f3) - - # Testing function aliasing 3 - f4 = Function.get_or_insert(m1, ft, "func") - self.assert_(f1 is f4) - - # Testing function aliasing 4 - f5 = Function.get(m1, "func") - self.assert_(f1 is f5) - - # Testing function aliasing 5 - f6 = m1.get_or_insert_function(ft, "func") - self.assert_(f1 is f6) - - # Testing function aliasing 6 - f7 = m1.functions[0] - self.assert_(f1 is f7) - - # Testing argument aliasing - a1 = f1.args[0] - a2 = f1.args[0] - self.assert_(a1 is a2) - - # Testing basic block aliasing 1 - b2 = f1.basic_blocks[0] - self.assert_(b1 is b2) - - # Testing basic block aliasing 2 - b3 = f1.entry_basic_block - self.assert_(b1 is b3) - - # Testing basic block aliasing 3 - b31 = f1.entry_basic_block - self.assert_(b1 is b31) - - # Testing basic block aliasing 4 - bldr = Builder.new(b1) - b4 = bldr.basic_block - self.assert_(b1 is b4) - - # Testing basic block aliasing 5 - i1 = bldr.ret_void() - b5 = i1.basic_block - self.assert_(b1 is b5) - - # Testing instruction aliasing 1 - i2 = b5.instructions[0] - self.assert_(i1 is i2) - - # phi node - phi = bldr.phi(t) - phi.add_incoming(f1.args[0], b1) - v2 = phi.get_incoming_value(0) - b6 = phi.get_incoming_block(0) - - # Testing PHI / basic block aliasing 5 - self.assert_(b1 is b6) - - # Testing PHI / value aliasing - self.assert_(f1.args[0] is v2) - -tests.append(TestObjCache) - -# --------------------------------------------------------------------------- - -class TestTargetMachines(TestCase): - '''Exercise target machines - - Require PTX backend - ''' - def test_native(self): - m, _ = self._build_module() - tm = le.EngineBuilder.new(m).select_target() - - self.assertTrue(tm.target_name) - self.assertTrue(tm.target_data) - self.assertTrue(tm.target_short_description) - self.assertTrue(tm.triple) - self.assertIn('foo', tm.emit_assembly(m)) - self.assertTrue(le.get_host_cpu_name()) - - def test_ptx(self): - if le.initialize_target('PTX', noraise=True): - arch = 'ptx64' - elif le.initialize_target('NVPTX', noraise=True): - arch = 'nvptx64' - else: - return # skip this test - - print(arch) - m, func = self._build_module() - func.calling_convention = lc.CC_PTX_KERNEL # set calling conv - ptxtm = le.TargetMachine.lookup(arch=arch, cpu='sm_20') - self.assertTrue(ptxtm.triple) - self.assertTrue(ptxtm.cpu) - ptxasm = ptxtm.emit_assembly(m) - self.assertIn('foo', ptxasm) - if arch == 'nvptx64': - self.assertIn('.address_size 64', ptxasm) - self.assertIn('sm_20', ptxasm) - - def _build_module(self): - m = Module.new('TestTargetMachines') - - fnty = Type.function(Type.void(), []) - func = m.add_function(fnty, name='foo') - - bldr = Builder.new(func.append_basic_block('entry')) - bldr.ret_void() - m.verify() - return m, func - - def _build_bad_archname(self): - with self.assertRaises(RuntimeError): - tm = TargetMachine.lookup("ain't no arch name") - -tests.append(TestTargetMachines) - -# --------------------------------------------------------------------------- - -class TestNative(TestCase): - - def setUp(self): - self.tmpdir = tempfile.mkdtemp() - - def tearDown(self): - shutil.rmtree(self.tmpdir) - - - def _make_module(self): - m = Module.new('module1') - m.add_global_variable(Type.int(), 'i') - - fty = Type.function(Type.int(), []) - f = m.add_function(fty, name='main') - - bldr = Builder.new(f.append_basic_block('entry')) - bldr.ret(Constant.int(Type.int(), 0xab)) - - return m - - def _compile(self, src): - cc = find_executable('cc') - if not cc: - return - - dst = os.path.join(self.tmpdir, 'llvmobj.out') - s = subprocess.call([cc, '-o', dst, src]) - if s != 0: - raise Exception("Cannot compile") - - s = subprocess.call([dst]) - self.assertEqual(s, 0xab) - - def test_assembly(self): - if sys.platform == 'darwin': - # skip this test on MacOSX for now - return - - m = self._make_module() - output = m.to_native_assembly() - - src = os.path.join(self.tmpdir, 'llvmasm.s') - with open(src, 'wb') as fout: - if is_py3k: - fout.write(output.encode('utf-8')) - else: - fout.write(output) - - self._compile(src) - - def test_object(self): - if sys.platform == 'darwin': - # skip this test on MacOSX for now - return - - m = self._make_module() - output = m.to_native_object() - - src = os.path.join(self.tmpdir, 'llvmobj.o') - with open(src, 'wb') as fout: - fout.write(output) - - self._compile(src) - -if sys.platform != 'win32': - tests.append(TestNative) - -# --------------------------------------------------------------------------- - -class TestNativeAsm(TestCase): - - def test_asm(self): - m = Module.new('module1') - - foo = m.add_function(Type.function(Type.int(), - [Type.int(), Type.int()]), - name="foo") - bldr = Builder.new(foo.append_basic_block('entry')) - x = bldr.add(foo.args[0], foo.args[1]) - bldr.ret(x) - - att_syntax = m.to_native_assembly() - os.environ["LLVMPY_OPTIONS"] = "-x86-asm-syntax=intel" - lc.parse_environment_options(sys.argv[0], "LLVMPY_OPTIONS") - intel_syntax = m.to_native_assembly() - - self.assertNotEqual(att_syntax, intel_syntax) - -tests.append(TestNativeAsm) - -# --------------------------------------------------------------------------- - -class TestUses(TestCase): - - def test_uses(self): - m = Module.new('a') - t = Type.int() - ft = Type.function(t, [t, t, t]) - f = m.add_function(ft, "func") - b = f.append_basic_block('entry') - bld = Builder.new(b) - tmp1 = bld.add(Constant.int(t, 100), f.args[0], "tmp1") - tmp2 = bld.add(tmp1, f.args[1], "tmp2") - tmp3 = bld.add(tmp1, f.args[2], "tmp3") - bld.ret(tmp3) - - # 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) - self.assertEqual(tmp1.use_count, 2) - self.assertEqual(tmp2.use_count, 0) - self.assertEqual(tmp3.use_count, 1) - - # Testing uses - self.assert_(f.args[0].uses[0] is tmp1) - self.assertEqual(len(f.args[0].uses), 1) - self.assert_(f.args[1].uses[0] is tmp2) - self.assertEqual(len(f.args[1].uses), 1) - self.assert_(f.args[2].uses[0] is tmp3) - self.assertEqual(len(f.args[2].uses), 1) - self.assertEqual(len(tmp1.uses), 2) - self.assertEqual(len(tmp2.uses), 0) - self.assertEqual(len(tmp3.uses), 1) - -tests.append(TestUses) - -# --------------------------------------------------------------------------- - -class TestMetaData(TestCase): - # test module metadata - def test_metadata(self): - m = Module.new('a') - t = Type.int() - metadata = MetaData.get(m, [Constant.int(t, 100), - MetaDataString.get(m, 'abcdef'), - None]) - MetaData.add_named_operand(m, 'foo', metadata) - self.assertEqual(MetaData.get_named_operands(m, 'foo'), [metadata]) - self.assertEqual(MetaData.get_named_operands(m, 'bar'), []) - self.assertEqual(len(metadata.operands), 3) - self.assertEqual(metadata.operands[0].z_ext_value, 100) - self.assertEqual(metadata.operands[1].string, 'abcdef') - self.assertTrue(metadata.operands[2] is None) - -tests.append(TestMetaData) - -# --------------------------------------------------------------------------- - -class TestInlining(TestCase): - def test_inline_call(self): - mod = Module.new(__name__) - callee = mod.add_function(Type.function(Type.int(), [Type.int()]), - name='bar') - - builder = Builder.new(callee.append_basic_block('entry')) - builder.ret(builder.add(callee.args[0], callee.args[0])) - - caller = mod.add_function(Type.function(Type.int(), []), - name='foo') - - builder = Builder.new(caller.append_basic_block('entry')) - callinst = builder.call(callee, [Constant.int(Type.int(), 1234)]) - builder.ret(callinst) - - pre_inlining = str(caller) - self.assertIn('call', pre_inlining) - - self.assertTrue(inline_function(callinst)) - - post_inlining = str(caller) - self.assertNotIn('call', post_inlining) - self.assertIn('2468', post_inlining) - -tests.append(TestInlining) - -# --------------------------------------------------------------------------- - -class TestIssue10(TestCase): - def test_issue10(self): - m = Module.new('a') - ti = Type.int() - tf = Type.function(ti, [ti, ti]) - - f = m.add_function(tf, "func1") - - bb = f.append_basic_block('entry') - - b = Builder.new(bb) - - # There are no instructions in bb. Positioning of the - # builder at beginning (or end) should succeed (trivially). - b.position_at_end(bb) - b.position_at_beginning(bb) - -tests.append(TestIssue10) - -# --------------------------------------------------------------------------- - -class TestOpaque(TestCase): - - def test_opaque(self): - # Create an opaque type - ts = Type.opaque('mystruct') - self.assertTrue('type opaque' in str(ts)) - self.assertTrue(ts.is_opaque) - self.assertTrue(ts.is_identified) - self.assertFalse(ts.is_literal) - #print(ts) - - # Create a recursive type - ts.set_body([Type.int(), Type.pointer(ts)]) - - self.assertEqual(ts.elements[0], Type.int()) - self.assertEqual(ts.elements[1], Type.pointer(ts)) - self.assertEqual(ts.elements[1].pointee, ts) - self.assertFalse(ts.is_opaque) # is not longer a opaque type - #print(ts) - - with self.assertRaises(llvm.LLVMException): - # Cannot redefine - ts.set_body([]) - - def test_opaque_with_no_name(self): - with self.assertRaises(llvm.LLVMException): - Type.opaque('') - -tests.append(TestOpaque) - -# --------------------------------------------------------------------------- -class TestCPUSupport(TestCase): - - def _build_test_module(self): - mod = Module.new('test') - - float = Type.double() - mysinty = Type.function( float, [float] ) - mysin = mod.add_function(mysinty, "mysin") - block = mysin.append_basic_block("entry") - b = Builder.new(block) - - sqrt = Function.intrinsic(mod, lc.INTR_SQRT, [float]) - pow = Function.intrinsic(mod, lc.INTR_POWI, [float]) - cos = Function.intrinsic(mod, lc.INTR_COS, [float]) - - mysin.args[0].name = "x" - x = mysin.args[0] - one = Constant.real(float, "1") - cosx = b.call(cos, [x], "cosx") - cos2 = b.call(pow, [cosx, Constant.int(Type.int(), 2)], "cos2") - onemc2 = b.fsub(one, cos2, "onemc2") # Should use fsub - sin = b.call(sqrt, [onemc2], "sin") - b.ret(sin) - return mod, mysin - - def _template(self, mattrs): - mod, func = self._build_test_module() - ee = self._build_engine(mod, mattrs=mattrs) - arg = le.GenericValue.real(Type.double(), 1.234) - retval = ee.run_function(func, [arg]) - - golden = math.sin(1.234) - answer = retval.as_real(Type.double()) - self.assertTrue(abs(answer-golden)/golden < 1e-5) - - - def _build_engine(self, mod, mattrs): - if mattrs: - return EngineBuilder.new(mod).mattrs(mattrs).create() - else: - return EngineBuilder.new(mod).create() - - def test_cpu_support2(self): - features = 'sse3', 'sse41', 'sse42', 'avx' - mattrs = ','.join(map(lambda s: '-%s' % s, features)) - print('disable mattrs', mattrs) - self._template(mattrs) - - def test_cpu_support3(self): - features = 'sse41', 'sse42', 'avx' - mattrs = ','.join(map(lambda s: '-%s' % s, features)) - print('disable mattrs', mattrs) - self._template(mattrs) - - def test_cpu_support4(self): - features = 'sse42', 'avx' - mattrs = ','.join(map(lambda s: '-%s' % s, features)) - print('disable mattrs', mattrs) - self._template(mattrs) - - def test_cpu_support5(self): - features = 'avx', - mattrs = ','.join(map(lambda s: '-%s' % s, features)) - print('disable mattrs', mattrs) - self._template(mattrs) - - def test_cpu_support6(self): - features = [] - from llvm.workaround.avx_support import detect_avx_support - if not detect_avx_support(): - print('Skipping: no AVX') - else: - mattrs = ','.join(map(lambda s: '-%s' % s, features)) - print('disable mattrs', mattrs) - self._template(mattrs) - -tests.append(TestCPUSupport) - -# --------------------------------------------------------------------------- -class TestIntrinsicBasic(TestCase): - - def _build_module(self, float): - mod = Module.new('test') - functy = Type.function(float, [float]) - func = mod.add_function(functy, "mytest%s" % float) - block = func.append_basic_block("entry") - b = Builder.new(block) - return mod, func, b - - def _template(self, mod, func, pyfunc): - float = func.type.pointee.return_type - - from llvm.workaround.avx_support import detect_avx_support - if not detect_avx_support(): - ee = le.EngineBuilder.new(mod).mattrs("-avx").create() - else: - ee = le.EngineBuilder.new(mod).create() - arg = le.GenericValue.real(float, 1.234) - retval = ee.run_function(func, [arg]) - golden = pyfunc(1.234) - answer = retval.as_real(float) - self.assertTrue(abs(answer - golden) / golden < 1e-7) - - def test_sqrt_f32(self): - float = Type.float() - mod, func, b = self._build_module(float) - intr = Function.intrinsic(mod, lc.INTR_SQRT, [float]) - b.ret(b.call(intr, func.args)) - self._template(mod, func, math.sqrt) - - def test_sqrt_f64(self): - float = Type.double() - mod, func, b = self._build_module(float) - intr = Function.intrinsic(mod, lc.INTR_SQRT, [float]) - b.ret(b.call(intr, func.args)) - self._template(mod, func, math.sqrt) - - def test_cos_f32(self): - if sys.platform == 'win32' and BITS == 32: - # float32 support is known to fail on 32-bit Windows - return - float = Type.float() - mod, func, b = self._build_module(float) - intr = Function.intrinsic(mod, lc.INTR_COS, [float]) - b.ret(b.call(intr, func.args)) - self._template(mod, func, math.cos) - - def test_cos_f64(self): - float = Type.double() - mod, func, b = self._build_module(float) - intr = Function.intrinsic(mod, lc.INTR_COS, [float]) - b.ret(b.call(intr, func.args)) - self._template(mod, func, math.cos) - - def test_sin_f32(self): - if sys.platform == 'win32' and BITS == 32: - # float32 support is known to fail on 32-bit Windows - return - float = Type.float() - mod, func, b = self._build_module(float) - intr = Function.intrinsic(mod, lc.INTR_SIN, [float]) - b.ret(b.call(intr, func.args)) - self._template(mod, func, math.sin) - - def test_sin_f64(self): - float = Type.double() - mod, func, b = self._build_module(float) - intr = Function.intrinsic(mod, lc.INTR_SIN, [float]) - b.ret(b.call(intr, func.args)) - self._template(mod, func, math.sin) - - def test_powi_f32(self): - float = Type.float() - mod, func, b = self._build_module(float) - intr = Function.intrinsic(mod, lc.INTR_POWI, [float]) - b.ret(b.call(intr, [func.args[0], lc.Constant.int(Type.int(), 2)])) - self._template(mod, func, lambda x: x**2) - - def test_powi_f64(self): - float = Type.double() - mod, func, b = self._build_module(float) - intr = Function.intrinsic(mod, lc.INTR_POWI, [float]) - b.ret(b.call(intr, [func.args[0], lc.Constant.int(Type.int(), 2)])) - self._template(mod, func, lambda x: x**2) - - - -tests.append(TestIntrinsicBasic) - -# --------------------------------------------------------------------------- - -class TestIntrinsic(TestCase): - def test_bswap(self): - # setup a function and a builder - mod = Module.new('test') - functy = Type.function(Type.int(), []) - func = mod.add_function(functy, "showme") - block = func.append_basic_block("entry") - b = Builder.new(block) - - # let's do bswap on a 32-bit integer using llvm.bswap - val = Constant.int(Type.int(), 0x42) - bswap = Function.intrinsic(mod, lc.INTR_BSWAP, [Type.int()]) - - bswap_res = b.call(bswap, [val]) - b.ret(bswap_res) - - # logging.debug(mod) - - # the output is: - # - # ; ModuleID = 'test' - # - # define void @showme() { - # entry: - # %0 = call i32 @llvm.bswap.i32(i32 42) - # ret i32 %0 - # } - - # let's run the function - ee = le.ExecutionEngine.new(mod) - retval = ee.run_function(func, []) - self.assertEqual(retval.as_int(), 0x42000000) - - def test_mysin(self): - if sys.platform == 'win32' and BITS == 32: - # float32 support is known to fail on 32-bit Windows - return - - # mysin(x) = sqrt(1.0 - pow(cos(x), 2)) - mod = Module.new('test') - - float = Type.float() - mysinty = Type.function( float, [float] ) - mysin = mod.add_function(mysinty, "mysin") - block = mysin.append_basic_block("entry") - b = Builder.new(block) - - sqrt = Function.intrinsic(mod, lc.INTR_SQRT, [float]) - pow = Function.intrinsic(mod, lc.INTR_POWI, [float]) - cos = Function.intrinsic(mod, lc.INTR_COS, [float]) - - mysin.args[0].name = "x" - x = mysin.args[0] - one = Constant.real(float, "1") - cosx = b.call(cos, [x], "cosx") - cos2 = b.call(pow, [cosx, Constant.int(Type.int(), 2)], "cos2") - onemc2 = b.fsub(one, cos2, "onemc2") # Should use fsub - sin = b.call(sqrt, [onemc2], "sin") - b.ret(sin) - #logging.debug(mod) - -# ; ModuleID = 'test' -# -# define void @showme() { -# entry: -# call i32 @llvm.bswap.i32( i32 42 ) ; :0 [#uses -# } -# -# declare i32 @llvm.bswap.i32(i32) nounwind readnone -# -# define float @mysin(float %x) { -# entry: -# %cosx = call float @llvm.cos.f32( float %x ) ; [#uses -# %sin = call float @llvm.sqrt.f32( float %onemc2 ) -# ret float %sin -# } -# -# declare float @llvm.sqrt.f32(float) nounwind readnone -# -# declare float @llvm.powi.f32(float, i32) nounwind readnone -# -# declare float @llvm.cos.f32(float) nounwind readnone - - # let's run the function - - from llvm.workaround.avx_support import detect_avx_support - if not detect_avx_support(): - ee = le.EngineBuilder.new(mod).mattrs("-avx").create() - else: - ee = le.EngineBuilder.new(mod).create() - - arg = le.GenericValue.real(Type.float(), 1.234) - retval = ee.run_function(mysin, [arg]) - - golden = math.sin(1.234) - answer = retval.as_real(Type.float()) - self.assertTrue(abs(answer-golden)/golden < 1e-5) - -tests.append(TestIntrinsic) - -# --------------------------------------------------------------------------- - -class TestVolatile(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") - -tests.append(TestVolatile) - -# --------------------------------------------------------------------------- - -class TestNamedMetaData(TestCase): - def test_named_md(self): - m = Module.new('test_named_md') - nmd = m.get_or_insert_named_metadata('something') - md = MetaData.get(m, [Constant.int(Type.int(), 0xbeef)]) - nmd.add(md) - self.assertTrue(str(nmd).startswith('!something')) - ir = str(m) - self.assertTrue('!something' in ir) - -tests.append(TestNamedMetaData) - - -# --------------------------------------------------------------------------- - -class TestStruct(TestCase): - def test_struct_identical(self): - m = Module.new('test_struct_identical') - ta = Type.struct([Type.int(32), Type.float()], name='ta') - tb = Type.struct([Type.int(32), Type.float()]) - self.assertTrue(ta.is_layout_identical(tb)) - -tests.append(TestStruct) - -# --------------------------------------------------------------------------- - -class TestTypeHash(TestCase): - def test_scalar_type(self): - i32a = Type.int(32) - i32b = Type.int(32) - i64a = Type.int(64) - i64b = Type.int(64) - ts = set([i32a, i32b, i64a, i64b]) - self.assertTrue(len(ts)) - self.assertTrue(i32a in ts) - self.assertTrue(i64b in ts) - - def test_struct_type(self): - ta = Type.struct([Type.int(32), Type.float()]) - tb = Type.struct([Type.int(32), Type.float()]) - tc = Type.struct([Type.int(32), Type.int(32), Type.float()]) - ts = set([ta, tb, tc]) - self.assertTrue(len(ts) == 2) - self.assertTrue(ta in ts) - self.assertTrue(tb in ts) - self.assertTrue(tc in ts) - -tests.append(TestTypeHash) - -# --------------------------------------------------------------------------- - -class TestArgAttr(TestCase): - def test_arg_attr(self): - m = Module.new('oifjda') - vptr = Type.pointer(Type.float()) - sptr = Type.pointer(Type.struct([])) - fnty = Type.function(Type.void(), [vptr] * 5) - func = m.add_function(fnty, 'foo') - attrs = [lc.ATTR_STRUCT_RET, lc.ATTR_BY_VAL, lc.ATTR_NEST, - lc.ATTR_NO_ALIAS, lc.ATTR_NO_CAPTURE] - for i, attr in enumerate(attrs): - arg = func.args[i] - self.assertEqual(i, arg.arg_no) - arg.add_attribute(attr) - self.assertTrue(attr in func.args[i]) - -tests.append(TestArgAttr) - -# --------------------------------------------------------------------------- - -class TestSwitch(TestCase): - def test_arg_attr(self): - m = Module.new('oifjda') - fnty = Type.function(Type.void(), [Type.int()]) - func = m.add_function(fnty, 'foo') - bb = func.append_basic_block('') - bbdef = func.append_basic_block('') - bbsw1 = func.append_basic_block('') - bbsw2 = func.append_basic_block('') - bldr = Builder.new(bb) - - swt = bldr.switch(func.args[0], bbdef, n=2) - swt.add_case(Constant.int(Type.int(), 0), bbsw1) - swt.add_case(Constant.int(Type.int(), 1), bbsw2) - - bldr.position_at_end(bbsw1) - bldr.ret_void() - - bldr.position_at_end(bbsw2) - bldr.ret_void() - - bldr.position_at_end(bbdef) - bldr.ret_void() - - func.verify() - -tests.append(TestSwitch) - -# --------------------------------------------------------------------------- - -class TestCmp(TestCase): - def test_arg_attr(self): - m = Module.new('oifjda') - fnty = Type.function(Type.void(), [Type.int()]) - func = m.add_function(fnty, 'foo') - bb = func.append_basic_block('') - bldr = Builder.new(bb) - - cmpinst = bldr.icmp(lc.ICMP_ULE, func.args[0], - Constant.int(Type.int(), 123)) - self.assertTrue(repr(cmpinst.predicate).startswith('ICMP_ULE')) - self.assertEqual(cmpinst.predicate, lc.ICMP_ULE) - bldr.ret_void() - - func.verify() - -tests.append(TestCmp) - - -# --------------------------------------------------------------------------- - -class TestMCJIT(TestCase): - def test_mcjit(self): - m = Module.new('oidfjs') - fnty = Type.function(Type.int(), [Type.int(), Type.int()]) - func = m.add_function(fnty, 'foo') - bb = func.append_basic_block('') - bldr = Builder.new(bb) - bldr.ret(bldr.add(*func.args)) - - func.verify() - - engine = EngineBuilder.new(m).mcjit(True).create() - ptr = engine.get_pointer_to_function(func) - - from ctypes import c_int, CFUNCTYPE - callee = CFUNCTYPE(c_int, c_int, c_int)(ptr) - self.assertEqual(321 + 123, callee(321, 123)) - - def test_multi_module_linking(self): - # generate external library module - m = Module.new('external-library-module') - fnty = Type.function(Type.int(), [Type.int(), Type.int()]) - libfname = 'myadd' - func = m.add_function(fnty, libfname) - bb = func.append_basic_block('') - bldr = Builder.new(bb) - bldr.ret(bldr.add(*func.args)) - func.verify() - - # JIT the lib module and bind dynamic symbol - libengine = EngineBuilder.new(m).mcjit(True).create() - myadd_ptr = libengine.get_pointer_to_function(func) - le.dylib_add_symbol(libfname, myadd_ptr) - - # reference external library - m = Module.new('user') - fnty = Type.function(Type.int(), [Type.int(), Type.int()]) - func = m.add_function(fnty, 'foo') - bb = func.append_basic_block('') - bldr = Builder.new(bb) - extadd = m.get_or_insert_function(fnty, name=libfname) - bldr.ret(bldr.call(extadd, func.args)) - func.verify() - - # JIT the user module - engine = EngineBuilder.new(m).mcjit(True).create() - ptr = engine.get_pointer_to_function(func) - self.assertEqual(myadd_ptr, - engine.get_pointer_to_named_function(libfname)) - - from ctypes import c_int, CFUNCTYPE - callee = CFUNCTYPE(c_int, c_int, c_int)(ptr) - self.assertEqual(321 + 123, callee(321, 123)) - - -if (llvm.version >= (3, 3) and - not (sys.platform.startswith('win32') and BITS == 64)): - # MCJIT broken in 3.2, the test will segfault in OSX? - # Compatbility problem on windows 7 64-bit? - tests.append(TestMCJIT) - - -class TestLLRT(TestCase): - def test_llrt_divmod(self): - from llvm import llrt - m = lc.Module.new('testllrt') - longlong = lc.Type.int(64) - lfunc = m.add_function(lc.Type.function(longlong, [longlong, longlong]), 'foo') - bldr = lc.Builder.new(lfunc.append_basic_block('')) - bldr.ret(bldr.udiv(*lfunc.args)) - - llrt.replace_divmod64(lfunc) - - rt = llrt.LLRT() - rt.install_symbols() - - engine = le.EngineBuilder.new(m).create() - pointer = engine.get_pointer_to_function(lfunc) - - from ctypes import CFUNCTYPE, c_uint64, c_int64 - func = CFUNCTYPE(c_uint64, c_uint64, c_uint64)(pointer) - a, b = 98342, 2231 - self.assertEqual(func(98342, 2231), 98342 // 2231) - - rt.uninstall_symbols() - -tests.append(TestLLRT) - -class TestArith(TestCase): - ''' - Test basic arithmetic support with LLVM MCJIT - ''' - def func_template(self, ty, op): - m = Module.new('dofjaa') - fnty = Type.function(ty, [ty, ty]) - fn = m.add_function(fnty, 'foo') - bldr = Builder.new(fn.append_basic_block('')) - bldr.ret(getattr(bldr, op)(*fn.args)) - - engine = EngineBuilder.new(m).mcjit(True).create() - ptr = engine.get_pointer_to_function(fn) - - from ctypes import c_uint32, c_uint64, c_float, c_double, CFUNCTYPE - - maptypes = { - Type.int(32): c_uint32, - Type.int(64): c_uint64, - Type.float(): c_float, - Type.double(): c_double, - } - cty = maptypes[ty] - prototype = CFUNCTYPE(*[cty] * 3) - callee = prototype(ptr) - callee(12, 23) - - def template(self, iop, fop): - inttys = [Type.int(32), Type.int(64)] - flttys = [Type.float(), Type.double()] - - if iop: - for ty in inttys: - self.func_template(ty, iop) - if fop: - for ty in flttys: - self.func_template(ty, fop) - - def test_add(self): - self.template('add', 'fadd') - - def test_sub(self): - self.template('sub', 'fsub') - - def test_mul(self): - self.template('mul', 'fmul') - - def test_div(self): - if BITS == 32: - print('skipped test for div') - print('known failure due to unresolved external symbol __udivdi3') - return - self.template('udiv', None) # 'fdiv') - - def test_rem(self): - if BITS == 32: - print('skipped test for rem') - print('known failure due to unresolved external symbol __umoddi3') - return - self.template('urem', None) # 'frem') - -if llvm.version >= (3, 3): - # MCJIT is broken in 3.2 - tests.append(TestArith) - -class TestNUWNSW(TestCase): - def make_module(self): - mod = Module.new('asdfa') - fnty = Type.function(Type.void(), [Type.int()] * 2) - func = mod.add_function(fnty, 'foo') - bldr = Builder.new(func.append_basic_block('')) - return mod, func, bldr - - def has_nsw(self, inst, op): - self.assertTrue(('%s nsw' % op) in str(inst), "NSW flag does not work") - - def has_nuw(self, inst, op): - self.assertTrue(('%s nuw' % op) in str(inst), "NUW flag does not work") - - def _test_template(self, opf, opname): - mod, func, bldr = self.make_module() - a, b = func.args - self.has_nsw(opf(bldr, a, b, nsw=True), opname) - self.has_nuw(opf(bldr, a, b, nuw=True), opname) - - def test_add_nuw_nsw(self): - self._test_template(Builder.add, 'add') - - def test_sub_nuw_nsw(self): - self._test_template(Builder.sub, 'sub') - - def test_mul_nuw_nsw(self): - self._test_template(Builder.mul, 'mul') - - def test_shl_nuw_nsw(self): - self._test_template(Builder.shl, 'shl') - - def test_neg_nuw_nsw(self): - mod, func, bldr = self.make_module() - a, b = func.args - self.has_nsw(bldr.neg(a, nsw=True), 'sub') - self.has_nuw(bldr.neg(a, nuw=True), 'sub') - - -tests.append(TestNUWNSW) - - -class TestExact(TestCase): - def make_module(self): - mod = Module.new('asdfa') - fnty = Type.function(Type.void(), [Type.int()] * 2) - func = mod.add_function(fnty, 'foo') - bldr = Builder.new(func.append_basic_block('')) - return mod, func, bldr - - def has_exact(self, inst, op): - self.assertTrue(('%s exact' % op) in str(inst), "exact flag does not work") - - def _test_template(self, opf, opname): - mod, func, bldr = self.make_module() - a, b = func.args - self.has_exact(opf(bldr, a, b, exact=True), opname) - - def test_udiv_exact(self): - self._test_template(Builder.udiv, 'udiv') - - def test_sdiv_exact(self): - self._test_template(Builder.sdiv, 'sdiv') - - def test_lshr_exact(self): - self._test_template(Builder.lshr, 'lshr') - - def test_ashr_exact(self): - self._test_template(Builder.ashr, 'ashr') - -tests.append(TestExact) - - diff --git a/llvm/tests/test_mcjit.py b/llvm/tests/test_mcjit.py new file mode 100644 index 0000000..8d00ac5 --- /dev/null +++ b/llvm/tests/test_mcjit.py @@ -0,0 +1,73 @@ +import unittest +import sys +import llvm +from llvm.core import (Module, Type, Builder) +from llvm.ee import EngineBuilder + +import llvm.ee as le +from .support import TestCase, tests, BITS + +class TestMCJIT(TestCase): + def test_mcjit(self): + m = Module.new('oidfjs') + fnty = Type.function(Type.int(), [Type.int(), Type.int()]) + func = m.add_function(fnty, 'foo') + bb = func.append_basic_block('') + bldr = Builder.new(bb) + bldr.ret(bldr.add(*func.args)) + + func.verify() + + engine = EngineBuilder.new(m).mcjit(True).create() + ptr = engine.get_pointer_to_function(func) + + from ctypes import c_int, CFUNCTYPE + callee = CFUNCTYPE(c_int, c_int, c_int)(ptr) + self.assertEqual(321 + 123, callee(321, 123)) + + def test_multi_module_linking(self): + # generate external library module + m = Module.new('external-library-module') + fnty = Type.function(Type.int(), [Type.int(), Type.int()]) + libfname = 'myadd' + func = m.add_function(fnty, libfname) + bb = func.append_basic_block('') + bldr = Builder.new(bb) + bldr.ret(bldr.add(*func.args)) + func.verify() + + # JIT the lib module and bind dynamic symbol + libengine = EngineBuilder.new(m).mcjit(True).create() + myadd_ptr = libengine.get_pointer_to_function(func) + le.dylib_add_symbol(libfname, myadd_ptr) + + # reference external library + m = Module.new('user') + fnty = Type.function(Type.int(), [Type.int(), Type.int()]) + func = m.add_function(fnty, 'foo') + bb = func.append_basic_block('') + bldr = Builder.new(bb) + extadd = m.get_or_insert_function(fnty, name=libfname) + bldr.ret(bldr.call(extadd, func.args)) + func.verify() + + # JIT the user module + engine = EngineBuilder.new(m).mcjit(True).create() + ptr = engine.get_pointer_to_function(func) + self.assertEqual(myadd_ptr, + engine.get_pointer_to_named_function(libfname)) + + from ctypes import c_int, CFUNCTYPE + callee = CFUNCTYPE(c_int, c_int, c_int)(ptr) + self.assertEqual(321 + 123, callee(321, 123)) + + +if (llvm.version >= (3, 3) and + not (sys.platform.startswith('win32') and BITS == 64)): + # MCJIT broken in 3.2, the test will segfault in OSX? + # Compatbility problem on windows 7 64-bit? + tests.append(TestMCJIT) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_metadata.py b/llvm/tests/test_metadata.py new file mode 100644 index 0000000..139a1da --- /dev/null +++ b/llvm/tests/test_metadata.py @@ -0,0 +1,25 @@ +import unittest +from llvm.core import (Module, Type, Constant, MetaData, MetaDataString) +from .support import TestCase, tests + +class TestMetaData(TestCase): + # test module metadata + def test_metadata(self): + m = Module.new('a') + t = Type.int() + metadata = MetaData.get(m, [Constant.int(t, 100), + MetaDataString.get(m, 'abcdef'), + None]) + MetaData.add_named_operand(m, 'foo', metadata) + self.assertEqual(MetaData.get_named_operands(m, 'foo'), [metadata]) + self.assertEqual(MetaData.get_named_operands(m, 'bar'), []) + self.assertEqual(len(metadata.operands), 3) + self.assertEqual(metadata.operands[0].z_ext_value, 100) + self.assertEqual(metadata.operands[1].string, 'abcdef') + self.assertTrue(metadata.operands[2] is None) + +tests.append(TestMetaData) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_named_metadata.py b/llvm/tests/test_named_metadata.py new file mode 100644 index 0000000..0c75da3 --- /dev/null +++ b/llvm/tests/test_named_metadata.py @@ -0,0 +1,20 @@ +import unittest +from llvm.core import (Module, Type, Constant, MetaData) +from .support import TestCase, tests + + +class TestNamedMetaData(TestCase): + def test_named_md(self): + m = Module.new('test_named_md') + nmd = m.get_or_insert_named_metadata('something') + md = MetaData.get(m, [Constant.int(Type.int(), 0xbeef)]) + nmd.add(md) + self.assertTrue(str(nmd).startswith('!something')) + ir = str(m) + self.assertTrue('!something' in ir) + +tests.append(TestNamedMetaData) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_native.py b/llvm/tests/test_native.py new file mode 100644 index 0000000..d7afea9 --- /dev/null +++ b/llvm/tests/test_native.py @@ -0,0 +1,81 @@ +import unittest +import os +import sys +import shutil +import subprocess +import tempfile +from distutils.spawn import find_executable +from llvm.core import (Module, Type, Builder, Constant) +from .support import TestCase, IS_PY3K, tests + +class TestNative(TestCase): + + def setUp(self): + self.tmpdir = tempfile.mkdtemp() + + def tearDown(self): + shutil.rmtree(self.tmpdir) + + + def _make_module(self): + m = Module.new('module1') + m.add_global_variable(Type.int(), 'i') + + fty = Type.function(Type.int(), []) + f = m.add_function(fty, name='main') + + bldr = Builder.new(f.append_basic_block('entry')) + bldr.ret(Constant.int(Type.int(), 0xab)) + + return m + + def _compile(self, src): + cc = find_executable('cc') + if not cc: + return + + dst = os.path.join(self.tmpdir, 'llvmobj.out') + s = subprocess.call([cc, '-o', dst, src]) + if s != 0: + raise Exception("Cannot compile") + + s = subprocess.call([dst]) + self.assertEqual(s, 0xab) + + def test_assembly(self): + if sys.platform == 'darwin': + # skip this test on MacOSX for now + return + + m = self._make_module() + output = m.to_native_assembly() + + src = os.path.join(self.tmpdir, 'llvmasm.s') + with open(src, 'wb') as fout: + if IS_PY3K: + fout.write(output.encode('utf-8')) + else: + fout.write(output) + + self._compile(src) + + def test_object(self): + if sys.platform == 'darwin': + # skip this test on MacOSX for now + return + + m = self._make_module() + output = m.to_native_object() + + src = os.path.join(self.tmpdir, 'llvmobj.o') + with open(src, 'wb') as fout: + fout.write(output) + + self._compile(src) + +if sys.platform != 'win32': + tests.append(TestNative) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_nuw_nsw.py b/llvm/tests/test_nuw_nsw.py new file mode 100644 index 0000000..70babb9 --- /dev/null +++ b/llvm/tests/test_nuw_nsw.py @@ -0,0 +1,48 @@ +import unittest +from llvm.core import Module, Type, Builder +from .support import TestCase, tests + +class TestNUWNSW(TestCase): + def make_module(self): + mod = Module.new('asdfa') + fnty = Type.function(Type.void(), [Type.int()] * 2) + func = mod.add_function(fnty, 'foo') + bldr = Builder.new(func.append_basic_block('')) + return mod, func, bldr + + def has_nsw(self, inst, op): + self.assertTrue(('%s nsw' % op) in str(inst), "NSW flag does not work") + + def has_nuw(self, inst, op): + self.assertTrue(('%s nuw' % op) in str(inst), "NUW flag does not work") + + def _test_template(self, opf, opname): + mod, func, bldr = self.make_module() + a, b = func.args + self.has_nsw(opf(bldr, a, b, nsw=True), opname) + self.has_nuw(opf(bldr, a, b, nuw=True), opname) + + def test_add_nuw_nsw(self): + self._test_template(Builder.add, 'add') + + def test_sub_nuw_nsw(self): + self._test_template(Builder.sub, 'sub') + + def test_mul_nuw_nsw(self): + self._test_template(Builder.mul, 'mul') + + def test_shl_nuw_nsw(self): + self._test_template(Builder.shl, 'shl') + + def test_neg_nuw_nsw(self): + mod, func, bldr = self.make_module() + a, b = func.args + self.has_nsw(bldr.neg(a, nsw=True), 'sub') + self.has_nuw(bldr.neg(a, nuw=True), 'sub') + + +tests.append(TestNUWNSW) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_obj_cache.py b/llvm/tests/test_obj_cache.py new file mode 100644 index 0000000..49cec6e --- /dev/null +++ b/llvm/tests/test_obj_cache.py @@ -0,0 +1,107 @@ +import unittest +from llvm.core import Module, Type, GlobalVariable, Function, Builder +from .support import TestCase, tests + +class TestObjCache(TestCase): + + def test_objcache(self): + # Testing module aliasing + m1 = Module.new('a') + t = Type.int() + ft = Type.function(t, [t]) + f1 = m1.add_function(ft, "func") + m2 = f1.module + self.assert_(m1 is m2) + + # Testing global vairable aliasing 1 + gv1 = GlobalVariable.new(m1, t, "gv") + gv2 = GlobalVariable.get(m1, "gv") + self.assert_(gv1 is gv2) + + # Testing global vairable aliasing 2 + gv3 = m1.global_variables[0] + self.assert_(gv1 is gv3) + + # Testing global vairable aliasing 3 + gv2 = None + gv3 = None + + gv1.delete() + + gv4 = GlobalVariable.new(m1, t, "gv") + + self.assert_(gv1 is not gv4) + + # Testing function aliasing 1 + b1 = f1.append_basic_block('entry') + f2 = b1.function + self.assert_(f1 is f2) + + # Testing function aliasing 2 + f3 = m1.get_function_named("func") + self.assert_(f1 is f3) + + # Testing function aliasing 3 + f4 = Function.get_or_insert(m1, ft, "func") + self.assert_(f1 is f4) + + # Testing function aliasing 4 + f5 = Function.get(m1, "func") + self.assert_(f1 is f5) + + # Testing function aliasing 5 + f6 = m1.get_or_insert_function(ft, "func") + self.assert_(f1 is f6) + + # Testing function aliasing 6 + f7 = m1.functions[0] + self.assert_(f1 is f7) + + # Testing argument aliasing + a1 = f1.args[0] + a2 = f1.args[0] + self.assert_(a1 is a2) + + # Testing basic block aliasing 1 + b2 = f1.basic_blocks[0] + self.assert_(b1 is b2) + + # Testing basic block aliasing 2 + b3 = f1.entry_basic_block + self.assert_(b1 is b3) + + # Testing basic block aliasing 3 + b31 = f1.entry_basic_block + self.assert_(b1 is b31) + + # Testing basic block aliasing 4 + bldr = Builder.new(b1) + b4 = bldr.basic_block + self.assert_(b1 is b4) + + # Testing basic block aliasing 5 + i1 = bldr.ret_void() + b5 = i1.basic_block + self.assert_(b1 is b5) + + # Testing instruction aliasing 1 + i2 = b5.instructions[0] + self.assert_(i1 is i2) + + # phi node + phi = bldr.phi(t) + phi.add_incoming(f1.args[0], b1) + v2 = phi.get_incoming_value(0) + b6 = phi.get_incoming_block(0) + + # Testing PHI / basic block aliasing 5 + self.assert_(b1 is b6) + + # Testing PHI / value aliasing + self.assert_(f1.args[0] is v2) + +tests.append(TestObjCache) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_opaque.py b/llvm/tests/test_opaque.py new file mode 100644 index 0000000..7bce43e --- /dev/null +++ b/llvm/tests/test_opaque.py @@ -0,0 +1,38 @@ +import unittest +import llvm +from llvm.core import Type +from .support import TestCase, tests + +class TestOpaque(TestCase): + + def test_opaque(self): + # Create an opaque type + ts = Type.opaque('mystruct') + self.assertTrue('type opaque' in str(ts)) + self.assertTrue(ts.is_opaque) + self.assertTrue(ts.is_identified) + self.assertFalse(ts.is_literal) + #print(ts) + + # Create a recursive type + ts.set_body([Type.int(), Type.pointer(ts)]) + + self.assertEqual(ts.elements[0], Type.int()) + self.assertEqual(ts.elements[1], Type.pointer(ts)) + self.assertEqual(ts.elements[1].pointee, ts) + self.assertFalse(ts.is_opaque) # is not longer a opaque type + #print(ts) + + with self.assertRaises(llvm.LLVMException): + # Cannot redefine + ts.set_body([]) + + def test_opaque_with_no_name(self): + with self.assertRaises(llvm.LLVMException): + Type.opaque('') + +tests.append(TestOpaque) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_operands.py b/llvm/tests/test_operands.py new file mode 100644 index 0000000..ef68b9e --- /dev/null +++ b/llvm/tests/test_operands.py @@ -0,0 +1,66 @@ +import unittest +try: + from StringIO import StringIO +except ImportError: + from io import StringIO + +from llvm.core import Module +from .support import TestCase, tests + +class TestOperands(TestCase): + # implement a test function + test_module = """ +define i32 @prod(i32, i32) { +entry: + %2 = mul i32 %0, %1 + ret i32 %2 +} + +define i32 @test_func(i32, i32, i32) { +entry: + %tmp1 = call i32 @prod(i32 %0, i32 %1) + %tmp2 = add i32 %tmp1, %2 + %tmp3 = add i32 %tmp2, 1 + %tmp4 = add i32 %tmp3, -1 + %tmp5 = add i64 -81985529216486895, 12297829382473034410 + ret i32 %tmp4 +} +""" + def test_operands(self): + m = Module.from_assembly(StringIO(self.test_module)) + + test_func = m.get_function_named("test_func") + prod = m.get_function_named("prod") + + # test operands + i1 = test_func.basic_blocks[0].instructions[0] + i2 = test_func.basic_blocks[0].instructions[1] + i3 = test_func.basic_blocks[0].instructions[2] + i4 = test_func.basic_blocks[0].instructions[3] + i5 = test_func.basic_blocks[0].instructions[4] + + self.assertEqual(i1.operand_count, 3) + self.assertEqual(i2.operand_count, 2) + + self.assertEqual(i3.operands[1].z_ext_value, 1) + self.assertEqual(i3.operands[1].s_ext_value, 1) + self.assertEqual(i4.operands[1].z_ext_value, 0xffffffff) + self.assertEqual(i4.operands[1].s_ext_value, -1) + self.assertEqual(i5.operands[0].s_ext_value, -81985529216486895) + self.assertEqual(i5.operands[1].z_ext_value, 12297829382473034410) + + self.assert_(i1.operands[-1] is prod) + self.assert_(i1.operands[0] is test_func.args[0]) + self.assert_(i1.operands[1] is test_func.args[1]) + self.assert_(i2.operands[0] is i1) + self.assert_(i2.operands[1] is test_func.args[2]) + self.assertEqual(len(i1.operands), 3) + self.assertEqual(len(i2.operands), 2) + + self.assert_(i1.called_function is prod) + +tests.append(TestOperands) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_passes.py b/llvm/tests/test_passes.py new file mode 100644 index 0000000..f4b957e --- /dev/null +++ b/llvm/tests/test_passes.py @@ -0,0 +1,143 @@ +import unittest +try: + from StringIO import StringIO +except ImportError: + from io import StringIO +import llvm +from llvm.core import Module +import llvm.passes as lp +import llvm.ee as le +from .support import TestCase, tests + + +class TestPasses(TestCase): + # Create a module. + asm = """ + +define i32 @test() nounwind { + ret i32 42 +} + +define i32 @test1() nounwind { +entry: + %tmp = alloca i32 + store i32 42, i32* %tmp, align 4 + %tmp1 = load i32* %tmp, align 4 + %tmp2 = call i32 @test() + %tmp3 = load i32* %tmp, align 4 + %tmp4 = load i32* %tmp, align 4 + ret i32 %tmp1 +} + +define i32 @test2() nounwind { +entry: + %tmp = call i32 @test() + ret i32 %tmp +} +""" + def test_passes(self): + m = Module.from_assembly(StringIO(self.asm)) + + fn_test1 = m.get_function_named('test1') + fn_test2 = m.get_function_named('test2') + + original_test1 = str(fn_test1) + original_test2 = str(fn_test2) + + # Let's run a module-level inlining pass. First, create a pass manager. + pm = lp.PassManager.new() + + # Add the target data as the first "pass". This is mandatory. + pm.add(le.TargetData.new('')) + + # Add the inlining pass. + pm.add(lp.PASS_INLINE) + + # Run it! + pm.run(m) + + # Done with the pass manager. + del pm + + # Make sure test2 is inlined + self.assertNotEqual(str(fn_test2).strip(), original_test2.strip()) + + bb_entry = fn_test2.basic_blocks[0] + + self.assertEqual(len(bb_entry.instructions), 1) + self.assertEqual(bb_entry.instructions[0].opcode_name, 'ret') + + # Let's run a DCE pass on the the function 'test1' now. First create a + # function pass manager. + fpm = lp.FunctionPassManager.new(m) + + # Add the target data as first "pass". This is mandatory. + fpm.add(le.TargetData.new('')) + + # Add a DCE pass + fpm.add(lp.PASS_ADCE) + + # Run the pass on the function 'test1' + fpm.run(m.get_function_named('test1')) + + # Make sure test1 is modified + self.assertNotEqual(str(fn_test1).strip(), original_test1.strip()) + + def test_passes_with_pmb(self): + m = Module.from_assembly(StringIO(self.asm)) + + fn_test1 = m.get_function_named('test1') + fn_test2 = m.get_function_named('test2') + + original_test1 = str(fn_test1) + original_test2 = str(fn_test2) + + # Try out the PassManagerBuilder + + pmb = lp.PassManagerBuilder.new() + + self.assertEqual(pmb.opt_level, 2) # ensure default is level 2 + pmb.opt_level = 3 + self.assertEqual(pmb.opt_level, 3) # make sure it works + + self.assertEqual(pmb.size_level, 0) # ensure default is level 0 + pmb.size_level = 2 + self.assertEqual(pmb.size_level, 2) # make sure it works + + self.assertFalse(pmb.vectorize) # ensure default is False + pmb.vectorize = True + self.assertTrue(pmb.vectorize) # make sure it works + + # make sure the default is False + self.assertFalse(pmb.disable_unit_at_a_time) + self.assertFalse(pmb.disable_unroll_loops) + if llvm.version <= (3, 3): + self.assertFalse(pmb.disable_simplify_lib_calls) + + pmb.disable_unit_at_a_time = True + self.assertTrue(pmb.disable_unit_at_a_time) + + # Do function pass + fpm = lp.FunctionPassManager.new(m) + pmb.populate(fpm) + fpm.run(fn_test1) + + # Make sure test1 has changed + self.assertNotEqual(str(fn_test1).strip(), original_test1.strip()) + + # Do module pass + pm = lp.PassManager.new() + pmb.populate(pm) + pm.run(m) + + # Make sure test2 has changed + self.assertNotEqual(str(fn_test2).strip(), original_test2.strip()) + + def test_dump_passes(self): + self.assertTrue(len(lp.PASSES)>0, msg="Cannot have no passes") + +tests.append(TestPasses) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_struct.py b/llvm/tests/test_struct.py new file mode 100644 index 0000000..3783a8c --- /dev/null +++ b/llvm/tests/test_struct.py @@ -0,0 +1,15 @@ +import unittest +from llvm.core import Type +from .support import TestCase, tests + +class TestStruct(TestCase): + def test_struct_identical(self): + ta = Type.struct([Type.int(32), Type.float()], name='ta') + tb = Type.struct([Type.int(32), Type.float()]) + self.assertTrue(ta.is_layout_identical(tb)) + +tests.append(TestStruct) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_struct_args.py b/llvm/tests/test_struct_args.py index cd3e3f9..8683a6e 100644 --- a/llvm/tests/test_struct_args.py +++ b/llvm/tests/test_struct_args.py @@ -59,7 +59,7 @@ class TestStructSystemVABI(unittest.TestCase, FloatTestMixin): ''' Non microsoft convention ''' - + #---------------------------------------------------------------------- # 64 bits @@ -160,7 +160,7 @@ class TestStructSystemVABI(unittest.TestCase, FloatTestMixin): @skip_if_not_64bits def test_two_halfwords(self): '''Arguments smaller or equal to a word is packed into a word. - + Passing as struct { float, float } occupies two XMM registers instead of one. The output must be in XMM. @@ -267,7 +267,7 @@ class TestStructSystemVABI(unittest.TestCase, FloatTestMixin): self.assertClose(arg.x / arg.y, ret.y) self.assertEqual(arg.z, ret.z) - + @skip_if_not_32bits def test_structure_abi_32_2(self): '''x86 is simple. Always pass structure as memory. @@ -378,7 +378,7 @@ class TestStructMicrosoftABI(unittest.TestCase, FloatTestMixin): ''' Microsoft convention ''' - + #---------------------------------------------------------------------- # 64 bits @@ -488,7 +488,7 @@ class TestStructMicrosoftABI(unittest.TestCase, FloatTestMixin): @skip_if_not_64bits def test_two_halfwords(self): '''Arguments smaller or equal to a word is packed into a word. - + Floats structure are not passed on the XMM. Treat it as a i64. ''' @@ -603,7 +603,7 @@ class TestStructMicrosoftABI(unittest.TestCase, FloatTestMixin): float_type = lc.Type.float() struct_type = lc.Type.struct([float_type, float_type]) - struct_ptr_type = lc.Type.pointer(struct_type) + abi_type = lc.Type.int(64) func_type = lc.Type.function(abi_type, [struct_type]) func = m.add_function(func_type, name='foo') diff --git a/llvm/tests/test_switch.py b/llvm/tests/test_switch.py new file mode 100644 index 0000000..12a4fbc --- /dev/null +++ b/llvm/tests/test_switch.py @@ -0,0 +1,36 @@ +import unittest +from llvm.core import (Module, Type, Builder, Constant) + +from .support import TestCase, tests + +class TestSwitch(TestCase): + def test_arg_attr(self): + m = Module.new('oifjda') + fnty = Type.function(Type.void(), [Type.int()]) + func = m.add_function(fnty, 'foo') + bb = func.append_basic_block('') + bbdef = func.append_basic_block('') + bbsw1 = func.append_basic_block('') + bbsw2 = func.append_basic_block('') + bldr = Builder.new(bb) + + swt = bldr.switch(func.args[0], bbdef, n=2) + swt.add_case(Constant.int(Type.int(), 0), bbsw1) + swt.add_case(Constant.int(Type.int(), 1), bbsw2) + + bldr.position_at_end(bbsw1) + bldr.ret_void() + + bldr.position_at_end(bbsw2) + bldr.ret_void() + + bldr.position_at_end(bbdef) + bldr.ret_void() + + func.verify() + +tests.append(TestSwitch) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_target_machines.py b/llvm/tests/test_target_machines.py new file mode 100644 index 0000000..e7ea7de --- /dev/null +++ b/llvm/tests/test_target_machines.py @@ -0,0 +1,62 @@ +import unittest +import llvm.core as lc +import llvm.ee as le +from llvm.core import Type, Builder +from .support import TestCase, tests + +class TestTargetMachines(TestCase): + '''Exercise target machines + + Require PTX backend + ''' + def test_native(self): + m, _ = self._build_module() + tm = le.EngineBuilder.new(m).select_target() + + self.assertTrue(tm.target_name) + self.assertTrue(tm.target_data) + self.assertTrue(tm.target_short_description) + self.assertTrue(tm.triple) + self.assertIn('foo', tm.emit_assembly(m)) + self.assertTrue(le.get_host_cpu_name()) + + def test_ptx(self): + if le.initialize_target('PTX', noraise=True): + arch = 'ptx64' + elif le.initialize_target('NVPTX', noraise=True): + arch = 'nvptx64' + else: + return # skip this test + + print(arch) + m, func = self._build_module() + func.calling_convention = lc.CC_PTX_KERNEL # set calling conv + ptxtm = le.TargetMachine.lookup(arch=arch, cpu='sm_20') + self.assertTrue(ptxtm.triple) + self.assertTrue(ptxtm.cpu) + ptxasm = ptxtm.emit_assembly(m) + self.assertIn('foo', ptxasm) + if arch == 'nvptx64': + self.assertIn('.address_size 64', ptxasm) + self.assertIn('sm_20', ptxasm) + + def _build_module(self): + m = lc.Module.new('TestTargetMachines') + + fnty = Type.function(Type.void(), []) + func = m.add_function(fnty, name='foo') + + bldr = Builder.new(func.append_basic_block('entry')) + bldr.ret_void() + m.verify() + return m, func + + def _build_bad_archname(self): + with self.assertRaises(RuntimeError): + le.TargetMachine.lookup("ain't no arch name") + +tests.append(TestTargetMachines) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_type_hash.py b/llvm/tests/test_type_hash.py new file mode 100644 index 0000000..49455a1 --- /dev/null +++ b/llvm/tests/test_type_hash.py @@ -0,0 +1,30 @@ +import unittest +from llvm.core import Type +from .support import TestCase, tests + +class TestTypeHash(TestCase): + def test_scalar_type(self): + i32a = Type.int(32) + i32b = Type.int(32) + i64a = Type.int(64) + i64b = Type.int(64) + ts = set([i32a, i32b, i64a, i64b]) + self.assertTrue(len(ts)) + self.assertTrue(i32a in ts) + self.assertTrue(i64b in ts) + + def test_struct_type(self): + ta = Type.struct([Type.int(32), Type.float()]) + tb = Type.struct([Type.int(32), Type.float()]) + tc = Type.struct([Type.int(32), Type.int(32), Type.float()]) + ts = set([ta, tb, tc]) + self.assertTrue(len(ts) == 2) + self.assertTrue(ta in ts) + self.assertTrue(tb in ts) + self.assertTrue(tc in ts) + +tests.append(TestTypeHash) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_uses.py b/llvm/tests/test_uses.py new file mode 100644 index 0000000..3d3bdbc --- /dev/null +++ b/llvm/tests/test_uses.py @@ -0,0 +1,43 @@ +import unittest +from llvm.core import Module, Type, Builder, Constant + +from .support import TestCase, tests + +class TestUses(TestCase): + + def test_uses(self): + m = Module.new('a') + t = Type.int() + ft = Type.function(t, [t, t, t]) + f = m.add_function(ft, "func") + b = f.append_basic_block('entry') + bld = Builder.new(b) + tmp1 = bld.add(Constant.int(t, 100), f.args[0], "tmp1") + tmp2 = bld.add(tmp1, f.args[1], "tmp2") + tmp3 = bld.add(tmp1, f.args[2], "tmp3") + bld.ret(tmp3) + + # 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) + self.assertEqual(tmp1.use_count, 2) + self.assertEqual(tmp2.use_count, 0) + self.assertEqual(tmp3.use_count, 1) + + # Testing uses + self.assert_(f.args[0].uses[0] is tmp1) + self.assertEqual(len(f.args[0].uses), 1) + self.assert_(f.args[1].uses[0] is tmp2) + self.assertEqual(len(f.args[1].uses), 1) + self.assert_(f.args[2].uses[0] is tmp3) + self.assertEqual(len(f.args[2].uses), 1) + self.assertEqual(len(tmp1.uses), 2) + self.assertEqual(len(tmp2.uses), 0) + self.assertEqual(len(tmp3.uses), 1) + +tests.append(TestUses) + +if __name__ == '__main__': + unittest.main() + diff --git a/llvm/tests/test_volatile.py b/llvm/tests/test_volatile.py new file mode 100644 index 0000000..dace8e8 --- /dev/null +++ b/llvm/tests/test_volatile.py @@ -0,0 +1,59 @@ +import unittest +from llvm.core import Module, Type, Builder +from .support import TestCase, tests + +class TestVolatile(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") + +tests.append(TestVolatile) + +if __name__ == '__main__': + unittest.main() + diff --git a/setup.py b/setup.py index 1e920f8..83745ba 100644 --- a/setup.py +++ b/setup.py @@ -189,7 +189,8 @@ setup( 'llpython', 'llvm_array', 'llvmpy.api', 'llvmpy.api.llvm', - 'llvm.tests'], + 'llvm.tests', + 'llvm.tests.isolated'], package_data = {'llvm': ['llrt/*.ll']}, py_modules = ['llvmpy', 'llvmpy._capsule',