2022-01-08 22:16:55 +08:00
|
|
|
use super::CodeGenContext;
|
|
|
|
use inkwell::{
|
2022-01-11 17:25:07 +08:00
|
|
|
attributes::{Attribute, AttributeLoc},
|
|
|
|
context::Context,
|
|
|
|
memory_buffer::MemoryBuffer,
|
|
|
|
module::Module,
|
2022-01-08 22:16:55 +08:00
|
|
|
values::IntValue,
|
|
|
|
};
|
|
|
|
|
2022-01-09 01:05:17 +08:00
|
|
|
pub fn load_irrt(ctx: &Context) -> Module {
|
2022-01-08 22:16:55 +08:00
|
|
|
let bitcode_buf = MemoryBuffer::create_from_memory_range(
|
|
|
|
include_bytes!(concat!(env!("OUT_DIR"), "/irrt.bc")),
|
|
|
|
"irrt_bitcode_buffer",
|
|
|
|
);
|
|
|
|
let irrt_mod = Module::parse_bitcode_from_buffer(&bitcode_buf, ctx).unwrap();
|
2022-01-11 17:25:07 +08:00
|
|
|
let inline_attr = Attribute::get_named_enum_kind_id("alwaysinline");
|
2022-01-08 22:16:55 +08:00
|
|
|
for symbol in &["__nac3_irrt_int_exp_int32_t", "__nac3_irrt_int_exp_int64_t"] {
|
|
|
|
let function = irrt_mod.get_function(symbol).unwrap();
|
2022-01-11 17:25:07 +08:00
|
|
|
function.add_attribute(AttributeLoc::Function, ctx.create_enum_attribute(inline_attr, 0));
|
2022-01-08 22:16:55 +08:00
|
|
|
}
|
2022-01-09 01:05:17 +08:00
|
|
|
irrt_mod
|
2022-01-08 22:16:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// repeated squaring method adapted from GNU Scientific Library:
|
|
|
|
// https://git.savannah.gnu.org/cgit/gsl.git/tree/sys/pow_int.c
|
|
|
|
pub fn integer_power<'ctx, 'a>(
|
|
|
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
|
|
|
base: IntValue<'ctx>,
|
|
|
|
exp: IntValue<'ctx>,
|
|
|
|
) -> IntValue<'ctx> {
|
|
|
|
let symbol = match (base.get_type().get_bit_width(), exp.get_type().get_bit_width()) {
|
|
|
|
(32, 32) => "__nac3_irrt_int_exp_int32_t",
|
|
|
|
(64, 64) => "__nac3_irrt_int_exp_int64_t",
|
|
|
|
_ => unreachable!(),
|
|
|
|
};
|
|
|
|
let base_type = base.get_type();
|
|
|
|
let pow_fun = ctx.module.get_function(symbol).unwrap_or_else(|| {
|
|
|
|
let fn_type = base_type.fn_type(&[base_type.into(), base_type.into()], false);
|
|
|
|
ctx.module.add_function(symbol, fn_type, None)
|
|
|
|
});
|
|
|
|
// TODO: throw exception when exp < 0
|
|
|
|
ctx.builder
|
|
|
|
.build_call(pow_fun, &[base.into(), exp.into()], "call_int_pow")
|
|
|
|
.try_as_basic_value()
|
|
|
|
.unwrap_left()
|
|
|
|
.into_int_value()
|
|
|
|
}
|