- import type { AssignStmt, Expr, Stmt, UnaryOp, BinaryOp } from "./ast"
-
- type LocationType = "register" | "temporary" | "variable"
-
- type Location = {
- type: LocationType,
- name: string,
- }
-
- type Operand = Location | number
-
- type ASSA<Data> = { dest: Location, source: Operand } & Data
-
- export type SSACopy = ASSA<{}> // dest = source
-
- export type SSAUnary = ASSA<{ op: UnaryOp }> // dest = op(source)
-
- export type SSABinary = ASSA<{ op: BinaryOp, source1: Operand }> // dest = op(source, source1)
-
- export type SSA = SSACopy | SSAUnary | SSABinary
-
- type IRState = {
- nextID: number
- ssa_stmts: Array<SSA>
- }
-
- const temp = (state: IRState): Location => ({
- type: "temporary",
- name: `t${state.nextID++}`,
- })
-
- const vari = (name: string): Location => ({
- type: "variable",
- name,
- })
-
- const reg = (name: string): Location => ({
- type: "register",
- name,
- })
-
- 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> => {
- return convertExpr(state, vari(stmt.args.name), stmt.args.expr)
- }
-
- export const convertExpr = (state: IRState, dest: Location, expr: Expr): Array<SSA> => {
- let expr_stmts = []
-
- if (typeof expr === "number") {
- expr_stmts = [{ dest, source: expr }]
- } else if (typeof expr === "string") {
- expr_stmts = [{ dest, source: vari(expr) }]
- } else if (expr.type === "unary") {
- const [source, stmts] = getSource(state, expr.arg)
- stmts.push({
- 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({
- dest,
- op: expr.op,
- source: left_source,
- source1: right_source,
- })
-
- expr_stmts = stmts
- }
-
- return expr_stmts
- }
-
- const getSource = (state: IRState, expr: Expr): [Operand, Array<SSA>] => {
- if (typeof expr === "number") {
- return [expr, []]
- } else if (typeof expr === "string") {
- return [vari(expr), []]
- }
-
- const source = temp(state)
- const stmts = convertExpr(state, source, expr)
- return [source, stmts]
- }
-
- export const prettyPrintIR = (ssa: SSA): string => {
- let output = ""
-
- if ("source1" in ssa) {
- output = `${ppLoc(ssa.dest)} = ${ssa.op}(${ppOp(ssa.source)}, ${ppOp(ssa.source1)})`
- } else if ("op" in ssa) {
- output = `${ppLoc(ssa.dest)} = ${ssa.op}(${ppOp(ssa.source)})`
- } else {
- output = `${ppLoc(ssa.dest)} = ${ppOp(ssa.source)}`
- }
-
- return output
- }
-
- const ppOp = (op: Operand): string =>
- typeof op === "number"
- ? op.toString()
- : ppLoc(op)
-
- const ppLoc = (loc: Location): string => {
- let output = ''
-
- switch (loc.type) {
- case "register":
- output = `%${loc.name}`
- break
-
- case "temporary":
- output = `#${loc.name}`
- break
-
- case "variable":
- output = loc.name
- break
- }
-
- return output
- }
|