diff --git a/test/call-jit-ctypes.py b/test/call-jit-ctypes.py index 735dfd9..ee54bc0 100755 --- a/test/call-jit-ctypes.py +++ b/test/call-jit-ctypes.py @@ -3,61 +3,68 @@ from llvm.core import Module,Type,Builder from llvm.ee import ExecutionEngine import llvm.core + import ctypes -def test_jit_ctypes(): +import logging +import unittest - # This example demonstrates calling an LLVM defined function using - # ctypes. It illustrates the common C pattern of having an output - # variable in the argument list to the function. The function also - # returns an error code upon exit. +class TestCallJITCtypes(unittest.TestCase): + def test_jit_ctypes(self): - # setup llvm types - ty_errcode = Type.int() - ty_float = Type.float() - ty_ptr_float = Type.pointer(Type.float()) - ty_func = Type.function(ty_errcode, [ty_float, ty_float, ty_ptr_float]) + # This example demonstrates calling an LLVM defined function using + # ctypes. It illustrates the common C pattern of having an output + # variable in the argument list to the function. The function also + # returns an error code upon exit. - # setup ctypes types - ct_errcode = ctypes.c_int - ct_float = ctypes.c_float - ct_ptr_float = ctypes.POINTER(ct_float) - ct_argtypes = [ct_float, ct_float, ct_ptr_float] + # setup llvm types + ty_errcode = Type.int() + ty_float = Type.float() + ty_ptr_float = Type.pointer(Type.float()) + ty_func = Type.function(ty_errcode, [ty_float, ty_float, ty_ptr_float]) - # generate the function using LLVM - my_module = Module.new('my_module') + # setup ctypes types + ct_errcode = ctypes.c_int + ct_float = ctypes.c_float + ct_ptr_float = ctypes.POINTER(ct_float) + ct_argtypes = [ct_float, ct_float, ct_ptr_float] - mult = my_module.add_function(ty_func, "mult") - mult.args[0].name = "a" - mult.args[1].name = "b" - mult.args[2].name = "out" - mult.args[2].add_attribute(llvm.core.ATTR_NO_CAPTURE) # add nocapture to output arg - mult.does_not_throw = True # add nounwind attribute to function + # generate the function using LLVM + my_module = Module.new('my_module') - bb = mult.append_basic_block("entry") - builder = Builder.new(bb) - tmp = builder.fmul( mult.args[0], mult.args[1] ) - builder.store( tmp, mult.args[2] ) - builder.ret(llvm.core.Constant.int(ty_errcode, 0)) + mult = my_module.add_function(ty_func, "mult") + mult.args[0].name = "a" + mult.args[1].name = "b" + mult.args[2].name = "out" + # add nocapture to output arg + mult.args[2].add_attribute(llvm.core.ATTR_NO_CAPTURE) + mult.does_not_throw = True # add nounwind attribute to function + + bb = mult.append_basic_block("entry") + builder = Builder.new(bb) + tmp = builder.fmul( mult.args[0], mult.args[1] ) + builder.store( tmp, mult.args[2] ) + builder.ret(llvm.core.Constant.int(ty_errcode, 0)) - if 0: # print the created module - print(my_module) + logging.debug(my_module) - # compile the function - ee = ExecutionEngine.new(my_module) + # compile the function + ee = ExecutionEngine.new(my_module) - # let ctypes know about the function - func_ptr_int = ee.get_pointer_to_function( mult ) - FUNC_TYPE = ctypes.CFUNCTYPE(ct_errcode, *ct_argtypes) - py_mult = FUNC_TYPE(func_ptr_int) + # let ctypes know about the function + func_ptr_int = ee.get_pointer_to_function( mult ) + FUNC_TYPE = ctypes.CFUNCTYPE(ct_errcode, *ct_argtypes) + py_mult = FUNC_TYPE(func_ptr_int) - # now run the function, calling via ctypes - output_value = ct_float(123456.0) - errcode = py_mult( 2.0, 3.0, ctypes.byref(output_value) ) - if errcode != 0: - raise RuntimeError('unexpected error') - assert output_value.value == 6.0 + # now run the function, calling via ctypes + output_value = ct_float(123456.0) + errcode = py_mult( 2.0, 3.0, ctypes.byref(output_value) ) + + self.assertEqual(errcode, 0, msg='unexpected error') + + self.assertEqual(output_value.value, 6.0) if __name__=='__main__': - test_jit_ctypes() + unittest.main() + diff --git a/test/example-jit.py b/test/example-jit.py index 3a4e88b..67556f1 100755 --- a/test/example-jit.py +++ b/test/example-jit.py @@ -5,29 +5,44 @@ from llvm import * from llvm.core import * from llvm.ee import * # new import: ee = Execution Engine -# Create a module, as in the previous example. -my_module = Module.new('my_module') -ty_int = Type.int() # by default 32 bits -ty_func = Type.function(ty_int, [ty_int, ty_int]) -f_sum = my_module.add_function(ty_func, "sum") -f_sum.args[0].name = "a" -f_sum.args[1].name = "b" -bb = f_sum.append_basic_block("entry") -builder = Builder.new(bb) -tmp = builder.add(f_sum.args[0], f_sum.args[1], "tmp") -builder.ret(tmp) +import logging +import unittest -# Create an execution engine object. This will create a JIT compiler -# on platforms that support it, or an interpreter otherwise. -ee = ExecutionEngine.new(my_module) -# The arguments needs to be passed as "GenericValue" objects. -arg1 = GenericValue.int(ty_int, 100) -arg2 = GenericValue.int(ty_int, 42) +class TestExampleJIT(unittest.TestCase): + def test_example_jit(self): + # Create a module, as in the previous example. + my_module = Module.new('my_module') + ty_int = Type.int() # by default 32 bits + ty_func = Type.function(ty_int, [ty_int, ty_int]) + f_sum = my_module.add_function(ty_func, "sum") + f_sum.args[0].name = "a" + f_sum.args[1].name = "b" + bb = f_sum.append_basic_block("entry") + builder = Builder.new(bb) + tmp = builder.add(f_sum.args[0], f_sum.args[1], "tmp") + builder.ret(tmp) -# Now let's compile and run! -retval = ee.run_function(f_sum, [arg1, arg2]) + # Create an execution engine object. This will create a JIT compiler + # on platforms that support it, or an interpreter otherwise. + ee = ExecutionEngine.new(my_module) -# The return value is also GenericValue. Let's print it. -print("returned", retval.as_int()) + # The arguments needs to be passed as "GenericValue" objects. + arg1_value = 100 + arg2_value = 42 + + arg1 = GenericValue.int(ty_int, arg1_value) + arg2 = GenericValue.int(ty_int, arg2_value) + + # Now let's compile and run! + retval = ee.run_function(f_sum, [arg1, arg2]) + + # The return value is also GenericValue. Let's print it. + logging.debug("returned %d", retval.as_int()) + + self.assertEqual(retval.as_int(), (arg1_value + arg2_value)) + + +if __name__ == '__main__': + unittest.main() diff --git a/test/example.py b/test/example.py index 8c8b17e..58c4ce4 100755 --- a/test/example.py +++ b/test/example.py @@ -4,42 +4,58 @@ from llvm import * from llvm.core import * -# Create an (empty) module. -my_module = Module.new('my_module') +import logging +import unittest -# All the types involved here are "int"s. This type is represented -# by an object of the llvm.core.Type class: -ty_int = Type.int() # by default 32 bits -# We need to represent the class of functions that accept two integers -# and return an integer. This is represented by an object of the -# function type (llvm.core.FunctionType): -ty_func = Type.function(ty_int, [ty_int, ty_int]) +class TestExample(unittest.TestCase): + def test_example(self): + # Create an (empty) module. + my_module = Module.new('my_module') -# Now we need a function named 'sum' of this type. Functions are not -# free-standing (in llvm-py); it needs to be contained in a module. -f_sum = my_module.add_function(ty_func, "sum") + # All the types involved here are "int"s. This type is represented + # by an object of the llvm.core.Type class: + ty_int = Type.int() # by default 32 bits -# Let's name the function arguments as 'a' and 'b'. -f_sum.args[0].name = "a" -f_sum.args[1].name = "b" + # We need to represent the class of functions that accept two integers + # and return an integer. This is represented by an object of the + # function type (llvm.core.FunctionType): + ty_func = Type.function(ty_int, [ty_int, ty_int]) -# Our function needs a "basic block" -- a set of instructions that -# end with a terminator (like return, branch etc.). By convention -# the first block is called "entry". -bb = f_sum.append_basic_block("entry") + # Now we need a function named 'sum' of this type. Functions are not + # free-standing (in llvm-py); it needs to be contained in a module. + f_sum = my_module.add_function(ty_func, "sum") -# Let's add instructions into the block. For this, we need an -# instruction builder: -builder = Builder.new(bb) + self.assertEqual(str(f_sum).strip(), 'declare i32 @sum(i32, i32)') -# OK, now for the instructions themselves. We'll create an add -# instruction that returns the sum as a value, which we'll use -# a ret instruction to return. -tmp = builder.add(f_sum.args[0], f_sum.args[1], "tmp") -builder.ret(tmp) + # Let's name the function arguments as 'a' and 'b'. + f_sum.args[0].name = "a" + f_sum.args[1].name = "b" -# We've completed the definition now! Let's see the LLVM assembly -# language representation of what we've created: -print(my_module) + # Our function needs a "basic block" -- a set of instructions that + # end with a terminator (like return, branch etc.). By convention + # the first block is called "entry". + bb = f_sum.append_basic_block("entry") + + # Let's add instructions into the block. For this, we need an + # instruction builder: + builder = Builder.new(bb) + + # OK, now for the instructions themselves. We'll create an add + # instruction that returns the sum as a value, which we'll use + # a ret instruction to return. + tmp = builder.add(f_sum.args[0], f_sum.args[1], "tmp") + + self.assertEqual(str(tmp).strip(), '%tmp = add i32 %a, %b') + + builder.ret(tmp) + + # We've completed the definition now! Let's see the LLVM assembly + # language representation of what we've created: + logging.debug(my_module) + + + +if __name__ == '__main__': + unittest.main() diff --git a/test/intrinsic.py b/test/intrinsic.py index e9e4cfe..34c70c8 100755 --- a/test/intrinsic.py +++ b/test/intrinsic.py @@ -5,75 +5,106 @@ from llvm.core import * from llvm.ee import * -# setup a function and a builder -mod = Module.new('test') -functy = Type.function(Type.void(), []) -func = mod.add_function(functy, "showme") -block = func.append_basic_block("entry") -b = Builder.new(block) +import logging +import unittest +import math -# let's do bswap on a 32-bit integer using llvm.bswap -val = Constant.int(Type.int(), 42) -bswap = Function.intrinsic(mod, INTR_BSWAP, [Type.int()]) -b.call(bswap, [val]) -print(mod) +class TestIntrinsic(unittest.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) -# the output is: -# -# ; ModuleID = 'test' -# -# define void @showme() { -# entry: -# call i32 @llvm.bswap.i32( i32 42 ) ; :0 [#uses=0] -# } -# -# declare i32 @llvm.bswap.i32(i32) nounwind readnone -# + # let's do bswap on a 32-bit integer using llvm.bswap + val = Constant.int(Type.int(), 0x42) + bswap = Function.intrinsic(mod, INTR_BSWAP, [Type.int()]) -# mysin(x) = sqrt(1.0 - pow(cos(x), 2)) + bswap_res = b.call(bswap, [val]) + b.ret(bswap_res) -float = Type.float() -mysinty = Type.function( float, [float] ) -mysin = mod.add_function(mysinty, "mysin") -block = mysin.append_basic_block("entry") -b = Builder.new(block) + # see the generated IR + logging.debug(mod) -sqrt = Function.intrinsic(mod, INTR_SQRT, [float]) -pow = Function.intrinsic(mod, INTR_POWI, [float]) -cos = Function.intrinsic(mod, INTR_COS, [float]) + # the output is: + # + # ; ModuleID = 'test' + # + # define void @showme() { + # entry: + # %0 = call i32 @llvm.bswap.i32(i32 42) + # ret i32 %0 + # } -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.sub(one, cos2, "onemc2") -sin = b.call(sqrt, [onemc2], "sin") -b.ret(sin) -print(mod) + # let's run the function + ee = ExecutionEngine.new(mod) + retval = ee.run_function(func, []) + self.assertEqual(retval.as_int(), 0x42000000) + + + def test_mysin(self): + # 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, INTR_SQRT, [float]) + pow = Function.intrinsic(mod, INTR_POWI, [float]) + cos = Function.intrinsic(mod, 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=0] + # } + # + # declare i32 @llvm.bswap.i32(i32) nounwind readnone + # + # define float @mysin(float %x) { + # entry: + # %cosx = call float @llvm.cos.f32( float %x ) ; [#uses=1] + # %cos2 = call float @llvm.powi.f32( float %cosx, i32 2 ) ; [#uses=1] + # %onemc2 = sub float 1.000000e+00, %cos2 ; [#uses=1] + # %sin = call float @llvm.sqrt.f32( float %onemc2 ) ; [#uses=1] + # 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 + ee = ExecutionEngine.new(mod) + arg = GenericValue.real(Type.float(), 1.234) + retval = ee.run_function(mysin, [arg]) + + golden = math.sin(1.234) + answer = retval.as_real(Type.float()) + self.assertLess(abs(answer-golden)/golden, 1e-5) + + +if __name__ == '__main__': + unittest.main() -# -# ; ModuleID = 'test' -# -# define void @showme() { -# entry: -# call i32 @llvm.bswap.i32( i32 42 ) ; :0 [#uses=0] -# } -# -# declare i32 @llvm.bswap.i32(i32) nounwind readnone -# -# define float @mysin(float %x) { -# entry: -# %cosx = call float @llvm.cos.f32( float %x ) ; [#uses=1] -# %cos2 = call float @llvm.powi.f32( float %cosx, i32 2 ) ; [#uses=1] -# %onemc2 = sub float 1.000000e+00, %cos2 ; [#uses=1] -# %sin = call float @llvm.sqrt.f32( float %onemc2 ) ; [#uses=1] -# 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 -# diff --git a/test/issue10.py b/test/issue10.py index 2969564..9c654f4 100755 --- a/test/issue10.py +++ b/test/issue10.py @@ -1,21 +1,27 @@ #!/usr/bin/env python from llvm.core import * -import llvm._core -m = Module.new('a') -ti = Type.int() -tf = Type.function(ti, [ti, ti]) +import unittest -f = m.add_function(tf, "func1") +class TestIssue10(unittest.TestCase): + def test_issue10(self): + m = Module.new('a') + ti = Type.int() + tf = Type.function(ti, [ti, ti]) -bb = f.append_basic_block('entry') + f = m.add_function(tf, "func1") -b = Builder.new(bb) + bb = f.append_basic_block('entry') -# There are no instructions in bb. Positioning of the -# builder at beginning (or end) should succeed (trivially). + b = Builder.new(bb) -b.position_at_end(bb) -b.position_at_beginning(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) + +if __name__ == '__main__': + unittest.main()