|
|
@ -1,77 +1,78 @@ |
|
|
|
import type { AssignStmt, Expr, Stmt } from "../ast" |
|
|
|
import { R8 } from "../sm83/cpu" |
|
|
|
import { Loc, LocType } from "./loc" |
|
|
|
import type { Operand, SSA, SSAWithBinary } from "./ssa" |
|
|
|
import type { Operand, AbsInsn2, AbsInsn3 } from "./insn" |
|
|
|
|
|
|
|
type IRState = { |
|
|
|
export type IRState = { |
|
|
|
nextID: number |
|
|
|
ssa_stmts: Array<SSA> |
|
|
|
insns: Array<AbsInsn2> |
|
|
|
} |
|
|
|
|
|
|
|
export const convertIR = (stmts: Array<Stmt>): Array<SSA> => { |
|
|
|
export const convertIR = (stmts: Array<Stmt>): Array<AbsInsn2> => { |
|
|
|
const state: IRState = { |
|
|
|
nextID: 0, |
|
|
|
ssa_stmts: [], |
|
|
|
insns: [], |
|
|
|
} |
|
|
|
|
|
|
|
stmts.forEach(stmt => { |
|
|
|
const ssa_stmts = convertAssignStmt(state, stmt) |
|
|
|
state.ssa_stmts.push(...ssa_stmts) |
|
|
|
convertAssignStmt(state, stmt) |
|
|
|
}) |
|
|
|
|
|
|
|
return state.ssa_stmts |
|
|
|
return state.insns |
|
|
|
} |
|
|
|
|
|
|
|
export const convertAssignStmt = (state: IRState, stmt: AssignStmt): Array<SSA> => { |
|
|
|
return convertExpr(state, Loc.vari(stmt.args.name), stmt.args.expr) |
|
|
|
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): Array<SSA> => { |
|
|
|
export const convertExpr = (state: IRState, dest: Loc, expr: Expr): void => { |
|
|
|
const threeAddress = convertExpr3(state, dest, expr) |
|
|
|
const output: Array<SSA> = [] |
|
|
|
|
|
|
|
threeAddress.forEach(ssa => { |
|
|
|
// skip copies
|
|
|
|
if (!("op" in ssa)) { |
|
|
|
output.push(ssa) |
|
|
|
return |
|
|
|
} else if ("source1" in ssa) { |
|
|
|
let source1 = ssa.source1 |
|
|
|
if (typeof source1 !== 'number' && source1.type === LocType.VARIABLE) { |
|
|
|
source1 = Loc.temp(`t${state.nextID++}`) |
|
|
|
output.push( |
|
|
|
{ dest: Loc.reg(R8.A), source: ssa.source1 }, |
|
|
|
{ dest: source1, source: Loc.reg(R8.A) }, |
|
|
|
switch (ssa.type) { |
|
|
|
case 'copy': |
|
|
|
state.insns.push(ssa) |
|
|
|
break |
|
|
|
|
|
|
|
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) }, |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
output.push( |
|
|
|
{ dest: Loc.reg(R8.A), source: ssa.source }, |
|
|
|
{ dest: Loc.reg(R8.A), op: ssa.op, source: source1 }, |
|
|
|
{ dest: ssa.dest, source: Loc.reg(R8.A) }, |
|
|
|
) |
|
|
|
} else { |
|
|
|
output.push( |
|
|
|
{ dest: Loc.reg(R8.A), source: ssa.source }, |
|
|
|
{ dest: Loc.reg(R8.A), source: Loc.reg(R8.A), op: ssa.op }, |
|
|
|
{ dest: ssa.dest, source: 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++}`) |
|
|
|
state.insns.push( |
|
|
|
{ type: "copy", dest: Loc.reg(R8.A), source: ssa.source1 }, |
|
|
|
{ type: "copy", dest: source1, source: 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) }, |
|
|
|
) |
|
|
|
break |
|
|
|
} |
|
|
|
}) |
|
|
|
|
|
|
|
return output |
|
|
|
} |
|
|
|
|
|
|
|
export const convertExpr3 = (state: IRState, dest: Loc, expr: Expr): Array<SSAWithBinary> => { |
|
|
|
let expr_stmts: Array<SSAWithBinary> = [] |
|
|
|
export const convertExpr3 = (state: IRState, dest: Loc, expr: Expr): Array<AbsInsn3> => { |
|
|
|
let expr_stmts: Array<AbsInsn3> = [] |
|
|
|
|
|
|
|
if (typeof expr === "number") { |
|
|
|
expr_stmts = [{ dest, source: expr }] |
|
|
|
expr_stmts = [{ type: "copy", dest, source: expr }] |
|
|
|
} else if (typeof expr === "string") { |
|
|
|
expr_stmts = [{ dest, source: Loc.vari(expr) }] |
|
|
|
expr_stmts = [{ type: "copy", dest, source: Loc.vari(expr) }] |
|
|
|
} else if (expr.type === "unary") { |
|
|
|
const [source, stmts] = getSource(state, expr.arg) |
|
|
|
stmts.push({ |
|
|
|
type: "unary", |
|
|
|
dest, |
|
|
|
op: expr.op, |
|
|
|
source, |
|
|
@ -84,6 +85,7 @@ export const convertExpr3 = (state: IRState, dest: Loc, expr: Expr): Array |
|
|
|
|
|
|
|
const stmts = [...left_stmts, ...right_stmts] |
|
|
|
stmts.push({ |
|
|
|
type: "binary", |
|
|
|
dest, |
|
|
|
op: expr.op, |
|
|
|
source: left_source, |
|
|
@ -96,7 +98,7 @@ export const convertExpr3 = (state: IRState, dest: Loc, expr: Expr): Array |
|
|
|
return expr_stmts |
|
|
|
} |
|
|
|
|
|
|
|
const getSource = (state: IRState, expr: Expr): [Operand, Array<SSAWithBinary>] => { |
|
|
|
const getSource = (state: IRState, expr: Expr): [Operand, Array<AbsInsn3>] => { |
|
|
|
if (typeof expr === "number") { |
|
|
|
return [expr, []] |
|
|
|
} else if (typeof expr === "string") { |
|
|
|