make stack work

This commit is contained in:
nora 2023-12-23 15:31:15 +01:00
parent e28469fcc0
commit 46e5662aab
15 changed files with 122 additions and 117 deletions

View file

@ -1,4 +1,5 @@
mod registers;
mod stack;
mod x86_64;
use std::process::Stdio;

View file

@ -53,7 +53,7 @@ pub struct MachineReg(pub usize);
pub enum RegValue {
/// The SSA register contains an address on the stack.
/// The offset is the offset from the start of the function.
StackRelative { offset: u64 },
StackRelativePtr { offset: u64 },
/// The SSA register resides on the stack as it has been spilled.
/// This should be rather rare in practice.
Spilled { offset: u64 },
@ -65,15 +65,13 @@ pub enum RegValue {
pub struct FunctionLayout {
/// Where a register comes from at a particular usage of a register.
register_uses: FxHashMap<(Location, Register), RegValue>,
total_stack_space: u64,
}
pub fn compute_layout(f: &Func) -> FunctionLayout {
pub fn compute_layout(_f: &Func) -> FunctionLayout {
let register_uses = FxHashMap::default();
FunctionLayout {
register_uses,
total_stack_space: 0,
}
}
@ -102,7 +100,7 @@ impl<'a> ir::pretty::Customizer<'a> for LayoutPrinter<'a> {
match layout {
Some(RegValue::MachineReg(mach)) => write!(f, "reg-{}", mach.0)?,
Some(RegValue::Spilled { offset }) => write!(f, "spill-{offset}")?,
Some(RegValue::StackRelative { offset }) => {
Some(RegValue::StackRelativePtr { offset }) => {
write!(f, "i-forgot-what-this-meant-{offset}")?
}
None => write!(f, "<unknown>")?,

43
codegen/src/stack.rs Normal file
View file

@ -0,0 +1,43 @@
use std::collections::HashMap;
use analysis::ir::{BbIdx, Func, Register, StatementKind};
#[derive(Debug)]
pub struct StackLayout {
pub allocas: HashMap<Register, u64>,
pub total_size: u64,
}
/// Based on the alloca's in the initial block, this calculcates stack pointer offsets for every allocation.
pub fn allocate_stack_space<'cx>(start_align: u64, func: &Func<'cx>) -> StackLayout {
assert_eq!(start_align, 8);
// REMEMBER: The stack grows down (on x86-64).
let mut temp_layout = HashMap::new();
let mut offset_backwards = 0;
for stmt in &func.bb(BbIdx::ZERO).statements {
if let StatementKind::Alloca {
result,
size,
align,
} = stmt.kind
{
if size != 8 || align != 8 {
todo!("non 8 integer {size} {align}")
}
offset_backwards += 8;
temp_layout.insert(result, offset_backwards);
}
}
let total_size = offset_backwards;
StackLayout {
allocas: temp_layout
.into_iter()
.map(|(reg, offset_back)| (reg, total_size - offset_back))
.collect(),
total_size,
}
}

View file

@ -40,7 +40,7 @@ use rustc_hash::FxHashMap;
use crate::{
registers::{MachineReg, RegValue},
Result,
stack, Result,
};
trait IcedErrExt {
@ -61,9 +61,10 @@ struct AsmCtxt<'cx> {
a: CodeAssembler,
reg_map: FxHashMap<Register, RegValue>,
reg_occupancy: Vec<Option<Register>>,
current_stack_offset: u64,
bb_idx: BbIdx,
stack_layout: stack::StackLayout,
// caches
last_register_uses: Vec<Option<Location>>,
}
@ -98,6 +99,9 @@ impl<'cx> AsmCtxt<'cx> {
// Prologue: Save rbp and save rsp in rbp.
self.a.push(x::rbp).sp(func.def_span)?;
self.a.mov(x::rbp, x::rsp).sp(func.def_span)?;
self.a
.sub(x::rsp, self.stack_layout.total_size as i32)
.sp(func.def_span)?;
loop {
let bb = &func.bbs[self.bb_idx.as_usize()];
@ -108,27 +112,15 @@ impl<'cx> AsmCtxt<'cx> {
} = *stmt;
match *kind {
StatementKind::Alloca {
result: reg,
size,
align: _,
} => {
// For alloca, we allocate some space on the stack by subtracting from RSP.
// TODO: Align
match size {
Operand::Const(c) => {
let offset = c.as_i32();
self.a.sub(x::rsp, offset).sp(st_sp)?;
self.current_stack_offset += offset as u64;
}
Operand::Reg(_) => {
todo!("dynamic alloca is not supported. get a better computer")
}
};
StatementKind::Alloca { result, .. } => {
self.reg_map.insert(
reg,
RegValue::StackRelative {
offset: self.current_stack_offset,
result,
RegValue::StackRelativePtr {
offset: *self
.stack_layout
.allocas
.get(&result)
.expect("no stack layout slot present for alloc register"),
},
);
}
@ -149,14 +141,15 @@ impl<'cx> AsmCtxt<'cx> {
Operand::Reg(reg) => {
let ptr_value = self.reg_map[&reg];
match (ptr_value, value) {
(RegValue::StackRelative { offset }, Operand::Const(c)) => {
let offset_from_cur = self.current_stack_offset - offset;
(RegValue::StackRelativePtr { offset }, Operand::Const(c)) => {
self.a
.mov(x::qword_ptr(x::rsp + offset_from_cur), c.as_i32())
.mov(x::qword_ptr(x::rsp + offset), c.as_i32())
.sp(st_sp)?;
}
(RegValue::StackRelative { offset }, Operand::Reg(value)) => {
(
RegValue::StackRelativePtr { offset },
Operand::Reg(value),
) => {
todo!("stack relative ptr + reg value")
}
(RegValue::Spilled { .. }, _) => todo!("spilled"),
@ -229,13 +222,16 @@ pub fn generate_func<'cx>(lcx: &'cx LoweringCx<'cx>, func: &Func<'cx>) -> Result
let fn_sp = func.def_span;
let a = CodeAssembler::new(64).sp(fn_sp)?;
let stack_layout = stack::allocate_stack_space(8, func);
dbg!(&stack_layout);
let mut cx = AsmCtxt {
lcx,
a,
reg_map: FxHashMap::default(),
reg_occupancy: vec![None; 8],
current_stack_offset: 0,
bb_idx: BbIdx(0),
stack_layout,
last_register_uses: ir::info::last_register_uses(func),
};