Get intrinsics to inline at codegen

This commit is contained in:
Sofia 2025-07-24 17:13:02 +03:00
parent 436ab319b8
commit 8810d34d54
6 changed files with 166 additions and 124 deletions

View File

@ -5,5 +5,5 @@ fn main() -> u32 {
let value = 6;
let other = 15;
return value + other;
return value * other + 7 * -value;
}

View File

@ -8,7 +8,7 @@ use std::{
};
use llvm_sys::{
LLVMIntPredicate, LLVMLinkage, LLVMRealPredicate, LLVMValueKind,
LLVMAttributeIndex, LLVMIntPredicate, LLVMLinkage, LLVMRealPredicate, LLVMValueKind,
analysis::LLVMVerifyModule,
core::*,
debuginfo::*,
@ -86,7 +86,7 @@ impl CompiledModule {
triple,
c"generic".as_ptr(),
c"".as_ptr(),
llvm_sys::target_machine::LLVMCodeGenOptLevel::LLVMCodeGenLevelNone,
llvm_sys::target_machine::LLVMCodeGenOptLevel::LLVMCodeGenLevelLess,
llvm_sys::target_machine::LLVMRelocMode::LLVMRelocDefault,
llvm_sys::target_machine::LLVMCodeModel::LLVMCodeModelDefault,
);
@ -601,6 +601,15 @@ impl FunctionHolder {
let function_ref =
LLVMAddFunction(module_ref, into_cstring(&self.data.name).as_ptr(), fn_type);
if self.data.flags.inline {
let attribute = LLVMCreateEnumAttribute(
context.context_ref,
LLVMEnumAttribute::AlwaysInline as u32,
0,
);
LLVMAddAttributeAtIndex(function_ref, 0, attribute);
}
let metadata = if let Some(debug) = debug {
if let Some(value) = &self.data.debug {
let subprogram = debug.debug.get_subprogram_data_unchecked(&value);
@ -1215,3 +1224,7 @@ impl Type {
}
}
}
pub enum LLVMEnumAttribute {
AlwaysInline = 3,
}

View File

@ -148,6 +148,7 @@ pub struct FunctionFlags {
pub is_main: bool,
pub is_pub: bool,
pub is_imported: bool,
pub inline: bool,
}
impl Default for FunctionFlags {
@ -157,6 +158,7 @@ impl Default for FunctionFlags {
is_main: false,
is_pub: false,
is_imported: false,
inline: false,
}
}
}

View File

@ -16,6 +16,7 @@ use reid_lib::{
use crate::{
allocator::{Allocator, AllocatorScope},
intrinsics::IntrinsicFunction,
lexer::{FullToken, Position},
mir::{
self,
@ -137,7 +138,7 @@ pub struct Debug<'ctx> {
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StackValue(StackValueKind, TypeKind);
pub struct StackValue(pub(super) StackValueKind, pub(super) TypeKind);
impl StackValue {
fn instr(&self) -> InstructionValue {
@ -188,7 +189,12 @@ impl StackValueKind {
pub struct StackBinopDefinition<'ctx> {
parameters: ((String, TypeKind), (String, TypeKind)),
return_ty: TypeKind,
ir: Function<'ctx>,
kind: StackBinopFunctionKind<'ctx>,
}
pub enum StackBinopFunctionKind<'ctx> {
UserGenerated(Function<'ctx>),
Intrinsic(&'ctx Box<dyn IntrinsicFunction>),
}
impl<'ctx> StackBinopDefinition<'ctx> {
@ -197,20 +203,30 @@ impl<'ctx> StackBinopDefinition<'ctx> {
lhs: &StackValue,
rhs: &StackValue,
scope: &mut Scope<'ctx, 'a>,
) -> StackValue {
) -> Result<StackValue, ErrorKind> {
let (lhs, rhs) = if lhs.1 == self.parameters.0 .1 && rhs.1 == self.parameters.1 .1 {
(lhs, rhs)
} else {
(rhs, lhs)
};
let instr = scope
.block
.build(Instr::FunctionCall(
self.ir.value(),
vec![lhs.instr(), rhs.instr()],
))
.unwrap();
StackValue(StackValueKind::Immutable(instr), self.return_ty.clone())
match &self.kind {
StackBinopFunctionKind::UserGenerated(ir) => {
let instr = scope
.block
.build(Instr::FunctionCall(
ir.value(),
vec![lhs.instr(), rhs.instr()],
))
.unwrap();
Ok(StackValue(
StackValueKind::Immutable(instr),
self.return_ty.clone(),
))
}
StackBinopFunctionKind::Intrinsic(fun) => {
fun.codegen(scope, &[lhs.instr(), rhs.instr()])
}
}
}
}
@ -326,7 +342,7 @@ impl mir::Module {
let is_main = self.is_main && function.name == "main";
let func = match &function.kind {
mir::FunctionDefinitionKind::Local(_, _) => module.function(
mir::FunctionDefinitionKind::Local(_, _) => Some(module.function(
&function.name,
function.return_type.get_type(&type_values),
param_types,
@ -336,8 +352,8 @@ impl mir::Module {
is_imported: function.is_imported,
..FunctionFlags::default()
},
),
mir::FunctionDefinitionKind::Extern(imported) => module.function(
)),
mir::FunctionDefinitionKind::Extern(imported) => Some(module.function(
&function.name,
function.return_type.get_type(&type_values),
param_types,
@ -346,87 +362,17 @@ impl mir::Module {
is_imported: *imported,
..FunctionFlags::default()
},
),
mir::FunctionDefinitionKind::Intrinsic(_) => module.function(
&function.name,
function.return_type.get_type(&type_values),
param_types,
FunctionFlags {
..FunctionFlags::default()
},
),
)),
mir::FunctionDefinitionKind::Intrinsic(_) => None,
};
functions.insert(function.name.clone(), func);
if let Some(func) = func {
functions.insert(function.name.clone(), func);
}
}
let mut binops = HashMap::new();
for binop in &self.binop_defs {
let binop_fn_name = format!(
"binop.{}.{:?}.{}.{}",
binop.lhs.1, binop.op, binop.rhs.1, binop.return_type
);
let ir_function = module.function(
&binop_fn_name,
binop.return_type.get_type(&type_values),
vec![
binop.lhs.1.get_type(&type_values),
binop.rhs.1.get_type(&type_values),
],
FunctionFlags::default(),
);
let mut entry = ir_function.block("entry");
let allocator = Allocator::from(
&binop.fn_kind,
&vec![binop.lhs.clone(), binop.rhs.clone()],
&mut AllocatorScope {
block: &mut entry,
module_id: self.module_id,
type_values: &type_values,
},
);
let mut scope = Scope {
context,
modules: &modules,
tokens,
module: &module,
module_id: self.module_id,
function: &ir_function,
block: entry,
functions: &functions,
types: &types,
type_values: &type_values,
stack_values: HashMap::new(),
debug: Some(Debug {
info: &debug,
scope: compile_unit,
types: &debug_types,
}),
binops: &binops,
allocator: Rc::new(RefCell::new(allocator)),
};
binop
.fn_kind
.codegen(
binop_fn_name.clone(),
false,
&mut scope,
&vec![binop.lhs.clone(), binop.rhs.clone()],
&binop.return_type,
&ir_function,
match &binop.fn_kind {
FunctionDefinitionKind::Local(_, meta) => {
meta.into_debug(tokens, compile_unit)
}
FunctionDefinitionKind::Extern(_) => None,
FunctionDefinitionKind::Intrinsic(_) => None,
},
)
.unwrap();
binops.insert(
ScopeBinopKey {
params: (binop.lhs.1.clone(), binop.rhs.1.clone()),
@ -435,7 +381,83 @@ impl mir::Module {
StackBinopDefinition {
parameters: (binop.lhs.clone(), binop.rhs.clone()),
return_ty: binop.return_type.clone(),
ir: ir_function,
kind: match &binop.fn_kind {
FunctionDefinitionKind::Local(block, metadata) => {
let binop_fn_name = format!(
"binop.{}.{:?}.{}.{}",
binop.lhs.1, binop.op, binop.rhs.1, binop.return_type
);
let ir_function = module.function(
&binop_fn_name,
binop.return_type.get_type(&type_values),
vec![
binop.lhs.1.get_type(&type_values),
binop.rhs.1.get_type(&type_values),
],
FunctionFlags {
inline: true,
..Default::default()
},
);
let mut entry = ir_function.block("entry");
let allocator = Allocator::from(
&binop.fn_kind,
&vec![binop.lhs.clone(), binop.rhs.clone()],
&mut AllocatorScope {
block: &mut entry,
module_id: self.module_id,
type_values: &type_values,
},
);
let mut scope = Scope {
context,
modules: &modules,
tokens,
module: &module,
module_id: self.module_id,
function: &ir_function,
block: entry,
functions: &functions,
types: &types,
type_values: &type_values,
stack_values: HashMap::new(),
debug: Some(Debug {
info: &debug,
scope: compile_unit,
types: &debug_types,
}),
binops: &binops,
allocator: Rc::new(RefCell::new(allocator)),
};
binop
.fn_kind
.codegen(
binop_fn_name.clone(),
false,
&mut scope,
&vec![binop.lhs.clone(), binop.rhs.clone()],
&binop.return_type,
&ir_function,
match &binop.fn_kind {
FunctionDefinitionKind::Local(_, meta) => {
meta.into_debug(tokens, compile_unit)
}
FunctionDefinitionKind::Extern(_) => None,
FunctionDefinitionKind::Intrinsic(_) => None,
},
)
.unwrap();
StackBinopFunctionKind::UserGenerated(ir_function)
}
FunctionDefinitionKind::Extern(_) => todo!(),
FunctionDefinitionKind::Intrinsic(intrinsic_function) => {
StackBinopFunctionKind::Intrinsic(intrinsic_function)
}
},
},
);
}
@ -619,7 +641,7 @@ impl FunctionDefinitionKind {
}
}
mir::FunctionDefinitionKind::Extern(_) => {}
mir::FunctionDefinitionKind::Intrinsic(kind) => kind.codegen(scope)?,
mir::FunctionDefinitionKind::Intrinsic(_) => {}
};
Ok(())
}
@ -877,7 +899,10 @@ impl mir::Expression {
});
if let Some(operation) = operation {
Some(operation.codegen(&lhs_val, &rhs_val, scope))
let a = operation.codegen(&lhs_val, &rhs_val, scope)?;
dbg!(&scope.context);
dbg!(&a);
Some(a)
} else {
dbg!((lhs_val.1.clone(), rhs_val.1.clone()));
dbg!(&operation.map(|b| &b.return_ty));

View File

@ -1,20 +1,15 @@
use reid_lib::Instr;
use reid_lib::{builder::InstructionValue, Instr};
use crate::{
codegen::{ErrorKind, Scope},
codegen::{ErrorKind, Scope, StackValue, StackValueKind},
mir::{BinaryOperator, BinopDefinition, FunctionDefinition, FunctionDefinitionKind, TypeKind},
};
#[derive(Debug, Clone, Copy)]
pub enum InstrinsicKind {
IAdd,
}
fn intrinsic(
name: &str,
ret_ty: TypeKind,
params: Vec<(&str, TypeKind)>,
kind: InstrinsicKind,
fun: impl IntrinsicFunction + 'static,
) -> FunctionDefinition {
FunctionDefinition {
name: name.into(),
@ -22,7 +17,7 @@ fn intrinsic(
is_imported: false,
return_type: ret_ty,
parameters: params.into_iter().map(|(n, ty)| (n.into(), ty)).collect(),
kind: FunctionDefinitionKind::Intrinsic(kind),
kind: FunctionDefinitionKind::Intrinsic(Box::new(fun)),
}
}
@ -31,20 +26,20 @@ fn intrinsic_binop(
lhs: TypeKind,
rhs: TypeKind,
ret_ty: TypeKind,
kind: InstrinsicKind,
fun: impl IntrinsicFunction + 'static,
) -> BinopDefinition {
BinopDefinition {
lhs: ("lhs".to_string(), lhs),
op,
rhs: ("rhs".to_owned(), rhs),
return_type: ret_ty,
fn_kind: FunctionDefinitionKind::Intrinsic(kind),
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(fun)),
meta: Default::default(),
}
}
pub fn form_intrinsics() -> Vec<FunctionDefinition> {
let mut intrinsics = Vec::new();
let intrinsics = Vec::new();
intrinsics
}
@ -57,25 +52,32 @@ pub fn form_intrinsic_binops() -> Vec<BinopDefinition> {
TypeKind::U32,
TypeKind::U32,
TypeKind::U32,
InstrinsicKind::IAdd,
IntrinsicIAdd(TypeKind::U32),
));
intrinsics
}
impl InstrinsicKind {
pub fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>) -> Result<(), ErrorKind> {
match self {
InstrinsicKind::IAdd => {
let lhs = scope.block.build(Instr::Param(0)).unwrap();
let rhs = scope.block.build(Instr::Param(1)).unwrap();
let add = scope.block.build(Instr::Add(lhs, rhs)).unwrap();
scope
.block
.terminate(reid_lib::TerminatorKind::Ret(add))
.unwrap()
}
}
Ok(())
pub trait IntrinsicFunction: std::fmt::Debug {
fn codegen<'ctx, 'a>(
&self,
scope: &mut Scope<'ctx, 'a>,
params: &[InstructionValue],
) -> Result<StackValue, ErrorKind>;
}
#[derive(Debug, Clone)]
pub struct IntrinsicIAdd(TypeKind);
impl IntrinsicFunction for IntrinsicIAdd {
fn codegen<'ctx, 'a>(
&self,
scope: &mut Scope<'ctx, 'a>,
params: &[InstructionValue],
) -> Result<StackValue, ErrorKind> {
let lhs = params.get(0).unwrap();
let rhs = params.get(1).unwrap();
let add = scope.block.build(Instr::Add(*lhs, *rhs)).unwrap();
Ok(StackValue(StackValueKind::Literal(add), self.0.clone()))
}
}

View File

@ -5,7 +5,7 @@
use std::{collections::HashMap, path::PathBuf};
use crate::{
intrinsics::InstrinsicKind,
intrinsics::IntrinsicFunction,
lexer::{FullToken, Position},
token_stream::TokenRange,
};
@ -303,7 +303,7 @@ pub enum FunctionDefinitionKind {
/// True = imported from other module, False = Is user defined extern
Extern(bool),
/// Intrinsic definition, defined within the compiler
Intrinsic(InstrinsicKind),
Intrinsic(Box<dyn IntrinsicFunction>),
}
impl FunctionDefinition {