def o_roundx(self, target_bits, builder): if builder is None: return VInt(target_bits) else: r = VInt(64) a, b = self._nd(builder) 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_signed( "<", a, ll.Constant(ll.IntType(64), 0)) builder.cbranch(condition, sub_block, add_block) builder.position_at_end(add_block) a_add = builder.add(a, h_b) builder.branch(merge_block) builder.position_at_end(sub_block) a_sub = builder.sub(a, h_b) builder.branch(merge_block) builder.position_at_end(merge_block) 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)) return r.o_intx(target_bits, builder)
def _signnum(builder, a, b): function = builder.basic_block.function orig_block = builder.basic_block swap_block = function.append_basic_block("sn_swap") merge_block = function.append_basic_block("sn_merge") 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 = 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(ll.IntType(64)) a_phi.add_incoming(a, orig_block) a_phi.add_incoming(a_swp, swap_block) b_phi = builder.phi(ll.IntType(64)) b_phi.add_incoming(b, orig_block) b_phi.add_incoming(b_swp, swap_block) return a_phi, b_phi
def _build_rpc(self, args, builder): r = base_types.VInt() if builder is not None: new_args = [] new_args.append(args[0].auto_load(builder)) # RPC number for arg in args[1:]: # type tag arg_type_str = _value_to_str(arg) arg_type_int = 0 for c in reversed(arg_type_str): arg_type_int <<= 8 arg_type_int |= ord(c) new_args.append(ll.Constant(ll.IntType(32), arg_type_int)) # pointer to value if not isinstance(arg, base_types.VNone): if isinstance(arg.llvm_value.type, ll.PointerType): new_args.append(arg.llvm_value) else: arg_ptr = arg.new() arg_ptr.alloca(builder) arg_ptr.auto_store(builder, arg.llvm_value) new_args.append(arg_ptr.llvm_value) # end marker new_args.append(ll.Constant(ll.IntType(32), 0)) r.auto_store(builder, builder.call(self.rpc, new_args)) return r
def o_len(self, builder): r = VInt() if builder is not None: count_ptr = builder.gep(self.llvm_value, [ ll.Constant(ll.IntType(32), 0), ll.Constant(ll.IntType(32), 0) ]) r.auto_store(builder, builder.load(count_ptr)) return r
def o_subscript(self, index, builder): r = self.el_type.new() if builder is not None and not isinstance(r, VNone): index = index.o_int(builder).auto_load(builder) ssa_r = builder.gep(self.llvm_value, [ ll.Constant(ll.IntType(32), 0), ll.Constant(ll.IntType(32), 1), index ]) r.auto_store(builder, ssa_r) return r
def _visit_stmt_Raise(self, node): if self._active_exception_stack: finally_block, propagate, propagate_eid = ( self._active_exception_stack[-1]) self.builder.store(ll.Constant(ll.IntType(1), 1), propagate) if node.exc is not None: eid = ll.Constant(ll.IntType(32), node.exc.args[0].n) self.builder.store(eid, propagate_eid) self.builder.branch(finally_block) else: eid = ll.Constant(ll.IntType(32), node.exc.args[0].n) self.runtime.build_raise(self.builder, eid)
def o_bool(self, builder): r = VBool() if builder is not None: 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_neg(self, builder): r = VFloat() if builder is not None: r.auto_store( builder, builder.fmul(self.auto_load(builder), ll.Constant(self.get_llvm_type(), -1.0))) return r
def o_neg(self, builder): r = VInt(self.nbits) if builder is not None: r.auto_store( builder, builder.mul(self.auto_load(builder), ll.Constant(self.get_llvm_type(), -1))) return r
def o_bool(self, builder, inv=False): r = VBool() if builder is not None: r.auto_store( builder, builder.icmp_signed("==" if inv else "!=", self.auto_load(builder), ll.Constant(self.get_llvm_type(), 0))) return r
def _visit_stmt_Assign(self, node): val = self.visit_expression(node.value) if isinstance(node.value, ast.List): if len(node.targets) > 1: raise NotImplementedError target = self.visit_expression(node.targets[0]) target.set_count(self.builder, val.alloc_count) for i, elt in enumerate(val.elts): idx = base_types.VInt() idx.set_const_value(self.builder, i) target.o_subscript(idx, self.builder).set_value(self.builder, elt) elif isinstance(node.value, ast.ListComp): if len(node.targets) > 1: raise NotImplementedError target = self.visit_expression(node.targets[0]) target.set_count(self.builder, val.alloc_count) i = base_types.VInt() i.alloca(self.builder) i.auto_store(self.builder, ll.Constant(ll.IntType(32), 0)) function = self.builder.basic_block.function copy_block = function.append_basic_block("ai_copy") end_block = function.append_basic_block("ai_end") self.builder.branch(copy_block) self.builder.position_at_end(copy_block) target.o_subscript(i, self.builder).set_value(self.builder, val.elt) i.auto_store( self.builder, self.builder.add(i.auto_load(self.builder), ll.Constant(ll.IntType(32), 1))) cont = self.builder.icmp_signed( "<", i.auto_load(self.builder), ll.Constant(ll.IntType(32), val.alloc_count)) self.builder.cbranch(cont, copy_block, end_block) self.builder.position_at_end(end_block) else: for target in node.targets: target = self.visit_expression(target) target.set_value(self.builder, val)
def _o_cmp(self, other, icmp, builder): diff = self.o_sub(other, builder) if diff is NotImplemented: return NotImplemented r = VBool() if builder is not None: diff = diff.auto_load(builder) a = builder.extract_value(diff, 0) zero = ll.Constant(ll.IntType(64), 0) ssa_r = builder.icmp_signed(icmp, a, zero) r.auto_store(builder, ssa_r) return r
def _handle_exception(self, function, finally_block, propagate, propagate_eid, handlers): eid = self.runtime.build_getid(self.builder) self._active_exception_stack.append( (finally_block, propagate, propagate_eid)) self.builder.store(ll.Constant(ll.IntType(1), 1), propagate) self.builder.store(eid, propagate_eid) for handler in handlers: handled_exc_block = function.append_basic_block("try_exc_h") cont_exc_block = function.append_basic_block("try_exc_c") if handler.type is None: self.builder.branch(handled_exc_block) else: if isinstance(handler.type, ast.Tuple): 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_signed( "==", eid, ll.Constant(ll.IntType(32), elt.args[0].n))) else: 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(ll.Constant(ll.IntType(1), 0), propagate) self.visit_statements(handler.body) if not self._bb_terminated(): self.builder.branch(finally_block) self.builder.position_at_end(cont_exc_block) self.builder.branch(finally_block) self._active_exception_stack.pop()
def _o_eq_inv(self, other, builder, ne): if not isinstance(other, (VInt, VFraction)): return NotImplemented r = VBool() if builder is not None: if isinstance(other, VInt): other = other.o_int64(builder) a, b = self._nd(builder) ssa_r = builder.and_( 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_signed("==", a, c), builder.icmp_signed("==", b, d)) if ne: ssa_r = builder.xor(ssa_r, ll.Constant(ll.IntType(1), 1)) r.auto_store(builder, ssa_r) return r
def main(): def process_diagnostic(diag): print("\n".join(diag.render())) if diag.level in ("fatal", "error"): exit(1) engine = diagnostic.Engine() engine.process = process_diagnostic mod = Module(Source.from_string("".join(fileinput.input()).expandtabs(), engine=engine)) target = NativeTarget() llmod = mod.build_llvm_ir(target=target) # Add main so that the result can be executed with lli llmain = ll.Function(llmod, ll.FunctionType(ll.VoidType(), []), "main") llbuilder = ll.IRBuilder(llmain.append_basic_block("entry")) llbuilder.call(llmod.get_global(llmod.name + ".__modinit__"), [ ll.Constant(ll.IntType(8).as_pointer(), None)]) llbuilder.ret_void() print(llmod)
def _visit_stmt_Try(self, node): function = self.builder.basic_block.function noexc_block = function.append_basic_block("try_noexc") exc_block = function.append_basic_block("try_exc") finally_block = function.append_basic_block("try_finally") propagate = self.builder.alloca(ll.IntType(1), name="propagate") self.builder.store(ll.Constant(ll.IntType(1), 0), propagate) propagate_eid = self.builder.alloca(ll.IntType(32), name="propagate_eid") exception_occured = self.runtime.build_catch(self.builder) self.builder.cbranch(exception_occured, exc_block, noexc_block) self.builder.position_at_end(noexc_block) self._exception_level_stack[-1] += 1 self.visit_statements(node.body) self._exception_level_stack[-1] -= 1 if not self._bb_terminated(): self.runtime.build_pop(self.builder, 1) self.visit_statements(node.orelse) if not self._bb_terminated(): self.builder.branch(finally_block) self.builder.position_at_end(exc_block) self._handle_exception(function, finally_block, propagate, propagate_eid, node.handlers) propagate_block = function.append_basic_block("try_propagate") merge_block = function.append_basic_block("try_merge") self.builder.position_at_end(finally_block) self.visit_statements(node.finalbody) if not self._bb_terminated(): self.builder.cbranch(self.builder.load(propagate), propagate_block, merge_block) self.builder.position_at_end(propagate_block) self.runtime.build_raise(self.builder, self.builder.load(propagate_eid)) self.builder.branch(merge_block) self.builder.position_at_end(merge_block)
def o_roundx(self, target_bits, builder): r = VInt(target_bits) if builder is not None: function = builder.basic_block.function neg_block = function.append_basic_block("fr_neg") merge_block = function.append_basic_block("fr_merge") half = VFloat() half.alloca(builder, "half") half.set_const_value(builder, 0.5) condition = builder.fcmp_ordered( "<", self.auto_load(builder), ll.Constant(self.get_llvm_type(), 0.0)) builder.cbranch(condition, neg_block, merge_block) builder.position_at_end(neg_block) half.set_const_value(builder, -0.5) builder.branch(merge_block) builder.position_at_end(merge_block) s = builder.fadd(self.auto_load(builder), half.auto_load(builder)) r.auto_store(builder, builder.fptosi(s, r.get_llvm_type())) return r
def _make_ssa(builder, n, d): 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
def set_const_value(self, builder, n): self.auto_store(builder, ll.Constant(self.get_llvm_type(), n))
def set_count(self, builder, count): count_ptr = builder.gep( self.llvm_value, [ll.Constant(ll.IntType(32), 0), ll.Constant(ll.IntType(32), 0)]) builder.store(ll.Constant(ll.IntType(32), count), count_ptr)
def build_pop(self, builder, levels): builder.call(self.eh_pop, [ll.Constant(ll.IntType(32), levels)])
def build_catch(self, builder): 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))