mirror of
https://github.com/Noratrieb/uwucc.git
synced 2026-01-14 08:35:08 +01:00
stores?
This commit is contained in:
parent
46e5662aab
commit
ce2ad5a957
6 changed files with 124 additions and 110 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -112,11 +112,9 @@ impl<W: Write> PrettyPrinter<W> {
|
|||
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)
|
||||
),
|
||||
StatementKind::Load {
|
||||
result,
|
||||
|
|
@ -125,11 +123,9 @@ impl<W: Write> PrettyPrinter<W> {
|
|||
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,
|
||||
|
|
|
|||
|
|
@ -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: _,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use object::{
|
|||
};
|
||||
use parser::Error;
|
||||
|
||||
type Result<T, E = Error> = std::result::Result<T, E>;
|
||||
type Result<T = (), E = Error> = std::result::Result<T, E>;
|
||||
|
||||
pub fn generate<'cx>(lcx: &'cx LoweringCx<'cx>, ir: &Ir<'cx>) -> Result<()> {
|
||||
let mut obj = Object::new(
|
||||
|
|
|
|||
|
|
@ -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<Self::T, Error>;
|
||||
fn sp(self, cx: &AsmCtxt<'_, '_>) -> Result<Self::T, Error>;
|
||||
}
|
||||
|
||||
impl<T> IcedErrExt for Result<T, IcedError> {
|
||||
type T = T;
|
||||
|
||||
fn sp(self, span: Span) -> Result<Self::T, Error> {
|
||||
self.map_err(|e| Error::new(e.to_string(), span))
|
||||
fn sp(self, cx: &AsmCtxt<'_, '_>) -> Result<Self::T, Error> {
|
||||
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<Register, RegValue>,
|
||||
reg_occupancy: Vec<Option<Register>>,
|
||||
|
|
@ -65,21 +63,18 @@ struct AsmCtxt<'cx> {
|
|||
|
||||
stack_layout: stack::StackLayout,
|
||||
|
||||
current_span: Span,
|
||||
|
||||
// caches
|
||||
last_register_uses: Vec<Option<Location>>,
|
||||
}
|
||||
|
||||
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]
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue