continued work on new register allocator implementation.
next commit will have it integrated if it works
This commit is contained in:
@@ -19,6 +19,11 @@
|
|||||||
"command": "cargo run --bin dsx-build",
|
"command": "cargo run --bin dsx-build",
|
||||||
"use_new_terminal": true,
|
"use_new_terminal": true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"label": "Check All",
|
||||||
|
"command": "cargo clippy --all-targets",
|
||||||
|
"use_new_terminal": false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"label": "Build All (Release)",
|
"label": "Build All (Release)",
|
||||||
"command": "cargo build --release",
|
"command": "cargo build --release",
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ mod codegen;
|
|||||||
mod instruction;
|
mod instruction;
|
||||||
mod registers;
|
mod registers;
|
||||||
mod scope;
|
mod scope;
|
||||||
mod variable;
|
|
||||||
|
|
||||||
pub fn generate_code(ast: &Program) -> Result<String, CompilerError> {
|
pub fn generate_code(ast: &Program) -> Result<String, CompilerError> {
|
||||||
let mut codegen = codegen::CodeGenerator::new(ast.clone());
|
let mut codegen = codegen::CodeGenerator::new(ast.clone());
|
||||||
|
|||||||
+273
-166
@@ -1,49 +1,211 @@
|
|||||||
use std::{cell::RefCell, collections::HashMap, ops::Deref, rc::Rc};
|
use std::{cell::RefCell, collections::HashMap, ops::Deref, rc::Rc};
|
||||||
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::dsa::{
|
backend::dsa::{
|
||||||
instruction::{InsBlock, Instruction},
|
instruction::{InsBlock, Instruction},
|
||||||
registers::{Register, RegisterAllocator},
|
registers::{Register, RegisterAllocator},
|
||||||
variable::Variable,
|
|
||||||
},
|
},
|
||||||
model::CompilerError,
|
error,
|
||||||
|
model::{CompilerError, Name, TypeId},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// scope object
|
||||||
|
pub struct Scope<'a> {
|
||||||
|
/// outer scope, for a function this will be the global scope.
|
||||||
|
parent: Option<&'a mut Scope<'a>>,
|
||||||
|
alloc: Rc<RefCell<Allocator>>,
|
||||||
|
|
||||||
|
/// is the scope a function body or just a loop?
|
||||||
|
/// depending on the type, ending a scope will have different behaviour
|
||||||
|
r#type: ScopeType,
|
||||||
|
|
||||||
|
/// variables
|
||||||
|
variables: HashMap<String, Variable>,
|
||||||
|
|
||||||
|
entry_stack_offset: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Scope<'a> {
|
||||||
|
pub fn new() -> Scope<'a> {
|
||||||
|
let alloc = Rc::new(RefCell::new(Allocator::new()));
|
||||||
|
let entry_stack_offset = alloc.borrow().get_stack_offset();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
alloc,
|
||||||
|
entry_stack_offset,
|
||||||
|
parent: None,
|
||||||
|
r#type: ScopeType::Function,
|
||||||
|
variables: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_from(parent: &'a mut Scope<'a>, r#type: ScopeType) -> Scope<'a> {
|
||||||
|
let alloc = Rc::clone(&parent.alloc);
|
||||||
|
let entry_stack_offset = alloc.borrow().get_stack_offset();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
alloc,
|
||||||
|
entry_stack_offset,
|
||||||
|
parent: Some(parent),
|
||||||
|
r#type,
|
||||||
|
variables: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_var(
|
||||||
|
&mut self,
|
||||||
|
name: String,
|
||||||
|
r#type: TypeId,
|
||||||
|
) -> Result<(), CompilerError> {
|
||||||
|
let mut var = Variable::new(name, r#type.clone());
|
||||||
|
|
||||||
|
if r#type.size() > 4 {
|
||||||
|
let slot = self.alloc.borrow_mut().allocate_stack_slot(r#type.size());
|
||||||
|
var.stack_slot = Some(slot);
|
||||||
|
} else {
|
||||||
|
let reg = self.alloc.borrow_mut().allocate_var()?;
|
||||||
|
var.register = Some(reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.variables.insert(var.name.clone(), var);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn alloc_temp(&mut self) -> Result<TempReg, CompilerError> {
|
||||||
|
self.alloc.borrow_mut().allocate_temp()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn free_temp(&mut self, temp: &TempReg) {
|
||||||
|
self.alloc.borrow_mut().free_temp(temp)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn free_var(&mut self, reg: &AssignedReg) {
|
||||||
|
self.alloc.borrow_mut().free_var(reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn close(&mut self) {
|
||||||
|
// tell the allocator that this scope is closing
|
||||||
|
// this reverts the stack offset to what it was before this scope was created.
|
||||||
|
self.alloc.clone().borrow_mut().destroy_scope(self);
|
||||||
|
|
||||||
|
for var in self.variables.clone().values() {
|
||||||
|
if let Some(reg) = var.register {
|
||||||
|
self.free_var(®);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_var(&mut self, var: &str) -> Option<&mut Variable> {
|
||||||
|
self.variables.get_mut(var)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offset_read(
|
||||||
|
&mut self,
|
||||||
|
var: &str,
|
||||||
|
offset: i32,
|
||||||
|
) -> Result<(TempReg, Instruction), CompilerError> {
|
||||||
|
if let Some(var) = self.get_var(var) {
|
||||||
|
let slot = var.stack_slot.ok_or_else(|| {
|
||||||
|
error("Attempt to read from a var without a stack slot!")
|
||||||
|
})?;
|
||||||
|
|
||||||
|
return self.alloc.borrow_mut().offset_read(&slot, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(CompilerError::Undefined(Name::new(var, None)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offset_write(
|
||||||
|
&mut self,
|
||||||
|
reg: &TempReg,
|
||||||
|
var: &str,
|
||||||
|
offset: i32,
|
||||||
|
) -> Result<Instruction, CompilerError> {
|
||||||
|
if let Some(var) = self.get_var(var) {
|
||||||
|
let slot = var.stack_slot.ok_or_else(|| {
|
||||||
|
error("Attempt to write to a var without a stack slot!")
|
||||||
|
})?;
|
||||||
|
|
||||||
|
return Ok(self.alloc.borrow_mut().offset_write(reg, &slot, offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(CompilerError::Undefined(Name::new(var, None)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_var(
|
||||||
|
&mut self,
|
||||||
|
var: &str,
|
||||||
|
) -> Result<(AssignedReg, Instruction), CompilerError> {
|
||||||
|
if let Some(v) = self.get_var(var).cloned()
|
||||||
|
&& let Some(slot) = v.stack_slot
|
||||||
|
{
|
||||||
|
let res = self.alloc.borrow_mut().load_var(&slot)?;
|
||||||
|
self.get_var(var).unwrap().register = Some(res.0);
|
||||||
|
return Ok(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
panic!("e")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spill_var(&mut self, var: &str) -> Result<Instruction, CompilerError> {
|
||||||
|
if let Some(v) = self.get_var(var).cloned()
|
||||||
|
&& let Some(rg) = v.register
|
||||||
|
{
|
||||||
|
let mut slot = v.stack_slot;
|
||||||
|
let res = self.alloc.borrow_mut().spill_var(&rg, &mut slot);
|
||||||
|
self.get_var(var).unwrap().stack_slot = slot;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(CompilerError::Undefined(Name::new(var, None)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Scope<'_> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Copy, Clone, Debug)]
|
||||||
|
pub enum ScopeType {
|
||||||
|
Function,
|
||||||
|
IfBlock,
|
||||||
|
LoopBlock,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Variable {
|
||||||
|
pub name: String,
|
||||||
|
|
||||||
|
/// the type of the variable.
|
||||||
|
r#type: TypeId,
|
||||||
|
|
||||||
|
/// size taken up in bytes.
|
||||||
|
/// if size > 4, value must be stored on the stack.
|
||||||
|
pub size: usize,
|
||||||
|
|
||||||
|
pub stack_slot: Option<StackSlot>,
|
||||||
|
pub register: Option<AssignedReg>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Variable {
|
||||||
|
pub fn new(name: String, r#type: TypeId) -> Self {
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
size: r#type.size(),
|
||||||
|
r#type,
|
||||||
|
stack_slot: None,
|
||||||
|
register: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Allocator {
|
pub struct Allocator {
|
||||||
stack_offset: i32,
|
stack_offset: i32,
|
||||||
in_use: [(Register, bool); 16],
|
in_use: [(Register, bool); 16],
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TempReg(Register);
|
|
||||||
pub struct AssignedReg(Register);
|
|
||||||
pub struct StackSlot(i32);
|
|
||||||
|
|
||||||
impl Deref for TempReg {
|
|
||||||
type Target = Register;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for AssignedReg {
|
|
||||||
type Target = Register;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for StackSlot {
|
|
||||||
type Target = i32;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Allocator {
|
impl Allocator {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut in_use = [(Register::Null, false); 16];
|
let mut in_use = [(Register::Null, false); 16];
|
||||||
@@ -64,7 +226,7 @@ impl Allocator {
|
|||||||
|
|
||||||
for var in scope.variables.drain() {
|
for var in scope.variables.drain() {
|
||||||
if let Some(assigned) = var.1.register {
|
if let Some(assigned) = var.1.register {
|
||||||
self.free_assigned(&assigned);
|
self.free_var(&assigned);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -82,71 +244,74 @@ impl Allocator {
|
|||||||
//
|
//
|
||||||
// - read / write bytes from the stack+offset in a larger variable into a register.
|
// - read / write bytes from the stack+offset in a larger variable into a register.
|
||||||
|
|
||||||
pub fn read_var(&mut self, var: &mut Variable) -> Result<InsBlock, CompilerError> {
|
pub fn offset_read(
|
||||||
if let Some(slot) = &mut var.stack_slot {
|
&mut self,
|
||||||
if var.register.is_none() {
|
slot: &StackSlot,
|
||||||
var.register = Some(self.allocate_var()?);
|
offset: i32,
|
||||||
|
) -> Result<(TempReg, Instruction), CompilerError> {
|
||||||
|
let register = self.allocate_temp()?;
|
||||||
|
|
||||||
|
// instruction: reg = *(&var + offset)
|
||||||
|
Ok((
|
||||||
|
register.clone(),
|
||||||
|
Instruction::ldw_reg_offset(
|
||||||
|
Register::Spr,
|
||||||
|
*register,
|
||||||
|
(**slot + offset) - self.stack_offset,
|
||||||
|
),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(reg) = &var.register {
|
pub fn offset_write(
|
||||||
return Ok(InsBlock::from(Instruction::ldw_reg_offset(
|
&mut self,
|
||||||
|
reg: &TempReg,
|
||||||
|
slot: &StackSlot,
|
||||||
|
offset: i32,
|
||||||
|
) -> Instruction {
|
||||||
|
// instruction: *(&var + offset) = reg
|
||||||
|
Instruction::stw_reg_offset(
|
||||||
|
**reg,
|
||||||
|
Register::Spr,
|
||||||
|
(**slot + offset) - self.stack_offset,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_var(
|
||||||
|
&mut self,
|
||||||
|
slot: &StackSlot,
|
||||||
|
) -> Result<(AssignedReg, Instruction), CompilerError> {
|
||||||
|
let reg = self.allocate_var()?;
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
reg.clone(),
|
||||||
|
Instruction::ldw_reg_offset(Register::Spr, *reg, **slot - self.stack_offset),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spill_var(
|
||||||
|
&mut self,
|
||||||
|
reg: &AssignedReg,
|
||||||
|
slot: &mut Option<StackSlot>,
|
||||||
|
// var: &mut Variable,
|
||||||
|
) -> Result<Instruction, CompilerError> {
|
||||||
|
if let Some(slot) = &slot {
|
||||||
|
let block = Instruction::stw_reg_offset(
|
||||||
**reg,
|
**reg,
|
||||||
Register::Spr,
|
Register::Spr,
|
||||||
**slot - self.stack_offset,
|
**slot - self.stack_offset,
|
||||||
)));
|
);
|
||||||
}
|
|
||||||
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(CompilerError::Generic(format!(
|
|
||||||
"Tried to write var {} to stack but var was not assigned a reg and/or stack slot",
|
|
||||||
var.name
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write_var(&mut self, var: &mut Variable) -> Result<InsBlock, CompilerError> {
|
|
||||||
if let Some(slot) = &var.stack_slot {
|
|
||||||
if let Some(reg) = &var.register {
|
|
||||||
return Ok(InsBlock::from(Instruction::stw_reg_offset(
|
|
||||||
**reg,
|
|
||||||
Register::Spr,
|
|
||||||
**slot - self.stack_offset,
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(CompilerError::Generic(format!(
|
|
||||||
"Tried to write var {} to stack but var was not assigned a reg and/or stack slot",
|
|
||||||
var.name
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn spill_var(&mut self, var: &mut Variable) -> Result<InsBlock, CompilerError> {
|
|
||||||
if let Some(slot) = &var.stack_slot {
|
|
||||||
let block = self.write_var(var)?;
|
|
||||||
if let Some(reg) = &var.register {
|
|
||||||
self.free_assigned(reg);
|
|
||||||
var.register = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
self.free_var(reg);
|
||||||
return Ok(block);
|
return Ok(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
// var doesn't have a stack slot so we need to create one
|
// var doesn't have a stack slot so we need to create one
|
||||||
if let Some(reg) = &var.register {
|
let new_slot = self.allocate_stack_slot(4); // alloc 4 bytes for reg value.
|
||||||
let slot = self.allocate_stack_slot(var.size);
|
let block = Instruction::push(**reg);
|
||||||
let block = InsBlock::from(Instruction::push(**reg));
|
|
||||||
|
|
||||||
self.free_assigned(reg);
|
self.free_var(reg);
|
||||||
var.register = None;
|
*slot = Some(new_slot);
|
||||||
var.stack_slot = Some(slot);
|
Ok(block)
|
||||||
return Ok(block);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Err(CompilerError::Generic(
|
|
||||||
"spill_var called on a variable without a register".to_string(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn allocate_stack_slot(&mut self, size: usize) -> StackSlot {
|
pub fn allocate_stack_slot(&mut self, size: usize) -> StackSlot {
|
||||||
@@ -179,7 +344,7 @@ impl Allocator {
|
|||||||
self.in_use[**temp as usize].1 = false;
|
self.in_use[**temp as usize].1 = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn free_assigned(&mut self, reg: &AssignedReg) {
|
pub fn free_var(&mut self, reg: &AssignedReg) {
|
||||||
// frees a register.
|
// frees a register.
|
||||||
self.in_use[**reg as usize].1 = false;
|
self.in_use[**reg as usize].1 = false;
|
||||||
}
|
}
|
||||||
@@ -197,91 +362,33 @@ impl Allocator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FunctionContext {
|
#[derive(Clone, Copy, Debug)]
|
||||||
name: String,
|
pub struct TempReg(Register);
|
||||||
allocator: RefCell<Allocator>,
|
#[derive(Clone, Copy, Debug)]
|
||||||
}
|
pub struct AssignedReg(Register);
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct StackSlot(i32);
|
||||||
|
|
||||||
impl FunctionContext {
|
impl Deref for TempReg {
|
||||||
pub fn new(name: String) -> Self {
|
type Target = Register;
|
||||||
Self {
|
|
||||||
name,
|
|
||||||
allocator: RefCell::new(Allocator::new()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_stack_offset(&self) -> i32 {
|
fn deref(&self) -> &Self::Target {
|
||||||
self.allocator.borrow().get_stack_offset()
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// scope object
|
impl Deref for AssignedReg {
|
||||||
pub struct Scope<'a> {
|
type Target = Register;
|
||||||
/// outer scope, for a function this will be the global scope.
|
|
||||||
parent: Option<&'a mut Scope<'a>>,
|
|
||||||
|
|
||||||
context: Rc<FunctionContext>,
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
/// is the scope a function body or just a loop?
|
|
||||||
/// depending on the type, ending a scope will have different behaviour
|
|
||||||
r#type: ScopeType,
|
|
||||||
|
|
||||||
/// variables
|
|
||||||
variables: HashMap<Uuid, Variable>,
|
|
||||||
|
|
||||||
entry_stack_offset: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Scope<'a> {
|
|
||||||
pub fn new(parent: &'a mut Scope<'a>, r#type: ScopeType) -> Scope<'a> {
|
|
||||||
Self {
|
|
||||||
entry_stack_offset: parent.context.get_stack_offset(),
|
|
||||||
context: Rc::clone(&parent.context),
|
|
||||||
parent: Some(parent),
|
|
||||||
r#type,
|
|
||||||
variables: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn close(&mut self) -> Result<(), CompilerError> {
|
|
||||||
// closing a scope means we need to drop all variables in scope and free
|
|
||||||
// registers.
|
|
||||||
for (name, var) in self.variables.iter() {
|
|
||||||
todo!()
|
|
||||||
// if let Some(reg) = var.allocated_register {}
|
|
||||||
|
|
||||||
// if let Some(offset) = var.bpr_offset {
|
|
||||||
// self.stack_offset -= offset;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn alloc_temp_reg(&mut self) -> Result<(Register, InsBlock), CompilerError> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn alloc_var_reg(&mut self) -> Result<(Register, InsBlock), CompilerError> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn alloc_var_stack(&mut self) -> Result<(Register, InsBlock), CompilerError> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn free_var_stack(&mut self) -> Result<(Register, InsBlock), CompilerError> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn free_temp_reg(&mut self) -> Result<(Register, InsBlock), CompilerError> {
|
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Copy, Clone, Debug)]
|
impl Deref for StackSlot {
|
||||||
pub enum ScopeType {
|
type Target = i32;
|
||||||
Function,
|
|
||||||
IfBlock,
|
fn deref(&self) -> &Self::Target {
|
||||||
LoopBlock,
|
&self.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,93 +0,0 @@
|
|||||||
use std::{collections::HashMap, hash::Hash, rc::Rc};
|
|
||||||
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
backend::dsa::{
|
|
||||||
instruction::InsBlock,
|
|
||||||
registers::Register,
|
|
||||||
scope::{AssignedReg, FunctionContext, Scope, StackSlot},
|
|
||||||
},
|
|
||||||
model::{CompilerError, TypeId},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct Variable {
|
|
||||||
pub name: String,
|
|
||||||
pub uuid: Uuid,
|
|
||||||
|
|
||||||
/// the type of the variable.
|
|
||||||
r#type: TypeId,
|
|
||||||
|
|
||||||
/// size taken up in bytes.
|
|
||||||
/// if size > 4, value must be stored on the stack.
|
|
||||||
pub size: usize,
|
|
||||||
|
|
||||||
pub stack_slot: Option<StackSlot>,
|
|
||||||
pub register: Option<AssignedReg>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Variable {
|
|
||||||
pub fn new_uninit(name: String, r#type: TypeId) -> Self {
|
|
||||||
Self {
|
|
||||||
name,
|
|
||||||
uuid: Uuid::new_v4(),
|
|
||||||
size: r#type.size(),
|
|
||||||
r#type,
|
|
||||||
stack_slot: None,
|
|
||||||
register: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new(
|
|
||||||
name: String,
|
|
||||||
r#type: TypeId,
|
|
||||||
scope: &'_ mut Scope,
|
|
||||||
) -> Result<Self, CompilerError> {
|
|
||||||
let mut var = Self::new_uninit(name, r#type);
|
|
||||||
var.alloc_default(scope);
|
|
||||||
|
|
||||||
Ok(var)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn alloc_default(&mut self, scope: &'_ mut Scope) {
|
|
||||||
if self.size > 4 {
|
|
||||||
self.alloc_stack(scope).unwrap();
|
|
||||||
} else {
|
|
||||||
self.alloc_register(scope).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn alloc_register(
|
|
||||||
&mut self,
|
|
||||||
scope: &'_ mut Scope,
|
|
||||||
) -> Result<Register, CompilerError> {
|
|
||||||
if self.size > 4 {
|
|
||||||
return Err(CompilerError::Generic(format!(
|
|
||||||
"Type {} cannot be allocated a register as it has a size of {} bytes",
|
|
||||||
self.r#type, self.size
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
todo!("integrate with register alloc logic")
|
|
||||||
|
|
||||||
// self.allocated_register = Some(...)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn alloc_stack(&mut self, scope: &'_ mut Scope) -> Result<usize, CompilerError> {
|
|
||||||
todo!("integrate with stack alloc logic")
|
|
||||||
|
|
||||||
// self.bpr_offset = Some(...)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load(&mut self, scope: &'_ mut Scope) -> Result<Register, CompilerError> {
|
|
||||||
todo!("load var from stack to reg (if possible)")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn drop(&mut self, scope: &'_ mut Scope) -> Result<(), CompilerError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn spill(&mut self, scope: &'_ mut Scope) -> Result<(), CompilerError> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+5
-1
@@ -4,7 +4,7 @@ use std::path::Path;
|
|||||||
|
|
||||||
use common::logging::log;
|
use common::logging::log;
|
||||||
|
|
||||||
use crate::specialised::build_specialised;
|
use crate::{model::CompilerError, specialised::build_specialised};
|
||||||
|
|
||||||
mod backend;
|
mod backend;
|
||||||
mod frontend;
|
mod frontend;
|
||||||
@@ -70,3 +70,7 @@ pub fn compile_file(
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn error(msg: impl Into<String>) -> CompilerError {
|
||||||
|
CompilerError::Generic(msg.into())
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user