import type { AssignStmt, Expr, Stmt } from "./ast"
|
|
|
|
// dest <- op(x, y)
|
|
type Operand = string | number
|
|
|
|
type ASSA<Data> = { dest: string, source: Operand } & Data
|
|
|
|
export type SSACopy = ASSA<{ source: Operand }> // dest = source
|
|
|
|
export type SSAUnary = ASSA<{ op: string }> // dest = op(source)
|
|
|
|
export type SSABinary = ASSA<{ op: string, source1: Operand }> // dest = op(source, source1)
|
|
|
|
export type SSA = SSACopy | SSAUnary | SSABinary
|
|
|
|
type IRState = {
|
|
nextID: number
|
|
ssa_stmts: Array<SSA>
|
|
}
|
|
|
|
export const convertIR = (stmts: Array<Stmt>): Array<SSA> => {
|
|
const state: IRState = {
|
|
nextID: 0,
|
|
ssa_stmts: [],
|
|
}
|
|
|
|
stmts.forEach(stmt => {
|
|
const ssa_stmts = convertAssignStmt(state, stmt)
|
|
state.ssa_stmts.push(...ssa_stmts)
|
|
})
|
|
|
|
return state.ssa_stmts
|
|
}
|
|
|
|
export const convertAssignStmt = (state: IRState, stmt: AssignStmt): Array<SSA> => {
|
|
const dest = stmt.args.name
|
|
const [source, expr_stmts] = convertExpr(state, stmt.args.expr)
|
|
|
|
expr_stmts.push({
|
|
dest,
|
|
source,
|
|
})
|
|
|
|
return expr_stmts
|
|
}
|
|
|
|
export const convertExpr = (state: IRState, expr: Expr): [string, Array<SSA>] => {
|
|
const name = `temp${state.nextID++}`
|
|
return [name, [{ dest: name, source: expr }]]
|
|
}
|
|
|
|
export const prettyPrintIR = (ssa: SSA): string => {
|
|
let output = ""
|
|
|
|
if ("source1" in ssa) {
|
|
output = `${ssa.dest} = ${ssa.source} ${ssa.op} ${ssa.source1}`
|
|
} else if ("op" in ssa) {
|
|
output = `${ssa.dest} = ${ssa.op} ${ssa.source}`
|
|
} else {
|
|
output = `${ssa.dest} = ${ssa.source}`
|
|
}
|
|
|
|
return output
|
|
}
|