Files
lang/src/backend/ir/mod.rs
T
2026-07-18 13:33:59 -04:00

154 lines
3.3 KiB
Rust

mod addr;
mod id;
mod symbol;
pub use addr::*;
pub use id::*;
pub use symbol::*;
use crate::{arch::Arch, backend::LinkedProgram, io::CompilerMsg};
pub struct Program<A: Arch> {
pub ro_data: Vec<Data>,
pub funcs: Vec<Func<A>>,
pub entry: Option<Symbol>,
pub external: Vec<External>,
pub call_convs: Vec<A::CallConv>,
sym_info: Vec<SymInfo>,
sym_count: usize,
}
pub struct Data {
pub bytes: Vec<u8>,
pub sym: Symbol,
}
pub struct Func<A: Arch> {
pub params: Vec<VarId>,
pub body: Body<A>,
pub sym: Symbol,
pub conv: usize,
}
pub struct External {
pub file: String,
pub syms: Vec<Symbol>,
}
pub struct SymInfo {
pub name: String,
pub external: bool,
}
pub type Body<A> = Vec<Instr<A>>;
pub enum Instr<A: Arch> {
Set {
dst: 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),
}
impl<A: Arch> Program<A> {
pub fn encode_data(&self, data: &mut Vec<u8>, sym_tab: &mut SymTable<A::Addr>) {
for d in &self.ro_data {
let addr = A::Addr::from_len(data.len());
data.extend(&d.bytes);
sym_tab.insert(d.sym, addr);
}
}
pub fn ro_data(&mut self, name: impl Into<String>, bytes: impl Into<Vec<u8>>) -> Symbol {
let bytes = bytes.into();
let sym = self.reserve(SymInfo {
name: name.into(),
external: false,
});
self.ro_data.push(Data { bytes, sym });
sym
}
pub fn func(&mut self, name: impl Into<String>, instrs: impl Into<Vec<Instr<A>>>) -> Symbol {
let instrs = instrs.into();
let sym = self.reserve(SymInfo {
name: name.into(),
external: false,
});
self.funcs.push(Func { body: instrs, sym });
sym
}
pub fn external<const LEN: usize>(
&mut self,
file: impl Into<String>,
names: [impl Into<String>; LEN],
) -> [Symbol; LEN] {
let syms = names.map(|s| {
self.reserve(SymInfo {
name: s.into(),
external: true,
})
});
self.external.push(External {
file: file.into(),
syms: syms.to_vec(),
});
syms
}
fn reserve(&mut self, info: SymInfo) -> Symbol {
let res = Symbol(self.sym_count);
self.sym_info.push(info);
self.sym_count += 1;
res
}
pub fn compile(&self) -> Result<LinkedProgram<A::Addr>, CompilerMsg> {
A::compile(self)
}
pub fn sym_count(&self) -> usize {
self.sym_count
}
pub fn sym_info(&self, sym: Symbol) -> &SymInfo {
&self.sym_info[sym.0]
}
}
impl<A: Arch> Default for Program<A> {
fn default() -> Self {
Self {
ro_data: Default::default(),
funcs: Default::default(),
entry: Default::default(),
sym_count: Default::default(),
external: Default::default(),
sym_info: Default::default(),
}
}
}