def compile_Select(self, expr, builder): cond = self.compile_expr(expr.cond, builder) cond = llvm_convert.to_bit(cond, builder) trueval = self.compile_expr(expr.true_value, builder) falseval = self.compile_expr(expr.false_value, builder) result = builder.select(cond, trueval, falseval, "select_result") return result
def compile_While(self, stmt, builder): # current flow ----> loop --------> exit--> after # | skip------------| # |----------------------/ self.compile_merge_left(stmt.merge, builder) loop_bb, body_start_builder = self.new_block("loop_body") after_bb, after_builder = self.new_block("after_loop") enter_cond = self.compile_expr(stmt.cond, builder) enter_cond = llvm_convert.to_bit(enter_cond, builder) builder.cbranch(enter_cond, loop_bb, after_bb) body_end_builder, body_always_returns = \ self.compile_block(stmt.body, body_start_builder) if not body_always_returns: exit_bb, exit_builder = self.new_block("loop_exit") self.compile_merge_right(stmt.merge, body_end_builder) repeat_cond = self.compile_expr(stmt.cond, body_end_builder) repeat_cond = llvm_convert.to_bit(repeat_cond, body_end_builder) body_end_builder.cbranch(repeat_cond, loop_bb, exit_bb) exit_builder.branch(after_bb) return after_builder, False
def compile_If(self, stmt, builder): cond = self.compile_expr(stmt.cond, builder) cond = llvm_convert.to_bit(cond, builder) if len(stmt.true) == 0 and len(stmt.false) == 0: # if nothing happens in the loop bodies, just # emit select instructions for (name, (true_expr, false_expr)) in stmt.merge.iteritems(): ref = self.vars[name] self.initialized.add(name) true_val = self.compile_expr(true_expr, builder) false_val = self.compile_expr(false_expr, builder) select_val = builder.select(cond, true_val, false_val) builder.store(select_val, ref) return builder, False else: # compile the two possible branches as distinct basic blocks # and then wire together the control flow with branches true_bb, true_builder = self.new_block("if_true") after_true, true_always_returns = \ self.compile_block(stmt.true, true_builder) false_bb, false_builder = self.new_block("if_false") after_false, false_always_returns = \ self.compile_block(stmt.false, false_builder) builder.cbranch(cond, true_bb, false_bb) # compile phi nodes as assignments and then branch # to the continuation block self.compile_merge_left(stmt.merge, after_true) self.compile_merge_right(stmt.merge, after_false) # if both branches return then there is no point # making a new block for more code # did both branches end in a return? both_always_return = true_always_returns and false_always_returns if both_always_return: return None, True after_bb, after_builder = self.new_block("if_after") if not true_always_returns: after_true.branch(after_bb) if not false_always_returns: after_false.branch(after_bb) return after_builder, False
def prim(self, prim, t, llvm_args, builder, result_name = None): if result_name is None: result_name = prim.name + "_result" if isinstance(prim, prims.Cmp): bit = self.cmp(prim, t, llvm_args[0], llvm_args[1], builder) return llvm_convert.to_bool(bit,builder) elif prim == prims.maximum: x, y = llvm_args bit = self.cmp(prims.greater_equal, t, x, y, builder) return builder.select(bit, x, y) elif prim == prims.minimum: x,y = llvm_args bit = self.cmp(prims.less_equal, t, x, y, builder) return builder.select(bit, x, y) elif prim == prims.negative: if t == Bool: bit = llvm_convert.to_bit(llvm_args[0], builder) negated = builder.not_(bit) return llvm_convert.to_bool(negated, builder) return self.neg(llvm_args[0], builder) # python's remainder is weird in that it preserve's the sign of # the second argument, whereas LLVM's srem/frem operators preserve # the sign of the first elif prim == prims.mod: x,y = llvm_args if isinstance(t, (UnsignedT, BoolT)): return builder.urem(llvm_args[0], llvm_args[1], "modulo") elif isinstance(t, SignedT): rem = builder.srem(x,y, "modulo") else: assert isinstance(t, FloatT) rem = builder.frem(llvm_args[0], llvm_args[1], "modulo") y_is_negative = self.lt(t, y, zero(y.type), builder, "second_arg_negative") rem_is_negative = self.lt(t, rem, zero(rem.type), builder, "rem_is_negative") y_nonzero = self.neq(t, y, zero(y.type), builder, "second_arg_nonzero") rem_nonzero = self.neq(t, rem, zero(x.type), builder, "rem_nonzero") neither_zero = builder.and_(y_nonzero, rem_nonzero, "neither_zero") diff_signs = builder.xor(y_is_negative, rem_is_negative, "different_signs") should_flip = builder.and_(neither_zero, diff_signs, "should_flip") flipped_rem = self.add(t, y, rem, builder, "flipped_rem") return builder.select(should_flip, flipped_rem, rem) elif prim == prims.power: x,y = llvm_args if isinstance(t, FloatT): new_t = t else: new_t = Float64 x = llvm_convert.convert(x, t, new_t, builder) y = llvm_convert.convert(y, t, new_t, builder) llvm_op = llvm_prims.get_float_op(prim, new_t) result = builder.call(llvm_op, [x,y]) return llvm_convert.convert(result, new_t, t, builder) elif isinstance(prim, prims.Arith) or isinstance(prim, prims.Bitwise): if isinstance(t, FloatT): instr = llvm_prims.float_binops[prim] elif isinstance(t, SignedT): instr = llvm_prims.signed_binops[prim] elif isinstance(t, UnsignedT): instr = llvm_prims.unsigned_binops[prim] else: assert isinstance(t, BoolT) instr = llvm_prims.bool_binops[prim] op = getattr(builder, instr) return op(name = result_name, *llvm_args) elif isinstance(prim, prims.Logical): if prim == prims.logical_and: result = builder.and_(name = result_name, lhs = to_bit(llvm_args[0], builder), rhs = to_bit(llvm_args[1], builder)) return from_bit(result, t, builder) elif prim == prims.logical_not: result = builder.not_(to_bit(llvm_args[0], builder), name = result_name) return from_bit(result, t, builder) else: assert prim == prims.logical_or result = builder.or_(lhs = to_bit(llvm_args[0], builder), rhs = to_bit(llvm_args[1], builder), name = result_name) return from_bit(result, t, builder) elif prim == prims.abs: x = llvm_args[0] bit = self.cmp(prims.greater_equal, t, x, zero(x.type), builder, "gt_zero") neg_value = self.neg(x, builder) return builder.select(bit, x, neg_value) elif isinstance(prim, prims.Float): llvm_op = llvm_prims.get_float_op(prim, t) return builder.call(llvm_op, llvm_args) else: assert False, "UNSUPPORTED PRIMITIVE: %s" % prim
def prim(self, prim, t, llvm_args, builder, result_name=None): if result_name is None: result_name = prim.name + "_result" if isinstance(prim, prims.Cmp): bit = self.cmp(prim, t, llvm_args[0], llvm_args[1], builder) return llvm_convert.to_bool(bit, builder) elif prim == prims.maximum: x, y = llvm_args bit = self.cmp(prims.greater_equal, t, x, y, builder) return builder.select(bit, x, y) elif prim == prims.minimum: x, y = llvm_args bit = self.cmp(prims.less_equal, t, x, y, builder) return builder.select(bit, x, y) elif prim == prims.negative: if t == Bool: bit = llvm_convert.to_bit(llvm_args[0], builder) negated = builder.not_(bit) return llvm_convert.to_bool(negated, builder) return self.neg(llvm_args[0], builder) # python's remainder is weird in that it preserve's the sign of # the second argument, whereas LLVM's srem/frem operators preserve # the sign of the first elif prim == prims.mod: x, y = llvm_args if isinstance(t, (UnsignedT, BoolT)): return builder.urem(llvm_args[0], llvm_args[1], "modulo") elif isinstance(t, SignedT): rem = builder.srem(x, y, "modulo") else: assert isinstance(t, FloatT) rem = builder.frem(llvm_args[0], llvm_args[1], "modulo") y_is_negative = self.lt(t, y, zero(y.type), builder, "second_arg_negative") rem_is_negative = self.lt(t, rem, zero(rem.type), builder, "rem_is_negative") y_nonzero = self.neq(t, y, zero(y.type), builder, "second_arg_nonzero") rem_nonzero = self.neq(t, rem, zero(x.type), builder, "rem_nonzero") neither_zero = builder.and_(y_nonzero, rem_nonzero, "neither_zero") diff_signs = builder.xor(y_is_negative, rem_is_negative, "different_signs") should_flip = builder.and_(neither_zero, diff_signs, "should_flip") flipped_rem = self.add(t, y, rem, builder, "flipped_rem") return builder.select(should_flip, flipped_rem, rem) elif prim == prims.power: x, y = llvm_args if isinstance(t, FloatT): new_t = t else: new_t = Float64 x = llvm_convert.convert(x, t, new_t, builder) y = llvm_convert.convert(y, t, new_t, builder) llvm_op = llvm_prims.get_float_op(prim, new_t) result = builder.call(llvm_op, [x, y]) return llvm_convert.convert(result, new_t, t, builder) elif isinstance(prim, prims.Arith) or isinstance(prim, prims.Bitwise): if isinstance(t, FloatT): instr = llvm_prims.float_binops[prim] elif isinstance(t, SignedT): instr = llvm_prims.signed_binops[prim] elif isinstance(t, UnsignedT): instr = llvm_prims.unsigned_binops[prim] else: assert isinstance(t, BoolT) instr = llvm_prims.bool_binops[prim] op = getattr(builder, instr) return op(name=result_name, *llvm_args) elif isinstance(prim, prims.Logical): if prim == prims.logical_and: result = builder.and_(name=result_name, lhs=to_bit(llvm_args[0], builder), rhs=to_bit(llvm_args[1], builder)) return from_bit(result, t, builder) elif prim == prims.logical_not: result = builder.not_(to_bit(llvm_args[0], builder), name=result_name) return from_bit(result, t, builder) else: assert prim == prims.logical_or result = builder.or_(lhs=to_bit(llvm_args[0], builder), rhs=to_bit(llvm_args[1], builder), name=result_name) return from_bit(result, t, builder) elif prim == prims.abs: x = llvm_args[0] bit = self.cmp(prims.greater_equal, t, x, zero(x.type), builder, "gt_zero") neg_value = self.neg(x, builder) return builder.select(bit, x, neg_value) elif isinstance(prim, prims.Float): llvm_op = llvm_prims.get_float_op(prim, t) return builder.call(llvm_op, llvm_args) else: assert False, "UNSUPPORTED PRIMITIVE: %s" % prim