Add intrinsic min/max to integers and floats
This commit is contained in:
		
							parent
							
								
									4a33e7d123
								
							
						
					
					
						commit
						5d19d38682
					
				
							
								
								
									
										5
									
								
								examples/math_intrinsics.reid
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								examples/math_intrinsics.reid
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| 
 | ||||
| fn main() -> i32 { | ||||
|     let b = 5; | ||||
|     return b.min(7); | ||||
| } | ||||
| @ -6,7 +6,7 @@ use std::{ | ||||
| }; | ||||
| 
 | ||||
| use crate::{ | ||||
|     CmpPredicate, Context, Instr, InstructionData, TerminatorKind, | ||||
|     CmpPredicate, Context, Instr, InstructionData, TerminatorKind, Type, | ||||
|     builder::*, | ||||
|     debug_information::{ | ||||
|         DebugArrayType, DebugBasicType, DebugFieldType, DebugInformation, DebugLocalVariable, DebugLocation, | ||||
|  | ||||
							
								
								
									
										69
									
								
								reid-llvm-lib/src/intrinsics.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								reid-llvm-lib/src/intrinsics.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,69 @@ | ||||
| use crate::{CompileResult, Type, builder::Builder}; | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub enum LLVMIntrinsic { | ||||
|     Max(Type), | ||||
|     Min(Type), | ||||
| } | ||||
| 
 | ||||
| impl LLVMIntrinsic { | ||||
|     pub fn check(&self, builder: &Builder) -> CompileResult<()> { | ||||
|         self.signature(builder)?; | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     pub fn signature(&self, builder: &Builder) -> CompileResult<(String, Vec<Type>, Type)> { | ||||
|         match self { | ||||
|             LLVMIntrinsic::Max(ty) => { | ||||
|                 let name = match ty.category() { | ||||
|                     crate::TypeCategory::SignedInteger => format!("llvm.smax.{}", ty.llvm_ty_str(builder)), | ||||
|                     crate::TypeCategory::UnsignedInteger => format!("llvm.umax.{}", ty.llvm_ty_str(builder)), | ||||
|                     crate::TypeCategory::Real => format!("llvm.max.{}", ty.llvm_ty_str(builder)), | ||||
|                     _ => return Err(crate::ErrorKind::Null), | ||||
|                 }; | ||||
|                 Ok((name, vec![ty.clone(), ty.clone()], ty.clone())) | ||||
|             } | ||||
|             LLVMIntrinsic::Min(ty) => { | ||||
|                 let name = match ty.category() { | ||||
|                     crate::TypeCategory::SignedInteger => format!("llvm.smin.{}", ty.llvm_ty_str(builder)), | ||||
|                     crate::TypeCategory::UnsignedInteger => format!("llvm.umin.{}", ty.llvm_ty_str(builder)), | ||||
|                     crate::TypeCategory::Real => format!("llvm.min.{}", ty.llvm_ty_str(builder)), | ||||
|                     _ => return Err(crate::ErrorKind::Null), | ||||
|                 }; | ||||
|                 Ok((name, vec![ty.clone(), ty.clone()], ty.clone())) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Type { | ||||
|     fn llvm_ty_str(&self, builder: &Builder) -> String { | ||||
|         match self { | ||||
|             Type::I8 => String::from("i8"), | ||||
|             Type::I16 => String::from("u16"), | ||||
|             Type::I32 => String::from("i32"), | ||||
|             Type::I64 => String::from("i64"), | ||||
|             Type::I128 => String::from("i128"), | ||||
|             Type::U8 => String::from("i8"), | ||||
|             Type::U16 => String::from("i16"), | ||||
|             Type::U32 => String::from("i32"), | ||||
|             Type::U64 => String::from("i64"), | ||||
|             Type::U128 => String::from("i128"), | ||||
|             Type::F16 => String::from("half"), | ||||
|             Type::F32B => String::from("bfloat"), | ||||
|             Type::F32 => String::from("float"), | ||||
|             Type::F64 => String::from("double"), | ||||
|             Type::F80 => String::from("x86_fp80"), | ||||
|             Type::F128 => String::from("fp128"), | ||||
|             Type::F128PPC => String::from("ppc_fp128"), | ||||
|             Type::Bool => String::from("i1"), | ||||
|             Type::Void => String::from("void"), | ||||
|             Type::CustomType(type_value) => { | ||||
|                 let ty = unsafe { builder.type_data(type_value) }; | ||||
|                 ty.name.clone() | ||||
|             } | ||||
|             Type::Array(ty, len) => format!("[{} x {}]", len, ty.llvm_ty_str(builder)), | ||||
|             Type::Ptr(_) => String::from("ptr"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -11,12 +11,14 @@ use fmt::PrintableModule; | ||||
| use crate::{ | ||||
|     builder::{ConstantValue, GlobalValue}, | ||||
|     debug_information::DebugScopeValue, | ||||
|     intrinsics::LLVMIntrinsic, | ||||
| }; | ||||
| 
 | ||||
| pub mod builder; | ||||
| pub mod compile; | ||||
| pub mod debug_information; | ||||
| mod fmt; | ||||
| pub mod intrinsics; | ||||
| mod pad_adapter; | ||||
| mod util; | ||||
| 
 | ||||
| @ -95,6 +97,25 @@ impl<'ctx> Module<'ctx> { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn intrinsic(&self, intrinsic: LLVMIntrinsic) -> CompileResult<FunctionValue> { | ||||
|         unsafe { | ||||
|             let (name, params, ret) = intrinsic.signature(&self.builder)?; | ||||
|             Ok(self.builder.add_function( | ||||
|                 &self.value, | ||||
|                 FunctionData { | ||||
|                     name: name.to_owned(), | ||||
|                     linkage_name: Some(name.to_owned()), | ||||
|                     ret, | ||||
|                     params, | ||||
|                     flags: FunctionFlags { | ||||
|                         is_extern: true, | ||||
|                         ..Default::default() | ||||
|                     }, | ||||
|                 }, | ||||
|             )) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn custom_type(&self, ty: CustomTypeKind) -> TypeValue { | ||||
|         unsafe { | ||||
|             let (name, kind) = match &ty { | ||||
|  | ||||
| @ -1021,9 +1021,8 @@ pub fn analyze_expr( | ||||
|             function_autocomplete.extend( | ||||
|                 get_intrinsic_assoc_functions(&invoked_ty) | ||||
|                     .iter() | ||||
|                     .filter_map(|(s, f)| f.as_ref().map(|f| (s, f))) | ||||
|                     .filter(|(_, fun)| fun.name.starts_with(name)) | ||||
|                     .map(|(_, fun)| Autocomplete { | ||||
|                     .filter(|fun| fun.name.starts_with(name)) | ||||
|                     .map(|fun| Autocomplete { | ||||
|                         text: fun.name.clone(), | ||||
|                         kind: AutocompleteKind::Function(fun.parameters.clone(), fun.return_type.clone()), | ||||
|                     }) | ||||
|  | ||||
| @ -1,12 +1,10 @@ | ||||
| use std::{collections::HashMap, hash::Hash}; | ||||
| 
 | ||||
| use reid_lib::{builder::InstructionValue, CmpPredicate, ConstValueKind, Instr, Type}; | ||||
| 
 | ||||
| use crate::{ | ||||
|     codegen::{ErrorKind, StackValueKind}, | ||||
|     codegen::{scope::IntrinsicKind, ErrorKind, StackValueKind}, | ||||
|     mir::{ | ||||
|         BinaryOperator, BinopDefinition, CmpOperator, FunctionDefinition, FunctionDefinitionKind, FunctionParam, | ||||
|         TypeKind, | ||||
|         implement::TypeCategory, BinaryOperator, BinopDefinition, CmpOperator, FunctionDefinition, | ||||
|         FunctionDefinitionKind, FunctionParam, TypeKind, | ||||
|     }, | ||||
| }; | ||||
| 
 | ||||
| @ -60,79 +58,108 @@ pub fn form_intrinsics() -> Vec<FunctionDefinition> { | ||||
|     intrinsics | ||||
| } | ||||
| 
 | ||||
| pub fn get_intrinsic_assoc_functions(ty: &TypeKind) -> HashMap<String, Option<FunctionDefinition>> { | ||||
|     let mut map = HashMap::new(); | ||||
|     map.insert("length".to_owned(), get_intrinsic_assoc_func(ty, "length")); | ||||
|     map.insert("sizeof".to_owned(), get_intrinsic_assoc_func(ty, "sizeof")); | ||||
|     map.insert("malloc".to_owned(), get_intrinsic_assoc_func(ty, "malloc")); | ||||
|     map.insert("null".to_owned(), get_intrinsic_assoc_func(ty, "null")); | ||||
|     map | ||||
| } | ||||
| 
 | ||||
| pub fn get_intrinsic_assoc_func(ty: &TypeKind, name: &str) -> Option<FunctionDefinition> { | ||||
| pub fn get_intrinsic_assoc_functions(ty: &TypeKind) -> Vec<FunctionDefinition> { | ||||
|     let mut intrinsics = Vec::new(); | ||||
|     if let TypeKind::Array(_, len) = ty { | ||||
|         match name { | ||||
|             "length" => { | ||||
|                 return Some(FunctionDefinition { | ||||
|                     name: "length".to_owned(), | ||||
|                     linkage_name: None, | ||||
|                     is_pub: true, | ||||
|                     is_imported: false, | ||||
|                     return_type: TypeKind::U64, | ||||
|                     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(), | ||||
|                 }); | ||||
|             } | ||||
|             _ => {} | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     match name { | ||||
|         "sizeof" => Some(FunctionDefinition { | ||||
|             name: "sizeof".to_owned(), | ||||
|         intrinsics.push(FunctionDefinition { | ||||
|             name: "length".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(), | ||||
|         }), | ||||
|         "malloc" => Some(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, | ||||
|                 name: String::from("self"), | ||||
|                 ty: TypeKind::Borrow(Box::new(ty.clone()), false), | ||||
|                 meta: Default::default(), | ||||
|             }], | ||||
|             kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicMalloc(ty.clone()))), | ||||
|             kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicConst(*len))), | ||||
|             source: None, | ||||
|             signature_meta: Default::default(), | ||||
|         }), | ||||
|         "null" => Some(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(), | ||||
|         }), | ||||
|         _ => None, | ||||
|         }); | ||||
|     } | ||||
|     match ty.category() { | ||||
|         TypeCategory::Integer | TypeCategory::Real | TypeCategory::Bool => { | ||||
|             intrinsics.push(FunctionDefinition { | ||||
|                 name: "max".to_owned(), | ||||
|                 linkage_name: None, | ||||
|                 is_pub: true, | ||||
|                 is_imported: false, | ||||
|                 return_type: ty.clone(), | ||||
|                 parameters: vec![ | ||||
|                     FunctionParam::from("self", ty.clone()), | ||||
|                     FunctionParam::from("other", ty.clone()), | ||||
|                 ], | ||||
|                 kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicLLVM( | ||||
|                     IntrinsicKind::Max(ty.clone()), | ||||
|                     ty.clone(), | ||||
|                 ))), | ||||
|                 source: None, | ||||
|                 signature_meta: Default::default(), | ||||
|             }); | ||||
|             intrinsics.push(FunctionDefinition { | ||||
|                 name: "min".to_owned(), | ||||
|                 linkage_name: None, | ||||
|                 is_pub: true, | ||||
|                 is_imported: false, | ||||
|                 return_type: ty.clone(), | ||||
|                 parameters: vec![ | ||||
|                     FunctionParam::from("self", ty.clone()), | ||||
|                     FunctionParam::from("other", ty.clone()), | ||||
|                 ], | ||||
|                 kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicLLVM( | ||||
|                     IntrinsicKind::Min(ty.clone()), | ||||
|                     ty.clone(), | ||||
|                 ))), | ||||
|                 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: "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<FunctionDefinition> { | ||||
|     get_intrinsic_assoc_functions(ty).into_iter().find(|f| f.name == name) | ||||
| } | ||||
| 
 | ||||
| fn simple_binop_def<T: Clone + 'static>(op: BinaryOperator, ty: &TypeKind, fun: T) -> BinopDefinition | ||||
| @ -441,6 +468,7 @@ impl IntrinsicFunction for IntrinsicNullPtr { | ||||
|         )) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub struct IntrinsicConst(u64); | ||||
| impl IntrinsicFunction for IntrinsicConst { | ||||
| @ -450,6 +478,23 @@ impl IntrinsicFunction for IntrinsicConst { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub struct IntrinsicLLVM(IntrinsicKind, TypeKind); | ||||
| impl IntrinsicFunction for IntrinsicLLVM { | ||||
|     fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[StackValue]) -> Result<StackValue, ErrorKind> { | ||||
|         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)) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // impl IntrinsicFunction for IntrinsicIAdd {
 | ||||
| //     fn codegen<'ctx, 'a>(
 | ||||
| //         &self,
 | ||||
|  | ||||
| @ -393,6 +393,7 @@ impl mir::Module { | ||||
|                                 }), | ||||
|                                 binops: &binops, | ||||
|                                 allocator: Rc::new(RefCell::new(allocator)), | ||||
|                                 llvm_intrinsics: Rc::new(RefCell::new(HashMap::new())), | ||||
|                             }; | ||||
| 
 | ||||
|                             binop | ||||
| @ -471,6 +472,7 @@ impl mir::Module { | ||||
|                     globals: &globals, | ||||
|                     binops: &binops, | ||||
|                     allocator: Rc::new(RefCell::new(allocator)), | ||||
|                     llvm_intrinsics: Rc::new(RefCell::new(HashMap::new())), | ||||
|                 }; | ||||
| 
 | ||||
|                 mir_function | ||||
| @ -533,6 +535,7 @@ impl mir::Module { | ||||
|                     globals: &globals, | ||||
|                     binops: &binops, | ||||
|                     allocator: Rc::new(RefCell::new(allocator)), | ||||
|                     llvm_intrinsics: Rc::new(RefCell::new(HashMap::new())), | ||||
|                 }; | ||||
| 
 | ||||
|                 mir_function | ||||
|  | ||||
| @ -1,8 +1,9 @@ | ||||
| use std::{cell::RefCell, collections::HashMap, mem, rc::Rc}; | ||||
| 
 | ||||
| use reid_lib::{ | ||||
|     builder::{GlobalValue, InstructionValue, TypeValue}, | ||||
|     builder::{FunctionValue, GlobalValue, InstructionValue, TypeValue}, | ||||
|     debug_information::{DebugInformation, DebugLocation, DebugScopeValue, DebugTypeValue}, | ||||
|     intrinsics::LLVMIntrinsic, | ||||
|     Block, Context, Function, Instr, Module, | ||||
| }; | ||||
| 
 | ||||
| @ -16,6 +17,12 @@ use crate::{ | ||||
| 
 | ||||
| use super::{allocator::Allocator, ErrorKind, IntrinsicFunction, ModuleCodegen}; | ||||
| 
 | ||||
| #[derive(Debug, Clone, Hash, Eq, PartialEq)] | ||||
| pub enum IntrinsicKind { | ||||
|     Max(TypeKind), | ||||
|     Min(TypeKind), | ||||
| } | ||||
| 
 | ||||
| pub struct Scope<'ctx, 'scope> { | ||||
|     pub(super) context: &'ctx Context, | ||||
|     pub(super) modules: &'scope HashMap<SourceModuleId, ModuleCodegen<'ctx>>, | ||||
| @ -34,6 +41,7 @@ pub struct Scope<'ctx, 'scope> { | ||||
|     pub(super) globals: &'scope HashMap<String, GlobalValue>, | ||||
|     pub(super) debug: Option<Debug<'ctx>>, | ||||
|     pub(super) allocator: Rc<RefCell<Allocator>>, | ||||
|     pub(super) llvm_intrinsics: Rc<RefCell<HashMap<IntrinsicKind, FunctionValue>>>, | ||||
| } | ||||
| 
 | ||||
| impl<'ctx, 'a> Scope<'ctx, 'a> { | ||||
| @ -56,6 +64,7 @@ impl<'ctx, 'a> Scope<'ctx, 'a> { | ||||
|             allocator: self.allocator.clone(), | ||||
|             globals: self.globals, | ||||
|             binops: self.binops, | ||||
|             llvm_intrinsics: self.llvm_intrinsics.clone(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -74,6 +83,23 @@ impl<'ctx, 'a> Scope<'ctx, 'a> { | ||||
|     pub fn allocate(&self, meta: &Metadata, ty: &TypeKind) -> Option<InstructionValue> { | ||||
|         self.allocator.borrow_mut().allocate(meta, ty) | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_intrinsic(&self, kind: IntrinsicKind) -> FunctionValue { | ||||
|         let mut intrinsics = self.llvm_intrinsics.borrow_mut(); | ||||
|         if let Some(fun) = intrinsics.get(&kind) { | ||||
|             *fun | ||||
|         } else { | ||||
|             let intrinsic = self | ||||
|                 .module | ||||
|                 .intrinsic(match &kind { | ||||
|                     IntrinsicKind::Max(ty) => LLVMIntrinsic::Max(ty.get_type(self.type_values)), | ||||
|                     IntrinsicKind::Min(ty) => LLVMIntrinsic::Min(ty.get_type(self.type_values)), | ||||
|                 }) | ||||
|                 .unwrap(); | ||||
|             intrinsics.insert(kind, intrinsic.clone()); | ||||
|             intrinsic | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
|  | ||||
| @ -315,6 +315,16 @@ pub struct FunctionParam { | ||||
|     pub meta: Metadata, | ||||
| } | ||||
| 
 | ||||
| impl FunctionParam { | ||||
|     pub fn from<T: Into<String>>(name: T, ty: TypeKind) -> FunctionParam { | ||||
|         FunctionParam { | ||||
|             name: name.into(), | ||||
|             ty: ty, | ||||
|             meta: Default::default(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub enum SelfKind { | ||||
|     Borrow, | ||||
|     MutBorrow, | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user