diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index cb33214..16f6daf 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -6,7 +6,6 @@ import contextlib import llvm.core as lc import llvm.ee as le - def _is_int(ty): return isinstance(ty, lc.IntegerType) @@ -31,6 +30,9 @@ def _is_cstruct(ty): except TypeError: return False +def _list_values(iterable): + return [i.value for i in iterable] + @contextlib.contextmanager def _change_block_temporarily(builder, bb): origbb = builder.basic_block @@ -111,7 +113,6 @@ class _Loop(object): def close(self): self.parent.builder.position_at_end(self._bbend) - class CBuilder(object): ''' A wrapper class for features in llvm-py package @@ -136,6 +137,32 @@ class CBuilder(object): func = mod.add_function(functype, name=name) return CBuilder(func) + def printf(self, fmt, *args): + mod = self.function.module + int_t = lc.Type.int() + char_ptr_t = lc.Type.pointer(lc.Type.int(8)) + functype = lc.Type.function(int_t, [char_ptr_t], True) + printf = mod.get_or_insert_function(functype, name='printf') + ret = self.builder.call(printf, [fmt.value]+_list_values(args)) + return CTemp(self, ret) + + def debug(self, *args): + type_mapper = { + 'i32': '%d', + 'double': '%e', + } + itemsfmt = [] + items = [] + for i in args: + if isinstance(i, str): + itemsfmt.append(i.replace('%', '%%')) + else: + ty = type_mapper[str(i.type)] + itemsfmt.append(ty) + items.append(i) + fmt = ' '.join(itemsfmt) + '\n' + return self.printf(self.constant_string(fmt), *items) + def var(self, ty, value=None, name=''): ''' Only allocate in the first block @@ -150,7 +177,7 @@ class CBuilder(object): if value is not None: if isinstance(value, CValue): value = value.value - if not isinstance(value, lc.Value): + elif not isinstance(value, lc.Value): value = self.constant(ty, value).value self.builder.store(value, ptr) if is_cstruct: @@ -213,6 +240,16 @@ class CBuilder(object): res = lc.Constant.null(ty) return CTemp(self, res) + def constant_string(self, string): + mod = self.function.module + name = '.conststr.%x' % hash(string) + content = lc.Constant.stringz(string) + globalstr = mod.add_global_variable(content.type, name=name) + globalstr.initializer = content + ptr = mod.add_global_variable(lc.Type.pointer(content.type.element), + name=name+".ptr") + return CTemp(self, globalstr.bitcast(lc.Type.pointer(content.type.element))) + def get_intrinsic(self, intrinsic_id, tys): lfunc = lc.Function.intrinsic(self.function.module, intrinsic_id, tys) return CFunc(self, lfunc) @@ -515,7 +552,7 @@ class CFunc(CValue): self.function = func def __call__(self, *args): - arg_value = list(map(lambda x: x.value, args)) + arg_value = _list_values(args) res = self.parent.builder.call(self.function, arg_value) return CTemp(self.parent, res) @@ -667,3 +704,4 @@ class CStruct(CValue): gep = self.parent.builder.gep(ptr, [makeind(0), makeind(i)]) setattr(self, fd, CVar(self.parent, gep)) + diff --git a/tests/test_atomic_add.py b/tests/test_atomic_add.py index 63b795a..27688e7 100644 --- a/tests/test_atomic_add.py +++ b/tests/test_atomic_add.py @@ -9,7 +9,7 @@ from llvm_cbuilder import * import llvm_cbuilder.shortnames as C import unittest, logging -logging.basicConfig(level=logging.DEBUG) +# logging.basicConfig(level=logging.DEBUG) NUM_OF_THREAD = 4 REPEAT = 10000 diff --git a/tests/test_atomic_cmpxchg.py b/tests/test_atomic_cmpxchg.py index eb2a45b..27fb763 100644 --- a/tests/test_atomic_cmpxchg.py +++ b/tests/test_atomic_cmpxchg.py @@ -9,7 +9,7 @@ from llvm_cbuilder import * import llvm_cbuilder.shortnames as C import unittest, logging -logging.basicConfig(level=logging.DEBUG) +# logging.basicConfig(level=logging.DEBUG) NUM_OF_THREAD = 4 REPEAT = 10000 diff --git a/tests/test_print.py b/tests/test_print.py new file mode 100644 index 0000000..d971e31 --- /dev/null +++ b/tests/test_print.py @@ -0,0 +1,60 @@ +from llvm.core import * +from llvm.passes import * +from llvm.ee import * +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C +import sys, unittest, logging +from subprocess import Popen, PIPE + +def gen_debugprint(mod): + functype = Type.function(C.void, []) + func = mod.add_function(functype, 'debugprint') + + cb = CBuilder(func) + fmt = cb.constant_string("Show %d %.3f %.3e\n") + + an_int = cb.constant(C.int, 123) + a_float = cb.constant(C.double, 1.234) + a_double = cb.constant(C.double, 1e-31) + cb.printf(fmt, an_int, a_float, a_double) + + cb.debug('an_int =', an_int, 'a_float =', a_float, 'a_double =', a_double) + + cb.ret() + cb.close() + return func + +def main_debugprint(): + # generate code + mod = Module.new(__name__) + lfunc = gen_debugprint(mod) + logging.debug(mod) + mod.verify() + # run + exe = CExecutor(mod) + func = exe.get_ctype_function(lfunc, 'void') + func() + +class TestPrint(unittest.TestCase): + def test_debugprint(self): + p = Popen(["python", "test_print.py", "-child"], stdout=PIPE) + p.wait() + + lines = p.stdout.read().decode().splitlines(False) + + expect = [ + 'Show 123 1.234 1.000e-31', + 'an_int = 123 a_float = 1.234000e+00 a_double = 1.000000e-31', + ] + self.assertEqual(expect, lines) + + p.stdout.close() + +if __name__ == '__main__': + try: + if sys.argv[1] == '-child': + main_debugprint() + except IndexError: + unittest.main() + + diff --git a/tests/test_pthread.py b/tests/test_pthread.py index d5212b0..d1d3a72 100644 --- a/tests/test_pthread.py +++ b/tests/test_pthread.py @@ -5,7 +5,7 @@ from llvm_cbuilder import * import llvm_cbuilder.shortnames as C import unittest, logging -logging.basicConfig(level=logging.DEBUG) +# logging.basicConfig(level=logging.DEBUG) NUM_OF_THREAD = 4