use std::fmt; use std::fmt::Formatter; use std::rc::Rc; use std::sync::atomic::{AtomicUsize, Ordering}; pub enum Statement { Const(VirtualReg, Literal), BinaryOp { left: VirtualReg, op: PrimitiveOperation, right: VirtualReg, result: VirtualReg }, AddressOf { value: VirtualReg, result: VirtualReg }, Dereference { address: VirtualReg, result: VirtualReg }, GetStructField { struct_addr: VirtualReg, result: VirtualReg, offset: usize }, SetStructField { struct_addr: VirtualReg, value: VirtualReg, offset: usize }, Call { return_value: VirtualReg, func: FunctionName, args: Vec }, } pub struct IRProgram { pub functions: Vec, } pub struct Function { pub name: FunctionName, pub params: Vec, pub blocks: Vec, } pub struct BasicBlock { pub label: Label, pub statements: Vec, pub terminator: Terminator, } pub enum Terminator { Jump(Label), ConditionalJump { if_flag: VirtualReg, then_goto: Label, else_goto: Label }, Return(VirtualReg), ReturnVoid, } pub type FunctionName = String; #[derive(Clone)] pub struct Label { id: usize, name: Rc } impl Label { pub fn new_with_id(name: impl Into, id: usize) -> Self { Self { id, name: Rc::new(name.into()) } } pub fn new(name: impl Into) -> Self { Self { id: Self::get_new_id(), name: Rc::new(name.into()) } } pub fn get_new_id() -> usize { LABEL_ID.fetch_add(1, Ordering::Relaxed) } } impl fmt::Display for Label { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "__{}_{}", self.name, self.id) } } static LABEL_ID: AtomicUsize = AtomicUsize::new(0); #[derive(Copy, Clone, Debug, PartialEq)] pub struct VirtualReg(pub isize); impl VirtualReg { pub fn void() -> Self { Self(-1) } } pub enum Literal { UInt(usize), Int(isize), Char(char), } pub enum PrimitiveOperation { Add, Sub, And, Or, Xor, Nor, Nand }