diff --git a/artiq/coredevice/runtime.py b/artiq/coredevice/runtime.py index e0157934e..317dc9d02 100644 --- a/artiq/coredevice/runtime.py +++ b/artiq/coredevice/runtime.py @@ -1,14 +1,15 @@ import os -from fractions import Fraction -from llvm import core as lc -from llvm import target as lt +import llvmlite.ir as ll +import llvmlite.binding as llvm from artiq.py2llvm import base_types from artiq.language import units -lt.initialize_all() +llvm.initialize() +llvm.initialize_all_targets() +llvm.initialize_all_asmprinters() _syscalls = { "rpc": "i+:i", @@ -23,10 +24,10 @@ _syscalls = { } _chr_to_type = { - "n": lambda: lc.Type.void(), - "b": lambda: lc.Type.int(1), - "i": lambda: lc.Type.int(32), - "I": lambda: lc.Type.int(64) + "n": lambda: ll.VoidType(), + "b": lambda: ll.IntType(1), + "i": lambda: ll.IntType(32), + "I": lambda: ll.IntType(64) } _chr_to_value = { @@ -45,45 +46,50 @@ def _str_to_functype(s): type_args = [] for n, c in enumerate(s[:-2]): if c == "+": - type_args.append(lc.Type.int()) + type_args.append(ll.IntType(32)) var_arg_fixcount = n elif c != "n": type_args.append(_chr_to_type[c]()) return (var_arg_fixcount, - lc.Type.function(type_ret, type_args, - var_arg=var_arg_fixcount is not None)) + ll.FunctionType(type_ret, type_args, + var_arg=var_arg_fixcount is not None)) class LinkInterface: def init_module(self, module): - self.llvm_module = module.llvm_module + self.module = module + llvm_module = self.module.llvm_module # syscalls + self.syscalls = dict() self.var_arg_fixcount = dict() for func_name, func_type_str in _syscalls.items(): var_arg_fixcount, func_type = _str_to_functype(func_type_str) if var_arg_fixcount is not None: self.var_arg_fixcount[func_name] = var_arg_fixcount - self.llvm_module.add_function(func_type, "__syscall_"+func_name) + self.syscalls[func_name] = ll.Function( + llvm_module, func_type, "__syscall_" + func_name) # exception handling - func_type = lc.Type.function(lc.Type.int(), [lc.Type.pointer(lc.Type.int(8))]) - function = self.llvm_module.add_function(func_type, "__eh_setjmp") - function.add_attribute(lc.ATTR_NO_UNWIND) - function.add_attribute(lc.ATTR_RETURNS_TWICE) + func_type = ll.FunctionType(ll.IntType(32), + [ll.PointerType(ll.IntType(8))]) + self.eh_setjmp = ll.Function(llvm_module, func_type, + "__eh_setjmp") + self.eh_setjmp.attributes.add("nounwind") + self.eh_setjmp.attributes.add("returns_twice") - func_type = lc.Type.function(lc.Type.pointer(lc.Type.int(8)), []) - self.llvm_module.add_function(func_type, "__eh_push") + func_type = ll.FunctionType(ll.PointerType(ll.IntType(8)), []) + self.eh_push = ll.Function(llvm_module, func_type, "__eh_push") - func_type = lc.Type.function(lc.Type.void(), [lc.Type.int()]) - self.llvm_module.add_function(func_type, "__eh_pop") + func_type = ll.FunctionType(ll.VoidType(), [ll.IntType(32)]) + self.eh_pop = ll.Function(llvm_module, func_type, "__eh_pop") - func_type = lc.Type.function(lc.Type.int(), []) - self.llvm_module.add_function(func_type, "__eh_getid") + func_type = ll.FunctionType(ll.IntType(32), []) + self.eh_getid = ll.Function(llvm_module, func_type, "__eh_getid") - func_type = lc.Type.function(lc.Type.void(), [lc.Type.int()]) - function = self.llvm_module.add_function(func_type, "__eh_raise") - function.add_attribute(lc.ATTR_NO_RETURN) + func_type = ll.FunctionType(ll.VoidType(), [ll.IntType(32)]) + self.eh_raise = ll.Function(llvm_module, func_type, "__eh_raise") + self.eh_raise.attributes.add("noreturn") def build_syscall(self, syscall_name, args, builder): r = _chr_to_value[_syscalls[syscall_name][-1]]() @@ -92,33 +98,27 @@ class LinkInterface: if syscall_name in self.var_arg_fixcount: fixcount = self.var_arg_fixcount[syscall_name] args = args[:fixcount] \ - + [lc.Constant.int(lc.Type.int(), len(args) - fixcount)] \ + + [ll.Constant(ll.IntType(32), len(args) - fixcount)] \ + args[fixcount:] - llvm_function = self.llvm_module.get_function_named( - "__syscall_" + syscall_name) - r.auto_store(builder, builder.call(llvm_function, args)) + r.auto_store(builder, builder.call(self.syscalls[syscall_name], + args)) return r def build_catch(self, builder): - eh_setjmp = self.llvm_module.get_function_named("__eh_setjmp") - eh_push = self.llvm_module.get_function_named("__eh_push") - jmpbuf = builder.call(eh_push, []) - exception_occured = builder.call(eh_setjmp, [jmpbuf]) - return builder.icmp(lc.ICMP_NE, - exception_occured, - lc.Constant.int(lc.Type.int(), 0)) + jmpbuf = builder.call(self.eh_push, []) + exception_occured = builder.call(self.eh_setjmp, [jmpbuf]) + return builder.icmp_signed("!=", + exception_occured, + ll.Constant(ll.IntType(32), 0)) def build_pop(self, builder, levels): - eh_pop = self.llvm_module.get_function_named("__eh_pop") - builder.call(eh_pop, [lc.Constant.int(lc.Type.int(), levels)]) + builder.call(self.eh_pop, [ll.Constant(ll.IntType(32), levels)]) def build_getid(self, builder): - eh_getid = self.llvm_module.get_function_named("__eh_getid") - return builder.call(eh_getid, []) + return builder.call(self.eh_getid, []) def build_raise(self, builder, eid): - eh_raise = self.llvm_module.get_function_named("__eh_raise") - builder.call(eh_raise, [eid]) + builder.call(self.eh_raise, [eid]) def _debug_dump_obj(obj): @@ -148,8 +148,8 @@ class Environment(LinkInterface): self.warmup_time = 1*units.ms def emit_object(self): - tm = lt.TargetMachine.new(triple=self.cpu_type, cpu="generic") - obj = tm.emit_object(self.llvm_module) + tm = llvm.Target.from_triple(self.cpu_type).create_target_machine() + obj = tm.emit_object(self.module.llvm_module) _debug_dump_obj(obj) return obj diff --git a/artiq/py2llvm/arrays.py b/artiq/py2llvm/arrays.py index c53263ae1..3a5e34d9b 100644 --- a/artiq/py2llvm/arrays.py +++ b/artiq/py2llvm/arrays.py @@ -1,4 +1,4 @@ -from llvm import core as lc +import llvmlite.ir as ll from artiq.py2llvm.values import VGeneric from artiq.py2llvm.base_types import VInt @@ -13,7 +13,7 @@ class VArray(VGeneric): raise TypeError("Arrays must have at least one element") def get_llvm_type(self): - return lc.Type.array(self.el_init.get_llvm_type(), self.count) + return ll.ArrayType(self.el_init.get_llvm_type(), self.count) def __repr__(self): return "".format(repr(self.el_init), self.count) @@ -42,7 +42,7 @@ class VArray(VGeneric): i = VInt() i.alloca(builder, "ai_i") - i.auto_store(builder, lc.Constant.int(lc.Type.int(), 0)) + i.auto_store(builder, ll.Constant(ll.IntType(32), 0)) function = builder.basic_block.function copy_block = function.append_basic_block("ai_copy") @@ -52,10 +52,10 @@ class VArray(VGeneric): builder.position_at_end(copy_block) self.o_subscript(i, builder).set_value(builder, v.el_init) i.auto_store(builder, builder.add( - i.auto_load(builder), lc.Constant.int(lc.Type.int(), 1))) - cont = builder.icmp( - lc.ICMP_SLT, i.auto_load(builder), - lc.Constant.int(lc.Type.int(), self.count)) + i.auto_load(builder), ll.Constant(ll.IntType(32), 1))) + cont = builder.icmp_signed( + "<", i.auto_load(builder), + ll.Constant(ll.IntType(32), self.count)) builder.cbranch(cont, copy_block, end_block) builder.position_at_end(end_block) @@ -65,6 +65,6 @@ class VArray(VGeneric): if builder is not None: index = index.o_int(builder).auto_load(builder) ssa_r = builder.gep(self.llvm_value, [ - lc.Constant.int(lc.Type.int(), 0), index]) + ll.Constant(ll.IntType(32), 0), index]) r.auto_store(builder, ssa_r) return r diff --git a/artiq/py2llvm/ast_body.py b/artiq/py2llvm/ast_body.py index 047bf01ed..783aa5f2f 100644 --- a/artiq/py2llvm/ast_body.py +++ b/artiq/py2llvm/ast_body.py @@ -1,5 +1,6 @@ import ast -from llvm import core as lc + +import llvmlite.ir as ll from artiq.py2llvm import values, base_types, fractions, arrays, iterators from artiq.py2llvm.tools import is_terminated @@ -368,13 +369,13 @@ class Visitor: if self._active_exception_stack: finally_block, propagate, propagate_eid = ( self._active_exception_stack[-1]) - self.builder.store(lc.Constant.int(lc.Type.int(1), 1), propagate) + self.builder.store(ll.Constant(ll.IntType(1), 1), propagate) if node.exc is not None: - eid = lc.Constant.int(lc.Type.int(), node.exc.args[0].n) + eid = ll.Constant(ll.IntType(32), node.exc.args[0].n) self.builder.store(eid, propagate_eid) self.builder.branch(finally_block) else: - eid = lc.Constant.int(lc.Type.int(), node.exc.args[0].n) + eid = ll.Constant(ll.IntType(32), node.exc.args[0].n) self.env.build_raise(self.builder, eid) def _handle_exception(self, function, finally_block, @@ -382,7 +383,7 @@ class Visitor: eid = self.env.build_getid(self.builder) self._active_exception_stack.append( (finally_block, propagate, propagate_eid)) - self.builder.store(lc.Constant.int(lc.Type.int(1), 1), propagate) + self.builder.store(ll.Constant(ll.IntType(1), 1), propagate) self.builder.store(eid, propagate_eid) for handler in handlers: @@ -392,23 +393,23 @@ class Visitor: self.builder.branch(handled_exc_block) else: if isinstance(handler.type, ast.Tuple): - match = self.builder.icmp( - lc.ICMP_EQ, eid, - lc.Constant.int(lc.Type.int(), - handler.type.elts[0].args[0].n)) + match = self.builder.icmp_signed( + "==", eid, + ll.Constant(ll.IntType(32), + handler.type.elts[0].args[0].n)) for elt in handler.type.elts[1:]: match = self.builder.or_( match, - self.builder.icmp( - lc.ICMP_EQ, eid, - lc.Constant.int(lc.Type.int(), elt.args[0].n))) + self.builder.icmp_signed( + "==", eid, + ll.Constant(ll.IntType(32), elt.args[0].n))) else: - match = self.builder.icmp( - lc.ICMP_EQ, eid, - lc.Constant.int(lc.Type.int(), handler.type.args[0].n)) + match = self.builder.icmp_signed( + "==", eid, + ll.Constant(ll.IntType(32), handler.type.args[0].n)) self.builder.cbranch(match, handled_exc_block, cont_exc_block) self.builder.position_at_end(handled_exc_block) - self.builder.store(lc.Constant.int(lc.Type.int(1), 0), propagate) + self.builder.store(ll.Constant(ll.IntType(1), 0), propagate) self.visit_statements(handler.body) if not self._bb_terminated(): self.builder.branch(finally_block) @@ -423,10 +424,10 @@ class Visitor: exc_block = function.append_basic_block("try_exc") finally_block = function.append_basic_block("try_finally") - propagate = self.builder.alloca(lc.Type.int(1), + propagate = self.builder.alloca(ll.IntType(1), name="propagate") - self.builder.store(lc.Constant.int(lc.Type.int(1), 0), propagate) - propagate_eid = self.builder.alloca(lc.Type.int(), + self.builder.store(ll.Constant(ll.IntType(1), 0), propagate) + propagate_eid = self.builder.alloca(ll.IntType(32), name="propagate_eid") exception_occured = self.env.build_catch(self.builder) self.builder.cbranch(exception_occured, exc_block, noexc_block) diff --git a/artiq/py2llvm/base_types.py b/artiq/py2llvm/base_types.py index fe214748e..c218facc8 100644 --- a/artiq/py2llvm/base_types.py +++ b/artiq/py2llvm/base_types.py @@ -1,11 +1,11 @@ -from llvm import core as lc +import llvmlite.ir as ll from artiq.py2llvm.values import VGeneric class VNone(VGeneric): def get_llvm_type(self): - return lc.Type.void() + return ll.VoidType() def alloca(self, builder, name): pass @@ -29,7 +29,7 @@ class VInt(VGeneric): self.nbits = nbits def get_llvm_type(self): - return lc.Type.int(self.nbits) + return ll.IntType(self.nbits) def __repr__(self): return "".format(self.nbits) @@ -50,16 +50,16 @@ class VInt(VGeneric): builder, n.o_intx(self.nbits, builder).auto_load(builder)) def set_const_value(self, builder, n): - self.auto_store(builder, lc.Constant.int(self.get_llvm_type(), n)) + self.auto_store(builder, ll.Constant(self.get_llvm_type(), n)) def o_bool(self, builder, inv=False): r = VBool() if builder is not None: r.auto_store( - builder, builder.icmp( - lc.ICMP_EQ if inv else lc.ICMP_NE, + builder, builder.icmp_signed( + "==" if inv else "!=", self.auto_load(builder), - lc.Constant.int(self.get_llvm_type(), 0))) + ll.Constant(self.get_llvm_type(), 0))) return r def o_float(self, builder): @@ -82,7 +82,7 @@ class VInt(VGeneric): r.auto_store( builder, builder.mul( self.auto_load(builder), - lc.Constant.int(self.get_llvm_type(), -1))) + ll.Constant(self.get_llvm_type(), -1))) return r def o_intx(self, target_bits, builder): @@ -102,7 +102,7 @@ class VInt(VGeneric): ef = builder.sext r.auto_store( builder, ef(self.auto_load(builder), - r.get_llvm_type())) + r.get_llvm_type())) return r o_roundx = o_intx @@ -157,7 +157,7 @@ def _make_vint_cmp_method(icmp_val): right = other.o_intx(target_bits, builder) r.auto_store( builder, - builder.icmp( + builder.icmp_signed( icmp_val, left.auto_load(builder), right.auto_load(builder))) return r @@ -165,12 +165,12 @@ def _make_vint_cmp_method(icmp_val): return NotImplemented return cmp_method -for _method_name, _icmp_val in (("o_eq", lc.ICMP_EQ), - ("o_ne", lc.ICMP_NE), - ("o_lt", lc.ICMP_SLT), - ("o_le", lc.ICMP_SLE), - ("o_gt", lc.ICMP_SGT), - ("o_ge", lc.ICMP_SGE)): +for _method_name, _icmp_val in (("o_eq", "=="), + ("o_ne", "!="), + ("o_lt", "<"), + ("o_le", "<="), + ("o_gt", ">"), + ("o_ge", ">=")): setattr(VInt, _method_name, _make_vint_cmp_method(_icmp_val)) @@ -188,7 +188,7 @@ class VBool(VInt): class VFloat(VGeneric): def get_llvm_type(self): - return lc.Type.double() + return ll.DoubleType() def set_value(self, builder, v): if not isinstance(v, VFloat): @@ -196,7 +196,7 @@ class VFloat(VGeneric): self.auto_store(builder, v.auto_load(builder)) def set_const_value(self, builder, n): - self.auto_store(builder, lc.Constant.real(self.get_llvm_type(), n)) + self.auto_store(builder, ll.Constant(self.get_llvm_type(), n)) def o_float(self, builder): r = VFloat() @@ -208,10 +208,10 @@ class VFloat(VGeneric): r = VBool() if builder is not None: r.auto_store( - builder, builder.fcmp( - lc.FCMP_UEQ if inv else lc.FCMP_UNE, + builder, builder.fcmp_ordered( + "==" if inv else "!=", self.auto_load(builder), - lc.Constant.real(self.get_llvm_type(), 0.0))) + ll.Constant(self.get_llvm_type(), 0.0))) return r def o_not(self, builder): @@ -223,7 +223,7 @@ class VFloat(VGeneric): r.auto_store( builder, builder.fmul( self.auto_load(builder), - lc.Constant.real(self.get_llvm_type(), -1.0))) + ll.Constant(self.get_llvm_type(), -1.0))) return r def o_intx(self, target_bits, builder): @@ -244,10 +244,10 @@ class VFloat(VGeneric): half.alloca(builder, "half") half.set_const_value(builder, 0.5) - condition = builder.icmp( - lc.FCMP_OLT, + condition = builder.fcmp_ordered( + "<", self.auto_load(builder), - lc.Constant.real(self.get_llvm_type(), 0.0)) + ll.Constant(self.get_llvm_type(), 0.0)) builder.cbranch(condition, neg_block, merge_block) builder.position_at_end(neg_block) @@ -299,16 +299,16 @@ def _make_vfloat_cmp_method(fcmp_val): right = other.o_float(builder) r.auto_store( builder, - builder.fcmp( + builder.fcmp_ordered( fcmp_val, left.auto_load(builder), right.auto_load(builder))) return r return cmp_method -for _method_name, _fcmp_val in (("o_eq", lc.FCMP_OEQ), - ("o_ne", lc.FCMP_ONE), - ("o_lt", lc.FCMP_OLT), - ("o_le", lc.FCMP_OLE), - ("o_gt", lc.FCMP_OGT), - ("o_ge", lc.FCMP_OGE)): +for _method_name, _fcmp_val in (("o_eq", "=="), + ("o_ne", "!="), + ("o_lt", "<"), + ("o_le", "<="), + ("o_gt", ">"), + ("o_ge", ">=")): setattr(VFloat, _method_name, _make_vfloat_cmp_method(_fcmp_val)) diff --git a/artiq/py2llvm/fractions.py b/artiq/py2llvm/fractions.py index 52b73b602..6908cb808 100644 --- a/artiq/py2llvm/fractions.py +++ b/artiq/py2llvm/fractions.py @@ -1,7 +1,7 @@ import inspect import ast -from llvm import core as lc +import llvmlite.ir as ll from artiq.py2llvm.values import VGeneric, operators from artiq.py2llvm.base_types import VBool, VInt, VFloat @@ -21,11 +21,15 @@ def init_module(module): func_def = ast.parse(inspect.getsource(_gcd)).body[0] function, _ = module.compile_function(func_def, {"a": VInt(64), "b": VInt(64)}) - function.linkage = lc.LINKAGE_INTERNAL + function.linkage = "internal" def _reduce(builder, a, b): - gcd_f = builder.basic_block.function.module.get_function_named("_gcd") + module = builder.basic_block.function.module + for f in module.functions: + if f.name == "_gcd": + gcd_f = f + break gcd = builder.call(gcd_f, [a, b]) a = builder.sdiv(a, gcd) b = builder.sdiv(b, gcd) @@ -38,21 +42,21 @@ def _signnum(builder, a, b): swap_block = function.append_basic_block("sn_swap") merge_block = function.append_basic_block("sn_merge") - condition = builder.icmp( - lc.ICMP_SLT, b, lc.Constant.int(lc.Type.int(64), 0)) + condition = builder.icmp_signed( + "<", b, ll.Constant(ll.IntType(64), 0)) builder.cbranch(condition, swap_block, merge_block) builder.position_at_end(swap_block) - minusone = lc.Constant.int(lc.Type.int(64), -1) + minusone = ll.Constant(ll.IntType(64), -1) a_swp = builder.mul(minusone, a) b_swp = builder.mul(minusone, b) builder.branch(merge_block) builder.position_at_end(merge_block) - a_phi = builder.phi(lc.Type.int(64)) + a_phi = builder.phi(ll.IntType(64)) a_phi.add_incoming(a, orig_block) a_phi.add_incoming(a_swp, swap_block) - b_phi = builder.phi(lc.Type.int(64)) + b_phi = builder.phi(ll.IntType(64)) b_phi.add_incoming(b, orig_block) b_phi.add_incoming(b_swp, swap_block) @@ -60,24 +64,20 @@ def _signnum(builder, a, b): def _make_ssa(builder, n, d): - value = lc.Constant.undef(lc.Type.vector(lc.Type.int(64), 2)) - value = builder.insert_element( - value, n, lc.Constant.int(lc.Type.int(), 0)) - value = builder.insert_element( - value, d, lc.Constant.int(lc.Type.int(), 1)) + value = ll.Constant(ll.ArrayType(ll.IntType(64), 2), ll.Undefined) + value = builder.insert_value(value, n, 0) + value = builder.insert_value(value, d, 1) return value class VFraction(VGeneric): def get_llvm_type(self): - return lc.Type.vector(lc.Type.int(64), 2) + return ll.ArrayType(ll.IntType(64), 2) def _nd(self, builder): ssa_value = self.auto_load(builder) - a = builder.extract_element( - ssa_value, lc.Constant.int(lc.Type.int(), 0)) - b = builder.extract_element( - ssa_value, lc.Constant.int(lc.Type.int(), 1)) + a = builder.extract_value(ssa_value, 0) + b = builder.extract_value(ssa_value, 1) return a, b def set_value_nd(self, builder, a, b): @@ -101,19 +101,16 @@ class VFraction(VGeneric): raise AttributeError r = VInt(64) if builder is not None: - elt = builder.extract_element( - self.auto_load(builder), - lc.Constant.int(lc.Type.int(), idx)) + elt = builder.extract_value(self.auto_load(builder), idx) r.auto_store(builder, elt) return r def o_bool(self, builder): r = VBool() if builder is not None: - zero = lc.Constant.int(lc.Type.int(64), 0) - a = builder.extract_element( - self.auto_load(builder), lc.Constant.int(lc.Type.int(), 0)) - r.auto_store(builder, builder.icmp(lc.ICMP_NE, a, zero)) + zero = ll.Constant(ll.IntType(64), 0) + a = builder.extract_element(self.auto_load(builder), 0) + r.auto_store(builder, builder.icmp_signed("!=", a, zero)) return r def o_intx(self, target_bits, builder): @@ -131,15 +128,15 @@ class VFraction(VGeneric): else: r = VInt(64) a, b = self._nd(builder) - h_b = builder.ashr(b, lc.Constant.int(lc.Type.int(64), 1)) + h_b = builder.ashr(b, ll.Constant(ll.IntType(64), 1)) function = builder.basic_block.function add_block = function.append_basic_block("fr_add") sub_block = function.append_basic_block("fr_sub") merge_block = function.append_basic_block("fr_merge") - condition = builder.icmp( - lc.ICMP_SLT, a, lc.Constant.int(lc.Type.int(64), 0)) + condition = builder.icmp_signed( + "<", a, ll.Constant(ll.IntType(64), 0)) builder.cbranch(condition, sub_block, add_block) builder.position_at_end(add_block) @@ -150,7 +147,7 @@ class VFraction(VGeneric): builder.branch(merge_block) builder.position_at_end(merge_block) - a = builder.phi(lc.Type.int(64)) + a = builder.phi(ll.IntType(64)) a.add_incoming(a_add, add_block) a.add_incoming(a_sub, sub_block) r.auto_store(builder, builder.sdiv(a, b)) @@ -165,19 +162,19 @@ class VFraction(VGeneric): other = other.o_int64(builder) a, b = self._nd(builder) ssa_r = builder.and_( - builder.icmp(lc.ICMP_EQ, a, - other.auto_load()), - builder.icmp(lc.ICMP_EQ, b, - lc.Constant.int(lc.Type.int(64), 1))) + builder.icmp_signed("==", a, + other.auto_load()), + builder.icmp_signed("==", b, + ll.Constant(ll.IntType(64), 1))) else: a, b = self._nd(builder) c, d = other._nd(builder) ssa_r = builder.and_( - builder.icmp(lc.ICMP_EQ, a, c), - builder.icmp(lc.ICMP_EQ, b, d)) + builder.icmp_signed("==", a, c), + builder.icmp_signed("==", b, d)) if ne: ssa_r = builder.xor(ssa_r, - lc.Constant.int(lc.Type.int(1), 1)) + ll.Constant(ll.IntType(1), 1)) r.auto_store(builder, ssa_r) return r @@ -194,24 +191,23 @@ class VFraction(VGeneric): r = VBool() if builder is not None: diff = diff.auto_load(builder) - a = builder.extract_element( - diff, lc.Constant.int(lc.Type.int(), 0)) - zero = lc.Constant.int(lc.Type.int(64), 0) + a = builder.extract_value(diff, 0) + zero = ll.Constant(ll.IntType(64), 0) ssa_r = builder.icmp(icmp, a, zero) r.auto_store(builder, ssa_r) return r def o_lt(self, other, builder): - return self._o_cmp(other, lc.ICMP_SLT, builder) + return self._o_cmp(other, "<", builder) def o_le(self, other, builder): - return self._o_cmp(other, lc.ICMP_SLE, builder) + return self._o_cmp(other, "<=", builder) def o_gt(self, other, builder): - return self._o_cmp(other, lc.ICMP_SGT, builder) + return self._o_cmp(other, ">", builder) def o_ge(self, other, builder): - return self._o_cmp(other, lc.ICMP_SGE, builder) + return self._o_cmp(other, ">=", builder) def _o_addsub(self, other, builder, sub, invert=False): if isinstance(other, VFloat): diff --git a/artiq/py2llvm/iterators.py b/artiq/py2llvm/iterators.py index 3e8d1eba9..0e1526319 100644 --- a/artiq/py2llvm/iterators.py +++ b/artiq/py2llvm/iterators.py @@ -1,7 +1,5 @@ -from llvm import core as lc - from artiq.py2llvm.values import operators -from artiq.py2llvm.base_types import VBool, VInt +from artiq.py2llvm.base_types import VInt class IRange: def __init__(self, builder, args): diff --git a/artiq/py2llvm/module.py b/artiq/py2llvm/module.py index faa35ee55..2ef443a63 100644 --- a/artiq/py2llvm/module.py +++ b/artiq/py2llvm/module.py @@ -1,13 +1,12 @@ -from llvm import core as lc -from llvm import passes as lp -from llvm import ee as le +import llvmlite.ir as ll +import llvmlite.binding as llvm from artiq.py2llvm import infer_types, ast_body, base_types, fractions, tools class Module: def __init__(self, env=None): - self.llvm_module = lc.Module.new("main") + self.llvm_module = ll.Module("main") self.env = env if self.env is not None: @@ -15,17 +14,19 @@ class Module: fractions.init_module(self) def finalize(self): - pass_manager = lp.PassManager.new() - pass_manager.add(lp.PASS_MEM2REG) - pass_manager.add(lp.PASS_INSTCOMBINE) - pass_manager.add(lp.PASS_REASSOCIATE) - pass_manager.add(lp.PASS_GVN) - pass_manager.add(lp.PASS_SIMPLIFYCFG) - pass_manager.run(self.llvm_module) + self.llvm_module = llvm.parse_assembly(str(self.llvm_module)) # FIXME + pmb = llvm.create_pass_manager_builder() + pmb.opt_level = 2 + pm = llvm.create_module_pass_manager() + pmb.populate(pm) + pm.run(self.llvm_module) def get_ee(self): self.finalize() - return le.ExecutionEngine.new(self.llvm_module) + tm = llvm.Target.from_default_triple().create_target_machine() + ee = llvm.create_mcjit_compiler(self.llvm_module, tm) + ee.finalize_object() + return ee def emit_object(self): self.finalize() @@ -35,11 +36,12 @@ class Module: ns = infer_types.infer_function_types(self.env, func_def, param_types) retval = ns["return"] - function_type = lc.Type.function(retval.get_llvm_type(), + function_type = ll.FunctionType(retval.get_llvm_type(), [ns[arg.arg].get_llvm_type() for arg in func_def.args.args]) - function = self.llvm_module.add_function(function_type, func_def.name) + function = ll.Function(self.llvm_module, function_type, func_def.name) bb = function.append_basic_block("entry") - builder = lc.Builder.new(bb) + builder = ll.IRBuilder() + builder.position_at_end(bb) for arg_ast, arg_llvm in zip(func_def.args.args, function.args): arg_llvm.name = arg_ast.arg diff --git a/artiq/py2llvm/tools.py b/artiq/py2llvm/tools.py index 067a55b61..27ffd8566 100644 --- a/artiq/py2llvm/tools.py +++ b/artiq/py2llvm/tools.py @@ -1,2 +1,5 @@ +import llvmlite.ir as ll + def is_terminated(basic_block): - return basic_block.instructions and basic_block.instructions[-1].is_terminator + return (basic_block.instructions + and isinstance(basic_block.instructions[-1], ll.Terminator)) diff --git a/artiq/py2llvm/values.py b/artiq/py2llvm/values.py index 037ba48a3..5963d007b 100644 --- a/artiq/py2llvm/values.py +++ b/artiq/py2llvm/values.py @@ -1,7 +1,7 @@ from types import SimpleNamespace from copy import copy -from llvm import core as lc +import llvmlite.ir as ll class VGeneric: @@ -25,7 +25,7 @@ class VGeneric: .format(repr(self), repr(other))) def auto_load(self, builder): - if isinstance(self.llvm_value.type, lc.PointerType): + if isinstance(self.llvm_value.type, ll.PointerType): return builder.load(self.llvm_value) else: return self.llvm_value @@ -33,7 +33,7 @@ class VGeneric: def auto_store(self, builder, llvm_value): if self.llvm_value is None: self.llvm_value = llvm_value - elif isinstance(self.llvm_value.type, lc.PointerType): + elif isinstance(self.llvm_value.type, ll.PointerType): builder.store(llvm_value, self.llvm_value) else: raise RuntimeError( @@ -60,14 +60,14 @@ class VGeneric: def _make_binary_operator(op_name): def op(l, r, builder): try: - opf = getattr(l, "o_"+op_name) + opf = getattr(l, "o_" + op_name) except AttributeError: result = NotImplemented else: result = opf(r, builder) if result is NotImplemented: try: - ropf = getattr(r, "or_"+op_name) + ropf = getattr(r, "or_" + op_name) except AttributeError: result = NotImplemented else: diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 05721ad50..fbf5986f5 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -98,7 +98,9 @@ These steps are required to generate bitstream (``.bit``) files, build the MiSoC $ cd ~/artiq-dev/misoc $ ./make.py -X ~/artiq/soc -t artiq all -* Then, build and flash the ARTIQ runtime: :: +* Then, build and flash the ARTIQ runtime: + + :: $ cd ~/artiq-dev $ git clone https://github.com/m-labs/artiq @@ -120,36 +122,30 @@ The communication parameters are 115200 8-N-1. Installing the host-side software --------------------------------- -* Install LLVM and its Python bindings: - - The main dependency of ARTIQ is LLVM and its Python bindings (http://llvmpy.org). Currently, this installation is tedious because of the OpenRISC support not being merged upstream LLVM and because of incompatibilities between the versions of LLVM that support OpenRISC and the versions of LLVM that support the Python bindings. :: +* Install LLVM and the llvmlite Python bindings: :: $ cd ~/artiq-dev $ git clone https://github.com/openrisc/llvm-or1k - $ cd ~/artiq-dev/llvm-or1k - $ git checkout b3a48efb2c05ed6cedc5395ae726c6a6573ef3ba - $ cat ~/artiq-dev/artiq/patches/llvm/* | patch -p1 - $ cd ~/artiq-dev/llvm-or1k/tools $ git clone https://github.com/openrisc/clang-or1k clang $ cd ~/artiq-dev/llvm-or1k/tools/clang - $ git checkout 02d831c7e7dc1517abed9cc96abdfb937af954eb - $ cat ~/artiq-dev/artiq/patches/clang/* | patch -p1 $ cd ~/artiq-dev/llvm-or1k $ mkdir build $ cd ~/artiq-dev/llvm-or1k/build $ ../configure --prefix=/usr/local/llvm-or1k - $ make ENABLE_OPTIMIZED=1 REQUIRES_RTTI=1 -j4 - $ sudo -E make install ENABLE_OPTIMIZED=1 REQUIRES_RTTI=1 + $ make ENABLE_OPTIMIZED=1 -j4 + $ sudo -E make install ENABLE_OPTIMIZED=1 $ cd ~/artiq-dev - $ git clone https://github.com/llvmpy/llvmpy - $ cd ~/artiq-dev/llvmpy - $ git checkout 7af2f7140391d4f708adf2721e84f23c1b89e97a - $ cat /path_to/artiq/patches/llvmpy/* | patch -p1 + $ git clone https://github.com/numba/llvmlite + $ cd ~/artiq-dev/llvmlite + $ cat /path_to/artiq/patches/llvmlite/* | patch -p1 $ LLVM_CONFIG_PATH=/usr/local/llvm-or1k/bin/llvm-config sudo -E python setup.py install +.. note:: + llvmlite is in development and its API is not stable yet. Commit ID ``11a8303d02e3d6dd2d1e0e9065701795cd8a979f`` is known to work. + .. note:: Compilation of LLVM can take more than 30 min on some machines. diff --git a/patches/clang/0001-exclude-some-broken-aarch64-builtins.patch b/patches/clang/0001-exclude-some-broken-aarch64-builtins.patch deleted file mode 100644 index 79ec2115c..000000000 --- a/patches/clang/0001-exclude-some-broken-aarch64-builtins.patch +++ /dev/null @@ -1,32 +0,0 @@ -From af106d252693b6af5c94d241fabed1c04cbb2fc6 Mon Sep 17 00:00:00 2001 -From: Robert Jordens -Date: Tue, 8 Jul 2014 22:35:58 -0600 -Subject: [PATCH] exclude some broken aarch64 builtins - ---- - lib/CodeGen/CGBuiltin.cpp | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp -index 52e40db..d089ad3 100644 ---- a/lib/CodeGen/CGBuiltin.cpp -+++ b/lib/CodeGen/CGBuiltin.cpp -@@ -1760,6 +1760,7 @@ static Value *EmitAArch64ScalarBuiltinExpr(CodeGenFunction &CGF, - // argument that specifies the vector type, need to handle each case. - switch (BuiltinID) { - default: break; -+#if 0 - // Scalar Add - case AArch64::BI__builtin_neon_vaddd_s64: - Int = Intrinsic::aarch64_neon_vaddds; -@@ -1945,6 +1946,7 @@ static Value *EmitAArch64ScalarBuiltinExpr(CodeGenFunction &CGF, - case AArch64::BI__builtin_neon_vminnmvq_f32: - Int = Intrinsic::aarch64_neon_vminnmv; - AcrossVec = true; ExtendEle = false; s = "vminnmv"; break; -+#endif - } - - if (!Int) --- -1.9.1 - diff --git a/patches/llvm/0001-or1k-initAsmInfo.patch b/patches/llvm/0001-or1k-initAsmInfo.patch deleted file mode 100644 index 38959f8e0..000000000 --- a/patches/llvm/0001-or1k-initAsmInfo.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 4dd12eaf0a14196f45ce4f25ed4a9f23bb3f55d5 Mon Sep 17 00:00:00 2001 -From: Robert Jordens -Date: Tue, 8 Jul 2014 22:37:03 -0600 -Subject: [PATCH] or1k: initAsmInfo() - ---- - lib/Target/OR1K/OR1KTargetMachine.cpp | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/lib/Target/OR1K/OR1KTargetMachine.cpp b/lib/Target/OR1K/OR1KTargetMachine.cpp -index 8f260f0..1771bce 100644 ---- a/lib/Target/OR1K/OR1KTargetMachine.cpp -+++ b/lib/Target/OR1K/OR1KTargetMachine.cpp -@@ -41,6 +41,7 @@ OR1KTargetMachine(const Target &T, StringRef TT, - "f64:32:32-v64:32:32-v128:32:32-a0:0:32-n32"), - InstrInfo(), TLInfo(*this), TSInfo(*this), - FrameLowering(Subtarget) { -+ initAsmInfo(); - } - namespace { - /// OR1K Code Generator Pass Configuration Options. --- -1.9.1 - diff --git a/patches/llvmlite/0001-add-all-targets.patch b/patches/llvmlite/0001-add-all-targets.patch new file mode 100644 index 000000000..6b52fad9f --- /dev/null +++ b/patches/llvmlite/0001-add-all-targets.patch @@ -0,0 +1,38 @@ +diff --git a/ffi/initfini.cpp b/ffi/initfini.cpp +index 42c8965..067be62 100644 +--- a/ffi/initfini.cpp ++++ b/ffi/initfini.cpp +@@ -37,9 +37,10 @@ LLVMPY_Shutdown(){ + // NOTE: it is important that we don't export functions which we don't use, + // especially those which may pull in large amounts of additional code or data. + +-// INIT(AllTargetInfos) +-// INIT(AllTargets) +-// INIT(AllTargetMCs) ++INIT(AllTargetInfos) ++INIT(AllTargets) ++INIT(AllTargetMCs) ++INIT(AllAsmPrinters) + INIT(NativeTarget) + INIT(NativeAsmParser) + INIT(NativeAsmPrinter) +diff --git a/llvmlite/binding/initfini.py b/llvmlite/binding/initfini.py +index bfaa5b2..7d0df11 100644 +--- a/llvmlite/binding/initfini.py ++++ b/llvmlite/binding/initfini.py +@@ -8,6 +8,15 @@ def initialize(): + ffi.lib.LLVMPY_InitializeCore() + + ++def initialize_all_targets(): ++ ffi.lib.LLVMPY_InitializeAllTargetInfos() ++ ffi.lib.LLVMPY_InitializeAllTargets() ++ ffi.lib.LLVMPY_InitializeAllTargetMCs() ++ ++def initialize_all_asmprinters(): ++ ffi.lib.LLVMPY_InitializeAllAsmPrinters() ++ ++ + def initialize_native_target(): + """ + Initialize the native (host) target. Necessary before doing any diff --git a/patches/llvmpy/0001-use-3.3-opcodes.patch b/patches/llvmpy/0001-use-3.3-opcodes.patch deleted file mode 100644 index 9cfdfad56..000000000 --- a/patches/llvmpy/0001-use-3.3-opcodes.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 7f84a57f4a73837e50df7a8c6905773c0de568ab Mon Sep 17 00:00:00 2001 -From: Robert Jordens -Date: Tue, 8 Jul 2014 22:40:10 -0600 -Subject: [PATCH] use 3.3 opcodes - ---- - llvm/core.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/llvm/core.py b/llvm/core.py -index 20ad062..d33860f 100644 ---- a/llvm/core.py -+++ b/llvm/core.py -@@ -174,7 +174,7 @@ class OpcodeEnum(Enum): - OPCODE_PTRTOINT = 42 - OPCODE_INTTOPTR = 43 - OPCODE_BITCAST = 44 -- if llvm.version <= (3, 3): -+ if llvm.version <= (3, 3) or True: - OPCODE_ICMP = 45 - OPCODE_FCMP = 46 - OPCODE_PHI = 47 --- -1.9.1 - diff --git a/patches/llvmpy/0002-add-returns-twice-attribute.patch b/patches/llvmpy/0002-add-returns-twice-attribute.patch deleted file mode 100644 index 20a9e0d77..000000000 --- a/patches/llvmpy/0002-add-returns-twice-attribute.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/llvm/core.py b/llvm/core.py -index 20ad062..245ac65 100644 ---- a/llvm/core.py -+++ b/llvm/core.py -@@ -379,6 +379,7 @@ class AttrEnum(Enum): - ATTR_NAKED = AttrVal.Naked - ATTR_INLINE_HINT = AttrVal.InlineHint - ATTR_STACK_ALIGNMENT = AttrVal.StackAlignment -+ ATTR_RETURNS_TWICE = AttrVal.ReturnsTwice - - AttrEnum.declare() - diff --git a/test/py2llvm.py b/test/py2llvm.py index 29c86ed89..69aa89231 100644 --- a/test/py2llvm.py +++ b/test/py2llvm.py @@ -2,8 +2,9 @@ import unittest import ast import inspect from fractions import Fraction +from ctypes import CFUNCTYPE, c_int, c_int32, c_int64, c_double -from llvm import ee as le +import llvmlite.binding as llvm from artiq.language.core import int64, array from artiq.py2llvm.infer_types import infer_function_types @@ -11,6 +12,11 @@ from artiq.py2llvm import base_types, arrays from artiq.py2llvm.module import Module +llvm.initialize() +llvm.initialize_native_target() +llvm.initialize_native_asmprinter() + + def _base_types(choice): a = 2 # promoted later to int64 b = a + 1 # initially int32, becomes int64 after a is promoted @@ -81,34 +87,42 @@ class FunctionArrayTypesCase(unittest.TestCase): self.assertEqual(self.ns["i"].nbits, 32) +def _value_to_ctype(v): + if isinstance(v, base_types.VBool): + return c_int + elif isinstance(v, base_types.VInt): + if v.nbits == 32: + return c_int32 + elif v.nbits == 64: + return c_int64 + else: + raise NotImplementedError(str(v)) + elif isinstance(v, base_types.VFloat): + return c_double + else: + raise NotImplementedError(str(v)) + + class CompiledFunction: def __init__(self, function, param_types): module = Module() + func_def = ast.parse(inspect.getsource(function)).body[0] - self.function, self.retval = module.compile_function( - func_def, param_types) - self.argval = [param_types[arg.arg] for arg in func_def.args.args] - self.ee = module.get_ee() + function, retval = module.compile_function(func_def, param_types) + argvals = [param_types[arg.arg] for arg in func_def.args.args] + + ee = module.get_ee() + cfptr = ee.get_pointer_to_global( + module.llvm_module.get_function(function.name)) + retval_ctype = _value_to_ctype(retval) + argval_ctypes = [_value_to_ctype(argval) for argval in argvals] + self.cfunc = CFUNCTYPE(retval_ctype, *argval_ctypes)(cfptr) + + # HACK: prevent garbage collection of self.cfunc internals + self.ee = ee def __call__(self, *args): - args_llvm = [] - for av, a in zip(self.argval, args): - if isinstance(av, base_types.VInt): - al = le.GenericValue.int(av.get_llvm_type(), a) - elif isinstance(av, base_types.VFloat): - al = le.GenericValue.real(av.get_llvm_type(), a) - else: - raise NotImplementedError - args_llvm.append(al) - result = self.ee.run_function(self.function, args_llvm) - if isinstance(self.retval, base_types.VBool): - return bool(result.as_int()) - elif isinstance(self.retval, base_types.VInt): - return result.as_int_signed() - elif isinstance(self.retval, base_types.VFloat): - return result.as_real(self.retval.get_llvm_type()) - else: - raise NotImplementedError + return self.cfunc(*args) def arith(op, a, b):