This commit is contained in:
2026-07-18 13:33:59 -04:00
parent 6cc81d7a5c
commit c062993130
14 changed files with 429 additions and 68 deletions
+1
View File
@@ -9,5 +9,6 @@ pub trait Arch: Sized {
const NAME: &str; const NAME: &str;
type Asm; type Asm;
type Addr: Addr; type Addr: Addr;
type CallConv;
fn compile(p: &Program<Self>) -> Result<LinkedProgram<Self::Addr>, CompilerMsg>; fn compile(p: &Program<Self>) -> Result<LinkedProgram<Self::Addr>, CompilerMsg>;
} }
+188 -8
View File
@@ -1,14 +1,28 @@
use std::collections::HashMap; use std::collections::{HashMap, HashSet, VecDeque};
use super::*; use super::*;
use crate::backend::{LibImport, LinkedProgram, SymImport, SymTable, Symbol}; use crate::backend::{Body, LibImport, LinkedProgram, SymImport, SymTable, Symbol, VarId};
use util::*;
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,
}
#[derive(Clone, Copy)]
pub struct VarUse {
pos: usize,
reg: Option<Reg>,
}
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 fn compile(p: &Program<X86_64>) -> Result<LinkedProgram<u64>, CompilerMsg> { pub fn compile(p: &Program<X86_64>) -> Result<LinkedProgram<u64>, CompilerMsg> {
@@ -19,7 +33,14 @@ pub fn compile(p: &Program<X86_64>) -> Result<LinkedProgram<u64>, CompilerMsg> {
for f in &p.funcs { for f in &p.funcs {
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);
for instr in &f.instrs { let mut segments = Vec::new();
calc_uses(&mut segments, &f.body);
}
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.compile_instr(instr)?;
} }
} }
@@ -60,24 +81,183 @@ pub fn compile(p: &Program<X86_64>) -> Result<LinkedProgram<u64>, CompilerMsg> {
}) })
} }
#[derive(Default)]
pub struct SegUses {
var: VarUses,
reg: RegUses,
}
pub fn calc_uses(segments: &mut Vec<SegUses>, body: &Body<X86_64>) -> (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 })
};
($var:ident, $pos:expr) => {
vars.entry($var.clone()).or_default().push_back(VarUse {
pos: $pos.pos + pos,
reg: $pos.reg,
})
};
}
for instr in body {
match instr {
BInstr::Set { dst, src: _ } => push!(dst),
BInstr::Call { dst, f, args } => {
push!(dst);
for (i, arg) in args.iter().enumerate() {
push!(arg);
if i < 8 {
regs[i].push_back(pos);
}
}
}
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);
let (seg_i2, len2) = calc_uses(segments, else_);
// 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);
// 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) => {
for &(reg, var) in &asm.args {
push!(
var,
VarUse {
pos: 0,
reg: Some(reg)
}
);
regs[reg as usize].push_back(pos);
}
}
}
pos += 1;
}
segments[seg_i].var = vars;
segments[seg_i].reg = regs;
return (seg_i, pos);
}
type BInstr = crate::backend::Instr<X86_64>; type BInstr = crate::backend::Instr<X86_64>;
impl<'a> Encoder<'a> { impl<'a> Encoder<'a> {
fn compile_instr(&mut self, instr: &BInstr) -> Result<(), CompilerMsg> { fn compile_instr(&mut self, instr: &BInstr) -> EncodeRes {
match instr { match instr {
BInstr::Asm(asm) => { BInstr::Asm(asm) => self.asm(asm)?,
self.code.extend(asm);
}
_ => todo!(), _ => todo!(),
} }
Ok(()) Ok(())
} }
pub fn asm(&mut self, asm: &Asm) -> EncodeRes {
let mut used = HashSet::default();
let mut vars = HashSet::default();
for &instr in &asm.instrs {
if let Some(regw) = instr.regw_set() {
used.insert(regw.reg());
}
for var in instr.vars() {
vars.insert(var);
}
}
let overlap = used.intersection(&self.vars.active.values());
for var in &vars {
if let Some(reg) = self.vars.active.get(var)
&& used.contains(reg)
{}
}
for &instr in &asm.instrs {
match instr {
Instr::Mov { dst, src } => self.code.mov(dst, src)?,
Instr::Push(rvmi) => todo!(),
Instr::Pop(rvm) => todo!(),
Instr::Lea { dst, src } => todo!(),
Instr::Int(code) => self.code.int(code),
Instr::Syscall => self.code.syscall(),
Instr::Call(sym) => self.code.call(sym),
Instr::CallAt(sym) => self.code.call_mem(sym),
Instr::Ret => self.code.ret(),
Instr::Add { dst, src } => todo!(),
Instr::Sub { dst, src } => todo!(),
}
}
Ok(())
}
pub fn new(program: &'a Program<X86_64>) -> Self { pub fn new(program: &'a Program<X86_64>) -> Self {
Self { Self {
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(),
program, program,
} }
} }
} }
pub struct VarMap {
active: HashMap<VarId, Reg>,
}
impl Default for VarMap {
fn default() -> Self {
Self {
active: Default::default(),
}
}
}
+9 -9
View File
@@ -1,7 +1,7 @@
use super::*; use super::*;
use crate::backend::Symbol; use crate::backend::Symbol;
type ERes = Result<(), CompilerMsg>; pub type EncodeRes = Result<(), CompilerMsg>;
/// machine code /// machine code
#[derive(Default)] #[derive(Default)]
@@ -11,7 +11,7 @@ pub struct Code {
} }
impl Code { impl Code {
pub fn mov(&mut self, dst: impl RegMem, src: impl Into<RegMemImm>) -> ERes { pub fn mov(&mut self, dst: impl RegMem, src: impl Into<RegMemImm>) -> EncodeRes {
let src = src.into(); let src = src.into();
match dst.kind() { match dst.kind() {
RegMemKind::Reg(mut dst) => match src { RegMemKind::Reg(mut dst) => match src {
@@ -92,7 +92,7 @@ impl Code {
Ok(()) Ok(())
} }
pub fn push(&mut self, reg: impl Into<RegMemImm>) -> ERes { pub fn push(&mut self, reg: impl Into<RegMemImm>) -> EncodeRes {
match reg.into() { match reg.into() {
RegMemImm::Reg(reg) => match reg.width() { RegMemImm::Reg(reg) => match reg.width() {
Width::B64 => { Width::B64 => {
@@ -120,7 +120,7 @@ impl Code {
Ok(()) Ok(())
} }
pub fn pop(&mut self, reg: Reg) -> ERes { pub fn pop(&mut self, reg: RegW) -> EncodeRes {
match reg.width() { match reg.width() {
Width::B64 | Width::B16 => (), Width::B64 | Width::B16 => (),
_ => return Err("register must be 64 or 16 bit".into()), _ => return Err("register must be 64 or 16 bit".into()),
@@ -133,7 +133,7 @@ impl Code {
Ok(()) Ok(())
} }
pub fn lea(&mut self, dst: Reg, sym: Symbol) -> ERes { pub fn lea(&mut self, dst: RegW, sym: Symbol) -> EncodeRes {
self.rex(1, dst, 0, 0)?; self.rex(1, dst, 0, 0)?;
self.bytes.push(0x8d); self.bytes.push(0x8d);
self.modrm(dst, sym); self.modrm(dst, sym);
@@ -162,7 +162,7 @@ impl Code {
self.bytes.push(0xc3); self.bytes.push(0xc3);
} }
fn add_sub(&mut self, dst: impl RegMem, src: impl Into<RegMemImm>, ext: u8) -> ERes { fn add_sub(&mut self, dst: impl RegMem, src: impl Into<RegMemImm>, ext: u8) -> EncodeRes {
match src.into() { match src.into() {
RegMemImm::Reg(src) => { RegMemImm::Reg(src) => {
if src.width() != dst.width() { if src.width() != dst.width() {
@@ -219,11 +219,11 @@ impl Code {
Ok(()) Ok(())
} }
pub fn add(&mut self, dst: impl RegMem, src: impl Into<RegMemImm>) -> ERes { pub fn add(&mut self, dst: impl RegMem, 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>) -> ERes { pub fn sub(&mut self, dst: impl RegMem, src: impl Into<RegMemImm>) -> EncodeRes {
self.add_sub(dst, src, 5) self.add_sub(dst, src, 5)
} }
@@ -245,7 +245,7 @@ impl Code {
Ok(()) Ok(())
} }
fn rex(&mut self, w: impl RexW, r: impl RexBit, x: u8, b: impl RexBit) -> ERes { fn rex(&mut self, w: impl RexW, r: impl RexBit, x: u8, b: impl RexBit) -> EncodeRes {
if r.req() && b.req_no() || r.req_no() && b.req() { if r.req() && b.req_no() || r.req_no() && b.req() {
return Err("registers incompatible (REX)".into()); return Err("registers incompatible (REX)".into());
} }
+7 -1
View File
@@ -20,9 +20,15 @@ pub struct X86_64;
impl Arch for X86_64 { impl Arch for X86_64 {
const NAME: &str = "x86_64"; const NAME: &str = "x86_64";
type Asm = Code; type Asm = Asm;
type Addr = u64; type Addr = u64;
type CallConv = CallConv;
fn compile(p: &Program<Self>) -> Result<LinkedProgram<Self::Addr>, CompilerMsg> { fn compile(p: &Program<Self>) -> Result<LinkedProgram<Self::Addr>, CompilerMsg> {
compile(p) compile(p)
} }
} }
pub struct CallConv {
volatile: Vec<Reg>,
nonvolatile: Vec<Reg>,
}
+3 -3
View File
@@ -36,13 +36,13 @@ pub fn imms() -> impl Iterator<Item = i128> {
IMMS.iter().cloned() IMMS.iter().cloned()
} }
pub fn regs() -> impl Iterator<Item = Reg> { pub fn regs() -> impl Iterator<Item = RegW> {
Reg::IMPORTANT.iter().cloned() RegW::IMPORTANT.iter().cloned()
} }
pub fn mems() -> impl Iterator<Item = Mem> { pub fn mems() -> impl Iterator<Item = Mem> {
gen move { gen move {
for &reg in Reg::IMPORTANT { for &reg in RegW::IMPORTANT {
for &disp in DISPS { for &disp in DISPS {
for &width in WIDTHS { for &width in WIDTHS {
yield mem(reg, disp, width); yield mem(reg, disp, width);
+12 -12
View File
@@ -8,13 +8,13 @@ pub trait RegMem: RexBit + RexW + ModRMRM + Copy + MaybeMem {
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum RegMemKind { pub enum RegMemKind {
Reg(Reg), Reg(RegW),
Mem(Mem), Mem(Mem),
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum RegMemImm { pub enum RegMemImm {
Reg(Reg), Reg(RegW),
Imm(Imm), Imm(Imm),
Mem(Mem), Mem(Mem),
} }
@@ -23,7 +23,7 @@ pub trait MaybeMem {
fn mem(&self) -> Option<Mem>; fn mem(&self) -> Option<Mem>;
} }
impl RegMem for Reg { impl RegMem for RegW {
fn width(&self) -> Width { fn width(&self) -> Width {
self.width() self.width()
} }
@@ -32,7 +32,7 @@ impl RegMem for Reg {
} }
} }
impl MaybeMem for Reg { impl MaybeMem for RegW {
fn mem(&self) -> Option<Mem> { fn mem(&self) -> Option<Mem> {
None None
} }
@@ -54,14 +54,14 @@ impl MaybeMem for Mem {
} }
// fromrot // fromrot
impl From<Reg> for RegMemImm { impl From<RegW> for RegMemImm {
fn from(value: Reg) -> Self { fn from(value: RegW) -> Self {
Self::Reg(value) Self::Reg(value)
} }
} }
impl From<Reg> for RegMemKind { impl From<RegW> for RegMemKind {
fn from(value: Reg) -> Self { fn from(value: RegW) -> Self {
Self::Reg(value) Self::Reg(value)
} }
} }
@@ -115,7 +115,7 @@ pub enum EffAddr {
None, None,
} }
impl ModRMRM for Reg { impl ModRMRM for RegW {
fn rm(&self) -> u8 { fn rm(&self) -> u8 {
self.base() self.base()
} }
@@ -171,7 +171,7 @@ impl ModRMReg for u8 {
} }
} }
impl ModRMReg for Reg { impl ModRMReg for RegW {
fn val(&self) -> u8 { fn val(&self) -> u8 {
self.base() self.base()
} }
@@ -207,7 +207,7 @@ impl RexBit for u8 {
} }
} }
impl RexBit for Reg { impl RexBit for RegW {
fn rex(&self) -> bool { fn rex(&self) -> bool {
self.gt8() self.gt8()
} }
@@ -238,7 +238,7 @@ impl RexW for Width {
} }
} }
impl RexW for Reg { impl RexW for RegW {
fn rexw(&self) -> bool { fn rexw(&self) -> bool {
self.width().rexw() self.width().rexw()
} }
+128
View File
@@ -0,0 +1,128 @@
use super::*;
use crate::backend::{Symbol, VarId};
pub struct Asm {
pub args: Vec<(Reg, VarId)>,
pub instrs: Vec<Instr>,
}
pub enum Instr {
Mov { dst: Rvm, src: Rvmi },
Push(Rvmi),
Pop(Rvm),
Lea { dst: Rv, src: Symbol },
Int(u8),
Syscall,
Call(Symbol),
CallAt(Symbol),
Ret,
Add { dst: Rvm, src: Rvmi },
Sub { dst: Rvm, src: Rvmi },
}
impl Instr {
pub fn regw_set(&self) -> Option<RegW> {
match self {
Instr::Mov { dst, src: _ } => dst.reg(),
Instr::Push(_) => None,
Instr::Pop(dst) => dst.reg(),
Instr::Lea { dst, src: _ } => dst.reg(),
Instr::Int(_) => None,
Instr::Syscall => None,
Instr::Call(_) => None,
Instr::CallAt(_) => None,
Instr::Ret => None,
Instr::Add { dst, src: _ } => dst.reg(),
Instr::Sub { dst, src: _ } => dst.reg(),
}
}
pub fn vars(&self) -> impl Iterator<Item = VarId> {
let mut vars = (None, None);
match self {
Instr::Mov { dst, src } => vars = (dst.var(), src.var()),
Instr::Push(src) => vars.0 = src.var(),
Instr::Pop(dst) => vars.0 = dst.var(),
Instr::Lea { dst, .. } => vars.0 = dst.var(),
Instr::Int(_) => (),
Instr::Syscall => (),
Instr::Call(_) => (),
Instr::CallAt(_) => (),
Instr::Ret => (),
Instr::Add { dst, src } => vars = (dst.var(), src.var()),
Instr::Sub { dst, src } => vars = (dst.var(), src.var()),
}
vars.0.into_iter().chain(vars.1)
}
}
#[derive(Clone, Copy)]
pub enum Rv {
Reg(RegW),
Var(VarId),
}
#[derive(Clone, Copy)]
pub enum Rvm {
Reg(RegW),
Var(VarId),
Mem(Mem),
}
#[derive(Clone, Copy)]
pub enum Rvmi {
Reg(RegW),
Var(VarId),
Mem(Mem),
Imm(Imm),
}
impl Rv {
pub fn reg(&self) -> Option<RegW> {
if let &Self::Reg(v) = self {
Some(v)
} else {
None
}
}
pub fn var(&self) -> Option<VarId> {
if let &Self::Var(v) = self {
Some(v)
} else {
None
}
}
}
impl Rvm {
pub fn reg(&self) -> Option<RegW> {
if let &Self::Reg(v) = self {
Some(v)
} else {
None
}
}
pub fn var(&self) -> Option<VarId> {
if let &Self::Var(v) = self {
Some(v)
} else {
None
}
}
}
impl Rvmi {
pub fn reg(&self) -> Option<RegW> {
if let &Self::Reg(v) = self {
Some(v)
} else {
None
}
}
pub fn var(&self) -> Option<VarId> {
if let &Self::Var(v) = self {
Some(v)
} else {
None
}
}
}
+2 -2
View File
@@ -4,12 +4,12 @@ use super::*;
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct Mem { pub struct Mem {
pub reg: Reg, pub reg: RegW,
pub disp: i32, pub disp: i32,
pub width: Width, pub width: Width,
} }
pub fn mem(reg: Reg, disp: i32, width: Width) -> Mem { pub fn mem(reg: RegW, disp: i32, width: Width) -> Mem {
Mem { reg, disp, width } Mem { reg, disp, width }
} }
+2
View File
@@ -1,10 +1,12 @@
mod arg; mod arg;
mod asm;
mod imm; mod imm;
mod mem; mod mem;
mod reg; mod reg;
mod width; mod width;
pub use arg::*; pub use arg::*;
pub use asm::*;
pub use imm::*; pub use imm::*;
pub use mem::*; pub use mem::*;
pub use reg::*; pub use reg::*;
+26 -20
View File
@@ -1,13 +1,15 @@
use super::Width; use super::Width;
#[derive(Clone, Copy, PartialEq)] #[derive(Clone, Copy, PartialEq)]
pub struct Reg { pub struct RegW {
val: u8, reg: Reg,
high: bool, high: bool,
width: Width, width: Width,
} }
def_regs! { pub type Reg = u8;
def_regs! { RegW;
0b0000 : rax eax ax al, 0b0000 : rax eax ax al,
0b0001 : rcx ecx cx cl !_, 0b0001 : rcx ecx cx cl !_,
0b0010 : rdx edx dx dl, 0b0010 : rdx edx dx dl,
@@ -28,16 +30,20 @@ def_regs! {
0b1111 : r15 r15d r15w r15b, 0b1111 : r15 r15d r15w r15b,
} }
impl Reg { impl RegW {
pub fn reg(&self) -> u8 {
self.reg
}
pub fn base(&self) -> u8 { pub fn base(&self) -> u8 {
self.val & 0b111 self.reg & 0b111
} }
/// checks if register is not one of the first 8 (0-7) /// checks if register is not one of the first 8 (0-7)
pub fn gt8(&self) -> bool { pub fn gt8(&self) -> bool {
self.val >= 0b1000 self.reg >= 0b1000
} }
pub fn gt4(&self) -> bool { pub fn gt4(&self) -> bool {
self.val >= 0b0100 self.reg >= 0b0100
} }
pub fn width(&self) -> Width { pub fn width(&self) -> Width {
@@ -65,12 +71,12 @@ impl Reg {
|| (self.gt4() && self.width == Width::B8 && !self.high) || (self.gt4() && self.width == Width::B8 && !self.high)
} }
pub fn incompatible(&self, other: &Reg) -> bool { pub fn incompatible(&self, other: &RegW) -> bool {
(self.requires_rex() && other.high) || (self.high && other.requires_rex()) (self.requires_rex() && other.high) || (self.high && other.requires_rex())
} }
const fn new(val: u8, width: Width, high: bool) -> Self { const fn new(reg: u8, width: Width, high: bool) -> Self {
Self { val, high, width } Self { reg, high, width }
} }
} }
@@ -117,30 +123,30 @@ macro_rules! filter {
use filter; use filter;
macro_rules! def_regs { macro_rules! def_regs {
($($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)?,)*) => {
$( $(
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
pub const $B64: Reg = Reg::new($val, Width::B64, false); pub const $B64: $reg = $reg::new($val, Width::B64, false);
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
pub const $B32: Reg = Reg::new($val, Width::B32, false); pub const $B32: $reg = $reg::new($val, Width::B32, false);
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
pub const $B16: Reg = Reg::new($val, Width::B16, false); pub const $B16: $reg = $reg::new($val, Width::B16, false);
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
pub const $B8 : Reg = Reg::new($val, Width::B8 , false); pub const $B8 : $reg = $reg::new($val, Width::B8 , false);
$( $(
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
pub const $B8H: Reg = Reg::new($val, Width::B8, true); pub const $B8H: $reg = $reg::new($val, Width::B8, true);
)? )?
)* )*
impl Reg { impl $reg {
// #[cfg(test)] // #[cfg(test)]
// pub const ALL: &[Reg] = &[ // pub const ALL: &[$reg] = &[
// $( $B64, $B32, $B16, $B8, $($B8H,)? )* // $( $B64, $B32, $B16, $B8, $($B8H,)? )*
// ]; // ];
#[cfg(test)] #[cfg(test)]
pub const IMPORTANT: &[Reg] = & pub const IMPORTANT: &[$reg] = &
filter!(; $($(!$imp)? $B64 $B32 $B16 $B8 $($B8H)?; )* ) filter!(; $($(!$imp)? $B64 $B32 $B16 $B8 $($B8H)?; )* )
; ;
@@ -159,7 +165,7 @@ macro_rules! def_regs {
}) })
} }
} }
impl std::fmt::Display for Reg { 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 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", match *self { write!(f, "{}", match *self {
+2 -2
View File
@@ -9,8 +9,8 @@ pub enum Width {
B64 = 3, B64 = 3,
} }
impl From<Reg> for Width { impl From<RegW> for Width {
fn from(value: Reg) -> Self { fn from(value: RegW) -> Self {
value.width() value.width()
} }
} }
+11
View File
@@ -0,0 +1,11 @@
ids!(VarId FnId);
macro_rules! ids {
($($name:ident)*) => {
$(
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct $name(usize);
)*
};
}
use ids;
+35 -8
View File
@@ -1,6 +1,8 @@
mod addr; mod addr;
mod id;
mod symbol; mod symbol;
pub use addr::*; pub use addr::*;
pub use id::*;
pub use symbol::*; pub use symbol::*;
use crate::{arch::Arch, backend::LinkedProgram, io::CompilerMsg}; use crate::{arch::Arch, backend::LinkedProgram, io::CompilerMsg};
@@ -10,6 +12,7 @@ pub struct Program<A: Arch> {
pub funcs: Vec<Func<A>>, pub funcs: Vec<Func<A>>,
pub entry: Option<Symbol>, pub entry: Option<Symbol>,
pub external: Vec<External>, pub external: Vec<External>,
pub call_convs: Vec<A::CallConv>,
sym_info: Vec<SymInfo>, sym_info: Vec<SymInfo>,
sym_count: usize, sym_count: usize,
@@ -21,8 +24,10 @@ pub struct Data {
} }
pub struct Func<A: Arch> { pub struct Func<A: Arch> {
pub instrs: Vec<Instr<A>>, pub params: Vec<VarId>,
pub body: Body<A>,
pub sym: Symbol, pub sym: Symbol,
pub conv: usize,
} }
pub struct External { pub struct External {
@@ -35,16 +40,38 @@ pub struct SymInfo {
pub external: bool, pub external: bool,
} }
pub type Body<A> = Vec<Instr<A>>;
pub enum Instr<A: Arch> { pub enum Instr<A: Arch> {
Set { dst: VarId, src: Vec<u8> }, Set {
Call { dst: FnId, args: Vec<VarId> }, dst: VarId,
Copy { dst: VarId, src: VarId }, src: Vec<u8>,
},
Call {
dst: VarId,
f: FnId,
args: Vec<VarId>,
},
Copy {
dst: VarId,
src: VarId,
},
Add {
dst: VarId,
src1: VarId,
src2: VarId,
},
If {
cond: VarId,
then: Body<A>,
else_: Body<A>,
},
Loop(Body<A>),
Return(Option<VarId>),
Break(Option<VarId>),
Asm(A::Asm), Asm(A::Asm),
} }
pub type VarId = usize;
pub type FnId = usize;
impl<A: Arch> Program<A> { impl<A: Arch> Program<A> {
pub fn encode_data(&self, data: &mut Vec<u8>, sym_tab: &mut SymTable<A::Addr>) { pub fn encode_data(&self, data: &mut Vec<u8>, sym_tab: &mut SymTable<A::Addr>) {
for d in &self.ro_data { for d in &self.ro_data {
@@ -70,7 +97,7 @@ impl<A: Arch> Program<A> {
name: name.into(), name: name.into(),
external: false, external: false,
}); });
self.funcs.push(Func { instrs, sym }); self.funcs.push(Func { body: instrs, sym });
sym sym
} }
+3 -3
View File
@@ -68,17 +68,17 @@ pub fn parse_rmi(ctx: &mut crate::parser::ParseCtx) -> Result<RegMemImm, Compile
let next = ctx.expect_next()?; let next = ctx.expect_next()?;
let err = || CompilerMsg::unexpected_token(&next, ctx.span, "a register or immediate"); let err = || CompilerMsg::unexpected_token(&next, ctx.span, "a register or immediate");
Ok(match &next { Ok(match &next {
Token::Ident(ident) => RegMemImm::Reg(Reg::parse(ident).ok_or_else(err)?), Token::Ident(ident) => RegMemImm::Reg(RegW::parse(ident).ok_or_else(err)?),
Token::Lit(LitTy::Number(num)) => RegMemImm::Imm(parse_imm(num, ctx.span)?), Token::Lit(LitTy::Number(num)) => RegMemImm::Imm(parse_imm(num, ctx.span)?),
_ => return Err(err()), _ => return Err(err()),
}) })
} }
pub fn parse_reg(ctx: &mut crate::parser::ParseCtx) -> Result<Reg, CompilerMsg> { pub fn parse_reg(ctx: &mut crate::parser::ParseCtx) -> Result<RegW, CompilerMsg> {
let next = ctx.expect_next()?; let next = ctx.expect_next()?;
let err = || CompilerMsg::unexpected_token(&next, ctx.span, "a register"); let err = || CompilerMsg::unexpected_token(&next, ctx.span, "a register");
let Token::Ident(next) = &next else { let Token::Ident(next) = &next else {
return Err(err()); return Err(err());
}; };
Reg::parse(next).ok_or_else(err) RegW::parse(next).ok_or_else(err)
} }