refactor(backend): Remove literal pool
This commit is contained in:
+53
-17
@@ -3,8 +3,9 @@ use std::{fmt::Display, ops::Add};
|
|||||||
use crate::{backend::register_allocator::{REG_FP, REG_LR, REG_PC, REG_R0, REG_R1, REG_R2, REG_R3, REG_R12, REG_SP, Register}, ir::types::CmpOp as IRCmpOp};
|
use crate::{backend::register_allocator::{REG_FP, REG_LR, REG_PC, REG_R0, REG_R1, REG_R2, REG_R3, REG_R12, REG_SP, Register}, ir::types::CmpOp as IRCmpOp};
|
||||||
pub enum ARMInstr{
|
pub enum ARMInstr{
|
||||||
Move(MoveInstr),
|
Move(MoveInstr),
|
||||||
|
Movw(MovwInstr),
|
||||||
|
Movt(MovtInstr),
|
||||||
Load(LoadInstr),
|
Load(LoadInstr),
|
||||||
LoadPseudo(LoadPseudoInstr),
|
|
||||||
Store(StoreInstr),
|
Store(StoreInstr),
|
||||||
Mul(MulInstr),
|
Mul(MulInstr),
|
||||||
SDiv(SDivInstr),
|
SDiv(SDivInstr),
|
||||||
@@ -24,8 +25,9 @@ impl Display for ARMInstr {
|
|||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
ARMInstr::Move(instr) => write!(f, "{}", instr),
|
ARMInstr::Move(instr) => write!(f, "{}", instr),
|
||||||
|
ARMInstr::Movw(instr) => write!(f, "{}", instr),
|
||||||
|
ARMInstr::Movt(instr) => write!(f, "{}", instr),
|
||||||
ARMInstr::Load(instr) => write!(f, "{}", instr),
|
ARMInstr::Load(instr) => write!(f, "{}", instr),
|
||||||
ARMInstr::LoadPseudo(instr) => write!(f, "{}", instr),
|
|
||||||
ARMInstr::Store(instr) => write!(f, "{}", instr),
|
ARMInstr::Store(instr) => write!(f, "{}", instr),
|
||||||
ARMInstr::Mul(instr) => write!(f, "{}", instr),
|
ARMInstr::Mul(instr) => write!(f, "{}", instr),
|
||||||
ARMInstr::SDiv(instr) => write!(f, "{}", instr),
|
ARMInstr::SDiv(instr) => write!(f, "{}", instr),
|
||||||
@@ -45,7 +47,7 @@ impl Display for ARMInstr {
|
|||||||
pub enum RegisterOrImm {
|
pub enum RegisterOrImm {
|
||||||
Reg(Register),
|
Reg(Register),
|
||||||
Imm(i32),
|
Imm(i32),
|
||||||
}
|
}
|
||||||
impl Display for RegisterOrImm {
|
impl Display for RegisterOrImm {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
@@ -73,7 +75,7 @@ impl From<IRCmpOp> for ConditionCode {
|
|||||||
IRCmpOp::Ge => ConditionCode::Ge,
|
IRCmpOp::Ge => ConditionCode::Ge,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Display for ConditionCode {
|
impl Display for ConditionCode {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let code_str = match self {
|
let code_str = match self {
|
||||||
@@ -127,6 +129,52 @@ impl Display for MoveInstr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum MoveWideOperand {
|
||||||
|
Imm(u16),
|
||||||
|
Symbol(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MovwInstr(Register, MoveWideOperand);
|
||||||
|
impl MovwInstr {
|
||||||
|
pub fn new_imm(dest: Register, value: u16) -> ARMInstr {
|
||||||
|
ARMInstr::Movw(MovwInstr(dest, MoveWideOperand::Imm(value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_symbol(dest: Register, name: String) -> ARMInstr {
|
||||||
|
ARMInstr::Movw(MovwInstr(dest, MoveWideOperand::Symbol(name)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Display for MovwInstr {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let MovwInstr(dest, operand) = self;
|
||||||
|
match operand {
|
||||||
|
MoveWideOperand::Imm(value) => write!(f, "movw {}, #{}", dest, value),
|
||||||
|
MoveWideOperand::Symbol(name) => write!(f, "movw {}, #:lower16:{}", dest, name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MovtInstr(Register, MoveWideOperand);
|
||||||
|
impl MovtInstr {
|
||||||
|
pub fn new_imm(dest: Register, value: u16) -> ARMInstr {
|
||||||
|
ARMInstr::Movt(MovtInstr(dest, MoveWideOperand::Imm(value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_symbol(dest: Register, name: String) -> ARMInstr {
|
||||||
|
ARMInstr::Movt(MovtInstr(dest, MoveWideOperand::Symbol(name)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Display for MovtInstr {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let MovtInstr(dest, operand) = self;
|
||||||
|
match operand {
|
||||||
|
MoveWideOperand::Imm(value) => write!(f, "movt {}, #{}", dest, value),
|
||||||
|
MoveWideOperand::Symbol(name) => write!(f, "movt {}, #:upper16:{}", dest, name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct LoadInstr(Register, Register, Option<RegisterOrImm>);
|
pub struct LoadInstr(Register, Register, Option<RegisterOrImm>);
|
||||||
impl LoadInstr {
|
impl LoadInstr {
|
||||||
pub fn new(dest: Register, base: Register, offset: Option<RegisterOrImm>) -> ARMInstr {
|
pub fn new(dest: Register, base: Register, offset: Option<RegisterOrImm>) -> ARMInstr {
|
||||||
@@ -146,18 +194,6 @@ impl Display for LoadInstr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub struct LoadPseudoInstr(Register, String);
|
|
||||||
impl LoadPseudoInstr {
|
|
||||||
pub fn new(dest: Register, name: String) -> ARMInstr {
|
|
||||||
ARMInstr::LoadPseudo(LoadPseudoInstr(dest, name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Display for LoadPseudoInstr {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let LoadPseudoInstr(dest, name) = self;
|
|
||||||
write!(f, "ldr {}, ={}", dest, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub struct StoreInstr(Register, Register, Option<RegisterOrImm>);
|
pub struct StoreInstr(Register, Register, Option<RegisterOrImm>);
|
||||||
impl StoreInstr {
|
impl StoreInstr {
|
||||||
pub fn new(src: Register, dest: Register, offset: Option<RegisterOrImm>) -> ARMInstr {
|
pub fn new(src: Register, dest: Register, offset: Option<RegisterOrImm>) -> ARMInstr {
|
||||||
@@ -347,4 +383,4 @@ impl BInstr {
|
|||||||
pub fn new_cond(condition: ConditionCode, label_name: String) -> ARMInstr {
|
pub fn new_cond(condition: ConditionCode, label_name: String) -> ARMInstr {
|
||||||
ARMInstr::B(BInstr(Some(condition), label_name))
|
ARMInstr::B(BInstr(Some(condition), label_name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+36
-15
@@ -1,6 +1,6 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use crate::{backend::{arm_instr::{ARMInstr, AddInstr, BInstr, BlInstr, CmpInstr, ConditionCode, LoadInstr, LoadPseudoInstr, MoveInstr, MulInstr, PopInstr, PushInstr, RegisterOrImm, RsbInstr, SDivInstr, StoreInstr, SubInstr}, register_allocator::{REG_FP, REG_R0, REG_R1, REG_R2, REG_R3, REG_SP, Register, RegisterAlloc, RegisterAllocator}, types::ARMAsmVar}, ir::types::{Function, IRInstr, MoveRValue, Variable, VariableOrIntLit, VariableType}};
|
use crate::{backend::{arm_instr::{ARMInstr, AddInstr, BInstr, BlInstr, CmpInstr, ConditionCode, LoadInstr, MoveInstr, MovtInstr, MovwInstr, MulInstr, PopInstr, PushInstr, RegisterOrImm, RsbInstr, SDivInstr, StoreInstr, SubInstr}, register_allocator::{REG_FP, REG_R0, REG_R1, REG_R2, REG_R3, REG_SP, Register, RegisterAlloc, RegisterAllocator}, types::ARMAsmVar}, ir::types::{Function, IRInstr, MoveRValue, Variable, VariableOrIntLit, VariableType}};
|
||||||
use crate::ir::types::BinaryOp as IRBinaryOp;
|
use crate::ir::types::BinaryOp as IRBinaryOp;
|
||||||
use crate::ir::types::CmpOp as IRCmpOp;
|
use crate::ir::types::CmpOp as IRCmpOp;
|
||||||
use crate::ir::types::UnaryOp as IRUnaryOp;
|
use crate::ir::types::UnaryOp as IRUnaryOp;
|
||||||
@@ -19,6 +19,22 @@ const ARG_REGS: [Register; 4] = [REG_R0, REG_R1, REG_R2, REG_R3];
|
|||||||
const ARM_DATA_IMM_CHUNK: i32 = 255;
|
const ARM_DATA_IMM_CHUNK: i32 = 255;
|
||||||
const ARM_LOAD_STORE_MAX_OFFSET: i32 = 4095;
|
const ARM_LOAD_STORE_MAX_OFFSET: i32 = 4095;
|
||||||
|
|
||||||
|
fn emit_load_imm32(dest: Register, value: i32, instrs: &mut Vec<ARMInstr>) {
|
||||||
|
let bits = value as u32;
|
||||||
|
let lower = (bits & 0xffff) as u16;
|
||||||
|
let upper = (bits >> 16) as u16;
|
||||||
|
|
||||||
|
instrs.push(MovwInstr::new_imm(dest, lower));
|
||||||
|
if upper != 0 {
|
||||||
|
instrs.push(MovtInstr::new_imm(dest, upper));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_load_symbol_addr(dest: Register, name: String, instrs: &mut Vec<ARMInstr>) {
|
||||||
|
instrs.push(MovwInstr::new_symbol(dest, name.clone()));
|
||||||
|
instrs.push(MovtInstr::new_symbol(dest, name));
|
||||||
|
}
|
||||||
|
|
||||||
fn emit_sub_imm(dest: Register, left: Register, imm: i32, instrs: &mut Vec<ARMInstr>) {
|
fn emit_sub_imm(dest: Register, left: Register, imm: i32, instrs: &mut Vec<ARMInstr>) {
|
||||||
if imm == 0 {
|
if imm == 0 {
|
||||||
if dest != left {
|
if dest != left {
|
||||||
@@ -97,7 +113,7 @@ fn load_variable(variable: Variable, reg_allocator: &mut RegisterAllocator, var_
|
|||||||
}
|
}
|
||||||
match variable.var_type {
|
match variable.var_type {
|
||||||
VariableType::Global => {
|
VariableType::Global => {
|
||||||
instrs.push(LoadPseudoInstr::new(var_alloc.reg, format!("global_var_{}", variable.index)));
|
emit_load_symbol_addr(var_alloc.reg, format!("global_var_{}", variable.index), instrs);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let stack_offset = var_index_to_stack_offset.get(&variable.index).expect("Variable not declared");
|
let stack_offset = var_index_to_stack_offset.get(&variable.index).expect("Variable not declared");
|
||||||
@@ -112,7 +128,7 @@ fn load_variable(variable: Variable, reg_allocator: &mut RegisterAllocator, var_
|
|||||||
let var_reg = var_alloc.reg;
|
let var_reg = var_alloc.reg;
|
||||||
// if !var_alloc.is_reused {
|
// if !var_alloc.is_reused {
|
||||||
let address_alloc = reg_allocator.alloc_any().expect("Ran out of registers");
|
let address_alloc = reg_allocator.alloc_any().expect("Ran out of registers");
|
||||||
instrs.push(LoadPseudoInstr::new(address_alloc.reg, format!("global_var_{}", variable.index)));
|
emit_load_symbol_addr(address_alloc.reg, format!("global_var_{}", variable.index), instrs);
|
||||||
instrs.push(LoadInstr::new(var_reg, address_alloc.reg, None));
|
instrs.push(LoadInstr::new(var_reg, address_alloc.reg, None));
|
||||||
// }
|
// }
|
||||||
var_alloc
|
var_alloc
|
||||||
@@ -144,7 +160,7 @@ fn save_variable(variable: Variable, reg: Register, reg_allocator: &mut Register
|
|||||||
match variable.var_type {
|
match variable.var_type {
|
||||||
VariableType::Global => {
|
VariableType::Global => {
|
||||||
let address_alloc = reg_allocator.alloc_any().expect("Ran out of registers");
|
let address_alloc = reg_allocator.alloc_any().expect("Ran out of registers");
|
||||||
instrs.push(LoadPseudoInstr::new(address_alloc.reg, format!("global_var_{}", variable.index)));
|
emit_load_symbol_addr(address_alloc.reg, format!("global_var_{}", variable.index), instrs);
|
||||||
instrs.push(StoreInstr::new(reg, address_alloc.reg, None));
|
instrs.push(StoreInstr::new(reg, address_alloc.reg, None));
|
||||||
},
|
},
|
||||||
VariableType::ParamTemp(_) => {
|
VariableType::ParamTemp(_) => {
|
||||||
@@ -169,7 +185,7 @@ impl Generator {
|
|||||||
for ir_instr in ir_instrs {
|
for ir_instr in ir_instrs {
|
||||||
match ir_instr {
|
match ir_instr {
|
||||||
IRInstr::DefineFunc(func, args, body) => self.emit_func_def(func, args, body),
|
IRInstr::DefineFunc(func, args, body) => self.emit_func_def(func, args, body),
|
||||||
IRInstr::Declare(var) => self.emit_global_decl(var),
|
IRInstr::DeclareGlobal(var, init) => self.emit_global_decl(var, init),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,8 +197,8 @@ impl Generator {
|
|||||||
text.push_str(&format!(".comm {}, {}, {}\n", var.name, var.size, var.align));
|
text.push_str(&format!(".comm {}, {}, {}\n", var.name, var.size, var.align));
|
||||||
}
|
}
|
||||||
for var in &self.var_inited {
|
for var in &self.var_inited {
|
||||||
text.push_str(&format!(".data\n.align {}\n.global {}\n.type {}, @object\n:{}\n", var.align, var.name, var.name, var.name));
|
text.push_str(&format!(".data\n.align {}\n.global {}\n.type {}, %object\n{}:\n", var.align, var.name, var.name, var.name));
|
||||||
text.push_str(&format!(".word 0\n"));
|
text.push_str(&format!(".word {}\n", var.init.unwrap_or(0)));
|
||||||
}
|
}
|
||||||
text.push_str(".text\n");
|
text.push_str(".text\n");
|
||||||
for instr in &self.instrs {
|
for instr in &self.instrs {
|
||||||
@@ -191,13 +207,18 @@ impl Generator {
|
|||||||
text
|
text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn emit_global_decl(&mut self, var: Variable, init: Option<i32>) {
|
||||||
fn emit_global_decl(&mut self, var: Variable) {
|
let asm_var = ARMAsmVar {
|
||||||
self.var_uninited.push(ARMAsmVar {
|
|
||||||
name: format!("global_var_{}", var.index),
|
name: format!("global_var_{}", var.index),
|
||||||
size: var.data_type.size_in_bytes(),
|
size: var.data_type.size_in_bytes(),
|
||||||
align: DEFAULT_VAR_ALIGN,
|
align: DEFAULT_VAR_ALIGN,
|
||||||
});
|
init,
|
||||||
|
};
|
||||||
|
if asm_var.init.is_some() {
|
||||||
|
self.var_inited.push(asm_var);
|
||||||
|
} else {
|
||||||
|
self.var_uninited.push(asm_var);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_func_def(&mut self, func: Function, _args: Vec<Variable>, body: Vec<IRInstr>) {
|
fn emit_func_def(&mut self, func: Function, _args: Vec<Variable>, body: Vec<IRInstr>) {
|
||||||
@@ -239,7 +260,7 @@ impl Generator {
|
|||||||
encounter_entry = true;
|
encounter_entry = true;
|
||||||
emit_sub_sp_imm(stack_size_needed as i32, &mut self.instrs);
|
emit_sub_sp_imm(stack_size_needed as i32, &mut self.instrs);
|
||||||
},
|
},
|
||||||
IRInstr::DefineFunc(_, _, _) => unreachable!(),
|
IRInstr::DefineFunc(_, _, _) | IRInstr::DeclareGlobal(_, _) => unreachable!(),
|
||||||
IRInstr::Cmp(variable, left, cmp_op, right) => self.emit_cmp(variable, left, cmp_op, right, &var_index_to_stack_offset),
|
IRInstr::Cmp(variable, left, cmp_op, right) => self.emit_cmp(variable, left, cmp_op, right, &var_index_to_stack_offset),
|
||||||
IRInstr::Unary(variable, unary_op, variable1) => self.emit_unary(variable, unary_op, variable1, &var_index_to_stack_offset),
|
IRInstr::Unary(variable, unary_op, variable1) => self.emit_unary(variable, unary_op, variable1, &var_index_to_stack_offset),
|
||||||
IRInstr::Goto(index) => self.instrs.push(BInstr::new(format!("label_{}_{}", func_name, index))),
|
IRInstr::Goto(index) => self.instrs.push(BInstr::new(format!("label_{}_{}", func_name, index))),
|
||||||
@@ -272,7 +293,7 @@ impl Generator {
|
|||||||
},
|
},
|
||||||
VariableOrIntLit::IntLit(lit) => {
|
VariableOrIntLit::IntLit(lit) => {
|
||||||
let alloc = self.register_allocator.alloc_any().expect("Ran out of registers");
|
let alloc = self.register_allocator.alloc_any().expect("Ran out of registers");
|
||||||
self.instrs.push(MoveInstr::new_uncond(alloc.reg, RegisterOrImm::Imm(lit)));
|
emit_load_imm32(alloc.reg, lit, &mut self.instrs);
|
||||||
alloc
|
alloc
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -283,7 +304,7 @@ impl Generator {
|
|||||||
},
|
},
|
||||||
VariableOrIntLit::IntLit(lit) => {
|
VariableOrIntLit::IntLit(lit) => {
|
||||||
let alloc = self.register_allocator.alloc_any().expect("Ran out of registers");
|
let alloc = self.register_allocator.alloc_any().expect("Ran out of registers");
|
||||||
self.instrs.push(MoveInstr::new_uncond(alloc.reg, RegisterOrImm::Imm(lit)));
|
emit_load_imm32(alloc.reg, lit, &mut self.instrs);
|
||||||
alloc
|
alloc
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -335,7 +356,7 @@ impl Generator {
|
|||||||
let src_alloc = load_variable(variable, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs);
|
let src_alloc = load_variable(variable, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs);
|
||||||
self.instrs.push(MoveInstr::new_uncond(dest_register, RegisterOrImm::Reg(src_alloc.reg)));
|
self.instrs.push(MoveInstr::new_uncond(dest_register, RegisterOrImm::Reg(src_alloc.reg)));
|
||||||
},
|
},
|
||||||
MoveRValue::ConstInt(literal_int) => self.instrs.push(MoveInstr::new_uncond(dest_register, RegisterOrImm::Imm(literal_int))),
|
MoveRValue::ConstInt(literal_int) => emit_load_imm32(dest_register, literal_int, &mut self.instrs),
|
||||||
};
|
};
|
||||||
save_variable(dest, dest_alloc.reg, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs);
|
save_variable(dest, dest_alloc.reg, &mut self.register_allocator, var_index_to_stack_offset, &mut self.instrs);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,4 +2,5 @@ pub struct ARMAsmVar {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
pub size: usize,
|
pub size: usize,
|
||||||
pub align: usize,
|
pub align: usize,
|
||||||
}
|
pub init: Option<i32>,
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user