use reid_lib::{builder::InstructionValue, CmpPredicate, ConstValueKind, Instr, Type}; use crate::{ codegen::{ErrorKind, StackValueKind}, mir::{ implement::TypeCategory, BinaryOperator, BinopDefinition, CmpOperator, FunctionDefinition, FunctionDefinitionKind, FunctionParam, TypeKind, }, }; use super::scope::{Scope, StackValue}; const INTEGERS: [TypeKind; 10] = [ TypeKind::U8, TypeKind::U16, TypeKind::U32, TypeKind::U64, TypeKind::U128, TypeKind::I8, TypeKind::I16, TypeKind::I32, TypeKind::I64, TypeKind::I128, ]; const FLOATS: [TypeKind; 7] = [ TypeKind::F16, TypeKind::F32, TypeKind::F32B, TypeKind::F64, TypeKind::F80, TypeKind::F128, TypeKind::F128PPC, ]; #[derive(Debug, Clone, Hash, Eq, PartialEq)] pub enum LLVMIntrinsicKind { Max(TypeKind), Min(TypeKind), Abs(TypeKind), Memcpy(TypeKind), Sqrt(TypeKind), PowI(TypeKind, TypeKind), Pow(TypeKind), Sin(TypeKind), Cos(TypeKind), Tan(TypeKind), ASin(TypeKind), ACos(TypeKind), ATan(TypeKind), ATan2(TypeKind), SinH(TypeKind), CosH(TypeKind), TanH(TypeKind), Log(TypeKind), Log2(TypeKind), Log10(TypeKind), Copysign(TypeKind), Floor(TypeKind), Ceil(TypeKind), Trunc(TypeKind), RoundEven(TypeKind), Round(TypeKind), } const INTRINSIC_IDENT: &str = "reid.intrinsic"; const MALLOC_IDENT: &str = "malloc"; pub fn form_intrinsics() -> Vec { let mut intrinsics = Vec::new(); intrinsics.push(FunctionDefinition { name: MALLOC_IDENT.to_owned(), linkage_name: Some("malloc".to_owned()), is_pub: false, is_imported: true, return_type: TypeKind::UserPtr(Box::new(TypeKind::U8)), parameters: vec![FunctionParam { name: "size".to_owned(), ty: TypeKind::U64, meta: Default::default(), }], kind: FunctionDefinitionKind::Extern(false), source: None, signature_meta: Default::default(), }); intrinsics } pub fn simple_intrinsic + Clone>( name: T, params: Vec, ret: TypeKind, intrisic: LLVMIntrinsicKind, ) -> FunctionDefinition { FunctionDefinition { name: name.into(), linkage_name: None, is_pub: true, is_imported: false, return_type: ret.clone(), parameters: params .iter() .map(|p| FunctionParam::from(p.clone(), ret.clone())) .collect(), kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicLLVM(intrisic, ret.clone()))), source: None, signature_meta: Default::default(), } } pub fn get_intrinsic_assoc_functions(ty: &TypeKind) -> Vec { let mut intrinsics = Vec::new(); if let TypeKind::Array(_, len) = ty { intrinsics.push(FunctionDefinition { name: "length".to_owned(), linkage_name: None, is_pub: true, is_imported: false, return_type: TypeKind::Void, parameters: vec![FunctionParam { name: String::from("self"), ty: TypeKind::Borrow(Box::new(ty.clone()), false), meta: Default::default(), }], kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicConst(*len))), source: None, signature_meta: Default::default(), }); } if ty.category() == TypeCategory::Real { intrinsics.push(simple_intrinsic( "sin", vec!["self"], ty.clone(), LLVMIntrinsicKind::Sin(ty.clone()), )); intrinsics.push(simple_intrinsic( "cos", vec!["self"], ty.clone(), LLVMIntrinsicKind::Cos(ty.clone()), )); intrinsics.push(simple_intrinsic( "tan", vec!["self"], ty.clone(), LLVMIntrinsicKind::Tan(ty.clone()), )); intrinsics.push(simple_intrinsic( "sinh", vec!["self"], ty.clone(), LLVMIntrinsicKind::SinH(ty.clone()), )); intrinsics.push(simple_intrinsic( "cosh", vec!["self"], ty.clone(), LLVMIntrinsicKind::CosH(ty.clone()), )); intrinsics.push(simple_intrinsic( "tanh", vec!["self"], ty.clone(), LLVMIntrinsicKind::TanH(ty.clone()), )); intrinsics.push(simple_intrinsic( "asin", vec!["self"], ty.clone(), LLVMIntrinsicKind::ASin(ty.clone()), )); intrinsics.push(simple_intrinsic( "acos", vec!["self"], ty.clone(), LLVMIntrinsicKind::ACos(ty.clone()), )); intrinsics.push(simple_intrinsic( "atan", vec!["self"], ty.clone(), LLVMIntrinsicKind::ATan(ty.clone()), )); intrinsics.push(simple_intrinsic( "atan2", vec!["self", "other"], ty.clone(), LLVMIntrinsicKind::ATan2(ty.clone()), )); intrinsics.push(simple_intrinsic( "log", vec!["self"], ty.clone(), LLVMIntrinsicKind::Log(ty.clone()), )); intrinsics.push(simple_intrinsic( "log2", vec!["self"], ty.clone(), LLVMIntrinsicKind::Log2(ty.clone()), )); intrinsics.push(simple_intrinsic( "log10", vec!["self"], ty.clone(), LLVMIntrinsicKind::Log10(ty.clone()), )); intrinsics.push(simple_intrinsic( "floor", vec!["self"], ty.clone(), LLVMIntrinsicKind::Floor(ty.clone()), )); intrinsics.push(simple_intrinsic( "ceil", vec!["self"], ty.clone(), LLVMIntrinsicKind::Ceil(ty.clone()), )); intrinsics.push(simple_intrinsic( "trunc", vec!["self"], ty.clone(), LLVMIntrinsicKind::Trunc(ty.clone()), )); intrinsics.push(simple_intrinsic( "round", vec!["self"], ty.clone(), LLVMIntrinsicKind::Round(ty.clone()), )); intrinsics.push(simple_intrinsic( "even", vec!["self"], ty.clone(), LLVMIntrinsicKind::RoundEven(ty.clone()), )); intrinsics.push(simple_intrinsic( "pow", vec!["self", "exponent"], ty.clone(), LLVMIntrinsicKind::Pow(ty.clone()), )); intrinsics.push(FunctionDefinition { name: "powi".to_owned(), linkage_name: None, is_pub: true, is_imported: false, return_type: ty.clone(), parameters: vec![ FunctionParam { name: String::from("self"), ty: ty.clone(), meta: Default::default(), }, FunctionParam { name: String::from("exponent"), ty: TypeKind::U32, meta: Default::default(), }, ], kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicLLVM( LLVMIntrinsicKind::PowI(ty.clone(), TypeKind::U32), ty.clone(), ))), source: None, signature_meta: Default::default(), }); } match ty.category() { TypeCategory::Integer | TypeCategory::Real | TypeCategory::Bool => { intrinsics.push(simple_intrinsic( "max", vec!["self", "other"], ty.clone(), LLVMIntrinsicKind::Max(ty.clone()), )); intrinsics.push(simple_intrinsic( "min", vec!["self", "other"], ty.clone(), LLVMIntrinsicKind::Min(ty.clone()), )); if ty.signed() { intrinsics.push(FunctionDefinition { name: "abs".to_owned(), linkage_name: None, is_pub: true, is_imported: false, return_type: ty.clone(), parameters: vec![FunctionParam { name: String::from("self"), ty: ty.clone(), meta: Default::default(), }], kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleUnaryInstr({ let ty = ty.clone(); |scope, param| { let intrinsic = scope.get_intrinsic(LLVMIntrinsicKind::Abs(ty)); let constant = scope.block.build(Instr::Constant(ConstValueKind::Bool(false))).unwrap(); let value = scope .block .build(Instr::FunctionCall(intrinsic, vec![param, constant])) .unwrap(); value } }))), source: None, signature_meta: Default::default(), }); } } _ => {} } intrinsics.push(FunctionDefinition { name: "sizeof".to_owned(), linkage_name: None, is_pub: true, is_imported: false, return_type: TypeKind::U64, parameters: Vec::new(), kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSizeOf(ty.clone()))), source: None, signature_meta: Default::default(), }); intrinsics.push(FunctionDefinition { name: "malloc".to_owned(), linkage_name: None, is_pub: true, is_imported: false, return_type: TypeKind::UserPtr(Box::new(ty.clone())), parameters: vec![FunctionParam { name: String::from("size"), ty: TypeKind::U64, meta: Default::default(), }], kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicMalloc(ty.clone()))), source: None, signature_meta: Default::default(), }); intrinsics.push(FunctionDefinition { name: "memcpy".to_owned(), linkage_name: None, is_pub: true, is_imported: false, return_type: TypeKind::Void, parameters: vec![ FunctionParam { name: String::from("destination"), ty: TypeKind::UserPtr(Box::new(ty.clone())), meta: Default::default(), }, FunctionParam { name: String::from("source"), ty: TypeKind::UserPtr(Box::new(ty.clone())), meta: Default::default(), }, FunctionParam { name: String::from("length"), ty: TypeKind::U64, meta: Default::default(), }, ], kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicMemcpy(ty.clone()))), source: None, signature_meta: Default::default(), }); intrinsics.push(FunctionDefinition { name: "null".to_owned(), linkage_name: None, is_pub: true, is_imported: false, return_type: TypeKind::UserPtr(Box::new(ty.clone())), parameters: Vec::new(), kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicNullPtr(ty.clone()))), source: None, signature_meta: Default::default(), }); intrinsics } pub fn get_intrinsic_assoc_func(ty: &TypeKind, name: &str) -> Option { get_intrinsic_assoc_functions(ty).into_iter().find(|f| f.name == name) } fn simple_binop_def(op: BinaryOperator, ty: &TypeKind, fun: T) -> BinopDefinition where T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue, { BinopDefinition { lhs: FunctionParam { name: "lhs".to_owned(), ty: ty.clone(), meta: Default::default(), }, op, rhs: FunctionParam { name: "rhs".to_owned(), ty: ty.clone(), meta: Default::default(), }, return_type: ty.clone(), fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleBinaryInstr(fun))), meta: Default::default(), exported: false, } } fn complex_binop_def(op: BinaryOperator, lhs: &TypeKind, rhs: &TypeKind, fun: T) -> BinopDefinition where T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue, { BinopDefinition { lhs: FunctionParam { name: "lhs".to_owned(), ty: lhs.clone(), meta: Default::default(), }, op, rhs: FunctionParam { name: "rhs".to_owned(), ty: rhs.clone(), meta: Default::default(), }, return_type: lhs.clone(), fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleBinaryInstr(fun))), meta: Default::default(), exported: false, } } fn boolean_binop_def(op: BinaryOperator, ty: &TypeKind, fun: T) -> BinopDefinition where T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue, { BinopDefinition { lhs: FunctionParam { name: "lhs".to_owned(), ty: ty.clone(), meta: Default::default(), }, op, rhs: FunctionParam { name: "rhs".to_owned(), ty: ty.clone(), meta: Default::default(), }, return_type: TypeKind::Bool, fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicBooleanInstr(fun))), meta: Default::default(), exported: false, } } pub fn form_intrinsic_binops() -> Vec { let mut intrinsics = Vec::new(); use BinaryOperator::*; for ty in INTEGERS { intrinsics.push(simple_binop_def(Add, &ty, |scope, lhs, rhs| { scope.block.build(Instr::Add(lhs, rhs)).unwrap() })); intrinsics.push(simple_binop_def(Mult, &ty, |scope, lhs, rhs| { scope.block.build(Instr::Mul(lhs, rhs)).unwrap() })); intrinsics.push(simple_binop_def(Minus, &ty, |scope, lhs, rhs| { scope.block.build(Instr::Sub(lhs, rhs)).unwrap() })); if ty.signed() { intrinsics.push(simple_binop_def(Div, &ty, |scope, lhs, rhs| { scope.block.build(Instr::SDiv(lhs, rhs)).unwrap() })); intrinsics.push(simple_binop_def(Mod, &ty, |scope, lhs, rhs| { let div = scope.block.build(Instr::SDiv(lhs, rhs)).unwrap(); let mul = scope.block.build(Instr::Mul(rhs, div)).unwrap(); scope.block.build(Instr::Sub(lhs, mul)).unwrap() })); } else { intrinsics.push(simple_binop_def(Div, &ty, |scope, lhs, rhs| { scope.block.build(Instr::UDiv(lhs, rhs)).unwrap() })); intrinsics.push(simple_binop_def(Mod, &ty, |scope, lhs, rhs| { let div = scope.block.build(Instr::UDiv(lhs, rhs)).unwrap(); let mul = scope.block.build(Instr::Mul(rhs, div)).unwrap(); scope.block.build(Instr::Sub(lhs, mul)).unwrap() })); } intrinsics.push(boolean_binop_def(Cmp(CmpOperator::GT), &ty, |scope, lhs, rhs| { scope.block.build(Instr::ICmp(CmpPredicate::GT, lhs, rhs)).unwrap() })); intrinsics.push(boolean_binop_def(Cmp(CmpOperator::GE), &ty, |scope, lhs, rhs| { scope.block.build(Instr::ICmp(CmpPredicate::GE, lhs, rhs)).unwrap() })); intrinsics.push(boolean_binop_def(Cmp(CmpOperator::LT), &ty, |scope, lhs, rhs| { scope.block.build(Instr::ICmp(CmpPredicate::LT, lhs, rhs)).unwrap() })); intrinsics.push(boolean_binop_def(Cmp(CmpOperator::LE), &ty, |scope, lhs, rhs| { scope.block.build(Instr::ICmp(CmpPredicate::LE, lhs, rhs)).unwrap() })); // Bitwise operations intrinsics.push(simple_binop_def(BitOr, &ty, |scope, lhs, rhs| { scope.block.build(Instr::Or(lhs, rhs)).unwrap() })); intrinsics.push(simple_binop_def(BitAnd, &ty, |scope, lhs, rhs| { scope.block.build(Instr::And(lhs, rhs)).unwrap() })); intrinsics.push(complex_binop_def(Xor, &ty, &TypeKind::U64, |scope, lhs, rhs| { scope.block.build(Instr::XOr(lhs, rhs)).unwrap() })); if ty.signed() { intrinsics.push(complex_binop_def(BitshiftRight, &ty, &ty, |scope, lhs, rhs| { scope.block.build(Instr::ShiftRightArithmetic(lhs, rhs)).unwrap() })); } else { intrinsics.push(complex_binop_def(BitshiftRight, &ty, &ty, |scope, lhs, rhs| { scope.block.build(Instr::ShiftRightLogical(lhs, rhs)).unwrap() })); } intrinsics.push(complex_binop_def(BitshiftLeft, &ty, &ty, |scope, lhs, rhs| { scope.block.build(Instr::ShiftLeft(lhs, rhs)).unwrap() })); } for ty in INTEGERS.iter().chain(&[TypeKind::Bool, TypeKind::Char]) { intrinsics.push(boolean_binop_def(Cmp(CmpOperator::EQ), &ty, |scope, lhs, rhs| { scope.block.build(Instr::ICmp(CmpPredicate::EQ, lhs, rhs)).unwrap() })); intrinsics.push(boolean_binop_def(Cmp(CmpOperator::NE), &ty, |scope, lhs, rhs| { scope.block.build(Instr::ICmp(CmpPredicate::NE, lhs, rhs)).unwrap() })); } for ty in FLOATS { intrinsics.push(simple_binop_def(BinaryOperator::Add, &ty, |scope, lhs, rhs| { scope.block.build(Instr::FAdd(lhs, rhs)).unwrap() })); intrinsics.push(simple_binop_def(BinaryOperator::Mult, &ty, |scope, lhs, rhs| { scope.block.build(Instr::FMul(lhs, rhs)).unwrap() })); intrinsics.push(simple_binop_def(BinaryOperator::Minus, &ty, |scope, lhs, rhs| { scope.block.build(Instr::FSub(lhs, rhs)).unwrap() })); intrinsics.push(simple_binop_def(Div, &ty, |scope, lhs, rhs| { scope.block.build(Instr::FDiv(lhs, rhs)).unwrap() })); intrinsics.push(simple_binop_def(Mod, &ty, |scope, lhs, rhs| { let div = scope.block.build(Instr::FDiv(lhs, rhs)).unwrap(); let mul = scope.block.build(Instr::Mul(rhs, div)).unwrap(); scope.block.build(Instr::Sub(lhs, mul)).unwrap() })); intrinsics.push(boolean_binop_def(Cmp(CmpOperator::EQ), &ty, |scope, lhs, rhs| { scope.block.build(Instr::FCmp(CmpPredicate::EQ, lhs, rhs)).unwrap() })); intrinsics.push(boolean_binop_def(Cmp(CmpOperator::NE), &ty, |scope, lhs, rhs| { scope.block.build(Instr::FCmp(CmpPredicate::NE, lhs, rhs)).unwrap() })); intrinsics.push(boolean_binop_def(Cmp(CmpOperator::GT), &ty, |scope, lhs, rhs| { scope.block.build(Instr::FCmp(CmpPredicate::GT, lhs, rhs)).unwrap() })); intrinsics.push(boolean_binop_def(Cmp(CmpOperator::GE), &ty, |scope, lhs, rhs| { scope.block.build(Instr::FCmp(CmpPredicate::GE, lhs, rhs)).unwrap() })); intrinsics.push(boolean_binop_def(Cmp(CmpOperator::LT), &ty, |scope, lhs, rhs| { scope.block.build(Instr::FCmp(CmpPredicate::LT, lhs, rhs)).unwrap() })); intrinsics.push(boolean_binop_def(Cmp(CmpOperator::LE), &ty, |scope, lhs, rhs| { scope.block.build(Instr::FCmp(CmpPredicate::LE, lhs, rhs)).unwrap() })); } intrinsics.push(boolean_binop_def(And, &TypeKind::Bool, |scope, lhs, rhs| { scope.block.build(Instr::And(lhs, rhs)).unwrap() })); intrinsics.push(boolean_binop_def(Or, &TypeKind::Bool, |scope, lhs, rhs| { scope.block.build(Instr::Or(lhs, rhs)).unwrap() })); intrinsics.push(boolean_binop_def(Xor, &TypeKind::Bool, |scope, lhs, rhs| { scope.block.build(Instr::XOr(lhs, rhs)).unwrap() })); intrinsics } pub trait IntrinsicFunction: std::fmt::Debug { 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 IntrinsicSimpleUnaryInstr(T) where T: FnOnce(&mut Scope, InstructionValue) -> InstructionValue; impl std::fmt::Debug for IntrinsicSimpleUnaryInstr where T: FnOnce(&mut Scope, InstructionValue) -> InstructionValue, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("IntrinsicSimpleUnaryInstr").finish() } } impl IntrinsicFunction for IntrinsicSimpleUnaryInstr where T: FnOnce(&mut Scope, InstructionValue) -> InstructionValue, { fn codegen<'b, 'c>(&self, scope: &mut Scope<'b, 'c>, params: &[StackValue]) -> Result { let param = params.get(0).unwrap(); let instr = self.clone().0(scope, param.instr()); Ok(StackValue(StackValueKind::Literal(instr), param.1.clone())) } } #[derive(Clone)] pub struct IntrinsicSimpleBinaryInstr(T) where T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue; intrinsic_debug!(IntrinsicSimpleBinaryInstr, "IntrinsicSimpleBinaryInstr"); impl IntrinsicFunction for IntrinsicSimpleBinaryInstr where T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue, { 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()); Ok(StackValue(StackValueKind::Literal(instr), lhs.1.clone())) } } #[derive(Clone)] pub struct IntrinsicBooleanInstr(T) where T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue; 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 { let lhs = params.get(0).unwrap(); let rhs = params.get(1).unwrap(); let instr = self.clone().0(scope, lhs.instr(), rhs.instr()); Ok(StackValue(StackValueKind::Literal(instr), TypeKind::Bool)) } } #[derive(Clone, Debug)] pub struct IntrinsicSizeOf(TypeKind); 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::ConstValueKind::U64( self.0.size_of(&scope.type_map) / 8, ))) .unwrap(); Ok(StackValue(StackValueKind::Literal(instr), self.0.clone())) } } #[derive(Clone, Debug)] pub struct IntrinsicMemcpy(TypeKind); impl IntrinsicFunction for IntrinsicMemcpy { fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[StackValue]) -> Result { let dest = params.get(0).unwrap(); let src = params.get(1).unwrap(); let length = params.get(2).unwrap(); let intrinsic = scope.get_intrinsic(LLVMIntrinsicKind::Memcpy(TypeKind::UserPtr(Box::new(self.0.clone())))); let sizeof = scope .block .build(Instr::Constant(ConstValueKind::U64( self.0.size_of(&scope.type_map) / 8, ))) .unwrap(); let bytes = scope.block.build(Instr::Mul(sizeof, length.instr())).unwrap(); dbg!(self.0.size_of(&scope.type_map) / 8); let params = vec![ dest.instr(), src.instr(), bytes, scope.block.build(Instr::Constant(ConstValueKind::Bool(false))).unwrap(), ]; let value = scope.block.build(Instr::FunctionCall(intrinsic, params)).unwrap(); Ok(StackValue(StackValueKind::Literal(value), TypeKind::Void)) } } #[derive(Clone, Debug)] pub struct IntrinsicMalloc(TypeKind); impl IntrinsicFunction for IntrinsicMalloc { fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[StackValue]) -> Result { let amount = params.get(0).unwrap(); let function = scope .block .find_function(&format!("{}.{}", INTRINSIC_IDENT, MALLOC_IDENT)) .unwrap(); let sizeof = scope .block .build(Instr::Constant(ConstValueKind::U64( self.0.size_of(&scope.type_map) / 8, ))) .unwrap(); let bytes = scope.block.build(Instr::Mul(sizeof, amount.instr())).unwrap(); let instr = scope.block.build(Instr::FunctionCall(function, vec![bytes])).unwrap(); Ok(StackValue(StackValueKind::Literal(instr), self.0.clone())) } } #[derive(Clone, Debug)] pub struct IntrinsicNullPtr(TypeKind); impl IntrinsicFunction for IntrinsicNullPtr { fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, _: &[StackValue]) -> Result { let zero = scope.block.build(Instr::Constant(ConstValueKind::I8(0))).unwrap(); let instr = scope .block .build(Instr::IntToPtr( zero, Type::Ptr(Box::new(self.0.get_type(scope.type_values))), )) .unwrap(); Ok(StackValue( StackValueKind::Literal(instr), TypeKind::UserPtr(Box::new(self.0.clone())), )) } } #[derive(Clone, Debug)] pub struct IntrinsicConst(u64); impl IntrinsicFunction for IntrinsicConst { fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, _: &[StackValue]) -> Result { let zero = scope.block.build(Instr::Constant(ConstValueKind::U64(self.0))).unwrap(); Ok(StackValue(StackValueKind::Literal(zero), TypeKind::U64)) } } #[derive(Clone, Debug)] pub struct IntrinsicLLVM(LLVMIntrinsicKind, TypeKind); impl IntrinsicFunction for IntrinsicLLVM { fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[StackValue]) -> Result { let intrinsic = scope.get_intrinsic(self.0.clone()); let value = scope .block .build(Instr::FunctionCall( intrinsic, params.iter().map(|p| p.instr()).collect(), )) .unwrap(); Ok(StackValue(StackValueKind::Literal(value), self.1.clone())) } } // impl IntrinsicFunction for IntrinsicIAdd { // fn codegen<'ctx, 'a>( // &self, // scope: &mut Scope<'ctx, 'a>, // params: &[InstructionValue], // ) -> Result { // 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())) // } // } // #[derive(Debug, Clone)] // pub struct IntrinsicIAdd(TypeKind); // impl IntrinsicFunction for IntrinsicIAdd { // fn codegen<'ctx, 'a>( // &self, // scope: &mut Scope<'ctx, 'a>, // params: &[InstructionValue], // ) -> Result { // 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())) // } // } // #[derive(Debug, Clone)] // pub struct IntrinsicUDiv(TypeKind); // impl IntrinsicFunction for IntrinsicUDiv { // fn codegen<'ctx, 'a>( // &self, // scope: &mut Scope<'ctx, 'a>, // params: &[InstructionValue], // ) -> Result { // let lhs = params.get(0).unwrap(); // let rhs = params.get(1).unwrap(); // let add = scope.block.build(Instr::UDiv(*lhs, *rhs)).unwrap(); // Ok(StackValue(StackValueKind::Literal(add), self.0.clone())) // } // } // #[derive(Debug, Clone)] // pub struct IntrinsicUMod(TypeKind); // impl IntrinsicFunction for IntrinsicUMod { // fn codegen<'ctx, 'a>( // &self, // scope: &mut Scope<'ctx, 'a>, // params: &[InstructionValue], // ) -> Result { // let lhs = params.get(0).unwrap(); // let rhs = params.get(1).unwrap(); // let div = scope.block.build(Instr::UDiv(*lhs, *rhs)).unwrap(); // let mul = scope.block.build(Instr::Mul(*rhs, div)).unwrap(); // let sub = scope.block.build(Instr::Sub(*lhs, mul)).unwrap(); // Ok(StackValue(StackValueKind::Literal(sub), self.0.clone())) // } // }