diff --git a/src/arch/x86_64/compile.rs b/src/arch/x86_64/compile.rs index 8ed4591..a28ae45 100644 --- a/src/arch/x86_64/compile.rs +++ b/src/arch/x86_64/compile.rs @@ -1,14 +1,15 @@ use std::collections::{HashMap, HashSet, VecDeque}; use super::*; -use crate::backend::{Body, LibImport, LinkedProgram, SymImport, SymTable, Symbol, VarId}; +use crate::backend::{Body, Func, LibImport, LinkedProgram, SymImport, SymTable, Symbol, VarId}; pub struct Encoder<'a> { pub code: Code, pub sym_tab: SymTable, pub sym_refs: HashMap>, pub program: &'a Program, - pub vars: VarMap, + pub segs: Vec, + pub vars: HashMap, } pub fn compile(p: &Program) -> Result, CompilerMsg> { @@ -17,18 +18,7 @@ pub fn compile(p: &Program) -> Result, CompilerMsg> { p.encode_data(&mut encoder.code.bytes, &mut encoder.sym_tab); for f in &p.funcs { - 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, p); - } - - for f in &p.funcs { - let addr = encoder.code.bytes.len(); - encoder.sym_tab.insert(f.sym, addr as u64); - for instr in &f.body { - encoder.compile_instr(instr)?; - } + encoder.func(f); } for (pos, sym) in encoder.code.missing.drain(..) { @@ -80,133 +70,143 @@ pub struct RegUse { var: Option, } -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 uses = SegUses::default(); - macro_rules! push { - ($var:ident) => { - push!($var, 0) - }; - ($var:ident, $pos:expr) => { - uses.var - .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 ® in conv.scratch() { - uses.reg[reg as usize].push_back(RegUse { pos, var: None }); - } - for (i, &arg) in args.iter().enumerate() { - push!(arg); - if let Some(®) = conv.param().get(i) { - uses.reg[reg as usize].back_mut().unwrap().var = Some(arg); - } - } - } - BInstr::Copy { dst, src } => { - push!(dst); - push!(src); - } - BInstr::Add { dst, src1, src2 } => { - push!(dst); - push!(src1); - push!(src2); - } - BInstr::If { cond, then, else_ } => { - push!(cond); - pos += 1; - 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) { - push!(var, poss1[0].min(poss2[0])); - } else { - push!(var, poss1[0]); - } - } - for (var, poss2) in &segments[seg_i2].var { - if !segments[seg_i1].var.contains_key(var) { - push!(var, poss2[0]); - } - } - pos += len1.max(len2); - continue; - } - BInstr::Loop(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]); - } - // during register allocation, want to insert the first use of each var - // at len + use, because if it jumps back up, that will be the next - // usage rather than if the loop exits; pad ensures there is room so - // the insertions are always before the rest of the usages (after loop) - let pad = (len * 2).saturating_sub(pos); - pos += len + pad; - continue; - } - BInstr::Break(var) => { - if let Some(var) = var { - push!(var); - } - } - BInstr::Return(var) => { - if let Some(var) = var { - push!(var); - } - } - 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); - used.remove(®); - uses.reg[reg as usize].push_back(RegUse { - pos, - var: Some(var), - }); - } - for reg in used { - uses.reg[reg as usize].push_back(RegUse { pos, var: None }); - } - } - } - pos += 1; - } - segments[seg_i] = uses; - return (seg_i, pos); -} - type BInstr = crate::backend::Instr; impl<'a> Encoder<'a> { - fn compile_instr(&mut self, instr: &BInstr) -> EncodeRes { - match instr { - BInstr::Asm(asm) => self.asm(asm)?, - _ => todo!(), + fn func(&mut self, f: &Func) -> EncodeRes { + let addr = self.code.bytes.len(); + self.sym_tab.insert(f.sym, addr as u64); + self.segs.clear(); + self.calc_uses(&f.body); + for instr in &f.body { + match instr { + BInstr::Asm(asm) => self.asm(asm)?, + _ => todo!(), + } } Ok(()) } + pub fn calc_uses(&mut self, body: &Body) -> (usize, usize) { + let mut pos = 0; + let seg_i = self.segs.len(); + self.segs.push(Default::default()); + let mut uses = SegUses::default(); + macro_rules! push { + ($var:ident) => { + push!($var, 0) + }; + ($var:ident, $pos:expr) => { + uses.var + .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 = &self.program.call_convs[self.program.funcs[f].conv]; + push!(dst); + + for ® in conv.scratch() { + uses.reg[reg as usize].push_back(RegUse { pos, var: None }); + } + for (i, &arg) in args.iter().enumerate() { + push!(arg); + if let Some(®) = conv.param().get(i) { + uses.reg[reg as usize].back_mut().unwrap().var = Some(arg); + } + } + } + BInstr::Copy { dst, src } => { + push!(dst); + push!(src); + } + BInstr::Add { dst, src1, src2 } => { + push!(dst); + push!(src1); + push!(src2); + } + BInstr::If { cond, then, else_ } => { + push!(cond); + pos += 1; + let (seg_i1, len1) = self.calc_uses(then); + let (seg_i2, len2) = self.calc_uses(else_); + // insert closest usages + for (var, poss1) in &self.segs[seg_i1].var { + if let Some(poss2) = self.segs[seg_i2].var.get(var) { + push!(var, poss1[0].min(poss2[0])); + } else { + push!(var, poss1[0]); + } + } + for (var, poss2) in &self.segs[seg_i2].var { + if !self.segs[seg_i1].var.contains_key(var) { + push!(var, poss2[0]); + } + } + pos += len1.max(len2); + continue; + } + BInstr::Loop(instrs) => { + let (seg_i2, len) = self.calc_uses(instrs); + // insert closest usages + for (var, poss) in &self.segs[seg_i2].var { + push!(var, poss[0]); + } + // during register allocation, want to insert the first use of each var + // at len + use, because if it jumps back up, that will be the next + // usage rather than if the loop exits; pad ensures there is room so + // the insertions are always before the rest of the usages (after loop) + let pad = (len * 2).saturating_sub(pos); + pos += len + pad; + continue; + } + BInstr::Break(var) => { + if let Some(var) = var { + push!(var); + } + } + BInstr::Return(var) => { + if let Some(var) = var { + push!(var); + } + } + 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); + used.remove(®); + uses.reg[reg as usize].push_back(RegUse { + pos, + var: Some(var), + }); + } + for reg in used { + uses.reg[reg as usize].push_back(RegUse { pos, var: None }); + } + } + } + pos += 1; + } + self.segs[seg_i] = uses; + return (seg_i, pos); + } + + pub fn rvm(&mut self, input: Rvm) -> RegMemKind { + match input { + Rvm::Reg(reg) => reg, + Rvm::Var(var_id) => todo!(), + Rvm::Mem(mem) => todo!(), + } + } + pub fn asm(&mut self, asm: &Asm) -> EncodeRes { let mut used = HashSet::default(); let mut vars = HashSet::default(); @@ -218,9 +218,9 @@ impl<'a> Encoder<'a> { vars.insert(var); } } - let overlap = used.intersection(&self.vars.active.values()); + let overlap = used.intersection(&self.vars.values()); for var in &vars { - if let Some(reg) = self.vars.active.get(var) + if let Some(reg) = self.vars.get(var) && used.contains(reg) {} } @@ -247,20 +247,8 @@ impl<'a> Encoder<'a> { code: Code::default(), sym_tab: SymTable::new(program.sym_count()), sym_refs: Default::default(), - vars: VarMap::default(), + segs: Default::default(), program, } } } - -pub struct VarMap { - active: HashMap, -} - -impl Default for VarMap { - fn default() -> Self { - Self { - active: Default::default(), - } - } -} diff --git a/src/arch/x86_64/encode.rs b/src/arch/x86_64/encode.rs index 9ef3d00..34f6ee2 100644 --- a/src/arch/x86_64/encode.rs +++ b/src/arch/x86_64/encode.rs @@ -11,9 +11,10 @@ pub struct Code { } impl Code { - pub fn mov(&mut self, dst: impl RegMem, src: impl Into) -> EncodeRes { + pub fn mov(&mut self, dst: impl Into, src: impl Into) -> EncodeRes { let src = src.into(); - match dst.kind() { + let dst = dst.into(); + match dst { RegMemKind::Reg(mut dst) => match src { RegMemImm::Reg(src) => { if dst.width() != src.width() { @@ -162,7 +163,13 @@ impl Code { self.bytes.push(0xc3); } - fn add_sub(&mut self, dst: impl RegMem, src: impl Into, ext: u8) -> EncodeRes { + fn add_sub( + &mut self, + dst: impl Into, + src: impl Into, + ext: u8, + ) -> EncodeRes { + let dst = dst.into(); match src.into() { RegMemImm::Reg(src) => { if src.width() != dst.width() { @@ -219,11 +226,11 @@ impl Code { Ok(()) } - pub fn add(&mut self, dst: impl RegMem, src: impl Into) -> EncodeRes { + pub fn add(&mut self, dst: impl Into, src: impl Into) -> EncodeRes { self.add_sub(dst, src, 0) } - pub fn sub(&mut self, dst: impl RegMem, src: impl Into) -> EncodeRes { + pub fn sub(&mut self, dst: impl Into, src: impl Into) -> EncodeRes { self.add_sub(dst, src, 5) } diff --git a/src/arch/x86_64/types/arg.rs b/src/arch/x86_64/types/arg.rs index 632919c..7cdd04d 100644 --- a/src/arch/x86_64/types/arg.rs +++ b/src/arch/x86_64/types/arg.rs @@ -1,11 +1,6 @@ use super::*; use crate::backend::Symbol; -pub trait RegMem: RexBit + RexW + ModRMRM + Copy + MaybeMem { - fn width(&self) -> Width; - fn kind(self) -> RegMemKind; -} - #[derive(Clone, Copy)] pub enum RegMemKind { Reg(RegW), @@ -23,12 +18,12 @@ pub trait MaybeMem { fn mem(&self) -> Option; } -impl RegMem for RegW { - fn width(&self) -> Width { - self.width() - } - fn kind(self) -> RegMemKind { - RegMemKind::Reg(self) +impl RegMemKind { + pub fn width(&self) -> Width { + match self { + RegMemKind::Reg(reg) => reg.width(), + RegMemKind::Mem(mem) => todo!(), + } } }