From 4985615442e4bc73c64de57b8003c87fa9211bf3 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Sun, 19 Aug 2012 16:01:17 -0500 Subject: [PATCH 1/8] add tests to llvm package --- llvm/__init__.py | 46 ++++++++------------------ llvm/test_llvmpy.py | 78 +++++++++++++++++++++++++++++++++++++++++++++ setup.py | 14 ++++---- 3 files changed, 99 insertions(+), 39 deletions(-) create mode 100644 llvm/test_llvmpy.py diff --git a/llvm/__init__.py b/llvm/__init__.py index b540270..65aa464 100644 --- a/llvm/__init__.py +++ b/llvm/__init__.py @@ -1,38 +1,9 @@ -# -# Copyright (c) 2008-10, Mahadevan R All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of this software, nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# - -"""Common classes related to LLVM. - +""" +Common classes related to LLVM. """ -VERSION = '0.7' +__version__ = '0.8.2' + from weakref import WeakValueDictionary @@ -158,3 +129,12 @@ class Cacheable(ObjectCache): def forget(self): ObjectCache.forget(self) + +def test(verbosity=1): + """test(verbosity=1) -> TextTestResult + + Run self-test, and return unittest.runner.TextTestResult object. + """ + from llvm.test_llvmpy import run + + return run(verbosity=verbosity) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py new file mode 100644 index 0000000..9876f28 --- /dev/null +++ b/llvm/test_llvmpy.py @@ -0,0 +1,78 @@ +""" +LLVM tests +""" +import os +import sys +import unittest + +is_py3k = bool(sys.version_info[0] == 3) + +if is_py3k: + from io import StringIO +else: + from cStringIO import StringIO + + +from llvm import __version__ +import llvm.core as lc + + +tests = [] + +class TestOperands(unittest.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 + ret i32 %tmp3 +} +""" + def test_operands(self): + m = lc.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] + + self.assertEqual(i1.operand_count, 3) + self.assertEqual(i2.operand_count, 2) + + 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) + +tests.append(TestOperands) + +# --------------------------------------------------------------------------- + +def run(verbosity=1): + print('llvmpy is installed in: ' + os.path.dirname(__file__)) + print('llvmpy version: ' + __version__) + print(sys.version) + + suite = unittest.TestSuite() + for cls in tests: + suite.addTest(unittest.makeSuite(cls)) + + runner = unittest.TextTestRunner(verbosity=verbosity) + return runner.run(suite) + + +if __name__ == '__main__': + run() diff --git a/setup.py b/setup.py index 3a21137..c38f736 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,6 @@ import re from distutils.core import setup, Extension -LLVM_PY_VERSION = '0.8.2' llvm_config = os.environ.get('LLVM_CONFIG_PATH', 'llvm-config') # set LLVMPY_DYNLINK=1, if you want to link _core.so dynamically to libLLVM.so @@ -88,7 +87,7 @@ extra_link_args = ["-fPIC"] if sys.platform == 'darwin': std_libs.append("ffi") -ext_core = Extension( +kwds = dict(ext_modules = Extension( name='llvm._core', sources=['llvm/_core.cpp', 'llvm/wrap.cpp', 'llvm/extra.cpp'], define_macros = [('__STDC_CONSTANT_MACROS', None), @@ -98,17 +97,20 @@ ext_core = Extension( library_dirs = [libdir], libraries = std_libs + libs_core, extra_objects = objs_core, - extra_link_args = extra_link_args, -) + extra_link_args = extra_link_args)) + +# Read version from llvm/__init__.py +pat = re.compile(r'__version__\s*=\s*(\S+)', re.M) +data = open('llvm/__init__.py').read() +kwds['version'] = eval(pat.search(data).group(1)) setup( name = 'llvm-py', - version = LLVM_PY_VERSION, description = 'Python bindings for LLVM', author = 'Mahadevan R', author_email = 'mdevan@mdevan.org', url = 'http://www.llvmpy.org/', packages = ['llvm'], py_modules = ['llvm.core'], - ext_modules = [ ext_core ], + **kwds ) From 4a090c8c76640d30b82c4fcf7eeca09c84ca6d54 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Sun, 19 Aug 2012 16:36:32 -0500 Subject: [PATCH 2/8] add passes tests --- llvm/test_llvmpy.py | 125 ++++++++++++++++++++++++++++++++++++++++++++ setup.py | 4 +- 2 files changed, 127 insertions(+), 2 deletions(-) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 9876f28..7a102b8 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -15,6 +15,8 @@ else: from llvm import __version__ import llvm.core as lc +import llvm.passes as lp +import llvm.ee as le tests = [] @@ -61,6 +63,129 @@ tests.append(TestOperands) # --------------------------------------------------------------------------- +class TestPasses(unittest.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 = lc.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(lp.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(lp.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 = lc.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) + self.assertFalse(pmb.disable_simplify_lib_calls) + + # 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()) + +tests.append(TestPasses) + +# --------------------------------------------------------------------------- + def run(verbosity=1): print('llvmpy is installed in: ' + os.path.dirname(__file__)) print('llvmpy version: ' + __version__) diff --git a/setup.py b/setup.py index c38f736..f5338d0 100644 --- a/setup.py +++ b/setup.py @@ -87,7 +87,7 @@ extra_link_args = ["-fPIC"] if sys.platform == 'darwin': std_libs.append("ffi") -kwds = dict(ext_modules = Extension( +kwds = dict(ext_modules = [Extension( name='llvm._core', sources=['llvm/_core.cpp', 'llvm/wrap.cpp', 'llvm/extra.cpp'], define_macros = [('__STDC_CONSTANT_MACROS', None), @@ -97,7 +97,7 @@ kwds = dict(ext_modules = Extension( library_dirs = [libdir], libraries = std_libs + libs_core, extra_objects = objs_core, - extra_link_args = extra_link_args)) + extra_link_args = extra_link_args)]) # Read version from llvm/__init__.py pat = re.compile(r'__version__\s*=\s*(\S+)', re.M) From 274a9e9cd255d2d2475445f675f23e7777b4bf73 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Sun, 19 Aug 2012 16:26:01 -0500 Subject: [PATCH 3/8] finished moving passes tests --- llvm/test_llvmpy.py | 7 +- test/passes.py | 174 -------------------------------------------- 2 files changed, 5 insertions(+), 176 deletions(-) delete mode 100644 test/passes.py diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 7a102b8..30c24ab 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -101,7 +101,7 @@ entry: pm = lp.PassManager.new() # Add the target data as the first "pass". This is mandatory. - pm.add(lp.TargetData.new('')) + pm.add(le.TargetData.new('')) # Add the inlining pass. pm.add(lp.PASS_INLINE) @@ -125,7 +125,7 @@ entry: fpm = lp.FunctionPassManager.new(m) # Add the target data as first "pass". This is mandatory. - fpm.add(lp.TargetData.new('')) + fpm.add(le.TargetData.new('')) # Add a DCE pass fpm.add(lp.PASS_ADCE) @@ -182,6 +182,9 @@ entry: # 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) # --------------------------------------------------------------------------- diff --git a/test/passes.py b/test/passes.py deleted file mode 100644 index ff8f6d1..0000000 --- a/test/passes.py +++ /dev/null @@ -1,174 +0,0 @@ -#!/usr/bin/env python - -from llvm.core import * -from llvm.passes import * -from llvm.ee import * -try: - from StringIO import StringIO -except ImportError: - from io import StringIO - - -import logging, unittest - -# A helper class. -#class strstream(object): -# def __init__(self, s): -# self.s = s -# def read(self): -# return self.s - -# 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 -} -""" - -class TestPasses(unittest.TestCase): - def test_passes(self): - m = Module.from_assembly(StringIO(asm)) - logging.debug("-"*72) - logging.debug(m) - - 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 = PassManager.new() - - # Add the target data as the first "pass". This is mandatory. - pm.add( TargetData.new('') ) - - # Add the inlining pass. - pm.add( PASS_INLINE ) - - # Run it! - pm.run(m) - - - # Done with the pass manager. - del pm - - # Print the result. Note the change in @test2. - logging.debug("-"*72) - logging.debug(m) - - # 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 = FunctionPassManager.new(m) - - # Add the target data as first "pass". This is mandatory. - fpm.add( TargetData.new('') ) - - # Add a DCE pass - fpm.add( PASS_ADCE ) - - # Run the pass on the function 'test1' - fpm.run( m.get_function_named('test1') ) - - # Print the result. Note the change in @test1. - logging.debug("-"*72) - logging.debug(m) - - # 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(asm)) - logging.debug("-"*72) - logging.debug(m) - - 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 = 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) - self.assertFalse(pmb.disable_simplify_lib_calls) - - # Do function pass - fpm = FunctionPassManager.new(m) - - pmb.populate(fpm) - - fpm.run(fn_test1) - - # Print the result. Note the change in @test1. - logging.debug("-"*72) - logging.debug(m) - - # Make sure test1 has changed - self.assertNotEqual(str(fn_test1).strip(), original_test1.strip()) - - - # Do module pass - pm = PassManager.new() - - pmb.populate(pm) - - pm.run(m) - - # Print the result. Note the change in @test2. - logging.debug("-"*72) - logging.debug(m) - - # Make sure test2 has changed - self.assertNotEqual(str(fn_test2).strip(), original_test2.strip()) - - - def test_dump_passes(self): - self.assertTrue(len(PASSES)>0, msg="Cannot have no passes") - - -if __name__ == '__main__': - unittest.main() - From a24d4a9f122470431d96b59328579c5b9d384a6e Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Sun, 19 Aug 2012 17:10:31 -0500 Subject: [PATCH 4/8] add object cahce tests --- llvm/test_llvmpy.py | 109 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 105 insertions(+), 4 deletions(-) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 30c24ab..f1f2a56 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -14,7 +14,7 @@ else: from llvm import __version__ -import llvm.core as lc +from llvm.core import Module, Type, GlobalVariable, Function, Builder import llvm.passes as lp import llvm.ee as le @@ -39,7 +39,7 @@ entry: } """ def test_operands(self): - m = lc.Module.from_assembly(StringIO(self.test_module)) + m = Module.from_assembly(StringIO(self.test_module)) test_func = m.get_function_named("test_func") prod = m.get_function_named("prod") @@ -89,7 +89,7 @@ entry: } """ def test_passes(self): - m = lc.Module.from_assembly(StringIO(self.asm)) + m = Module.from_assembly(StringIO(self.asm)) fn_test1 = m.get_function_named('test1') fn_test2 = m.get_function_named('test2') @@ -137,7 +137,7 @@ entry: self.assertNotEqual(str(fn_test1).strip(), original_test1.strip()) def test_passes_with_pmb(self): - m = lc.Module.from_assembly(StringIO(self.asm)) + m = Module.from_assembly(StringIO(self.asm)) fn_test1 = m.get_function_named('test1') fn_test2 = m.get_function_named('test2') @@ -189,6 +189,107 @@ tests.append(TestPasses) # --------------------------------------------------------------------------- +class TestObjCache(unittest.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.get_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) + +# --------------------------------------------------------------------------- + def run(verbosity=1): print('llvmpy is installed in: ' + os.path.dirname(__file__)) print('llvmpy version: ' + __version__) From 501c3d0f614a6252865028871a28bcfaf318c730 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Sun, 19 Aug 2012 17:08:34 -0500 Subject: [PATCH 5/8] move native tests --- llvm/test_llvmpy.py | 51 +++++++++++++++++++- test/native.py | 53 -------------------- test/objcache.py | 115 -------------------------------------------- 3 files changed, 50 insertions(+), 169 deletions(-) delete mode 100644 test/native.py delete mode 100644 test/objcache.py diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index f1f2a56..f0e5143 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -4,6 +4,7 @@ LLVM tests import os import sys import unittest +import subprocess is_py3k = bool(sys.version_info[0] == 3) @@ -14,7 +15,8 @@ else: from llvm import __version__ -from llvm.core import Module, Type, GlobalVariable, Function, Builder +from llvm.core import (Module, Type, GlobalVariable, Function, Builder, + Constant) import llvm.passes as lp import llvm.ee as le @@ -290,6 +292,53 @@ tests.append(TestObjCache) # --------------------------------------------------------------------------- +class TestNative(unittest.TestCase): + + 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): + dst = '/tmp/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): + m = self._make_module() + output = m.to_native_assembly() + + src = '/tmp/llvmasm.s' + with open(src, 'wb') as fout: + fout.write(output) + + self._compile(src) + + def test_object(self): + m = self._make_module() + output = m.to_native_object() + + src = '/tmp/llvmobj.o' + with open(src, 'wb') as fout: + fout.write(output) + + self._compile(src) + +tests.append(TestNative) + +# --------------------------------------------------------------------------- + def run(verbosity=1): print('llvmpy is installed in: ' + os.path.dirname(__file__)) print('llvmpy version: ' + __version__) diff --git a/test/native.py b/test/native.py deleted file mode 100644 index f4287c9..0000000 --- a/test/native.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env python - -from llvm import * -from llvm.core import * - -import unittest, subprocess - -class TestNative(unittest.TestCase): - - 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): - dst = '/tmp/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): - m = self._make_module() - output = m.to_native_assembly() - - src = '/tmp/llvmasm.s' - with open(src, 'wb') as fout: - fout.write(output) - - self._compile(src) - - def test_object(self): - m = self._make_module() - output = m.to_native_object() - - src = '/tmp/llvmobj.o' - with open(src, 'wb') as fout: - fout.write(output) - - self._compile(src) - -if __name__ == '__main__': - unittest.main() diff --git a/test/objcache.py b/test/objcache.py deleted file mode 100644 index c8bc7e4..0000000 --- a/test/objcache.py +++ /dev/null @@ -1,115 +0,0 @@ -#!/usr/bin/env python - -from llvm.core import * - -import logging, sys, unittest - -class TestObjCache(unittest.TestCase): - - if sys.version_info[:2] < (2, 7): - def assertIs(self, expr1, expr2, msg=None): - if expr1 is not expr2: - standardMsg = '%s is not %s' % (safe_repr(expr1), - safe_repr(expr2)) - self.fail(self._formatMessage(msg, standardMsg)) - - def test_objcache(self): - logging.debug("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.assertIs(m1, m2) - - logging.debug("Testing global vairable aliasing 1 .. ") - gv1 = GlobalVariable.new(m1, t, "gv") - gv2 = GlobalVariable.get(m1, "gv") - self.assertIs(gv1, gv2) - - logging.debug("Testing global vairable aliasing 2 .. ") - gv3 = m1.global_variables[0] - self.assertIs(gv1, gv3) - - logging.debug("Testing global vairable aliasing 3 .. ") - - gv2 = None - gv3 = None - - gv1.delete() - gv4 = GlobalVariable.new(m1, t, "gv") - - self.assert_(gv1 is not gv4) - - logging.debug("Testing function aliasing 1 ..") - b1 = f1.append_basic_block('entry') - f2 = b1.function - self.assertIs(f1, f2) - - logging.debug("Testing function aliasing 2 ..") - f3 = m1.get_function_named("func") - self.assertIs(f1, f3) - - logging.debug("Testing function aliasing 3 ..") - f4 = Function.get_or_insert(m1, ft, "func") - self.assertIs(f1, f4) - - logging.debug("Testing function aliasing 4 ..") - f5 = Function.get(m1, "func") - self.assertIs(f1, f5) - - logging.debug("Testing function aliasing 5 ..") - f6 = m1.get_or_insert_function(ft, "func") - self.assertIs(f1, f6) - - logging.debug("Testing function aliasing 6 ..") - f7 = m1.functions[0] - self.assertIs(f1, f7) - - logging.debug("Testing argument aliasing .. ") - a1 = f1.args[0] - a2 = f1.args[0] - self.assertIs(a1, a2) - - logging.debug("Testing basic block aliasing 1 .. ") - b2 = f1.basic_blocks[0] - self.assertIs(b1, b2) - - logging.debug("Testing basic block aliasing 2 .. ") - b3 = f1.get_entry_basic_block() - self.assertIs(b1, b3) - - logging.debug("Testing basic block aliasing 3 .. ") - b31 = f1.entry_basic_block - self.assertIs(b1, b31) - - logging.debug("Testing basic block aliasing 4 .. ") - bldr = Builder.new(b1) - b4 = bldr.basic_block - self.assertIs(b1, b4) - - logging.debug("Testing basic block aliasing 5 .. ") - i1 = bldr.ret_void() - b5 = i1.basic_block - self.assertIs(b1, b5) - - logging.debug("Testing instruction aliasing 1 .. ") - i2 = b5.instructions[0] - self.assertIs(i1, 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) - - logging.debug("Testing PHI / basic block aliasing 5 .. ") - self.assertIs(b1, b6) - - logging.debug("Testing PHI / value aliasing .. ") - self.assertIs(f1.args[0], v2) - - - -if __name__ == '__main__': - unittest.main() From 552bae186480591dc3ae9c5fc9a4f4e72c961fa0 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Sun, 19 Aug 2012 17:32:15 -0500 Subject: [PATCH 6/8] add uses tests --- llvm/test_llvmpy.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index f0e5143..d3ef55a 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -339,6 +339,43 @@ tests.append(TestNative) # --------------------------------------------------------------------------- +class TestUses(unittest.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) + +# --------------------------------------------------------------------------- + def run(verbosity=1): print('llvmpy is installed in: ' + os.path.dirname(__file__)) print('llvmpy version: ' + __version__) From 46c185f530b5a8c2b37bd186cf529d0962a3e337 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Sun, 19 Aug 2012 17:17:05 -0500 Subject: [PATCH 7/8] remove unused test module --- test/uses.py | 45 --------------------------------------------- 1 file changed, 45 deletions(-) delete mode 100644 test/uses.py diff --git a/test/uses.py b/test/uses.py deleted file mode 100644 index d95dc90..0000000 --- a/test/uses.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python - -from llvm.core import * - -import unittest, logging - -class TestUses(unittest.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) - - logging.debug("-"*60) - logging.debug(m) - logging.debug("-"*60) - - logging.debug("Testing use count ..") - self.assertEqual(f.args[0].use_count, 1) - self.assertEqual(f.args[1].use_count, 1) - self.assertEqual(f.args[2].use_count, 1) - self.assertEqual(tmp1.use_count, 2) - self.assertEqual(tmp2.use_count, 0) - self.assertEqual(tmp3.use_count, 1) - - logging.debug("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) - -if __name__ == '__main__': - unittest.main() - From 3dcd1cf8f5f37195d8f2c3c27965c2f97b6a3617 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Sun, 19 Aug 2012 17:57:29 -0500 Subject: [PATCH 8/8] add note about running tests --- README.md | 24 ------------------------ README.rst | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 24 deletions(-) delete mode 100644 README.md create mode 100644 README.rst diff --git a/README.md b/README.md deleted file mode 100644 index f0d1f09..0000000 --- a/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# llvm-py: Python Bindings for LLVM # -llvm-py provides Python bindings for LLVM. - -## Home page ## -http://www.llvmpy.org - -## Versions ## -This package has only been tested with LLVM 3.1, and Python 2.7, (not Python 3.x). - -## Quickstart ## -1. Get 3.1 version of LLVM, build it. Make sure '--enable-pic' is passed to LLVM's 'configure'. -2. Get llvm-py and install it: - -``` -$ git clone git@github.com:llvmpy/llvmpy.git -$ cd llvmpy -$ python setup.py install -``` - -3. See documentation at 'http://www.llvmpy.org/pages.html' and examples under 'test'. - -## LICENSE ## -llvm-py is distributed under the new BSD license, which is similar to the LLVM license itself. -See the file called LICENSE for the full license text. diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..da506c7 --- /dev/null +++ b/README.rst @@ -0,0 +1,39 @@ +================================= +llvm-py: Python bindings for LLVM +================================= + +Home page +--------- + +http://www.llvmpy.org + +Versions +-------- + +This package has only been tested with LLVM 3.1, and Python 2.7, (not Python 3.x). + +Quickstart +---------- + +1. Get 3.1 version of LLVM, build it. Make sure ``--enable-pic`` is passed to + LLVM's ``configure``. + +2. Get llvm-py and install it:: + + $ git clone git@github.com:llvmpy/llvmpy.git + $ cd llvmpy + $ python setup.py install + + Run the tests:: + + $ python -c "import llvm; llvm.test()" + +3. See documentation at 'http://www.llvmpy.org/pages.html' and examples + under 'test'. + +LICENSE +------- + +llvmpy is distributed under the new BSD license, which is similar to the LLVM +license itself. +See the file called LICENSE for the full license text.