Refactor stuff into codegen-module
This commit is contained in:
		
							parent
							
								
									d79d396814
								
							
						
					
					
						commit
						6ee43d4012
					
				| @ -7,6 +7,6 @@ edition = "2024" | ||||
| 
 | ||||
| [dependencies] | ||||
| ## LLVM Bindings | ||||
| llvm-sys = {version ="201.0.1", features=["force-static"] } | ||||
| llvm-sys = {version ="201.0.1", features=["prefer-dynamic"] } | ||||
| ## Make it easier to generate errors | ||||
| thiserror = "1.0.44" | ||||
| @ -1,10 +1,12 @@ | ||||
| use reid_lib::{builder::InstructionValue, Instr}; | ||||
| 
 | ||||
| use crate::{ | ||||
|     codegen::{ErrorKind, Scope, StackValue, StackValueKind}, | ||||
|     codegen::{ErrorKind, StackValueKind}, | ||||
|     mir::{BinopDefinition, FunctionDefinition, TypeKind}, | ||||
| }; | ||||
| 
 | ||||
| use super::scope::{Scope, StackValue}; | ||||
| 
 | ||||
| pub fn form_intrinsics() -> Vec<FunctionDefinition> { | ||||
|     let intrinsics = Vec::new(); | ||||
| 
 | ||||
| @ -1,31 +1,33 @@ | ||||
| use std::{cell::RefCell, collections::HashMap, mem, rc::Rc}; | ||||
| use std::{cell::RefCell, collections::HashMap, rc::Rc}; | ||||
| 
 | ||||
| use allocator::{Allocator, AllocatorScope}; | ||||
| use intrinsics::*; | ||||
| use reid_lib::{ | ||||
|     builder::{InstructionValue, TypeValue}, | ||||
|     compile::CompiledModule, | ||||
|     debug_information::{ | ||||
|         DebugArrayType, DebugBasicType, DebugFieldType, DebugFileData, DebugInformation, | ||||
|         DebugLocalVariable, DebugLocation, DebugMetadata, DebugPointerType, DebugPosition, | ||||
|         DebugProgramValue, DebugRecordKind, DebugStructType, DebugSubprogramData, | ||||
|         DebugSubprogramOptionals, DebugSubprogramType, DebugTypeData, DebugTypeValue, | ||||
|         DwarfEncoding, DwarfFlags, InstructionDebugRecordData, | ||||
|         DebugFileData, DebugLocalVariable, DebugLocation, DebugMetadata, DebugRecordKind, | ||||
|         DebugSubprogramData, DebugSubprogramOptionals, DebugSubprogramType, DebugTypeData, | ||||
|         DwarfFlags, InstructionDebugRecordData, | ||||
|     }, | ||||
|     Block, CmpPredicate, ConstValue, Context, CustomTypeKind, Function, FunctionFlags, Instr, | ||||
|     Module, NamedStruct, TerminatorKind as Term, Type, | ||||
|     CmpPredicate, ConstValue, Context, CustomTypeKind, Function, FunctionFlags, Instr, Module, | ||||
|     NamedStruct, TerminatorKind as Term, Type, | ||||
| }; | ||||
| use scope::*; | ||||
| 
 | ||||
| use crate::{ | ||||
|     allocator::{Allocator, AllocatorScope}, | ||||
|     intrinsics::IntrinsicFunction, | ||||
|     lexer::{FullToken, Position}, | ||||
|     mir::{ | ||||
|         self, implement::TypeCategory, pass::ScopeBinopKey, CustomTypeKey, FunctionDefinitionKind, | ||||
|         Metadata, NamedVariableRef, SourceModuleId, StructField, StructType, TypeDefinition, | ||||
|         TypeDefinitionKind, TypeKind, VagueLiteral, WhileStatement, | ||||
|         NamedVariableRef, SourceModuleId, StructField, StructType, TypeDefinitionKind, TypeKind, | ||||
|         WhileStatement, | ||||
|     }, | ||||
|     util::try_all, | ||||
| }; | ||||
| 
 | ||||
| mod allocator; | ||||
| pub mod intrinsics; | ||||
| pub(super) mod scope; | ||||
| pub(super) mod util; | ||||
| 
 | ||||
| #[derive(thiserror::Error, Debug, Clone, PartialEq, PartialOrd)] | ||||
| pub enum ErrorKind { | ||||
|     #[error("NULL error, should never occur!")] | ||||
| @ -73,160 +75,6 @@ impl<'ctx> std::fmt::Debug for ModuleCodegen<'ctx> { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct Scope<'ctx, 'scope> { | ||||
|     context: &'ctx Context, | ||||
|     modules: &'scope HashMap<SourceModuleId, ModuleCodegen<'ctx>>, | ||||
|     tokens: &'ctx Vec<FullToken>, | ||||
|     module: &'ctx Module<'ctx>, | ||||
|     module_id: SourceModuleId, | ||||
|     function: &'ctx Function<'ctx>, | ||||
|     pub(super) block: Block<'ctx>, | ||||
|     types: &'scope HashMap<TypeValue, TypeDefinition>, | ||||
|     type_values: &'scope HashMap<CustomTypeKey, TypeValue>, | ||||
|     functions: &'scope HashMap<String, Function<'ctx>>, | ||||
|     binops: &'scope HashMap<ScopeBinopKey, StackBinopDefinition<'ctx>>, | ||||
|     stack_values: HashMap<String, StackValue>, | ||||
|     debug: Option<Debug<'ctx>>, | ||||
|     allocator: Rc<RefCell<Allocator>>, | ||||
| } | ||||
| 
 | ||||
| impl<'ctx, 'a> Scope<'ctx, 'a> { | ||||
|     fn with_block(&self, block: Block<'ctx>) -> Scope<'ctx, 'a> { | ||||
|         Scope { | ||||
|             block, | ||||
|             modules: self.modules, | ||||
|             tokens: self.tokens, | ||||
|             function: self.function, | ||||
|             context: self.context, | ||||
|             module: self.module, | ||||
|             module_id: self.module_id, | ||||
|             functions: self.functions, | ||||
|             types: self.types, | ||||
|             type_values: self.type_values, | ||||
|             stack_values: self.stack_values.clone(), | ||||
|             debug: self.debug.clone(), | ||||
|             allocator: self.allocator.clone(), | ||||
|             binops: self.binops, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Takes the block out from this scope, swaps the given block in it's place
 | ||||
|     /// and returns the old block.
 | ||||
|     fn swap_block(&mut self, block: Block<'ctx>) -> Block<'ctx> { | ||||
|         let mut old_block = block; | ||||
|         mem::swap(&mut self.block, &mut old_block); | ||||
|         old_block | ||||
|     } | ||||
| 
 | ||||
|     fn get_typedef(&self, key: &CustomTypeKey) -> Option<&TypeDefinition> { | ||||
|         self.type_values.get(key).and_then(|v| self.types.get(v)) | ||||
|     } | ||||
| 
 | ||||
|     fn allocate(&self, name: &String, ty: &TypeKind) -> Option<InstructionValue> { | ||||
|         self.allocator.borrow_mut().allocate(name, ty) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct Debug<'ctx> { | ||||
|     info: &'ctx DebugInformation, | ||||
|     scope: DebugProgramValue, | ||||
|     types: &'ctx HashMap<TypeKind, DebugTypeValue>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||
| pub struct StackValue(pub(super) StackValueKind, pub(super) TypeKind); | ||||
| 
 | ||||
| impl StackValue { | ||||
|     fn instr(&self) -> InstructionValue { | ||||
|         self.0.instr() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||||
| pub enum StackValueKind { | ||||
|     Immutable(InstructionValue), | ||||
|     Mutable(InstructionValue), | ||||
|     Literal(InstructionValue), | ||||
| } | ||||
| 
 | ||||
| impl StackValueKind { | ||||
|     fn mutable(mutable: bool, instr: InstructionValue) -> StackValueKind { | ||||
|         match mutable { | ||||
|             true => StackValueKind::Mutable(instr), | ||||
|             false => StackValueKind::Immutable(instr), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn instr(&self) -> InstructionValue { | ||||
|         match &self { | ||||
|             StackValueKind::Immutable(val) => *val, | ||||
|             StackValueKind::Mutable(val) => *val, | ||||
|             StackValueKind::Literal(val) => *val, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn derive(&self, instr: InstructionValue) -> StackValueKind { | ||||
|         match &self { | ||||
|             StackValueKind::Immutable(_) => StackValueKind::Immutable(instr), | ||||
|             StackValueKind::Mutable(_) => StackValueKind::Mutable(instr), | ||||
|             StackValueKind::Literal(_) => StackValueKind::Literal(instr), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     #[allow(dead_code)] | ||||
|     fn map<F>(&self, lambda: F) -> StackValueKind | ||||
|     where | ||||
|         F: FnOnce(InstructionValue) -> InstructionValue, | ||||
|     { | ||||
|         self.derive(lambda(self.instr())) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct StackBinopDefinition<'ctx> { | ||||
|     parameters: ((String, TypeKind), (String, TypeKind)), | ||||
|     return_ty: TypeKind, | ||||
|     kind: StackBinopFunctionKind<'ctx>, | ||||
| } | ||||
| 
 | ||||
| pub enum StackBinopFunctionKind<'ctx> { | ||||
|     UserGenerated(Function<'ctx>), | ||||
|     Intrinsic(&'ctx Box<dyn IntrinsicFunction>), | ||||
| } | ||||
| 
 | ||||
| impl<'ctx> StackBinopDefinition<'ctx> { | ||||
|     fn codegen<'a>( | ||||
|         &self, | ||||
|         lhs: &StackValue, | ||||
|         rhs: &StackValue, | ||||
|         scope: &mut Scope<'ctx, 'a>, | ||||
|     ) -> Result<StackValue, ErrorKind> { | ||||
|         let (lhs, rhs) = if lhs.1 == self.parameters.0 .1 && rhs.1 == self.parameters.1 .1 { | ||||
|             (lhs, rhs) | ||||
|         } else { | ||||
|             (rhs, lhs) | ||||
|         }; | ||||
|         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()]) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] | ||||
| struct State { | ||||
|     should_load: bool, | ||||
| @ -1567,262 +1415,3 @@ impl mir::IfExpression { | ||||
|         } | ||||
|     } | ||||
| } | ||||
| impl mir::CmpOperator { | ||||
|     fn predicate(&self) -> CmpPredicate { | ||||
|         match self { | ||||
|             mir::CmpOperator::LT => CmpPredicate::LT, | ||||
|             mir::CmpOperator::GT => CmpPredicate::GT, | ||||
|             mir::CmpOperator::LE => CmpPredicate::LE, | ||||
|             mir::CmpOperator::GE => CmpPredicate::GE, | ||||
|             mir::CmpOperator::EQ => CmpPredicate::EQ, | ||||
|             mir::CmpOperator::NE => CmpPredicate::NE, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl mir::Literal { | ||||
|     fn as_const(&self, block: &mut Block) -> InstructionValue { | ||||
|         block | ||||
|             .build_named(format!("{}", self), self.as_const_kind()) | ||||
|             .unwrap() | ||||
|     } | ||||
| 
 | ||||
|     fn as_const_kind(&self) -> Instr { | ||||
|         Instr::Constant(match self.clone() { | ||||
|             mir::Literal::I8(val) => ConstValue::I8(val), | ||||
|             mir::Literal::I16(val) => ConstValue::I16(val), | ||||
|             mir::Literal::I32(val) => ConstValue::I32(val), | ||||
|             mir::Literal::I64(val) => ConstValue::I64(val), | ||||
|             mir::Literal::I128(val) => ConstValue::I128(val), | ||||
|             mir::Literal::U8(val) => ConstValue::U8(val), | ||||
|             mir::Literal::U16(val) => ConstValue::U16(val), | ||||
|             mir::Literal::U32(val) => ConstValue::U32(val), | ||||
|             mir::Literal::U64(val) => ConstValue::U64(val), | ||||
|             mir::Literal::U128(val) => ConstValue::U128(val), | ||||
|             mir::Literal::Bool(val) => ConstValue::Bool(val), | ||||
|             mir::Literal::String(val) => ConstValue::Str(val.clone()), | ||||
|             mir::Literal::Vague(VagueLiteral::Number(val)) => ConstValue::I32(val as i32), | ||||
|             mir::Literal::Vague(VagueLiteral::Decimal(val)) => ConstValue::F32(val as f32), | ||||
|             mir::Literal::F16(val) => ConstValue::F16(val), | ||||
|             mir::Literal::F32B(val) => ConstValue::F32B(val), | ||||
|             mir::Literal::F32(val) => ConstValue::F32(val), | ||||
|             mir::Literal::F64(val) => ConstValue::F64(val), | ||||
|             mir::Literal::F80(val) => ConstValue::F80(val), | ||||
|             mir::Literal::F128(val) => ConstValue::F128(val), | ||||
|             mir::Literal::F128PPC(val) => ConstValue::F128PPC(val), | ||||
|             mir::Literal::Char(c) => ConstValue::U8(c as u8), | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl TypeKind { | ||||
|     pub(super) fn get_type(&self, type_vals: &HashMap<CustomTypeKey, TypeValue>) -> Type { | ||||
|         match &self { | ||||
|             TypeKind::I8 => Type::I8, | ||||
|             TypeKind::I16 => Type::I16, | ||||
|             TypeKind::I32 => Type::I32, | ||||
|             TypeKind::I64 => Type::I64, | ||||
|             TypeKind::I128 => Type::I128, | ||||
|             TypeKind::U8 => Type::U8, | ||||
|             TypeKind::U16 => Type::U16, | ||||
|             TypeKind::U32 => Type::U32, | ||||
|             TypeKind::U64 => Type::U64, | ||||
|             TypeKind::U128 => Type::U128, | ||||
|             TypeKind::Bool => Type::Bool, | ||||
|             TypeKind::F16 => Type::F16, | ||||
|             TypeKind::F32B => Type::F32B, | ||||
|             TypeKind::F32 => Type::F32, | ||||
|             TypeKind::F64 => Type::F64, | ||||
|             TypeKind::F128 => Type::F128, | ||||
|             TypeKind::F80 => Type::F80, | ||||
|             TypeKind::F128PPC => Type::F128PPC, | ||||
|             TypeKind::Char => Type::U8, | ||||
|             TypeKind::Array(elem_t, len) => Type::Array(Box::new(elem_t.get_type(type_vals)), *len), | ||||
|             TypeKind::Void => Type::Void, | ||||
|             TypeKind::Vague(_) => panic!("Tried to compile a vague type!"), | ||||
|             TypeKind::CustomType(n) => { | ||||
|                 let type_val = type_vals.get(n).unwrap().clone(); | ||||
|                 Type::CustomType(type_val) | ||||
|             } | ||||
|             TypeKind::UserPtr(type_kind) => Type::Ptr(Box::new(type_kind.get_type(type_vals))), | ||||
|             TypeKind::CodegenPtr(type_kind) => Type::Ptr(Box::new(type_kind.get_type(type_vals))), | ||||
|             TypeKind::Borrow(type_kind, _) => Type::Ptr(Box::new(type_kind.get_type(type_vals))), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl TypeKind { | ||||
|     fn get_debug_type(&self, debug: &Debug, scope: &Scope) -> DebugTypeValue { | ||||
|         self.get_debug_type_hard( | ||||
|             debug.scope, | ||||
|             debug.info, | ||||
|             debug.types, | ||||
|             scope.type_values, | ||||
|             scope.types, | ||||
|             scope.module_id, | ||||
|             scope.tokens, | ||||
|             scope.modules, | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     fn get_debug_type_hard( | ||||
|         &self, | ||||
|         scope: DebugProgramValue, | ||||
|         debug_info: &DebugInformation, | ||||
|         debug_types: &HashMap<TypeKind, DebugTypeValue>, | ||||
|         type_values: &HashMap<CustomTypeKey, TypeValue>, | ||||
|         types: &HashMap<TypeValue, TypeDefinition>, | ||||
|         local_mod: SourceModuleId, | ||||
|         tokens: &Vec<FullToken>, | ||||
|         modules: &HashMap<SourceModuleId, ModuleCodegen>, | ||||
|     ) -> DebugTypeValue { | ||||
|         if let Some(ty) = debug_types.get(self) { | ||||
|             return *ty; | ||||
|         } | ||||
| 
 | ||||
|         let name = format!("{}", self); | ||||
| 
 | ||||
|         let data = match self { | ||||
|             TypeKind::CodegenPtr(inner) | TypeKind::UserPtr(inner) | TypeKind::Borrow(inner, _) => { | ||||
|                 DebugTypeData::Pointer(DebugPointerType { | ||||
|                     name, | ||||
|                     pointee: inner.get_debug_type_hard( | ||||
|                         scope, | ||||
|                         debug_info, | ||||
|                         debug_types, | ||||
|                         type_values, | ||||
|                         types, | ||||
|                         local_mod, | ||||
|                         tokens, | ||||
|                         modules, | ||||
|                     ), | ||||
|                     size_bits: self.size_of(), | ||||
|                 }) | ||||
|             } | ||||
|             TypeKind::Array(elem_ty, len) => { | ||||
|                 let elem_ty = elem_ty.clone().get_debug_type_hard( | ||||
|                     scope, | ||||
|                     debug_info, | ||||
|                     debug_types, | ||||
|                     type_values, | ||||
|                     types, | ||||
|                     local_mod, | ||||
|                     tokens, | ||||
|                     modules, | ||||
|                 ); | ||||
|                 DebugTypeData::Array(DebugArrayType { | ||||
|                     size_bits: self.size_of(), | ||||
|                     align_bits: self.alignment(), | ||||
|                     element_type: elem_ty, | ||||
|                     length: *len, | ||||
|                 }) | ||||
|             } | ||||
|             TypeKind::CustomType(key) => { | ||||
|                 let typedef = types.get(type_values.get(key).unwrap()).unwrap(); | ||||
|                 match &typedef.kind { | ||||
|                     TypeDefinitionKind::Struct(struct_type) => { | ||||
|                         let mut fields = Vec::new(); | ||||
|                         let mut size_bits = 0; | ||||
| 
 | ||||
|                         for field in &struct_type.0 { | ||||
|                             let location = if typedef.source_module != local_mod { | ||||
|                                 None | ||||
|                             } else { | ||||
|                                 field.2.into_debug(&tokens, scope) | ||||
|                             }; | ||||
|                             fields.push(DebugFieldType { | ||||
|                                 name: field.0.clone(), | ||||
|                                 scope, | ||||
|                                 pos: location.map(|l| l.pos), | ||||
|                                 size_bits: field.1.size_of(), | ||||
|                                 offset: size_bits, | ||||
|                                 flags: DwarfFlags, | ||||
|                                 ty: field.1.get_debug_type_hard( | ||||
|                                     scope, | ||||
|                                     debug_info, | ||||
|                                     debug_types, | ||||
|                                     type_values, | ||||
|                                     types, | ||||
|                                     local_mod, | ||||
|                                     tokens, | ||||
|                                     modules, | ||||
|                                 ), | ||||
|                             }); | ||||
|                             size_bits += field.1.size_of(); | ||||
|                         } | ||||
|                         { | ||||
|                             let location = if typedef.source_module != local_mod { | ||||
|                                 None | ||||
|                             } else { | ||||
|                                 typedef.meta.into_debug(&tokens, scope) | ||||
|                             }; | ||||
|                             DebugTypeData::Struct(DebugStructType { | ||||
|                                 name: key.0.clone(), | ||||
|                                 scope, | ||||
|                                 pos: location.map(|l| l.pos), | ||||
|                                 size_bits, | ||||
|                                 flags: DwarfFlags, | ||||
|                                 fields, | ||||
|                             }) | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             _ => DebugTypeData::Basic(DebugBasicType { | ||||
|                 name, | ||||
|                 size_bits: self.size_of(), | ||||
|                 encoding: match self { | ||||
|                     TypeKind::Bool => DwarfEncoding::Boolean, | ||||
|                     TypeKind::I8 => DwarfEncoding::SignedChar, | ||||
|                     TypeKind::U8 => DwarfEncoding::UnsignedChar, | ||||
|                     TypeKind::I16 | TypeKind::I32 | TypeKind::I64 | TypeKind::I128 => { | ||||
|                         DwarfEncoding::Signed | ||||
|                     } | ||||
|                     TypeKind::U16 | TypeKind::U32 | TypeKind::U64 | TypeKind::U128 => { | ||||
|                         DwarfEncoding::Unsigned | ||||
|                     } | ||||
|                     TypeKind::F16 | ||||
|                     | TypeKind::F32 | ||||
|                     | TypeKind::F32B | ||||
|                     | TypeKind::F64 | ||||
|                     | TypeKind::F80 | ||||
|                     | TypeKind::F128 | ||||
|                     | TypeKind::F128PPC => DwarfEncoding::Float, | ||||
|                     TypeKind::Void => DwarfEncoding::Address, | ||||
|                     TypeKind::Char => DwarfEncoding::UnsignedChar, | ||||
|                     TypeKind::Array(_, _) => DwarfEncoding::Address, | ||||
|                     TypeKind::CustomType(_) => DwarfEncoding::Address, | ||||
|                     _ => panic!("tried fetching debug-type for non-supported type!"), | ||||
|                 }, | ||||
|                 flags: DwarfFlags, | ||||
|             }), | ||||
|         }; | ||||
|         debug_info.debug_type(data) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Metadata { | ||||
|     pub fn into_debug( | ||||
|         &self, | ||||
|         tokens: &Vec<FullToken>, | ||||
|         scope: DebugProgramValue, | ||||
|     ) -> Option<DebugLocation> { | ||||
|         if let Some((start, _)) = self.into_positions(tokens) { | ||||
|             Some(start.debug(scope)) | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Position { | ||||
|     fn debug(self, scope: DebugProgramValue) -> DebugLocation { | ||||
|         DebugLocation { | ||||
|             pos: DebugPosition { | ||||
|                 line: self.1, | ||||
|                 column: self.0, | ||||
|             }, | ||||
|             scope, | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										168
									
								
								reid/src/codegen/scope.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								reid/src/codegen/scope.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,168 @@ | ||||
| use std::{cell::RefCell, collections::HashMap, mem, rc::Rc}; | ||||
| 
 | ||||
| use reid_lib::{ | ||||
|     builder::{InstructionValue, TypeValue}, | ||||
|     debug_information::{DebugInformation, DebugProgramValue, DebugTypeValue}, | ||||
|     Block, Context, Function, Instr, Module, | ||||
| }; | ||||
| 
 | ||||
| use crate::{ | ||||
|     lexer::FullToken, | ||||
|     mir::{pass::ScopeBinopKey, CustomTypeKey, SourceModuleId, TypeDefinition, TypeKind}, | ||||
| }; | ||||
| 
 | ||||
| use super::{allocator::Allocator, ErrorKind, IntrinsicFunction, ModuleCodegen}; | ||||
| 
 | ||||
| pub struct Scope<'ctx, 'scope> { | ||||
|     pub(super) context: &'ctx Context, | ||||
|     pub(super) modules: &'scope HashMap<SourceModuleId, ModuleCodegen<'ctx>>, | ||||
|     pub(super) tokens: &'ctx Vec<FullToken>, | ||||
|     pub(super) module: &'ctx Module<'ctx>, | ||||
|     pub(super) module_id: SourceModuleId, | ||||
|     pub(super) function: &'ctx Function<'ctx>, | ||||
|     pub(super) block: Block<'ctx>, | ||||
|     pub(super) types: &'scope HashMap<TypeValue, TypeDefinition>, | ||||
|     pub(super) type_values: &'scope HashMap<CustomTypeKey, TypeValue>, | ||||
|     pub(super) functions: &'scope HashMap<String, Function<'ctx>>, | ||||
|     pub(super) binops: &'scope HashMap<ScopeBinopKey, StackBinopDefinition<'ctx>>, | ||||
|     pub(super) stack_values: HashMap<String, StackValue>, | ||||
|     pub(super) debug: Option<Debug<'ctx>>, | ||||
|     pub(super) allocator: Rc<RefCell<Allocator>>, | ||||
| } | ||||
| 
 | ||||
| impl<'ctx, 'a> Scope<'ctx, 'a> { | ||||
|     pub fn with_block(&self, block: Block<'ctx>) -> Scope<'ctx, 'a> { | ||||
|         Scope { | ||||
|             block, | ||||
|             modules: self.modules, | ||||
|             tokens: self.tokens, | ||||
|             function: self.function, | ||||
|             context: self.context, | ||||
|             module: self.module, | ||||
|             module_id: self.module_id, | ||||
|             functions: self.functions, | ||||
|             types: self.types, | ||||
|             type_values: self.type_values, | ||||
|             stack_values: self.stack_values.clone(), | ||||
|             debug: self.debug.clone(), | ||||
|             allocator: self.allocator.clone(), | ||||
|             binops: self.binops, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Takes the block out from this scope, swaps the given block in it's place
 | ||||
|     /// and returns the old block.
 | ||||
|     pub fn swap_block(&mut self, block: Block<'ctx>) -> Block<'ctx> { | ||||
|         let mut old_block = block; | ||||
|         mem::swap(&mut self.block, &mut old_block); | ||||
|         old_block | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_typedef(&self, key: &CustomTypeKey) -> Option<&TypeDefinition> { | ||||
|         self.type_values.get(key).and_then(|v| self.types.get(v)) | ||||
|     } | ||||
| 
 | ||||
|     pub fn allocate(&self, name: &String, ty: &TypeKind) -> Option<InstructionValue> { | ||||
|         self.allocator.borrow_mut().allocate(name, ty) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct Debug<'ctx> { | ||||
|     pub(super) info: &'ctx DebugInformation, | ||||
|     pub(super) scope: DebugProgramValue, | ||||
|     pub(super) types: &'ctx HashMap<TypeKind, DebugTypeValue>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||
| pub struct StackValue(pub(super) StackValueKind, pub(super) TypeKind); | ||||
| 
 | ||||
| impl StackValue { | ||||
|     pub fn instr(&self) -> InstructionValue { | ||||
|         self.0.instr() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||||
| pub enum StackValueKind { | ||||
|     Immutable(InstructionValue), | ||||
|     Mutable(InstructionValue), | ||||
|     Literal(InstructionValue), | ||||
| } | ||||
| 
 | ||||
| impl StackValueKind { | ||||
|     pub fn mutable(mutable: bool, instr: InstructionValue) -> StackValueKind { | ||||
|         match mutable { | ||||
|             true => StackValueKind::Mutable(instr), | ||||
|             false => StackValueKind::Immutable(instr), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn instr(&self) -> InstructionValue { | ||||
|         match &self { | ||||
|             StackValueKind::Immutable(val) => *val, | ||||
|             StackValueKind::Mutable(val) => *val, | ||||
|             StackValueKind::Literal(val) => *val, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn derive(&self, instr: InstructionValue) -> StackValueKind { | ||||
|         match &self { | ||||
|             StackValueKind::Immutable(_) => StackValueKind::Immutable(instr), | ||||
|             StackValueKind::Mutable(_) => StackValueKind::Mutable(instr), | ||||
|             StackValueKind::Literal(_) => StackValueKind::Literal(instr), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     #[allow(dead_code)] | ||||
|     fn map<F>(&self, lambda: F) -> StackValueKind | ||||
|     where | ||||
|         F: FnOnce(InstructionValue) -> InstructionValue, | ||||
|     { | ||||
|         self.derive(lambda(self.instr())) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct StackBinopDefinition<'ctx> { | ||||
|     pub(super) parameters: ((String, TypeKind), (String, TypeKind)), | ||||
|     pub(super) return_ty: TypeKind, | ||||
|     pub(super) kind: StackBinopFunctionKind<'ctx>, | ||||
| } | ||||
| 
 | ||||
| pub enum StackBinopFunctionKind<'ctx> { | ||||
|     UserGenerated(Function<'ctx>), | ||||
|     Intrinsic(&'ctx Box<dyn IntrinsicFunction>), | ||||
| } | ||||
| 
 | ||||
| impl<'ctx> StackBinopDefinition<'ctx> { | ||||
|     pub fn codegen<'a>( | ||||
|         &self, | ||||
|         lhs: &StackValue, | ||||
|         rhs: &StackValue, | ||||
|         scope: &mut Scope<'ctx, 'a>, | ||||
|     ) -> Result<StackValue, ErrorKind> { | ||||
|         let (lhs, rhs) = if lhs.1 == self.parameters.0 .1 && rhs.1 == self.parameters.1 .1 { | ||||
|             (lhs, rhs) | ||||
|         } else { | ||||
|             (rhs, lhs) | ||||
|         }; | ||||
|         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()]) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										284
									
								
								reid/src/codegen/util.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										284
									
								
								reid/src/codegen/util.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,284 @@ | ||||
| use std::collections::HashMap; | ||||
| 
 | ||||
| use reid_lib::{ | ||||
|     builder::{InstructionValue, TypeValue}, | ||||
|     debug_information::{ | ||||
|         DebugArrayType, DebugBasicType, DebugFieldType, DebugInformation, DebugLocation, | ||||
|         DebugPointerType, DebugPosition, DebugProgramValue, DebugStructType, DebugTypeData, | ||||
|         DebugTypeValue, DwarfEncoding, DwarfFlags, | ||||
|     }, | ||||
|     Block, CmpPredicate, ConstValue, Instr, Type, | ||||
| }; | ||||
| 
 | ||||
| use crate::{ | ||||
|     lexer::{FullToken, Position}, | ||||
|     mir::{ | ||||
|         self, CustomTypeKey, Metadata, SourceModuleId, TypeDefinition, TypeDefinitionKind, | ||||
|         TypeKind, VagueLiteral, | ||||
|     }, | ||||
| }; | ||||
| 
 | ||||
| use super::{ | ||||
|     scope::{Debug, Scope}, | ||||
|     ModuleCodegen, | ||||
| }; | ||||
| 
 | ||||
| impl mir::CmpOperator { | ||||
|     pub(super) fn predicate(&self) -> CmpPredicate { | ||||
|         match self { | ||||
|             mir::CmpOperator::LT => CmpPredicate::LT, | ||||
|             mir::CmpOperator::GT => CmpPredicate::GT, | ||||
|             mir::CmpOperator::LE => CmpPredicate::LE, | ||||
|             mir::CmpOperator::GE => CmpPredicate::GE, | ||||
|             mir::CmpOperator::EQ => CmpPredicate::EQ, | ||||
|             mir::CmpOperator::NE => CmpPredicate::NE, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl mir::Literal { | ||||
|     pub(super) fn as_const(&self, block: &mut Block) -> InstructionValue { | ||||
|         block | ||||
|             .build_named(format!("{}", self), self.as_const_kind()) | ||||
|             .unwrap() | ||||
|     } | ||||
| 
 | ||||
|     pub(super) fn as_const_kind(&self) -> Instr { | ||||
|         Instr::Constant(match self.clone() { | ||||
|             mir::Literal::I8(val) => ConstValue::I8(val), | ||||
|             mir::Literal::I16(val) => ConstValue::I16(val), | ||||
|             mir::Literal::I32(val) => ConstValue::I32(val), | ||||
|             mir::Literal::I64(val) => ConstValue::I64(val), | ||||
|             mir::Literal::I128(val) => ConstValue::I128(val), | ||||
|             mir::Literal::U8(val) => ConstValue::U8(val), | ||||
|             mir::Literal::U16(val) => ConstValue::U16(val), | ||||
|             mir::Literal::U32(val) => ConstValue::U32(val), | ||||
|             mir::Literal::U64(val) => ConstValue::U64(val), | ||||
|             mir::Literal::U128(val) => ConstValue::U128(val), | ||||
|             mir::Literal::Bool(val) => ConstValue::Bool(val), | ||||
|             mir::Literal::String(val) => ConstValue::Str(val.clone()), | ||||
|             mir::Literal::Vague(VagueLiteral::Number(val)) => ConstValue::I32(val as i32), | ||||
|             mir::Literal::Vague(VagueLiteral::Decimal(val)) => ConstValue::F32(val as f32), | ||||
|             mir::Literal::F16(val) => ConstValue::F16(val), | ||||
|             mir::Literal::F32B(val) => ConstValue::F32B(val), | ||||
|             mir::Literal::F32(val) => ConstValue::F32(val), | ||||
|             mir::Literal::F64(val) => ConstValue::F64(val), | ||||
|             mir::Literal::F80(val) => ConstValue::F80(val), | ||||
|             mir::Literal::F128(val) => ConstValue::F128(val), | ||||
|             mir::Literal::F128PPC(val) => ConstValue::F128PPC(val), | ||||
|             mir::Literal::Char(c) => ConstValue::U8(c as u8), | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl TypeKind { | ||||
|     pub(super) fn get_type(&self, type_vals: &HashMap<CustomTypeKey, TypeValue>) -> Type { | ||||
|         match &self { | ||||
|             TypeKind::I8 => Type::I8, | ||||
|             TypeKind::I16 => Type::I16, | ||||
|             TypeKind::I32 => Type::I32, | ||||
|             TypeKind::I64 => Type::I64, | ||||
|             TypeKind::I128 => Type::I128, | ||||
|             TypeKind::U8 => Type::U8, | ||||
|             TypeKind::U16 => Type::U16, | ||||
|             TypeKind::U32 => Type::U32, | ||||
|             TypeKind::U64 => Type::U64, | ||||
|             TypeKind::U128 => Type::U128, | ||||
|             TypeKind::Bool => Type::Bool, | ||||
|             TypeKind::F16 => Type::F16, | ||||
|             TypeKind::F32B => Type::F32B, | ||||
|             TypeKind::F32 => Type::F32, | ||||
|             TypeKind::F64 => Type::F64, | ||||
|             TypeKind::F128 => Type::F128, | ||||
|             TypeKind::F80 => Type::F80, | ||||
|             TypeKind::F128PPC => Type::F128PPC, | ||||
|             TypeKind::Char => Type::U8, | ||||
|             TypeKind::Array(elem_t, len) => Type::Array(Box::new(elem_t.get_type(type_vals)), *len), | ||||
|             TypeKind::Void => Type::Void, | ||||
|             TypeKind::Vague(_) => panic!("Tried to compile a vague type!"), | ||||
|             TypeKind::CustomType(n) => { | ||||
|                 let type_val = type_vals.get(n).unwrap().clone(); | ||||
|                 Type::CustomType(type_val) | ||||
|             } | ||||
|             TypeKind::UserPtr(type_kind) => Type::Ptr(Box::new(type_kind.get_type(type_vals))), | ||||
|             TypeKind::CodegenPtr(type_kind) => Type::Ptr(Box::new(type_kind.get_type(type_vals))), | ||||
|             TypeKind::Borrow(type_kind, _) => Type::Ptr(Box::new(type_kind.get_type(type_vals))), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl TypeKind { | ||||
|     pub(super) fn get_debug_type(&self, debug: &Debug, scope: &Scope) -> DebugTypeValue { | ||||
|         self.get_debug_type_hard( | ||||
|             debug.scope, | ||||
|             debug.info, | ||||
|             debug.types, | ||||
|             scope.type_values, | ||||
|             scope.types, | ||||
|             scope.module_id, | ||||
|             scope.tokens, | ||||
|             scope.modules, | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     pub(super) fn get_debug_type_hard( | ||||
|         &self, | ||||
|         scope: DebugProgramValue, | ||||
|         debug_info: &DebugInformation, | ||||
|         debug_types: &HashMap<TypeKind, DebugTypeValue>, | ||||
|         type_values: &HashMap<CustomTypeKey, TypeValue>, | ||||
|         types: &HashMap<TypeValue, TypeDefinition>, | ||||
|         local_mod: SourceModuleId, | ||||
|         tokens: &Vec<FullToken>, | ||||
|         modules: &HashMap<SourceModuleId, ModuleCodegen>, | ||||
|     ) -> DebugTypeValue { | ||||
|         if let Some(ty) = debug_types.get(self) { | ||||
|             return *ty; | ||||
|         } | ||||
| 
 | ||||
|         let name = format!("{}", self); | ||||
| 
 | ||||
|         let data = match self { | ||||
|             TypeKind::CodegenPtr(inner) | TypeKind::UserPtr(inner) | TypeKind::Borrow(inner, _) => { | ||||
|                 DebugTypeData::Pointer(DebugPointerType { | ||||
|                     name, | ||||
|                     pointee: inner.get_debug_type_hard( | ||||
|                         scope, | ||||
|                         debug_info, | ||||
|                         debug_types, | ||||
|                         type_values, | ||||
|                         types, | ||||
|                         local_mod, | ||||
|                         tokens, | ||||
|                         modules, | ||||
|                     ), | ||||
|                     size_bits: self.size_of(), | ||||
|                 }) | ||||
|             } | ||||
|             TypeKind::Array(elem_ty, len) => { | ||||
|                 let elem_ty = elem_ty.clone().get_debug_type_hard( | ||||
|                     scope, | ||||
|                     debug_info, | ||||
|                     debug_types, | ||||
|                     type_values, | ||||
|                     types, | ||||
|                     local_mod, | ||||
|                     tokens, | ||||
|                     modules, | ||||
|                 ); | ||||
|                 DebugTypeData::Array(DebugArrayType { | ||||
|                     size_bits: self.size_of(), | ||||
|                     align_bits: self.alignment(), | ||||
|                     element_type: elem_ty, | ||||
|                     length: *len, | ||||
|                 }) | ||||
|             } | ||||
|             TypeKind::CustomType(key) => { | ||||
|                 let typedef = types.get(type_values.get(key).unwrap()).unwrap(); | ||||
|                 match &typedef.kind { | ||||
|                     TypeDefinitionKind::Struct(struct_type) => { | ||||
|                         let mut fields = Vec::new(); | ||||
|                         let mut size_bits = 0; | ||||
| 
 | ||||
|                         for field in &struct_type.0 { | ||||
|                             let location = if typedef.source_module != local_mod { | ||||
|                                 None | ||||
|                             } else { | ||||
|                                 field.2.into_debug(&tokens, scope) | ||||
|                             }; | ||||
|                             fields.push(DebugFieldType { | ||||
|                                 name: field.0.clone(), | ||||
|                                 scope, | ||||
|                                 pos: location.map(|l| l.pos), | ||||
|                                 size_bits: field.1.size_of(), | ||||
|                                 offset: size_bits, | ||||
|                                 flags: DwarfFlags, | ||||
|                                 ty: field.1.get_debug_type_hard( | ||||
|                                     scope, | ||||
|                                     debug_info, | ||||
|                                     debug_types, | ||||
|                                     type_values, | ||||
|                                     types, | ||||
|                                     local_mod, | ||||
|                                     tokens, | ||||
|                                     modules, | ||||
|                                 ), | ||||
|                             }); | ||||
|                             size_bits += field.1.size_of(); | ||||
|                         } | ||||
|                         { | ||||
|                             let location = if typedef.source_module != local_mod { | ||||
|                                 None | ||||
|                             } else { | ||||
|                                 typedef.meta.into_debug(&tokens, scope) | ||||
|                             }; | ||||
|                             DebugTypeData::Struct(DebugStructType { | ||||
|                                 name: key.0.clone(), | ||||
|                                 scope, | ||||
|                                 pos: location.map(|l| l.pos), | ||||
|                                 size_bits, | ||||
|                                 flags: DwarfFlags, | ||||
|                                 fields, | ||||
|                             }) | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             _ => DebugTypeData::Basic(DebugBasicType { | ||||
|                 name, | ||||
|                 size_bits: self.size_of(), | ||||
|                 encoding: match self { | ||||
|                     TypeKind::Bool => DwarfEncoding::Boolean, | ||||
|                     TypeKind::I8 => DwarfEncoding::SignedChar, | ||||
|                     TypeKind::U8 => DwarfEncoding::UnsignedChar, | ||||
|                     TypeKind::I16 | TypeKind::I32 | TypeKind::I64 | TypeKind::I128 => { | ||||
|                         DwarfEncoding::Signed | ||||
|                     } | ||||
|                     TypeKind::U16 | TypeKind::U32 | TypeKind::U64 | TypeKind::U128 => { | ||||
|                         DwarfEncoding::Unsigned | ||||
|                     } | ||||
|                     TypeKind::F16 | ||||
|                     | TypeKind::F32 | ||||
|                     | TypeKind::F32B | ||||
|                     | TypeKind::F64 | ||||
|                     | TypeKind::F80 | ||||
|                     | TypeKind::F128 | ||||
|                     | TypeKind::F128PPC => DwarfEncoding::Float, | ||||
|                     TypeKind::Void => DwarfEncoding::Address, | ||||
|                     TypeKind::Char => DwarfEncoding::UnsignedChar, | ||||
|                     TypeKind::Array(_, _) => DwarfEncoding::Address, | ||||
|                     TypeKind::CustomType(_) => DwarfEncoding::Address, | ||||
|                     _ => panic!("tried fetching debug-type for non-supported type!"), | ||||
|                 }, | ||||
|                 flags: DwarfFlags, | ||||
|             }), | ||||
|         }; | ||||
|         debug_info.debug_type(data) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Metadata { | ||||
|     pub(super) fn into_debug( | ||||
|         &self, | ||||
|         tokens: &Vec<FullToken>, | ||||
|         scope: DebugProgramValue, | ||||
|     ) -> Option<DebugLocation> { | ||||
|         if let Some((start, _)) = self.into_positions(tokens) { | ||||
|             Some(start.debug(scope)) | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Position { | ||||
|     pub(super) fn debug(self, scope: DebugProgramValue) -> DebugLocation { | ||||
|         DebugLocation { | ||||
|             pos: DebugPosition { | ||||
|                 line: self.1, | ||||
|                 column: self.0, | ||||
|             }, | ||||
|             scope, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -43,8 +43,8 @@ | ||||
| 
 | ||||
| use std::path::PathBuf; | ||||
| 
 | ||||
| use codegen::intrinsics::{form_intrinsic_binops, form_intrinsics}; | ||||
| use error_raporting::{ErrorKind as ErrorRapKind, ErrorModules, ReidError}; | ||||
| use intrinsics::{form_intrinsic_binops, form_intrinsics}; | ||||
| use lexer::FullToken; | ||||
| use mir::{ | ||||
|     linker::LinkerPass, typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs, | ||||
| @ -53,11 +53,9 @@ use reid_lib::{compile::CompileOutput, Context}; | ||||
| 
 | ||||
| use crate::{ast::TopLevelStatement, lexer::Token, token_stream::TokenStream}; | ||||
| 
 | ||||
| mod allocator; | ||||
| mod ast; | ||||
| mod codegen; | ||||
| pub mod error_raporting; | ||||
| pub mod intrinsics; | ||||
| pub mod ld; | ||||
| mod lexer; | ||||
| pub mod mir; | ||||
|  | ||||
| @ -5,7 +5,7 @@ | ||||
| use std::{collections::HashMap, path::PathBuf}; | ||||
| 
 | ||||
| use crate::{ | ||||
|     intrinsics::IntrinsicFunction, | ||||
|     codegen::intrinsics::IntrinsicFunction, | ||||
|     lexer::{FullToken, Position}, | ||||
|     token_stream::TokenRange, | ||||
| }; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user