Browse Source

Add constructors for IR instructions

master
Forest Belton 3 years ago
parent
commit
0cb2ff091e
3 changed files with 81 additions and 84 deletions
  1. +39
    -50
      lib/ir/convert.ts
  2. +27
    -9
      lib/ir/insn.ts
  3. +15
    -25
      lib/ir/pretty.ts

+ 39
- 50
lib/ir/convert.ts View File

@ -1,18 +1,24 @@
import type { AssignStmt, Expr, Stmt } from "../ast" import type { AssignStmt, Expr, Stmt } from "../ast"
import { R8 } from "../sm83/cpu" import { R8 } from "../sm83/cpu"
import { Loc, LocType } from "./loc" 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 nextID: number
insns: Array<AbsInsn2> 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> => { export const convertIR = (stmts: Array<Stmt>): Array<AbsInsn2> => {
const state: IRState = {
nextID: 0,
insns: [],
}
const state: IRState = new IRState()
stmts.forEach(stmt => { stmts.forEach(stmt => {
convertAssignStmt(state, stmt) convertAssignStmt(state, stmt)
@ -36,26 +42,26 @@ export const convertExpr = (state: IRState, dest: Loc, expr: Expr): void => {
case 'unary': case 'unary':
state.insns.push( 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 break
case 'binary': case 'binary':
let source1 = ssa.source1 let source1 = ssa.source1
if (typeof source1 !== 'number' && source1.type === LocType.VARIABLE) { if (typeof source1 !== 'number' && source1.type === LocType.VARIABLE) {
source1 = Loc.temp(`t${state.nextID++}`)
source1 = state.temp()
state.insns.push( 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( 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 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<AbsInsn3> => { export const convertExpr3 = (state: IRState, dest: Loc, expr: Expr): Array<AbsInsn3> => {
let expr_stmts: 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") { if (typeof expr === "number") {
expr_stmts = [{ type: "copy", dest, source: expr }]
expr_stmts.push(CopyInsn(dest, expr))
} else if (typeof expr === "string") { } 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") { } 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 expr_stmts = stmts
} else { } 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 return expr_stmts
} }
const getSource = (state: IRState, expr: Expr): [Operand, Array<AbsInsn3>] => {
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]
}

+ 27
- 9
lib/ir/insn.ts View File

@ -9,23 +9,20 @@ export type AbsInsnCopy = {
source: Operand, source: Operand,
} }
export type AbsInsn2Unary = {
type UnaryInsn<Op> = {
type: "unary", type: "unary",
dest: Loc, dest: Loc,
// NOTE: We convert binary -> unary when going SSA3 -> SSA2
op: UnaryOp | BinaryOp,
op: Op,
source: Operand, source: Operand,
} }
// NOTE: We convert binary -> unary when going SSA3 -> SSA2
export type AbsInsn2Unary = UnaryInsn<UnaryOp | BinaryOp>
// Abstract instruction in two-address form // Abstract instruction in two-address form
export type AbsInsn2 = AbsInsnCopy | AbsInsn2Unary export type AbsInsn2 = AbsInsnCopy | AbsInsn2Unary
export type AbsInsn3Unary = {
type: "unary",
dest: Loc,
op: UnaryOp,
source: Operand,
}
export type AbsInsn3Unary = UnaryInsn<UnaryOp>
export type AbsInsnBinary = { export type AbsInsnBinary = {
type: "binary", type: "binary",
@ -37,3 +34,24 @@ export type AbsInsnBinary = {
// Abstract instruction in three-address form // Abstract instruction in three-address form
export type AbsInsn3 = AbsInsnCopy | AbsInsn3Unary | AbsInsnBinary export type AbsInsn3 = AbsInsnCopy | AbsInsn3Unary | AbsInsnBinary
export const CopyInsn = (dest: Loc, source: Operand): AbsInsnCopy => ({
type: 'copy',
dest,
source,
})
export const UnaryInsn = <Op>(dest: Loc, op: Op, source: Operand): UnaryInsn<Op> => ({
type: 'unary',
dest,
op,
source,
})
export const BinaryInsn = (dest: Loc, source: Operand, op: BinaryOp, source1: Operand): AbsInsnBinary => ({
type: 'binary',
dest,
source,
op,
source1,
})

+ 15
- 25
lib/ir/pretty.ts View File

@ -8,12 +8,16 @@ export const prettyPrintBlock = (block: Array)
export const prettyPrintInsn = (ssa: AbsInsn2 | AbsInsn3): string => { export const prettyPrintInsn = (ssa: AbsInsn2 | AbsInsn3): string => {
let output = "" 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 return output
@ -24,22 +28,8 @@ const ppOp = (op: Operand): string =>
? op.toString() ? op.toString()
: ppLoc(op) : 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])

Loading…
Cancel
Save