powi.f64.i32

This commit is contained in:
ychenfo 2022-04-04 14:55:36 +08:00
parent f4e9c2eb31
commit 1f5d338c04

View File

@ -948,45 +948,16 @@ pub fn gen_binop_expr<'ctx, 'a, G: CodeGenerator>(
} else if ty1 == ctx.primitives.float && ty2 == ctx.primitives.int32 {
// Pow is the only operator that would pass typecheck between float and int
assert!(*op == Operator::Pow);
// TODO: throw exception when rhs is out of i16 bound
// since llvm intrinsic only support to i16 for f64
let i16_t = ctx.ctx.i16_type();
let pow_intr = ctx.module.get_function("llvm.powi.f64.i16").unwrap_or_else(|| {
let i32_t = ctx.ctx.i32_type();
let pow_intr = ctx.module.get_function("llvm.powi.f64.i32").unwrap_or_else(|| {
let f64_t = ctx.ctx.f64_type();
let ty = f64_t.fn_type(&[f64_t.into(), i16_t.into()], false);
ctx.module.add_function("llvm.powi.f64.i16", ty, None)
let ty = f64_t.fn_type(&[f64_t.into(), i32_t.into()], false);
ctx.module.add_function("llvm.powi.f64.i32", ty, None)
});
let right = ctx.builder.build_int_truncate(right.into_int_value(), i16_t, "r_pow");
let is_neg = ctx.builder.build_int_compare(
inkwell::IntPredicate::SLT,
right,
i16_t.const_zero(),
"powi_pow_neg",
);
let abs_intr = ctx.module.get_function("llvm.abs.i16").unwrap_or_else(|| {
let ty = i16_t.fn_type(&[i16_t.into(), ctx.ctx.bool_type().into()], false);
ctx.module.add_function("llvm.abs.i16", ty, None)
});
let right = ctx
.builder
.build_call(
abs_intr,
&[right.into(), ctx.ctx.bool_type().const_int(0, false).into()],
"pow_abs",
)
.try_as_basic_value()
.unwrap_left();
let pow = ctx
.builder
ctx.builder
.build_call(pow_intr, &[left.into(), right.into()], "f_pow_i")
.try_as_basic_value()
.unwrap_left();
let reciprocal = ctx.builder.build_float_div(
ctx.ctx.f64_type().const_float(1.0),
pow.into_float_value(),
"recip",
);
ctx.builder.build_select(is_neg, reciprocal, pow.into_float_value(), "float_pow_i")
.unwrap_left()
} else {
unimplemented!()
}