From 537167fe4feb8cd123bf9a161e41864bb33198a7 Mon Sep 17 00:00:00 2001 From: sofia Date: Sun, 27 Jul 2025 19:55:28 +0300 Subject: [PATCH] Add intrinsic associated functions --- examples/associated_functions.reid | 1 + reid/src/codegen/intrinsics.rs | 71 ++++-- reid/src/codegen/mod.rs | 291 +++++++++++++----------- reid/src/codegen/scope.rs | 55 +++-- reid/src/mir/pass.rs | 20 +- reid/src/mir/typecheck/typecheck.rs | 4 +- reid/src/mir/typecheck/typeinference.rs | 3 +- 7 files changed, 267 insertions(+), 178 deletions(-) diff --git a/examples/associated_functions.reid b/examples/associated_functions.reid index 46c3274..cc5c95d 100644 --- a/examples/associated_functions.reid +++ b/examples/associated_functions.reid @@ -22,6 +22,7 @@ fn main() -> u32 { let otus = Otus { field: 17 }; print(from_str("otus: ") + Otus::test(&otus) as u64); print(from_str("i32: ") + i32::test(54) as u64); + print(from_str("sizeof i32: ") + i32::sizeof()); return Otus::test(&otus); } diff --git a/reid/src/codegen/intrinsics.rs b/reid/src/codegen/intrinsics.rs index 9da734c..3bca6ff 100644 --- a/reid/src/codegen/intrinsics.rs +++ b/reid/src/codegen/intrinsics.rs @@ -36,6 +36,20 @@ pub fn form_intrinsics() -> Vec { intrinsics } +pub fn get_intrinsic_assoc_func(ty: &TypeKind, name: &str) -> Option { + match name { + "sizeof" => Some(FunctionDefinition { + name: "sizeof".to_owned(), + is_pub: true, + is_imported: false, + return_type: TypeKind::U64, + parameters: Vec::new(), + kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSizeOf(ty.clone()))), + }), + _ => None, + } +} + fn simple_binop_def(op: BinaryOperator, ty: &TypeKind, fun: T) -> BinopDefinition where T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue, @@ -167,28 +181,33 @@ pub fn form_intrinsic_binops() -> Vec { } pub trait IntrinsicFunction: std::fmt::Debug { - fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[&StackValue]) -> Result; + fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[StackValue]) -> Result; +} + +macro_rules! intrinsic_debug { + ($kind:ty, $name:literal) => { + impl std::fmt::Debug for $kind + where + T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue, + { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_tuple($name).finish() + } + } + }; } #[derive(Clone)] pub struct IntrinsicSimpleInstr(T) where T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue; - -impl std::fmt::Debug for IntrinsicSimpleInstr -where - T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_tuple("IntrinsicSimpleInstr").finish() - } -} +intrinsic_debug!(IntrinsicSimpleInstr, "IntrinsicSimpleInstr"); impl IntrinsicFunction for IntrinsicSimpleInstr where T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue, { - fn codegen<'b, 'c>(&self, scope: &mut Scope<'b, 'c>, params: &[&StackValue]) -> Result { + fn codegen<'b, 'c>(&self, scope: &mut Scope<'b, 'c>, params: &[StackValue]) -> Result { let lhs = params.get(0).unwrap(); let rhs = params.get(1).unwrap(); let instr = self.clone().0(scope, lhs.instr(), rhs.instr()); @@ -200,21 +219,13 @@ where pub struct IntrinsicBooleanInstr(T) where T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue; - -impl std::fmt::Debug for IntrinsicBooleanInstr -where - T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_tuple("IntrinsicBooleanInstr").finish() - } -} +intrinsic_debug!(IntrinsicBooleanInstr, "IntrinsicBooleanInstr"); impl IntrinsicFunction for IntrinsicBooleanInstr where T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue, { - fn codegen<'b, 'c>(&self, scope: &mut Scope<'b, 'c>, params: &[&StackValue]) -> Result { + fn codegen<'b, 'c>(&self, scope: &mut Scope<'b, 'c>, params: &[StackValue]) -> Result { let lhs = params.get(0).unwrap(); let rhs = params.get(1).unwrap(); let instr = self.clone().0(scope, lhs.instr(), rhs.instr()); @@ -222,6 +233,24 @@ where } } +#[derive(Clone)] +pub struct IntrinsicSizeOf(TypeKind); +impl std::fmt::Debug for IntrinsicSizeOf { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("IntrinsicSizeOf").finish() + } +} + +impl IntrinsicFunction for IntrinsicSizeOf { + fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, _: &[StackValue]) -> Result { + let instr = scope + .block + .build(Instr::Constant(reid_lib::ConstValue::U64(self.0.size_of()))) + .unwrap(); + Ok(StackValue(StackValueKind::Literal(instr), self.0.clone())) + } +} + // impl IntrinsicFunction for IntrinsicIAdd { // fn codegen<'ctx, 'a>( // &self, diff --git a/reid/src/codegen/mod.rs b/reid/src/codegen/mod.rs index 99cbc35..27afe75 100644 --- a/reid/src/codegen/mod.rs +++ b/reid/src/codegen/mod.rs @@ -211,7 +211,7 @@ impl mir::Module { }; if let Some(func) = func { - functions.insert(function.name.clone(), func); + functions.insert(function.name.clone(), ScopeFunctionKind::UserGenerated(func)); } } @@ -251,7 +251,10 @@ impl mir::Module { }; if let Some(func) = func { - associated_functions.insert(AssociatedFunctionKey(ty.clone(), function.name.clone()), func); + associated_functions.insert( + AssociatedFunctionKey(ty.clone(), function.name.clone()), + ScopeFunctionKind::UserGenerated(func), + ); } } @@ -332,22 +335,20 @@ impl mir::Module { ) .unwrap(); - StackBinopFunctionKind::UserGenerated(ir_function) - } - FunctionDefinitionKind::Extern(imported) => { - StackBinopFunctionKind::UserGenerated(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 { - is_extern: true, - is_imported: *imported, - ..FunctionFlags::default() - }, - )) + ScopeFunctionKind::UserGenerated(ir_function) } + FunctionDefinitionKind::Extern(imported) => ScopeFunctionKind::UserGenerated(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 { + is_extern: true, + is_imported: *imported, + ..FunctionFlags::default() + }, + )), FunctionDefinitionKind::Intrinsic(intrinsic_function) => { - StackBinopFunctionKind::Intrinsic(intrinsic_function) + ScopeFunctionKind::Intrinsic(intrinsic_function) } }, }, @@ -355,111 +356,118 @@ impl mir::Module { } for mir_function in &self.functions { - let function = functions.get(&mir_function.name).unwrap(); - let mut entry = function.block("entry"); + if let ScopeFunctionKind::UserGenerated(function) = functions.get(&mir_function.name).unwrap() { + let mut entry = function.block("entry"); - let allocator = Allocator::from( - &mir_function.kind, - &mir_function.parameters, - &mut AllocatorScope { - block: &mut entry, - type_values: &type_values, - }, - ); - - let mut scope = Scope { - context, - modules: &modules, - tokens, - module: &module, - module_id: self.module_id, - function, - block: entry, - assoc_functions: &associated_functions, - 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)), - }; - - mir_function - .kind - .codegen( - mir_function.name.clone(), - mir_function.is_pub, - &mut scope, + let allocator = Allocator::from( + &mir_function.kind, &mir_function.parameters, - &mir_function.return_type, - &function, - match &mir_function.kind { - FunctionDefinitionKind::Local(..) => mir_function.signature().into_debug(tokens, compile_unit), - FunctionDefinitionKind::Extern(_) => None, - FunctionDefinitionKind::Intrinsic(_) => None, + &mut AllocatorScope { + block: &mut entry, + type_values: &type_values, }, - ) - .unwrap(); + ); + + let mut scope = Scope { + context, + modules: &modules, + tokens, + module: &module, + module_id: self.module_id, + function, + block: entry, + assoc_functions: &associated_functions, + 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)), + }; + + mir_function + .kind + .codegen( + mir_function.name.clone(), + mir_function.is_pub, + &mut scope, + &mir_function.parameters, + &mir_function.return_type, + &function, + match &mir_function.kind { + FunctionDefinitionKind::Local(..) => { + mir_function.signature().into_debug(tokens, compile_unit) + } + FunctionDefinitionKind::Extern(_) => None, + FunctionDefinitionKind::Intrinsic(_) => None, + }, + ) + .unwrap(); + } } for (ty, mir_function) in &self.associated_functions { - let function = associated_functions + if let ScopeFunctionKind::UserGenerated(function) = associated_functions .get(&AssociatedFunctionKey(ty.clone(), mir_function.name.clone())) - .unwrap(); - let mut entry = function.block("entry"); + .unwrap() + { + let mut entry = function.block("entry"); - let allocator = Allocator::from( - &mir_function.kind, - &mir_function.parameters, - &mut AllocatorScope { - block: &mut entry, - type_values: &type_values, - }, - ); - - let mut scope = Scope { - context, - modules: &modules, - tokens, - module: &module, - module_id: self.module_id, - function, - block: entry, - assoc_functions: &associated_functions, - 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)), - }; - - mir_function - .kind - .codegen( - mir_function.name.clone(), - mir_function.is_pub, - &mut scope, + let allocator = Allocator::from( + &mir_function.kind, &mir_function.parameters, - &mir_function.return_type, - &function, - match &mir_function.kind { - FunctionDefinitionKind::Local(..) => mir_function.signature().into_debug(tokens, compile_unit), - FunctionDefinitionKind::Extern(_) => None, - FunctionDefinitionKind::Intrinsic(_) => None, + &mut AllocatorScope { + block: &mut entry, + type_values: &type_values, }, - ) - .unwrap(); + ); + + let mut scope = Scope { + context, + modules: &modules, + tokens, + module: &module, + module_id: self.module_id, + function, + block: entry, + assoc_functions: &associated_functions, + 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)), + }; + + mir_function + .kind + .codegen( + mir_function.name.clone(), + mir_function.is_pub, + &mut scope, + &mir_function.parameters, + &mir_function.return_type, + &function, + match &mir_function.kind { + FunctionDefinitionKind::Local(..) => { + mir_function.signature().into_debug(tokens, compile_unit) + } + FunctionDefinitionKind::Extern(_) => None, + FunctionDefinitionKind::Intrinsic(_) => None, + }, + ) + .unwrap(); + } } Ok(ModuleCodegen { module }) @@ -821,7 +829,7 @@ impl mir::Expression { }); if let Some(operation) = operation { - let a = operation.codegen(&lhs_val, &rhs_val, scope)?; + let a = operation.codegen(lhs_val.clone(), rhs_val.clone(), scope)?; Some(a) } else { let lhs_type = lhs_exp.return_type(&Default::default(), scope.module_id).unwrap().1; @@ -906,19 +914,19 @@ impl mir::Expression { .map(|v| v.unwrap()) .collect::>(); - let param_instrs = params.iter().map(|e| e.instr()).collect(); let callee = scope.functions.get(&call.name).expect("function not found!"); - let val = scope - .block - .build_named(call.name.clone(), Instr::FunctionCall(callee.value(), param_instrs)) - .unwrap(); - - if let Some(debug) = &scope.debug { - let location = call.meta.into_debug(scope.tokens, debug.scope).unwrap(); - let location_val = debug.info.location(&debug.scope, location); - val.with_location(&mut scope.block, location_val); - } + let val = callee.codegen( + &call.name, + params.as_slice(), + &call.return_type, + if let Some(debug) = &scope.debug { + call.meta.into_debug(scope.tokens, debug.scope) + } else { + None + }, + scope, + )?; let ptr = if ret_type_kind != TypeKind::Void { let ptr = scope @@ -927,7 +935,7 @@ impl mir::Expression { .unwrap(); scope .block - .build_named(format!("{}.store", call.name), Instr::Store(ptr, val)) + .build_named(format!("{}.store", call.name), Instr::Store(ptr, val.instr())) .unwrap(); Some(ptr) @@ -1332,31 +1340,38 @@ impl mir::Expression { .map(|v| v.unwrap()) .collect::>(); - let param_instrs = params.iter().map(|e| e.instr()).collect(); + let assoc_key = AssociatedFunctionKey(ty.clone(), call.name.clone()); + let intrinsic = get_intrinsic_assoc_func(&ty, &call.name); + let intrinsic_owned = intrinsic.map(|func_def| { + let FunctionDefinitionKind::Intrinsic(intrinsic) = func_def.kind else { + panic!(); + }; + ScopeFunctionKind::IntrinsicOwned(intrinsic) + }); let callee = scope .assoc_functions - .get(&AssociatedFunctionKey(ty.clone(), call.name.clone())) - .expect("function not found!"); + .get(&assoc_key) + .or(intrinsic_owned.as_ref()) + .expect(&format!("Function {} does not exist!", call_name)); - let val = scope - .block - .build_named(&call_name, Instr::FunctionCall(callee.value(), param_instrs)) + let location = if let Some(debug) = &scope.debug { + call.meta.into_debug(scope.tokens, debug.scope) + } else { + None + }; + + let val = callee + .codegen(&call_name, params.as_slice(), &call.return_type, location, scope) .unwrap(); - if let Some(debug) = &scope.debug { - let location = call.meta.into_debug(scope.tokens, debug.scope).unwrap(); - let location_val = debug.info.location(&debug.scope, location); - val.with_location(&mut scope.block, location_val); - } - let ptr = if ret_type_kind != TypeKind::Void { let ptr = scope .block - .build_named(&call_name, Instr::Alloca(ret_type.clone())) + .build_named(&call.name, Instr::Alloca(ret_type.clone())) .unwrap(); scope .block - .build_named(format!("{}.store", call_name), Instr::Store(ptr, val)) + .build_named(format!("{}.store", call_name), Instr::Store(ptr, val.instr())) .unwrap(); Some(ptr) diff --git a/reid/src/codegen/scope.rs b/reid/src/codegen/scope.rs index aa24cf7..d3a70c5 100644 --- a/reid/src/codegen/scope.rs +++ b/reid/src/codegen/scope.rs @@ -2,7 +2,7 @@ use std::{cell::RefCell, collections::HashMap, mem, rc::Rc}; use reid_lib::{ builder::{InstructionValue, TypeValue}, - debug_information::{DebugInformation, DebugProgramValue, DebugTypeValue}, + debug_information::{DebugInformation, DebugLocation, DebugProgramValue, DebugTypeValue}, Block, Context, Function, Instr, Module, }; @@ -26,8 +26,8 @@ pub struct Scope<'ctx, 'scope> { pub(super) block: Block<'ctx>, pub(super) types: &'scope HashMap, pub(super) type_values: &'scope HashMap, - pub(super) assoc_functions: &'scope HashMap>, - pub(super) functions: &'scope HashMap>, + pub(super) assoc_functions: &'scope HashMap>, + pub(super) functions: &'scope HashMap>, pub(super) binops: &'scope HashMap>, pub(super) stack_values: HashMap, pub(super) debug: Option>, @@ -131,19 +131,20 @@ impl StackValueKind { pub struct StackBinopDefinition<'ctx> { pub(super) parameters: ((String, TypeKind), (String, TypeKind)), pub(super) return_ty: TypeKind, - pub(super) kind: StackBinopFunctionKind<'ctx>, + pub(super) kind: ScopeFunctionKind<'ctx>, } -pub enum StackBinopFunctionKind<'ctx> { +pub enum ScopeFunctionKind<'ctx> { UserGenerated(Function<'ctx>), Intrinsic(&'ctx Box), + IntrinsicOwned(Box), } impl<'ctx> StackBinopDefinition<'ctx> { pub fn codegen<'a>( &self, - lhs: &StackValue, - rhs: &StackValue, + lhs: StackValue, + rhs: StackValue, scope: &mut Scope<'ctx, 'a>, ) -> Result { let (lhs, rhs) = if lhs.1 == self.parameters.0 .1 && rhs.1 == self.parameters.1 .1 { @@ -151,15 +152,43 @@ impl<'ctx> StackBinopDefinition<'ctx> { } else { (rhs, lhs) }; - match &self.kind { - StackBinopFunctionKind::UserGenerated(ir) => { - let instr = scope + let name = format!( + "binop.{}.{}.{}.call", + self.parameters.0 .1, self.parameters.1 .1, self.return_ty + ); + self.kind.codegen(&name, &[lhs, rhs], &self.return_ty, None, scope) + } +} + +impl<'ctx> ScopeFunctionKind<'ctx> { + pub fn codegen<'a>( + &self, + name: &str, + params: &[StackValue], + return_ty: &TypeKind, + location: Option, + scope: &mut Scope<'ctx, 'a>, + ) -> Result { + match self { + ScopeFunctionKind::UserGenerated(function) => { + let val = scope .block - .build(Instr::FunctionCall(ir.value(), vec![lhs.instr(), rhs.instr()])) + .build_named( + name, + Instr::FunctionCall(function.value(), params.iter().map(|p| p.instr()).collect()), + ) .unwrap(); - Ok(StackValue(StackValueKind::Immutable(instr), self.return_ty.clone())) + + if let Some(debug) = &scope.debug { + if let Some(location) = location { + let location_val = debug.info.location(&debug.scope, location); + val.with_location(&mut scope.block, location_val); + } + } + Ok(StackValue(StackValueKind::Immutable(val), return_ty.clone())) } - StackBinopFunctionKind::Intrinsic(fun) => fun.codegen(scope, &[&lhs, &rhs]), + ScopeFunctionKind::Intrinsic(fun) => fun.codegen(scope, params), + ScopeFunctionKind::IntrinsicOwned(fun) => fun.codegen(scope, params), } } } diff --git a/reid/src/mir/pass.rs b/reid/src/mir/pass.rs index 45e53a3..ef6a7ab 100644 --- a/reid/src/mir/pass.rs +++ b/reid/src/mir/pass.rs @@ -5,7 +5,7 @@ use std::collections::HashMap; use std::convert::Infallible; use std::error::Error as STDError; -use crate::codegen::intrinsics::form_intrinsic_binops; +use crate::codegen::intrinsics::{form_intrinsic_binops, get_intrinsic_assoc_func}; use crate::error_raporting::ReidError; use super::*; @@ -169,6 +169,24 @@ impl Scope { .find(|(key, def)| key.0 == typekey.0 && def.importer == Some(typekey.1)) .map(|(_, v)| v)) } + + pub fn get_associated_function(&mut self, key: &AssociatedFunctionKey) -> Option { + let func = self.associated_functions.get(key); + if let Some(func) = func { + Some(func.clone()) + } else if let Some(func) = get_intrinsic_assoc_func(&key.0, &key.1) { + self.associated_functions.set( + key.clone(), + ScopeFunction { + ret: func.return_type, + params: func.parameters.iter().map(|(_, p)| p.clone()).collect(), + }, + ); + self.associated_functions.get(key).cloned() + } else { + None + } + } } #[derive(Clone, Debug)] diff --git a/reid/src/mir/typecheck/typecheck.rs b/reid/src/mir/typecheck/typecheck.rs index 0478079..2c8aa3b 100644 --- a/reid/src/mir/typecheck/typecheck.rs +++ b/reid/src/mir/typecheck/typecheck.rs @@ -732,12 +732,10 @@ impl Expression { ExprKind::AssociatedFunctionCall(type_kind, function_call) => { let true_function = state .scope - .associated_functions - .get(&pass::AssociatedFunctionKey( + .get_associated_function(&pass::AssociatedFunctionKey( type_kind.clone(), function_call.name.clone(), )) - .cloned() .ok_or(ErrorKind::FunctionNotDefined(function_call.name.clone())); if let Some(f) = state.ok(true_function, self.1) { diff --git a/reid/src/mir/typecheck/typeinference.rs b/reid/src/mir/typecheck/typeinference.rs index d08dc33..a49862e 100644 --- a/reid/src/mir/typecheck/typeinference.rs +++ b/reid/src/mir/typecheck/typeinference.rs @@ -598,8 +598,7 @@ impl Expression { // Get function definition and types let fn_call = state .scope - .associated_functions - .get(&AssociatedFunctionKey(type_kind.clone(), function_call.name.clone())) + .get_associated_function(&AssociatedFunctionKey(type_kind.clone(), function_call.name.clone())) .ok_or(ErrorKind::AssocFunctionNotDefined( function_call.name.clone(), type_kind.clone(),