def to_bit(llvm_value, builder): llvm_t = llvm_value.type if llvm_t == int1_t: return llvm_value if isinstance(llvm_t, llcore.IntegerType): return builder.icmp(llcore.ICMP_NE, llvm_value, zero(llvm_t), "ne_zero") else: return builder.fcmp(llcore.FCMP_ONE, llvm_value, zero(llvm_t), "ne_zero")
def from_bit(llvm_value, new_ptype, builder): llvm_t = llvm_value_type(new_ptype) name = "%s.cast.%s" % (llvm_value.name, new_ptype) return builder.select(llvm_value, one(llvm_t), zero(llvm_t), name)
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 neg(self, x, builder): if isinstance(x.type, llc.IntegerType): return builder.neg(x, "neg") else: return builder.fsub(zero(x.type), x, "neg")
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