mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 12:18:19 +00:00
refactor llvm lowlevel code into its own file
This commit is contained in:
parent
06a49e0255
commit
653741ccde
7 changed files with 2685 additions and 2632 deletions
File diff suppressed because it is too large
Load diff
|
@ -13,8 +13,9 @@ use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
|||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout};
|
||||
|
||||
use super::build::{dec_binop_with_unchecked, load_roc_value, use_roc_value};
|
||||
use super::build::{load_roc_value, use_roc_value};
|
||||
use super::convert::argument_type_from_union_layout;
|
||||
use super::lowlevel::dec_binop_with_unchecked;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum WhenRecursive<'a> {
|
||||
|
|
|
@ -7,7 +7,8 @@ use inkwell::values::BasicValue;
|
|||
use inkwell::AddressSpace;
|
||||
use roc_builtins::bitcode;
|
||||
|
||||
use super::build::{get_sjlj_buffer, LLVM_LONGJMP};
|
||||
use super::build::get_sjlj_buffer;
|
||||
use super::intrinsics::LLVM_LONGJMP;
|
||||
|
||||
/// Define functions for roc_alloc, roc_realloc, and roc_dealloc
|
||||
/// which use libc implementations (malloc, realloc, and free)
|
||||
|
|
197
crates/compiler/gen_llvm/src/llvm/intrinsics.rs
Normal file
197
crates/compiler/gen_llvm/src/llvm/intrinsics.rs
Normal file
|
@ -0,0 +1,197 @@
|
|||
use inkwell::{
|
||||
context::Context,
|
||||
module::{Linkage, Module},
|
||||
types::FunctionType,
|
||||
values::FunctionValue,
|
||||
AddressSpace,
|
||||
};
|
||||
use roc_builtins::{
|
||||
bitcode::{FloatWidth, IntWidth, IntrinsicName},
|
||||
float_intrinsic, llvm_int_intrinsic,
|
||||
};
|
||||
|
||||
use super::build::{add_func, FunctionSpec};
|
||||
|
||||
fn add_float_intrinsic<'ctx, F>(
|
||||
ctx: &'ctx Context,
|
||||
module: &Module<'ctx>,
|
||||
name: &IntrinsicName,
|
||||
construct_type: F,
|
||||
) where
|
||||
F: Fn(inkwell::types::FloatType<'ctx>) -> inkwell::types::FunctionType<'ctx>,
|
||||
{
|
||||
macro_rules! check {
|
||||
($width:expr, $typ:expr) => {
|
||||
let full_name = &name[$width];
|
||||
|
||||
if let Some(_) = module.get_function(full_name) {
|
||||
// zig defined this function already
|
||||
} else {
|
||||
add_intrinsic(ctx, module, full_name, construct_type($typ));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
check!(FloatWidth::F32, ctx.f32_type());
|
||||
check!(FloatWidth::F64, ctx.f64_type());
|
||||
// check!(IntWidth::F128, ctx.i128_type());
|
||||
}
|
||||
|
||||
fn add_int_intrinsic<'ctx, F>(
|
||||
ctx: &'ctx Context,
|
||||
module: &Module<'ctx>,
|
||||
name: &IntrinsicName,
|
||||
construct_type: F,
|
||||
) where
|
||||
F: Fn(inkwell::types::IntType<'ctx>) -> inkwell::types::FunctionType<'ctx>,
|
||||
{
|
||||
macro_rules! check {
|
||||
($width:expr, $typ:expr) => {
|
||||
let full_name = &name[$width];
|
||||
|
||||
if let Some(_) = module.get_function(full_name) {
|
||||
// zig defined this function already
|
||||
} else {
|
||||
add_intrinsic(ctx, module, full_name, construct_type($typ));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
check!(IntWidth::U8, ctx.i8_type());
|
||||
check!(IntWidth::U16, ctx.i16_type());
|
||||
check!(IntWidth::U32, ctx.i32_type());
|
||||
check!(IntWidth::U64, ctx.i64_type());
|
||||
check!(IntWidth::U128, ctx.i128_type());
|
||||
|
||||
check!(IntWidth::I8, ctx.i8_type());
|
||||
check!(IntWidth::I16, ctx.i16_type());
|
||||
check!(IntWidth::I32, ctx.i32_type());
|
||||
check!(IntWidth::I64, ctx.i64_type());
|
||||
check!(IntWidth::I128, ctx.i128_type());
|
||||
}
|
||||
|
||||
pub(crate) fn add_intrinsics<'ctx>(ctx: &'ctx Context, module: &Module<'ctx>) {
|
||||
// List of all supported LLVM intrinsics:
|
||||
//
|
||||
// https://releases.llvm.org/10.0.0/docs/LangRef.html#standard-c-library-intrinsics
|
||||
let i1_type = ctx.bool_type();
|
||||
let i8_type = ctx.i8_type();
|
||||
let i8_ptr_type = i8_type.ptr_type(AddressSpace::Generic);
|
||||
let i32_type = ctx.i32_type();
|
||||
let void_type = ctx.void_type();
|
||||
|
||||
if let Some(func) = module.get_function("__muloti4") {
|
||||
func.set_linkage(Linkage::WeakAny);
|
||||
}
|
||||
|
||||
add_intrinsic(
|
||||
ctx,
|
||||
module,
|
||||
LLVM_SETJMP,
|
||||
i32_type.fn_type(&[i8_ptr_type.into()], false),
|
||||
);
|
||||
|
||||
add_intrinsic(
|
||||
ctx,
|
||||
module,
|
||||
LLVM_LONGJMP,
|
||||
void_type.fn_type(&[i8_ptr_type.into()], false),
|
||||
);
|
||||
|
||||
add_intrinsic(
|
||||
ctx,
|
||||
module,
|
||||
LLVM_FRAME_ADDRESS,
|
||||
i8_ptr_type.fn_type(&[i32_type.into()], false),
|
||||
);
|
||||
|
||||
add_intrinsic(
|
||||
ctx,
|
||||
module,
|
||||
LLVM_STACK_SAVE,
|
||||
i8_ptr_type.fn_type(&[], false),
|
||||
);
|
||||
|
||||
add_float_intrinsic(ctx, module, &LLVM_LOG, |t| t.fn_type(&[t.into()], false));
|
||||
add_float_intrinsic(ctx, module, &LLVM_POW, |t| {
|
||||
t.fn_type(&[t.into(), t.into()], false)
|
||||
});
|
||||
add_float_intrinsic(ctx, module, &LLVM_FABS, |t| t.fn_type(&[t.into()], false));
|
||||
add_float_intrinsic(ctx, module, &LLVM_SIN, |t| t.fn_type(&[t.into()], false));
|
||||
add_float_intrinsic(ctx, module, &LLVM_COS, |t| t.fn_type(&[t.into()], false));
|
||||
add_float_intrinsic(ctx, module, &LLVM_CEILING, |t| {
|
||||
t.fn_type(&[t.into()], false)
|
||||
});
|
||||
add_float_intrinsic(ctx, module, &LLVM_FLOOR, |t| t.fn_type(&[t.into()], false));
|
||||
|
||||
add_int_intrinsic(ctx, module, &LLVM_ADD_WITH_OVERFLOW, |t| {
|
||||
let fields = [t.into(), i1_type.into()];
|
||||
ctx.struct_type(&fields, false)
|
||||
.fn_type(&[t.into(), t.into()], false)
|
||||
});
|
||||
|
||||
add_int_intrinsic(ctx, module, &LLVM_SUB_WITH_OVERFLOW, |t| {
|
||||
let fields = [t.into(), i1_type.into()];
|
||||
ctx.struct_type(&fields, false)
|
||||
.fn_type(&[t.into(), t.into()], false)
|
||||
});
|
||||
|
||||
add_int_intrinsic(ctx, module, &LLVM_MUL_WITH_OVERFLOW, |t| {
|
||||
let fields = [t.into(), i1_type.into()];
|
||||
ctx.struct_type(&fields, false)
|
||||
.fn_type(&[t.into(), t.into()], false)
|
||||
});
|
||||
|
||||
add_int_intrinsic(ctx, module, &LLVM_ADD_SATURATED, |t| {
|
||||
t.fn_type(&[t.into(), t.into()], false)
|
||||
});
|
||||
|
||||
add_int_intrinsic(ctx, module, &LLVM_SUB_SATURATED, |t| {
|
||||
t.fn_type(&[t.into(), t.into()], false)
|
||||
});
|
||||
}
|
||||
|
||||
pub const LLVM_POW: IntrinsicName = float_intrinsic!("llvm.pow");
|
||||
pub const LLVM_FABS: IntrinsicName = float_intrinsic!("llvm.fabs");
|
||||
pub static LLVM_SQRT: IntrinsicName = float_intrinsic!("llvm.sqrt");
|
||||
pub static LLVM_LOG: IntrinsicName = float_intrinsic!("llvm.log");
|
||||
|
||||
pub static LLVM_SIN: IntrinsicName = float_intrinsic!("llvm.sin");
|
||||
pub static LLVM_COS: IntrinsicName = float_intrinsic!("llvm.cos");
|
||||
pub static LLVM_CEILING: IntrinsicName = float_intrinsic!("llvm.ceil");
|
||||
pub static LLVM_FLOOR: IntrinsicName = float_intrinsic!("llvm.floor");
|
||||
pub static LLVM_ROUND: IntrinsicName = float_intrinsic!("llvm.round");
|
||||
|
||||
pub static LLVM_MEMSET_I64: &str = "llvm.memset.p0i8.i64";
|
||||
pub static LLVM_MEMSET_I32: &str = "llvm.memset.p0i8.i32";
|
||||
|
||||
pub static LLVM_FRAME_ADDRESS: &str = "llvm.frameaddress.p0i8";
|
||||
pub static LLVM_STACK_SAVE: &str = "llvm.stacksave";
|
||||
|
||||
pub static LLVM_SETJMP: &str = "llvm.eh.sjlj.setjmp";
|
||||
pub static LLVM_LONGJMP: &str = "llvm.eh.sjlj.longjmp";
|
||||
|
||||
pub const LLVM_ADD_WITH_OVERFLOW: IntrinsicName =
|
||||
llvm_int_intrinsic!("llvm.sadd.with.overflow", "llvm.uadd.with.overflow");
|
||||
pub const LLVM_SUB_WITH_OVERFLOW: IntrinsicName =
|
||||
llvm_int_intrinsic!("llvm.ssub.with.overflow", "llvm.usub.with.overflow");
|
||||
pub const LLVM_MUL_WITH_OVERFLOW: IntrinsicName =
|
||||
llvm_int_intrinsic!("llvm.smul.with.overflow", "llvm.umul.with.overflow");
|
||||
|
||||
pub const LLVM_ADD_SATURATED: IntrinsicName = llvm_int_intrinsic!("llvm.sadd.sat", "llvm.uadd.sat");
|
||||
pub const LLVM_SUB_SATURATED: IntrinsicName = llvm_int_intrinsic!("llvm.ssub.sat", "llvm.usub.sat");
|
||||
|
||||
fn add_intrinsic<'ctx>(
|
||||
context: &Context,
|
||||
module: &Module<'ctx>,
|
||||
intrinsic_name: &str,
|
||||
fn_type: FunctionType<'ctx>,
|
||||
) -> FunctionValue<'ctx> {
|
||||
add_func(
|
||||
context,
|
||||
module,
|
||||
intrinsic_name,
|
||||
FunctionSpec::intrinsic(fn_type),
|
||||
Linkage::External,
|
||||
)
|
||||
}
|
2454
crates/compiler/gen_llvm/src/llvm/lowlevel.rs
Normal file
2454
crates/compiler/gen_llvm/src/llvm/lowlevel.rs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -6,4 +6,6 @@ pub mod compare;
|
|||
pub mod convert;
|
||||
mod expect;
|
||||
pub mod externs;
|
||||
mod intrinsics;
|
||||
mod lowlevel;
|
||||
pub mod refcounting;
|
||||
|
|
|
@ -2358,15 +2358,7 @@ impl<'a> Stmt<'a> {
|
|||
pub fn is_terminal(&self) -> bool {
|
||||
use Stmt::*;
|
||||
|
||||
match self {
|
||||
Switch { .. } => {
|
||||
// TODO is this the reason Lean only looks at the outermost `when`?
|
||||
true
|
||||
}
|
||||
Ret(_) => true,
|
||||
Jump(_, _) => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(self, Switch { .. } | Ret(_) | Jump(_, _))
|
||||
}
|
||||
|
||||
pub fn if_then_else(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue