core: Add helper for outputting const values

This commit is contained in:
David Mak 2024-05-30 13:56:45 +08:00
parent 4d0d4e0eae
commit 35c346881d
1 changed files with 68 additions and 6 deletions

View File

@ -1,8 +1,9 @@
use inkwell::AddressSpace;
use inkwell::attributes::{Attribute, AttributeLoc}; use inkwell::attributes::{Attribute, AttributeLoc};
use inkwell::values::{BasicValueEnum, CallSiteValue, FloatValue, IntValue, PointerValue}; use inkwell::values::{BasicValueEnum, CallSiteValue, FloatValue, IntValue, PointerValue};
use itertools::Either; use itertools::Either;
use crate::codegen::{CodeGenContext, CodeGenerator}; use crate::codegen::{CodeGenContext, CodeGenerator, llvm_intrinsics};
/// Invokes `dbl_nan` in the demo library. /// Invokes `dbl_nan` in the demo library.
pub fn call_dbl_nan<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>) -> FloatValue<'ctx> { pub fn call_dbl_nan<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>) -> FloatValue<'ctx> {
@ -113,6 +114,13 @@ pub fn call_output_bool<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>, value: IntValu
} }
} }
/// Helper function for invoking `output_bool` with a compile-time constant value.
pub fn call_output_bool_const(ctx: &mut CodeGenContext<'_, '_>, value: bool) {
let llvm_i1 = ctx.ctx.bool_type();
call_output_bool(ctx, llvm_i1.const_int(value as u64, false));
}
/// Invokes `output_int32` in the demo library. /// Invokes `output_int32` in the demo library.
pub fn call_output_int32<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>, value: IntValue<'ctx>) { pub fn call_output_int32<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>, value: IntValue<'ctx>) {
const FN_NAME: &str = "output_int32"; const FN_NAME: &str = "output_int32";
@ -146,6 +154,13 @@ pub fn call_output_int32<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>, value: IntVal
} }
} }
/// Helper function for invoking `output_int32` with a compile-time constant value.
pub fn call_output_int32_const(ctx: &mut CodeGenContext<'_, '_>, value: i32) {
let llvm_i32 = ctx.ctx.i32_type();
call_output_int32(ctx, llvm_i32.const_int(value as u64, true));
}
/// Invokes `output_int64` in the demo library. /// Invokes `output_int64` in the demo library.
pub fn call_output_int64<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>, value: IntValue<'ctx>) { pub fn call_output_int64<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>, value: IntValue<'ctx>) {
const FN_NAME: &str = "output_int64"; const FN_NAME: &str = "output_int64";
@ -179,6 +194,13 @@ pub fn call_output_int64<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>, value: IntVal
} }
} }
/// Helper function for invoking `output_int64` with a compile-time constant value.
pub fn call_output_int64_const(ctx: &mut CodeGenContext<'_, '_>, value: i64) {
let llvm_i64 = ctx.ctx.i64_type();
call_output_int64(ctx, llvm_i64.const_int(value as u64, true));
}
/// Invokes `output_uint32` in the demo library. /// Invokes `output_uint32` in the demo library.
pub fn call_output_uint32<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>, value: IntValue<'ctx>) { pub fn call_output_uint32<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>, value: IntValue<'ctx>) {
const FN_NAME: &str = "output_uint32"; const FN_NAME: &str = "output_uint32";
@ -212,6 +234,13 @@ pub fn call_output_uint32<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>, value: IntVa
} }
} }
/// Helper function for invoking `output_uint32` with a compile-time constant value.
pub fn call_output_uint32_const(ctx: &mut CodeGenContext<'_, '_>, value: u32) {
let llvm_i32 = ctx.ctx.i32_type();
call_output_uint32(ctx, llvm_i32.const_int(value as u64, false));
}
/// Invokes `output_uint64` in the demo library. /// Invokes `output_uint64` in the demo library.
pub fn call_output_uint64<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>, value: IntValue<'ctx>) { pub fn call_output_uint64<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>, value: IntValue<'ctx>) {
const FN_NAME: &str = "output_uint64"; const FN_NAME: &str = "output_uint64";
@ -245,6 +274,13 @@ pub fn call_output_uint64<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>, value: IntVa
} }
} }
/// Helper function for invoking `output_uint64` with a compile-time constant value.
pub fn call_output_uint64_const(ctx: &mut CodeGenContext<'_, '_>, value: u64) {
let llvm_i64 = ctx.ctx.i64_type();
call_output_uint64(ctx, llvm_i64.const_int(value, false));
}
/// Invokes `output_float64` in the demo library. /// Invokes `output_float64` in the demo library.
pub fn call_output_float64<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>, value: FloatValue<'ctx>) { pub fn call_output_float64<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>, value: FloatValue<'ctx>) {
const FN_NAME: &str = "output_float64"; const FN_NAME: &str = "output_float64";
@ -278,9 +314,16 @@ pub fn call_output_float64<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>, value: Floa
} }
} }
/// Helper function for invoking `output_float64` with a compile-time constant value.
pub fn call_output_float64_const(ctx: &mut CodeGenContext<'_, '_>, value: f64) {
let llvm_f64 = ctx.ctx.f64_type();
call_output_float64(ctx, llvm_f64.const_float(value));
}
/// Invokes `output_str` in the demo library. /// Invokes `output_str` in the demo library.
pub fn call_output_str<'ctx>( pub fn call_output_str<'ctx, G: CodeGenerator + ?Sized>(
generator: &mut dyn CodeGenerator, generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>, ctx: &mut CodeGenContext<'ctx, '_>,
value: PointerValue<'ctx>, value: PointerValue<'ctx>,
) { ) {
@ -288,12 +331,13 @@ pub fn call_output_str<'ctx>(
if ctx.registry.codegen_options.use_demo_lib { if ctx.registry.codegen_options.use_demo_lib {
let llvm_void = ctx.ctx.void_type(); let llvm_void = ctx.ctx.void_type();
let llvm_str = ctx.get_llvm_type(generator, ctx.primitives.str).into_pointer_type(); let llvm_str = ctx.get_llvm_type(generator, ctx.primitives.str).into_struct_type();
let llvm_pstr = llvm_str.ptr_type(AddressSpace::default());
debug_assert_eq!(value.get_type(), llvm_str); debug_assert_eq!(value.get_type(), llvm_pstr);
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| { let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
let fn_type = llvm_void.fn_type(&[llvm_str.into()], false); let fn_type = llvm_void.fn_type(&[llvm_pstr.into()], false);
let func = ctx.module.add_function(FN_NAME, fn_type, None); let func = ctx.module.add_function(FN_NAME, fn_type, None);
for attr in [ for attr in [
"nofree", "nofree",
@ -314,3 +358,21 @@ pub fn call_output_str<'ctx>(
.unwrap(); .unwrap();
} }
} }
/// Helper function for invoking `output_str` with a compile-time constant value.
pub fn call_output_str_const<G: CodeGenerator + ?Sized>(
generator: &mut G,
ctx: &mut CodeGenContext<'_, '_>,
value: &str,
) {
let str = ctx.gen_string(generator, value).into_struct_value();
// The alloca is necessary to form a pointer to the string struct, but since we only need it for
// the call to `call_output_str`, do a stack save-and-restore to ensure that this can be called
// anywhere
let stack_addr = llvm_intrinsics::call_stacksave(ctx, None);
let pstr = ctx.builder.build_alloca(str.get_type(), "").unwrap();
ctx.builder.build_store(pstr, str).unwrap();
call_output_str(generator, ctx, pstr);
llvm_intrinsics::call_stackrestore(ctx, stack_addr);
}