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