work
This commit is contained in:
+40
-36
@@ -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 ® 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(®) = 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(®);
|
||||||
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
@@ -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],
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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;
|
|
||||||
|
|||||||
@@ -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};
|
||||||
|
|||||||
Reference in New Issue
Block a user