import type { AssignStmt, Expr, Stmt } from "../ast"
|
|
import { R8 } from "../sm83/cpu"
|
|
import { Loc, LocType } from "./loc"
|
|
import { Operand, AbsInsn2, AbsInsn3, CopyInsn, UnaryInsn, BinaryInsn } from "./insn"
|
|
|
|
export class IRState {
|
|
nextID: number
|
|
insns: Array<AbsInsn2>
|
|
|
|
constructor() {
|
|
this.nextID = 0
|
|
this.insns = []
|
|
}
|
|
|
|
temp(): Loc {
|
|
return Loc.temp(`t${this.nextID++}`)
|
|
}
|
|
}
|
|
|
|
export const convertIR = (stmts: Array<Stmt>): Array<AbsInsn2> => {
|
|
const state: IRState = new IRState()
|
|
|
|
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(
|
|
CopyInsn(Loc.reg(R8.A), ssa.source),
|
|
UnaryInsn(Loc.reg(R8.A), ssa.op, Loc.reg(R8.A)),
|
|
CopyInsn(ssa.dest, Loc.reg(R8.A)),
|
|
)
|
|
break
|
|
|
|
case 'binary':
|
|
let source1 = ssa.source1
|
|
if (typeof source1 !== 'number' && source1.type === LocType.VARIABLE) {
|
|
source1 = state.temp()
|
|
state.insns.push(
|
|
CopyInsn(Loc.reg(R8.A), ssa.source1),
|
|
CopyInsn(source1, Loc.reg(R8.A)),
|
|
)
|
|
}
|
|
|
|
state.insns.push(
|
|
CopyInsn(Loc.reg(R8.A), ssa.source),
|
|
UnaryInsn(Loc.reg(R8.A), ssa.op, source1),
|
|
CopyInsn(ssa.dest, Loc.reg(R8.A)),
|
|
)
|
|
break
|
|
}
|
|
})
|
|
}
|
|
|
|
export const convertExpr3 = (state: IRState, dest: Loc, expr: Expr): Array<AbsInsn3> => {
|
|
let expr_stmts: Array<AbsInsn3> = []
|
|
|
|
const getSource = (expr: Expr): [Operand, Array<AbsInsn3>] => {
|
|
if (typeof expr === "number") {
|
|
return [expr, []]
|
|
} else if (typeof expr === "string") {
|
|
return [Loc.vari(expr), []]
|
|
}
|
|
const source = state.temp()
|
|
const stmts = convertExpr3(state, source, expr)
|
|
return [source, stmts]
|
|
}
|
|
|
|
if (typeof expr === "number") {
|
|
expr_stmts.push(CopyInsn(dest, expr))
|
|
} else if (typeof expr === "string") {
|
|
expr_stmts.push(CopyInsn(dest, Loc.vari(expr)))
|
|
} else if (expr.type === "unary") {
|
|
const [source, stmts] = getSource(expr.arg)
|
|
stmts.push(UnaryInsn(dest, expr.op, source))
|
|
expr_stmts = stmts
|
|
} else {
|
|
const [left_source, left_stmts] = getSource(expr.left)
|
|
const [right_source, right_stmts] = getSource(expr.right)
|
|
expr_stmts = [...left_stmts, ...right_stmts, BinaryInsn(dest, left_source, expr.op, right_source)]
|
|
}
|
|
|
|
return expr_stmts
|
|
}
|