From 0cb2ff091e017c237a96d11bf05f42e0186e2243 Mon Sep 17 00:00:00 2001 From: Forest Belton Date: Fri, 17 Sep 2021 18:37:59 -0400 Subject: [PATCH] Add constructors for IR instructions --- lib/ir/convert.ts | 89 +++++++++++++++++++++-------------------------- lib/ir/insn.ts | 36 ++++++++++++++----- lib/ir/pretty.ts | 40 ++++++++------------- 3 files changed, 81 insertions(+), 84 deletions(-) diff --git a/lib/ir/convert.ts b/lib/ir/convert.ts index 66bd948..baafbfe 100644 --- a/lib/ir/convert.ts +++ b/lib/ir/convert.ts @@ -1,18 +1,24 @@ import type { AssignStmt, Expr, Stmt } from "../ast" import { R8 } from "../sm83/cpu" import { Loc, LocType } from "./loc" -import type { Operand, AbsInsn2, AbsInsn3 } from "./insn" +import { Operand, AbsInsn2, AbsInsn3, CopyInsn, UnaryInsn, BinaryInsn } from "./insn" -export type IRState = { +export class IRState { nextID: number insns: Array + + constructor() { + this.nextID = 0 + this.insns = [] + } + + temp(): Loc { + return Loc.temp(`t${this.nextID++}`) + } } export const convertIR = (stmts: Array): Array => { - const state: IRState = { - nextID: 0, - insns: [], - } + const state: IRState = new IRState() stmts.forEach(stmt => { convertAssignStmt(state, stmt) @@ -36,26 +42,26 @@ export const convertExpr = (state: IRState, dest: Loc, expr: Expr): void => { 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) }, + 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 = Loc.temp(`t${state.nextID++}`) + source1 = state.temp() state.insns.push( - { type: "copy", dest: Loc.reg(R8.A), source: ssa.source1 }, - { type: "copy", dest: source1, source: Loc.reg(R8.A) }, + CopyInsn(Loc.reg(R8.A), ssa.source1), + CopyInsn(source1, 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) }, + CopyInsn(Loc.reg(R8.A), ssa.source), + UnaryInsn(Loc.reg(R8.A), ssa.op, source1), + CopyInsn(ssa.dest, Loc.reg(R8.A)), ) break } @@ -65,47 +71,30 @@ export const convertExpr = (state: IRState, dest: Loc, expr: Expr): void => { export const convertExpr3 = (state: IRState, dest: Loc, expr: Expr): Array => { let expr_stmts: Array = [] + const getSource = (expr: Expr): [Operand, Array] => { + 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 = [{ type: "copy", dest, source: expr }] + expr_stmts.push(CopyInsn(dest, expr)) } else if (typeof expr === "string") { - expr_stmts = [{ type: "copy", dest, source: Loc.vari(expr) }] + expr_stmts.push(CopyInsn(dest, Loc.vari(expr))) } else if (expr.type === "unary") { - const [source, stmts] = getSource(state, expr.arg) - stmts.push({ - type: "unary", - dest, - op: expr.op, - source, - }) - + const [source, stmts] = getSource(expr.arg) + stmts.push(UnaryInsn(dest, 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 + 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 } - -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] -} diff --git a/lib/ir/insn.ts b/lib/ir/insn.ts index 981a918..fd0d7ad 100644 --- a/lib/ir/insn.ts +++ b/lib/ir/insn.ts @@ -9,23 +9,20 @@ export type AbsInsnCopy = { source: Operand, } -export type AbsInsn2Unary = { +type UnaryInsn = { type: "unary", dest: Loc, - // NOTE: We convert binary -> unary when going SSA3 -> SSA2 - op: UnaryOp | BinaryOp, + op: Op, source: Operand, } +// NOTE: We convert binary -> unary when going SSA3 -> SSA2 +export type AbsInsn2Unary = UnaryInsn + // Abstract instruction in two-address form export type AbsInsn2 = AbsInsnCopy | AbsInsn2Unary -export type AbsInsn3Unary = { - type: "unary", - dest: Loc, - op: UnaryOp, - source: Operand, -} +export type AbsInsn3Unary = UnaryInsn export type AbsInsnBinary = { type: "binary", @@ -37,3 +34,24 @@ export type AbsInsnBinary = { // Abstract instruction in three-address form export type AbsInsn3 = AbsInsnCopy | AbsInsn3Unary | AbsInsnBinary + +export const CopyInsn = (dest: Loc, source: Operand): AbsInsnCopy => ({ + type: 'copy', + dest, + source, +}) + +export const UnaryInsn = (dest: Loc, op: Op, source: Operand): UnaryInsn => ({ + type: 'unary', + dest, + op, + source, +}) + +export const BinaryInsn = (dest: Loc, source: Operand, op: BinaryOp, source1: Operand): AbsInsnBinary => ({ + type: 'binary', + dest, + source, + op, + source1, +}) diff --git a/lib/ir/pretty.ts b/lib/ir/pretty.ts index f9ab860..8117cbe 100644 --- a/lib/ir/pretty.ts +++ b/lib/ir/pretty.ts @@ -8,12 +8,16 @@ export const prettyPrintBlock = (block: Array) export const prettyPrintInsn = (ssa: AbsInsn2 | AbsInsn3): 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)}` + switch (ssa.type) { + case 'copy': + output = `${ppLoc(ssa.dest)} = ${ppOp(ssa.source)}` + break + case 'unary': + output = `${ppLoc(ssa.dest)} = ${ssa.op}(${ppOp(ssa.source)})` + break + case 'binary': + output = `${ppLoc(ssa.dest)} = ${ssa.op}(${ppOp(ssa.source)}, ${ppOp(ssa.source1)})` + break } return output @@ -24,22 +28,8 @@ const ppOp = (op: Operand): string => ? op.toString() : ppLoc(op) -const ppLoc = (loc: Loc): 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 -} +const ppLoc = (loc: Loc): string => ({ + 'register': `%${loc.name}`, + 'temporary': `#${loc.name}`, + 'variable': loc.name, +}[loc.type])