work
This commit is contained in:
+41
-53
@@ -1,14 +1,15 @@
|
|||||||
use std::collections::{HashMap, HashSet, VecDeque};
|
use std::collections::{HashMap, HashSet, VecDeque};
|
||||||
|
|
||||||
use super::*;
|
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 struct Encoder<'a> {
|
||||||
pub code: Code,
|
pub code: Code,
|
||||||
pub sym_tab: SymTable<u64>,
|
pub sym_tab: SymTable<u64>,
|
||||||
pub sym_refs: HashMap<Symbol, Vec<usize>>,
|
pub sym_refs: HashMap<Symbol, Vec<usize>>,
|
||||||
pub program: &'a Program<X86_64>,
|
pub program: &'a Program<X86_64>,
|
||||||
pub vars: VarMap,
|
pub segs: Vec<SegUses>,
|
||||||
|
pub vars: HashMap<VarId, Reg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile(p: &Program<X86_64>) -> Result<LinkedProgram<u64>, CompilerMsg> {
|
pub fn compile(p: &Program<X86_64>) -> Result<LinkedProgram<u64>, CompilerMsg> {
|
||||||
@@ -17,18 +18,7 @@ pub fn compile(p: &Program<X86_64>) -> Result<LinkedProgram<u64>, CompilerMsg> {
|
|||||||
p.encode_data(&mut encoder.code.bytes, &mut encoder.sym_tab);
|
p.encode_data(&mut encoder.code.bytes, &mut encoder.sym_tab);
|
||||||
|
|
||||||
for f in &p.funcs {
|
for f in &p.funcs {
|
||||||
let addr = encoder.code.bytes.len();
|
encoder.func(f);
|
||||||
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)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (pos, sym) in encoder.code.missing.drain(..) {
|
for (pos, sym) in encoder.code.missing.drain(..) {
|
||||||
@@ -80,14 +70,26 @@ pub struct RegUse {
|
|||||||
var: Option<VarId>,
|
var: Option<VarId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn calc_uses(
|
type BInstr = crate::backend::Instr<X86_64>;
|
||||||
segments: &mut Vec<SegUses>,
|
impl<'a> Encoder<'a> {
|
||||||
body: &Body<X86_64>,
|
fn func(&mut self, f: &Func<X86_64>) -> EncodeRes {
|
||||||
p: &Program<X86_64>,
|
let addr = self.code.bytes.len();
|
||||||
) -> (usize, usize) {
|
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<X86_64>) -> (usize, usize) {
|
||||||
let mut pos = 0;
|
let mut pos = 0;
|
||||||
let seg_i = segments.len();
|
let seg_i = self.segs.len();
|
||||||
segments.push(Default::default());
|
self.segs.push(Default::default());
|
||||||
let mut uses = SegUses::default();
|
let mut uses = SegUses::default();
|
||||||
macro_rules! push {
|
macro_rules! push {
|
||||||
($var:ident) => {
|
($var:ident) => {
|
||||||
@@ -104,7 +106,7 @@ pub fn calc_uses(
|
|||||||
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];
|
let conv = &self.program.call_convs[self.program.funcs[f].conv];
|
||||||
push!(dst);
|
push!(dst);
|
||||||
|
|
||||||
for ® in conv.scratch() {
|
for ® in conv.scratch() {
|
||||||
@@ -129,18 +131,18 @@ pub fn calc_uses(
|
|||||||
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, p);
|
let (seg_i1, len1) = self.calc_uses(then);
|
||||||
let (seg_i2, len2) = calc_uses(segments, else_, p);
|
let (seg_i2, len2) = self.calc_uses(else_);
|
||||||
// insert closest usages
|
// insert closest usages
|
||||||
for (var, poss1) in &segments[seg_i1].var {
|
for (var, poss1) in &self.segs[seg_i1].var {
|
||||||
if let Some(poss2) = segments[seg_i2].var.get(var) {
|
if let Some(poss2) = self.segs[seg_i2].var.get(var) {
|
||||||
push!(var, poss1[0].min(poss2[0]));
|
push!(var, poss1[0].min(poss2[0]));
|
||||||
} else {
|
} else {
|
||||||
push!(var, poss1[0]);
|
push!(var, poss1[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (var, poss2) in &segments[seg_i2].var {
|
for (var, poss2) in &self.segs[seg_i2].var {
|
||||||
if !segments[seg_i1].var.contains_key(var) {
|
if !self.segs[seg_i1].var.contains_key(var) {
|
||||||
push!(var, poss2[0]);
|
push!(var, poss2[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -148,9 +150,9 @@ pub fn calc_uses(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
BInstr::Loop(instrs) => {
|
BInstr::Loop(instrs) => {
|
||||||
let (seg_i2, len) = calc_uses(segments, instrs, p);
|
let (seg_i2, len) = self.calc_uses(instrs);
|
||||||
// insert closest usages
|
// insert closest usages
|
||||||
for (var, poss) in &segments[seg_i2].var {
|
for (var, poss) in &self.segs[seg_i2].var {
|
||||||
push!(var, poss[0]);
|
push!(var, poss[0]);
|
||||||
}
|
}
|
||||||
// during register allocation, want to insert the first use of each var
|
// during register allocation, want to insert the first use of each var
|
||||||
@@ -193,18 +195,16 @@ pub fn calc_uses(
|
|||||||
}
|
}
|
||||||
pos += 1;
|
pos += 1;
|
||||||
}
|
}
|
||||||
segments[seg_i] = uses;
|
self.segs[seg_i] = uses;
|
||||||
return (seg_i, pos);
|
return (seg_i, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
type BInstr = crate::backend::Instr<X86_64>;
|
pub fn rvm(&mut self, input: Rvm) -> RegMemKind {
|
||||||
impl<'a> Encoder<'a> {
|
match input {
|
||||||
fn compile_instr(&mut self, instr: &BInstr) -> EncodeRes {
|
Rvm::Reg(reg) => reg,
|
||||||
match instr {
|
Rvm::Var(var_id) => todo!(),
|
||||||
BInstr::Asm(asm) => self.asm(asm)?,
|
Rvm::Mem(mem) => todo!(),
|
||||||
_ => todo!(),
|
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn asm(&mut self, asm: &Asm) -> EncodeRes {
|
pub fn asm(&mut self, asm: &Asm) -> EncodeRes {
|
||||||
@@ -218,9 +218,9 @@ impl<'a> Encoder<'a> {
|
|||||||
vars.insert(var);
|
vars.insert(var);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let overlap = used.intersection(&self.vars.active.values());
|
let overlap = used.intersection(&self.vars.values());
|
||||||
for var in &vars {
|
for var in &vars {
|
||||||
if let Some(reg) = self.vars.active.get(var)
|
if let Some(reg) = self.vars.get(var)
|
||||||
&& used.contains(reg)
|
&& used.contains(reg)
|
||||||
{}
|
{}
|
||||||
}
|
}
|
||||||
@@ -247,20 +247,8 @@ impl<'a> Encoder<'a> {
|
|||||||
code: Code::default(),
|
code: Code::default(),
|
||||||
sym_tab: SymTable::new(program.sym_count()),
|
sym_tab: SymTable::new(program.sym_count()),
|
||||||
sym_refs: Default::default(),
|
sym_refs: Default::default(),
|
||||||
vars: VarMap::default(),
|
segs: Default::default(),
|
||||||
program,
|
program,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct VarMap {
|
|
||||||
active: HashMap<VarId, Reg>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for VarMap {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
active: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ pub struct Code {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Code {
|
impl Code {
|
||||||
pub fn mov(&mut self, dst: impl RegMem, src: impl Into<RegMemImm>) -> EncodeRes {
|
pub fn mov(&mut self, dst: impl Into<RegMemKind>, src: impl Into<RegMemImm>) -> EncodeRes {
|
||||||
let src = src.into();
|
let src = src.into();
|
||||||
match dst.kind() {
|
let dst = dst.into();
|
||||||
|
match dst {
|
||||||
RegMemKind::Reg(mut dst) => match src {
|
RegMemKind::Reg(mut dst) => match src {
|
||||||
RegMemImm::Reg(src) => {
|
RegMemImm::Reg(src) => {
|
||||||
if dst.width() != src.width() {
|
if dst.width() != src.width() {
|
||||||
@@ -162,7 +163,13 @@ impl Code {
|
|||||||
self.bytes.push(0xc3);
|
self.bytes.push(0xc3);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_sub(&mut self, dst: impl RegMem, src: impl Into<RegMemImm>, ext: u8) -> EncodeRes {
|
fn add_sub(
|
||||||
|
&mut self,
|
||||||
|
dst: impl Into<RegMemKind>,
|
||||||
|
src: impl Into<RegMemImm>,
|
||||||
|
ext: u8,
|
||||||
|
) -> EncodeRes {
|
||||||
|
let dst = dst.into();
|
||||||
match src.into() {
|
match src.into() {
|
||||||
RegMemImm::Reg(src) => {
|
RegMemImm::Reg(src) => {
|
||||||
if src.width() != dst.width() {
|
if src.width() != dst.width() {
|
||||||
@@ -219,11 +226,11 @@ impl Code {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(&mut self, dst: impl RegMem, src: impl Into<RegMemImm>) -> EncodeRes {
|
pub fn add(&mut self, dst: impl Into<RegMemKind>, src: impl Into<RegMemImm>) -> EncodeRes {
|
||||||
self.add_sub(dst, src, 0)
|
self.add_sub(dst, src, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sub(&mut self, dst: impl RegMem, src: impl Into<RegMemImm>) -> EncodeRes {
|
pub fn sub(&mut self, dst: impl Into<RegMemKind>, src: impl Into<RegMemImm>) -> EncodeRes {
|
||||||
self.add_sub(dst, src, 5)
|
self.add_sub(dst, src, 5)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::backend::Symbol;
|
use crate::backend::Symbol;
|
||||||
|
|
||||||
pub trait RegMem: RexBit + RexW + ModRMRM + Copy + MaybeMem {
|
|
||||||
fn width(&self) -> Width;
|
|
||||||
fn kind(self) -> RegMemKind;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum RegMemKind {
|
pub enum RegMemKind {
|
||||||
Reg(RegW),
|
Reg(RegW),
|
||||||
@@ -23,12 +18,12 @@ pub trait MaybeMem {
|
|||||||
fn mem(&self) -> Option<Mem>;
|
fn mem(&self) -> Option<Mem>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RegMem for RegW {
|
impl RegMemKind {
|
||||||
fn width(&self) -> Width {
|
pub fn width(&self) -> Width {
|
||||||
self.width()
|
match self {
|
||||||
|
RegMemKind::Reg(reg) => reg.width(),
|
||||||
|
RegMemKind::Mem(mem) => todo!(),
|
||||||
}
|
}
|
||||||
fn kind(self) -> RegMemKind {
|
|
||||||
RegMemKind::Reg(self)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user