import type { AssignStmt, Expr, Stmt } from "../ast" import { R8 } from "../sm83/cpu" import { Loc, LocType } from "./loc" import type { Operand, AbsInsn2, AbsInsn3 } from "./insn" export type IRState = { nextID: number insns: Array } export const convertIR = (stmts: Array): Array => { const state: IRState = { nextID: 0, insns: [], } stmts.forEach(stmt => { convertAssignStmt(state, stmt) }) return state.insns } export const convertAssignStmt = (state: IRState, stmt: AssignStmt): void => { convertExpr(state, Loc.vari(stmt.args.name), stmt.args.expr) } export const convertExpr = (state: IRState, dest: Loc, expr: Expr): void => { const threeAddress = convertExpr3(state, dest, expr) threeAddress.forEach(ssa => { switch (ssa.type) { case 'copy': state.insns.push(ssa) break case 'unary': state.insns.push( { type: "copy", dest: Loc.reg(R8.A), source: ssa.source }, { type: "unary", dest: Loc.reg(R8.A), source: Loc.reg(R8.A), op: ssa.op }, { type: "copy", dest: ssa.dest, source: Loc.reg(R8.A) }, ) break case 'binary': let source1 = ssa.source1 if (typeof source1 !== 'number' && source1.type === LocType.VARIABLE) { source1 = Loc.temp(`t${state.nextID++}`) state.insns.push( { type: "copy", dest: Loc.reg(R8.A), source: ssa.source1 }, { type: "copy", dest: source1, source: Loc.reg(R8.A) }, ) } state.insns.push( { type: "copy", dest: Loc.reg(R8.A), source: ssa.source }, { type: "unary", dest: Loc.reg(R8.A), op: ssa.op, source: source1 }, { type: "copy", dest: ssa.dest, source: Loc.reg(R8.A) }, ) break } }) } export const convertExpr3 = (state: IRState, dest: Loc, expr: Expr): Array => { let expr_stmts: Array = [] if (typeof expr === "number") { expr_stmts = [{ type: "copy", dest, source: expr }] } else if (typeof expr === "string") { expr_stmts = [{ type: "copy", dest, source: Loc.vari(expr) }] } else if (expr.type === "unary") { const [source, stmts] = getSource(state, expr.arg) stmts.push({ type: "unary", dest, op: expr.op, source, }) expr_stmts = stmts } else { const [left_source, left_stmts] = getSource(state, expr.left) const [right_source, right_stmts] = getSource(state, expr.right) const stmts = [...left_stmts, ...right_stmts] stmts.push({ type: "binary", dest, op: expr.op, source: left_source, source1: right_source, }) expr_stmts = stmts } return expr_stmts } const getSource = (state: IRState, expr: Expr): [Operand, Array] => { if (typeof expr === "number") { return [expr, []] } else if (typeof expr === "string") { return [Loc.vari(expr), []] } const source = Loc.temp(`t${state.nextID++}`) const stmts = convertExpr3(state, source, expr) return [source, stmts] }