This commit is contained in:
2026-07-18 16:39:35 -04:00
parent c062993130
commit 3cbd50e619
5 changed files with 148 additions and 98 deletions
+40 -36
View File
@@ -12,18 +12,13 @@ pub struct Encoder<'a> {
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct VarUse { pub struct RegUse {
pos: usize, pos: usize,
reg: Option<Reg>, // required var, if any
} var: Option<VarId>,
pub type VarUses = HashMap<VarId, VecDeque<VarUse>>;
pub type RegUses = [VecDeque<usize>; 16];
impl VarUse {
pub fn min(self, other: Self) -> Self {
if self.pos <= other.pos { self } else { other }
}
} }
pub type VarUses = HashMap<VarId, VecDeque<usize>>;
pub type RegUses = [VecDeque<RegUse>; 16];
pub fn compile(p: &Program<X86_64>) -> Result<LinkedProgram<u64>, CompilerMsg> { pub fn compile(p: &Program<X86_64>) -> Result<LinkedProgram<u64>, CompilerMsg> {
let mut encoder = Encoder::new(p); let mut encoder = Encoder::new(p);
@@ -34,7 +29,7 @@ pub fn compile(p: &Program<X86_64>) -> Result<LinkedProgram<u64>, CompilerMsg> {
let addr = encoder.code.bytes.len(); let addr = encoder.code.bytes.len();
encoder.sym_tab.insert(f.sym, addr as u64); encoder.sym_tab.insert(f.sym, addr as u64);
let mut segments = Vec::new(); let mut segments = Vec::new();
calc_uses(&mut segments, &f.body); calc_uses(&mut segments, &f.body, p);
} }
for f in &p.funcs { for f in &p.funcs {
@@ -87,36 +82,38 @@ pub struct SegUses {
reg: RegUses, reg: RegUses,
} }
pub fn calc_uses(segments: &mut Vec<SegUses>, body: &Body<X86_64>) -> (usize, usize) { pub fn calc_uses(
segments: &mut Vec<SegUses>,
body: &Body<X86_64>,
p: &Program<X86_64>,
) -> (usize, usize) {
let mut pos = 0; let mut pos = 0;
let seg_i = segments.len(); let seg_i = segments.len();
segments.push(Default::default()); segments.push(Default::default());
let mut vars = VarUses::default(); let mut vars = VarUses::default();
let mut regs = RegUses::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 { macro_rules! push {
($var:ident) => { ($var:ident) => {
push!($var, VarUse { pos: 0, reg: None }) push!($var, 0)
}; };
($var:ident, $pos:expr) => { ($var:ident, $pos:expr) => {
vars.entry($var.clone()).or_default().push_back(VarUse { vars.entry($var.clone()).or_default().push_back(pos + $pos)
pos: $pos.pos + pos,
reg: $pos.reg,
})
}; };
} }
for instr in body { for instr in body {
match instr { match instr {
BInstr::Set { dst, src: _ } => push!(dst), BInstr::Set { dst, src: _ } => push!(dst),
BInstr::Call { dst, f, args } => { BInstr::Call { dst, f, args } => {
let conv = &p.call_convs[p.funcs[f].conv];
push!(dst); push!(dst);
for (i, arg) in args.iter().enumerate() {
for &reg in conv.scratch() {
regs[reg as usize].push_back(RegUse { pos, var: None });
}
for (i, &arg) in args.iter().enumerate() {
push!(arg); push!(arg);
if i < 8 { if let Some(&reg) = conv.param().get(i) {
regs[i].push_back(pos); regs[reg as usize].back_mut().unwrap().var = Some(arg);
} }
} }
} }
@@ -132,8 +129,8 @@ pub fn calc_uses(segments: &mut Vec<SegUses>, body: &Body<X86_64>) -> (usize, us
BInstr::If { cond, then, else_ } => { BInstr::If { cond, then, else_ } => {
push!(cond); push!(cond);
pos += 1; pos += 1;
let (seg_i1, len1) = calc_uses(segments, then); let (seg_i1, len1) = calc_uses(segments, then, p);
let (seg_i2, len2) = calc_uses(segments, else_); let (seg_i2, len2) = calc_uses(segments, else_, p);
// insert closest usages // insert closest usages
for (var, poss1) in &segments[seg_i1].var { for (var, poss1) in &segments[seg_i1].var {
if let Some(poss2) = segments[seg_i2].var.get(var) { if let Some(poss2) = segments[seg_i2].var.get(var) {
@@ -151,7 +148,7 @@ pub fn calc_uses(segments: &mut Vec<SegUses>, body: &Body<X86_64>) -> (usize, us
continue; continue;
} }
BInstr::Loop(instrs) => { BInstr::Loop(instrs) => {
let (seg_i2, len) = calc_uses(segments, instrs); let (seg_i2, len) = calc_uses(segments, instrs, p);
// insert closest usages // insert closest usages
for (var, poss) in &segments[seg_i2].var { for (var, poss) in &segments[seg_i2].var {
push!(var, poss[0]); push!(var, poss[0]);
@@ -175,15 +172,22 @@ pub fn calc_uses(segments: &mut Vec<SegUses>, body: &Body<X86_64>) -> (usize, us
} }
} }
BInstr::Asm(asm) => { 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 { for &(reg, var) in &asm.args {
push!( push!(var);
var, used.remove(&reg);
VarUse { regs[reg as usize].push_back(RegUse {
pos: 0, pos,
reg: Some(reg) var: Some(var),
} });
); }
regs[reg as usize].push_back(pos); 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 used = HashSet::default();
let mut vars = HashSet::default(); let mut vars = HashSet::default();
for &instr in &asm.instrs { for &instr in &asm.instrs {
if let Some(regw) = instr.regw_set() { if let Some(regw) = instr.dst_reg() {
used.insert(regw.reg()); used.insert(regw.reg());
} }
for var in instr.vars() { for var in instr.vars() {
+23 -3
View File
@@ -28,7 +28,27 @@ impl Arch for X86_64 {
} }
} }
pub struct CallConv { pub enum CallConv {
volatile: Vec<Reg>, SystemV,
nonvolatile: Vec<Reg>, }
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],
}
}
} }
+1 -1
View File
@@ -21,7 +21,7 @@ pub enum Instr {
} }
impl Instr { impl Instr {
pub fn regw_set(&self) -> Option<RegW> { pub fn dst_reg(&self) -> Option<RegW> {
match self { match self {
Instr::Mov { dst, src: _ } => dst.reg(), Instr::Mov { dst, src: _ } => dst.reg(),
Instr::Push(_) => None, Instr::Push(_) => None,
+64 -58
View File
@@ -124,67 +124,73 @@ use filter;
macro_rules! def_regs { macro_rules! def_regs {
($reg:ident; $($val:literal : $B64:ident $B32:ident $B16:ident $B8:ident $(norex=$B8H:ident)? $(!$imp:tt)?,)*) => { ($reg:ident; $($val:literal : $B64:ident $B32:ident $B16:ident $B8:ident $(norex=$B8H:ident)? $(!$imp:tt)?,)*) => {
$( pub mod regs {
#[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<Self> {
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)] #[allow(non_upper_case_globals)]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { pub const $B64: u8 = $val;
write!(f, "{}", match *self { )*
$( }
$B64 => stringify!($B64), pub mod regws {
$B32 => stringify!($B32), use super::*;
$B16 => stringify!($B16), $(
$B8 => stringify!($B8), #[allow(non_upper_case_globals)]
$( pub const $B64: $reg = $reg::new($val, Width::B64, false);
$B8H => stringify!($B8H), #[allow(non_upper_case_globals)]
)? pub const $B32: $reg = $reg::new($val, Width::B32, false);
)* #[allow(non_upper_case_globals)]
_ => "UNKNOWN", 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<Self> {
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 def_regs;
use crate::arch::x86_64::Imm;
+20
View File
@@ -1,5 +1,21 @@
ids!(VarId FnId); ids!(VarId FnId);
impl<A: Arch> Index<FnId> for Vec<Func<A>> {
type Output = Func<A>;
fn index(&self, index: FnId) -> &Self::Output {
&self[index.0]
}
}
impl<A: Arch> Index<&FnId> for Vec<Func<A>> {
type Output = Func<A>;
fn index(&self, index: &FnId) -> &Self::Output {
&self[index.0]
}
}
macro_rules! ids { macro_rules! ids {
($($name:ident)*) => { ($($name:ident)*) => {
$( $(
@@ -8,4 +24,8 @@ macro_rules! ids {
)* )*
}; };
} }
use std::ops::Index;
use ids; use ids;
use crate::{arch::Arch, backend::Func};