From ce2ad5a9576706e824d49ef09e3ef19ea8855802 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Fri, 29 Dec 2023 17:18:20 +0100 Subject: [PATCH] stores? --- analysis/src/ir.rs | 8 +- analysis/src/ir/pretty.rs | 10 +- analysis/src/ir/visit.rs | 12 +-- analysis/src/lower/builder.rs | 8 +- codegen/src/lib.rs | 2 +- codegen/src/x86_64.rs | 194 +++++++++++++++++++--------------- 6 files changed, 124 insertions(+), 110 deletions(-) diff --git a/analysis/src/ir.rs b/analysis/src/ir.rs index 8a5d80c..60b0bd1 100644 --- a/analysis/src/ir.rs +++ b/analysis/src/ir.rs @@ -138,15 +138,15 @@ pub enum StatementKind { ptr: Operand, value: Operand, /// Amount of bytes to store. - size: Operand, - align: Operand, + size: u64, + align: u64, }, Load { result: Register, ptr: Operand, /// Amount of bytes to load. - size: Operand, - align: Operand, + size: u64, + align: u64, }, BinOp { result: Register, diff --git a/analysis/src/ir/pretty.rs b/analysis/src/ir/pretty.rs index b294f71..92226ff 100644 --- a/analysis/src/ir/pretty.rs +++ b/analysis/src/ir/pretty.rs @@ -112,11 +112,9 @@ impl PrettyPrinter { align, } => writeln!( self.out, - " store {}, {}, size={}, align={}", + " store {}, {}, size={size}, align={align}", print_op(ptr_reg), - print_op(value), - print_op(size), - print_op(align) + print_op(value), ), StatementKind::Load { result, @@ -125,11 +123,9 @@ impl PrettyPrinter { align, } => writeln!( self.out, - " {} = load {}, size={}, align={}", + " {} = load {}, size={size}, align={align}", print_reg(result), print_op(ptr_reg), - print_op(size), - print_op(align) ), StatementKind::BinOp { kind, diff --git a/analysis/src/ir/visit.rs b/analysis/src/ir/visit.rs index 4c8cce3..39ef168 100644 --- a/analysis/src/ir/visit.rs +++ b/analysis/src/ir/visit.rs @@ -40,24 +40,20 @@ pub trait Visitor { StatementKind::Store { ptr, value, - size, - align, + size: _, + align: _, } => { self.visit_operand(ptr); self.visit_operand(value); - self.visit_operand(size); - self.visit_operand(align); } StatementKind::Load { result, ptr, - size, - align, + size: _, + align: _, } => { self.visit_reg(result); self.visit_operand(ptr); - self.visit_operand(size); - self.visit_operand(align); } StatementKind::BinOp { kind: _, diff --git a/analysis/src/lower/builder.rs b/analysis/src/lower/builder.rs index fa2dd3b..b4ed57f 100644 --- a/analysis/src/lower/builder.rs +++ b/analysis/src/lower/builder.rs @@ -118,8 +118,8 @@ impl<'a, 'cx> FuncBuilder<'a, 'cx> { let stmt = StatementKind::Load { result: reg, ptr, - size: Operand::const_u64(tyl.layout.size), - align: Operand::const_u64(tyl.layout.align), + size: tyl.layout.size, + align: tyl.layout.align, }; self.cur_bb_mut() .statements @@ -131,8 +131,8 @@ impl<'a, 'cx> FuncBuilder<'a, 'cx> { let stmt = StatementKind::Store { ptr, value: rhs, - size: Operand::const_u64(layout.size), - align: Operand::const_u64(layout.align), + size: layout.size, + align: layout.align, }; self.cur_bb_mut() .statements diff --git a/codegen/src/lib.rs b/codegen/src/lib.rs index a82d069..e5f341e 100644 --- a/codegen/src/lib.rs +++ b/codegen/src/lib.rs @@ -11,7 +11,7 @@ use object::{ }; use parser::Error; -type Result = std::result::Result; +type Result = std::result::Result; pub fn generate<'cx>(lcx: &'cx LoweringCx<'cx>, ir: &Ir<'cx>) -> Result<()> { let mut obj = Object::new( diff --git a/codegen/src/x86_64.rs b/codegen/src/x86_64.rs index 1d48ab4..a217e97 100644 --- a/codegen/src/x86_64.rs +++ b/codegen/src/x86_64.rs @@ -24,15 +24,12 @@ //! | %r11 | temporary register | No | //! | %r12-r14 | callee-saved registers | Yes | //! | %r15 | callee-saved register; optionally used as GOT base pointer | Yes | - -#![allow(unused_variables, dead_code)] - use analysis::{ ir::{self, BbIdx, Branch, Func, Location, Operand, Register, Statement, StatementKind}, LoweringCx, }; use iced_x86::{ - code_asm::{self as x, CodeAssembler}, + code_asm::{self as x, AsmRegister64, CodeAssembler}, Formatter, IcedError, NasmFormatter, }; use parser::{Error, Span}; @@ -45,19 +42,20 @@ use crate::{ trait IcedErrExt { type T; - fn sp(self, span: Span) -> Result; + fn sp(self, cx: &AsmCtxt<'_, '_>) -> Result; } impl IcedErrExt for Result { type T = T; - fn sp(self, span: Span) -> Result { - self.map_err(|e| Error::new(e.to_string(), span)) + fn sp(self, cx: &AsmCtxt<'_, '_>) -> Result { + self.map_err(|e| Error::new(e.to_string(), cx.current_span)) } } -struct AsmCtxt<'cx> { +struct AsmCtxt<'f, 'cx> { lcx: &'cx LoweringCx<'cx>, + func: &'f Func<'cx>, a: CodeAssembler, reg_map: FxHashMap, reg_occupancy: Vec>, @@ -65,21 +63,18 @@ struct AsmCtxt<'cx> { stack_layout: stack::StackLayout, + current_span: Span, + // caches last_register_uses: Vec>, } -impl<'cx> AsmCtxt<'cx> { - fn allocate_result_ssa_reg( - &mut self, - f: &Func<'_>, - reg: Register, - location: Location, - ) -> RegValue { +impl<'cx> AsmCtxt<'_, 'cx> { + fn allocate_result_ssa_reg(&mut self, reg: Register, location: Location) -> RegValue { for (i, opt_reg) in self.reg_occupancy.iter_mut().enumerate() { if let Some(reg) = opt_reg.as_mut() { if let Some(last_use) = self.last_register_uses[reg.as_usize()] { - if ir::info::dominates_location(f, last_use, location) { + if ir::info::dominates_location(self.func, last_use, location) { // The last use dominates our location - the SSA reg is dead now. *opt_reg = None; } @@ -88,28 +83,94 @@ impl<'cx> AsmCtxt<'cx> { if opt_reg.is_none() { *opt_reg = Some(reg); - return RegValue::MachineReg(MachineReg(i)); + let value = RegValue::MachineReg(MachineReg(i)); + self.reg_map.insert(reg, value); + return value; } } todo!("spill.") } - fn generate_func(&mut self, func: &Func<'cx>) -> Result<()> { + fn gen_store(&mut self, ptr: Operand, value: Operand, size: u64, _align: u64) -> Result<()> { + if size != 8 { + todo!("stores of less or more than 8 bytes: {size}"); + } + match ptr { + Operand::Const(_) => todo!("const stores not implemented"), + Operand::Reg(reg) => { + let ptr_value = self.reg_map[®]; + match (ptr_value, value) { + (RegValue::StackRelativePtr { offset }, Operand::Const(c)) => { + self.a + .mov(x::qword_ptr(x::rsp + offset), c.as_i32()) + .sp(self)?; + } + (RegValue::StackRelativePtr { offset: offset_ptr }, Operand::Reg(value)) => { + let value = self.reg_map[&value]; + match value { + RegValue::StackRelativePtr { + offset: offset_value, + } => { + self.a.mov(x::rax, x::rsp + offset_value).sp(self)?; + self.a.mov(x::rsp + offset_ptr, x::rax).sp(self)?; + } + RegValue::MachineReg(reg) => { + self.a.mov(x::rsp + offset_ptr, machine_reg_to_reg(reg)).sp(self)?; + } + RegValue::Spilled { .. } => todo!("spills"), + } + } + (RegValue::Spilled { .. }, _) => todo!("spilled"), + (RegValue::MachineReg(_), _) => todo!("machine reg"), + }; + } + } + Ok(()) + } + + fn gen_load( + &mut self, + loc: Location, + result: Register, + ptr: Operand, + size: u64, + _align: u64, + ) -> Result { + assert_eq!(size, 8); + let result = self.allocate_result_ssa_reg(result, loc); + + match (result, ptr) { + (RegValue::MachineReg(num), Operand::Reg(ptr)) => { + let into = machine_reg_to_reg(num); + + match self.reg_map[&ptr] { + RegValue::StackRelativePtr { offset } => { + self.a.mov(into, x::qword_ptr(x::rsp + offset)).sp(self)?; + } + _ => {} + } + } + _ => todo!("loading into a not-reg or from a not-reg"), + } + + Ok(()) + } + + fn generate_func(&mut self, func: &Func<'cx>) -> Result { // 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.push(x::rbp).sp(self)?; + self.a.mov(x::rbp, x::rsp).sp(self)?; self.a .sub(x::rsp, self.stack_layout.total_size as i32) - .sp(func.def_span)?; + .sp(self)?; loop { let bb = &func.bbs[self.bb_idx.as_usize()]; - for stmt in &bb.statements { - let Statement { - span: st_sp, - ref kind, - } = *stmt; + for (idx, stmt) in bb.statements.iter().enumerate() { + let loc = Location::stmt(self.bb_idx, idx); + let Statement { span, ref kind } = *stmt; + self.current_span = span; match *kind { StatementKind::Alloca { result, .. } => { @@ -130,78 +191,32 @@ impl<'cx> AsmCtxt<'cx> { size, align, } => { - let Operand::Const(size) = size else { - todo!("non const size"); - }; - if size.as_i32() != 8 { - todo!("stores of less or more than 8 bytes: {size}"); - } - match ptr { - Operand::Const(_) => todo!("const stores not implemented"), - Operand::Reg(reg) => { - let ptr_value = self.reg_map[®]; - match (ptr_value, value) { - (RegValue::StackRelativePtr { offset }, Operand::Const(c)) => { - self.a - .mov(x::qword_ptr(x::rsp + offset), c.as_i32()) - .sp(st_sp)?; - } - ( - RegValue::StackRelativePtr { offset }, - Operand::Reg(value), - ) => { - todo!("stack relative ptr + reg value") - } - (RegValue::Spilled { .. }, _) => todo!("spilled"), - (RegValue::MachineReg(_), _) => todo!("machine reg"), - }; - //let rhs = match value { - // Operand::Const(c) => {} - // Operand::Reg(reg) => {} - //}; - - // mov [rsp + OFFSET], RHS - - //self.a.add_instruction(Instruction::with2(Code::Mov, op0, op1)) - // self.a.mov(x::ptr(x::rax), x::rbx).sp(st_sp); - } - } + self.gen_store(ptr, value, size, align)?; } StatementKind::Load { result, ptr, size, align, - } => todo!("loads."), - StatementKind::BinOp { - kind, - lhs, - rhs, - result, - } => todo!("binary operations"), - StatementKind::UnaryOperation { rhs, kind, result } => { + } => { + self.gen_load(loc, result, ptr, size, align)?; + } + StatementKind::BinOp { .. } => todo!("binary operations"), + StatementKind::UnaryOperation { .. } => { todo!("unary operations") } - StatementKind::PtrOffset { - result, - ptr: reg, - amount, - } => todo!("pointer offset :D"), - StatementKind::Call { - result, - func, - ref args, - } => todo!("function calls 💀"), + StatementKind::PtrOffset { .. } => todo!("pointer offset :D"), + StatementKind::Call { .. } => todo!("function calls 💀"), } } match bb.term { Branch::Ret(_) => { // Epilogue: Restore rsp, rbp and return. - self.a.mov(x::rsp, x::rbp).sp(func.def_span)?; - self.a.pop(x::rbp).sp(func.def_span)?; - self.a.mov(x::rax, 0_u64).sp(func.def_span)?; - self.a.ret().sp(func.def_span)?; + self.a.mov(x::rsp, x::rbp).sp(self)?; + self.a.pop(x::rbp).sp(self)?; + self.a.mov(x::rax, 0_u64).sp(self)?; + self.a.ret().sp(self)?; break; } Branch::Switch { .. } => todo!("switch"), @@ -220,7 +235,7 @@ pub fn generate_func<'cx>(lcx: &'cx LoweringCx<'cx>, func: &Func<'cx>) -> Result crate::registers::debug_layout(func, &layout); let fn_sp = func.def_span; - let a = CodeAssembler::new(64).sp(fn_sp)?; + let a = CodeAssembler::new(64).unwrap(); let stack_layout = stack::allocate_stack_space(8, func); dbg!(&stack_layout); @@ -228,16 +243,18 @@ pub fn generate_func<'cx>(lcx: &'cx LoweringCx<'cx>, func: &Func<'cx>) -> Result let mut cx = AsmCtxt { lcx, a, + func, reg_map: FxHashMap::default(), reg_occupancy: vec![None; 8], bb_idx: BbIdx(0), stack_layout, + current_span: fn_sp, last_register_uses: ir::info::last_register_uses(func), }; cx.generate_func(func)?; - let code = cx.a.assemble(0x4000).sp(fn_sp)?; + let code = cx.a.assemble(0x4000).sp(&cx)?; print!("{}:\n---", func.name); let mut output = String::new(); @@ -250,3 +267,8 @@ pub fn generate_func<'cx>(lcx: &'cx LoweringCx<'cx>, func: &Func<'cx>) -> Result Ok(code) } + +fn machine_reg_to_reg(reg: MachineReg) -> AsmRegister64 { + use x::*; + [rcx, rdx, rsi, rdi, r8, r9, r11][reg.0] +}