From 3cbd50e619d5856e1477d1eab9e5154e3f358558 Mon Sep 17 00:00:00 2001 From: Shadow Cat Date: Sat, 18 Jul 2026 16:39:35 -0400 Subject: [PATCH] work --- src/arch/x86_64/compile.rs | 76 +++++++++++----------- src/arch/x86_64/mod.rs | 26 +++++++- src/arch/x86_64/types/asm.rs | 2 +- src/arch/x86_64/types/reg.rs | 122 ++++++++++++++++++----------------- src/backend/ir/id.rs | 20 ++++++ 5 files changed, 148 insertions(+), 98 deletions(-) diff --git a/src/arch/x86_64/compile.rs b/src/arch/x86_64/compile.rs index e2bcb07..f393e7c 100644 --- a/src/arch/x86_64/compile.rs +++ b/src/arch/x86_64/compile.rs @@ -12,18 +12,13 @@ pub struct Encoder<'a> { } #[derive(Clone, Copy)] -pub struct VarUse { +pub struct RegUse { pos: usize, - reg: Option, -} -pub type VarUses = HashMap>; -pub type RegUses = [VecDeque; 16]; - -impl VarUse { - pub fn min(self, other: Self) -> Self { - if self.pos <= other.pos { self } else { other } - } + // required var, if any + var: Option, } +pub type VarUses = HashMap>; +pub type RegUses = [VecDeque; 16]; pub fn compile(p: &Program) -> Result, CompilerMsg> { let mut encoder = Encoder::new(p); @@ -34,7 +29,7 @@ pub fn compile(p: &Program) -> Result, CompilerMsg> { let addr = encoder.code.bytes.len(); encoder.sym_tab.insert(f.sym, addr as u64); let mut segments = Vec::new(); - calc_uses(&mut segments, &f.body); + calc_uses(&mut segments, &f.body, p); } for f in &p.funcs { @@ -87,36 +82,38 @@ pub struct SegUses { reg: RegUses, } -pub fn calc_uses(segments: &mut Vec, body: &Body) -> (usize, usize) { +pub fn calc_uses( + segments: &mut Vec, + body: &Body, + p: &Program, +) -> (usize, usize) { let mut pos = 0; let seg_i = segments.len(); segments.push(Default::default()); let mut vars = VarUses::default(); let mut regs = RegUses::default(); - let volatile = [ - rax, rbx, rcx, rdx, rbp, rsp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15, - ] - .map(|r| r.reg()); macro_rules! push { ($var:ident) => { - push!($var, VarUse { pos: 0, reg: None }) + push!($var, 0) }; ($var:ident, $pos:expr) => { - vars.entry($var.clone()).or_default().push_back(VarUse { - pos: $pos.pos + pos, - reg: $pos.reg, - }) + vars.entry($var.clone()).or_default().push_back(pos + $pos) }; } for instr in body { match instr { BInstr::Set { dst, src: _ } => push!(dst), BInstr::Call { dst, f, args } => { + let conv = &p.call_convs[p.funcs[f].conv]; push!(dst); - for (i, arg) in args.iter().enumerate() { + + for ® in conv.scratch() { + regs[reg as usize].push_back(RegUse { pos, var: None }); + } + for (i, &arg) in args.iter().enumerate() { push!(arg); - if i < 8 { - regs[i].push_back(pos); + if let Some(®) = conv.param().get(i) { + regs[reg as usize].back_mut().unwrap().var = Some(arg); } } } @@ -132,8 +129,8 @@ pub fn calc_uses(segments: &mut Vec, body: &Body) -> (usize, us BInstr::If { cond, then, else_ } => { push!(cond); pos += 1; - let (seg_i1, len1) = calc_uses(segments, then); - let (seg_i2, len2) = calc_uses(segments, else_); + let (seg_i1, len1) = calc_uses(segments, then, p); + let (seg_i2, len2) = calc_uses(segments, else_, p); // insert closest usages for (var, poss1) in &segments[seg_i1].var { if let Some(poss2) = segments[seg_i2].var.get(var) { @@ -151,7 +148,7 @@ pub fn calc_uses(segments: &mut Vec, body: &Body) -> (usize, us continue; } BInstr::Loop(instrs) => { - let (seg_i2, len) = calc_uses(segments, instrs); + let (seg_i2, len) = calc_uses(segments, instrs, p); // insert closest usages for (var, poss) in &segments[seg_i2].var { push!(var, poss[0]); @@ -175,15 +172,22 @@ pub fn calc_uses(segments: &mut Vec, body: &Body) -> (usize, us } } BInstr::Asm(asm) => { + let mut used = HashSet::new(); + for i in &asm.instrs { + if let Some(reg) = i.dst_reg() { + used.insert(reg.reg()); + } + } for &(reg, var) in &asm.args { - push!( - var, - VarUse { - pos: 0, - reg: Some(reg) - } - ); - regs[reg as usize].push_back(pos); + push!(var); + used.remove(®); + regs[reg as usize].push_back(RegUse { + pos, + var: Some(var), + }); + } + for reg in used { + regs[reg as usize].push_back(RegUse { pos, var: None }); } } } @@ -208,7 +212,7 @@ impl<'a> Encoder<'a> { let mut used = HashSet::default(); let mut vars = HashSet::default(); for &instr in &asm.instrs { - if let Some(regw) = instr.regw_set() { + if let Some(regw) = instr.dst_reg() { used.insert(regw.reg()); } for var in instr.vars() { diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs index a39118f..ba0b18d 100644 --- a/src/arch/x86_64/mod.rs +++ b/src/arch/x86_64/mod.rs @@ -28,7 +28,27 @@ impl Arch for X86_64 { } } -pub struct CallConv { - volatile: Vec, - nonvolatile: Vec, +pub enum CallConv { + SystemV, +} + +impl CallConv { + pub fn param(&self) -> &[Reg] { + use regs::*; + match self { + Self::SystemV => &[rdi, rsi, rdx, rcx, r8, r9], + } + } + pub fn scratch(&self) -> &[Reg] { + use regs::*; + match self { + Self::SystemV => &[rax, rdi, rsi, rdx, rcx, r8, r9, r10, r11], + } + } + pub fn ret(&self) -> &[Reg] { + use regs::*; + match self { + Self::SystemV => &[rax, rdx], + } + } } diff --git a/src/arch/x86_64/types/asm.rs b/src/arch/x86_64/types/asm.rs index b567ae3..bff8e4c 100644 --- a/src/arch/x86_64/types/asm.rs +++ b/src/arch/x86_64/types/asm.rs @@ -21,7 +21,7 @@ pub enum Instr { } impl Instr { - pub fn regw_set(&self) -> Option { + pub fn dst_reg(&self) -> Option { match self { Instr::Mov { dst, src: _ } => dst.reg(), Instr::Push(_) => None, diff --git a/src/arch/x86_64/types/reg.rs b/src/arch/x86_64/types/reg.rs index 0a471c8..851a89a 100644 --- a/src/arch/x86_64/types/reg.rs +++ b/src/arch/x86_64/types/reg.rs @@ -124,67 +124,73 @@ use filter; macro_rules! def_regs { ($reg:ident; $($val:literal : $B64:ident $B32:ident $B16:ident $B8:ident $(norex=$B8H:ident)? $(!$imp:tt)?,)*) => { - $( - #[allow(non_upper_case_globals)] - pub const $B64: $reg = $reg::new($val, Width::B64, false); - #[allow(non_upper_case_globals)] - pub const $B32: $reg = $reg::new($val, Width::B32, false); - #[allow(non_upper_case_globals)] - pub const $B16: $reg = $reg::new($val, Width::B16, false); - #[allow(non_upper_case_globals)] - pub const $B8 : $reg = $reg::new($val, Width::B8 , false); - $( - #[allow(non_upper_case_globals)] - pub const $B8H: $reg = $reg::new($val, Width::B8, true); - )? - )* - - impl $reg { - // #[cfg(test)] - // pub const ALL: &[$reg] = &[ - // $( $B64, $B32, $B16, $B8, $($B8H,)? )* - // ]; - - #[cfg(test)] - pub const IMPORTANT: &[$reg] = & - filter!(; $($(!$imp)? $B64 $B32 $B16 $B8 $($B8H)?; )* ) - ; - - pub fn parse(s: &str) -> Option { - Some(match s.to_lowercase().as_str() { - $( - stringify!($B64) => $B64, - stringify!($B32) => $B32, - stringify!($B16) => $B16, - stringify!($B8 ) => $B8, - $( - stringify!($B8H) => $B8H, - )? - )* - _ => return None, - }) - } - } - impl std::fmt::Display for $reg { + pub mod regs { + $( #[allow(non_upper_case_globals)] - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", match *self { - $( - $B64 => stringify!($B64), - $B32 => stringify!($B32), - $B16 => stringify!($B16), - $B8 => stringify!($B8), - $( - $B8H => stringify!($B8H), - )? - )* - _ => "UNKNOWN", - }) + pub const $B64: u8 = $val; + )* + } + pub mod regws { + use super::*; + $( + #[allow(non_upper_case_globals)] + pub const $B64: $reg = $reg::new($val, Width::B64, false); + #[allow(non_upper_case_globals)] + pub const $B32: $reg = $reg::new($val, Width::B32, false); + #[allow(non_upper_case_globals)] + pub const $B16: $reg = $reg::new($val, Width::B16, false); + #[allow(non_upper_case_globals)] + pub const $B8 : $reg = $reg::new($val, Width::B8 , false); + $( + #[allow(non_upper_case_globals)] + pub const $B8H: $reg = $reg::new($val, Width::B8, true); + )? + )* + + impl $reg { + // #[cfg(test)] + // pub const ALL: &[$reg] = &[ + // $( $B64, $B32, $B16, $B8, $($B8H,)? )* + // ]; + + #[cfg(test)] + pub const IMPORTANT: &[$reg] = & + filter!(; $($(!$imp)? $B64 $B32 $B16 $B8 $($B8H)?; )* ) + ; + + pub fn parse(s: &str) -> Option { + Some(match s.to_lowercase().as_str() { + $( + stringify!($B64) => $B64, + stringify!($B32) => $B32, + stringify!($B16) => $B16, + stringify!($B8 ) => $B8, + $( + stringify!($B8H) => $B8H, + )? + )* + _ => return None, + }) + } + } + impl std::fmt::Display for $reg { + #[allow(non_upper_case_globals)] + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", match *self { + $( + $B64 => stringify!($B64), + $B32 => stringify!($B32), + $B16 => stringify!($B16), + $B8 => stringify!($B8), + $( + $B8H => stringify!($B8H), + )? + )* + _ => "UNKNOWN", + }) + } } } }; } - use def_regs; - -use crate::arch::x86_64::Imm; diff --git a/src/backend/ir/id.rs b/src/backend/ir/id.rs index c152fbe..a28ef87 100644 --- a/src/backend/ir/id.rs +++ b/src/backend/ir/id.rs @@ -1,5 +1,21 @@ ids!(VarId FnId); +impl Index for Vec> { + type Output = Func; + + fn index(&self, index: FnId) -> &Self::Output { + &self[index.0] + } +} + +impl Index<&FnId> for Vec> { + type Output = Func; + + fn index(&self, index: &FnId) -> &Self::Output { + &self[index.0] + } +} + macro_rules! ids { ($($name:ident)*) => { $( @@ -8,4 +24,8 @@ macro_rules! ids { )* }; } +use std::ops::Index; + use ids; + +use crate::{arch::Arch, backend::Func};