use super::{LIROp, Label, Reg};
use crate::tir::TIROp;
pub fn tir_to_lir(_ops: &[TIROp]) -> Vec<LIROp> {
todo!("TIRβLIR conversion: simulate stack, assign virtual registers, flatten control flow")
}
#[allow(dead_code)]
pub(crate) struct ConvertCtx {
next_reg: u32,
stack: Vec<Reg>,
next_label: u32,
out: Vec<LIROp>,
}
#[allow(dead_code)]
impl ConvertCtx {
pub fn new() -> Self {
Self {
next_reg: 0,
stack: Vec::new(),
next_label: 0,
out: Vec::new(),
}
}
pub fn fresh_reg(&mut self) -> Reg {
let r = Reg(self.next_reg);
self.next_reg += 1;
r
}
pub fn fresh_label(&mut self, prefix: &str) -> Label {
self.next_label += 1;
Label::new(format!("{}{}", prefix, self.next_label))
}
pub fn push(&mut self, reg: Reg) {
self.stack.push(reg);
}
pub fn pop(&mut self) -> Reg {
self.stack
.pop()
.expect("ConvertCtx::pop called on empty stack")
}
pub fn peek(&self, depth: u32) -> Reg {
let idx = self.stack.len() - 1 - depth as usize;
self.stack[idx]
}
pub fn emit(&mut self, op: LIROp) {
self.out.push(op);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_convert_ctx_fresh_reg() {
let mut ctx = ConvertCtx::new();
assert_eq!(ctx.fresh_reg(), Reg(0));
assert_eq!(ctx.fresh_reg(), Reg(1));
assert_eq!(ctx.fresh_reg(), Reg(2));
}
#[test]
fn test_convert_ctx_fresh_label() {
let mut ctx = ConvertCtx::new();
assert_eq!(ctx.fresh_label("then_"), Label::new("then_1"));
assert_eq!(ctx.fresh_label("else_"), Label::new("else_2"));
}
#[test]
fn test_convert_ctx_stack() {
let mut ctx = ConvertCtx::new();
let r0 = ctx.fresh_reg();
let r1 = ctx.fresh_reg();
ctx.push(r0);
ctx.push(r1);
assert_eq!(ctx.peek(0), r1);
assert_eq!(ctx.peek(1), r0);
assert_eq!(ctx.pop(), r1);
assert_eq!(ctx.pop(), r0);
}
}