A "high-level" language for the Gameboy
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

111 lines
3.4 KiB

import type { AssignStmt, Expr, Stmt } from "../ast"
import { R8 } from "../sm83/cpu"
import { Loc, LocType } from "./loc"
import type { Operand, AbsInsn2, AbsInsn3 } from "./insn"
export type IRState = {
nextID: number
insns: Array<AbsInsn2>
}
export const convertIR = (stmts: Array<Stmt>): Array<AbsInsn2> => {
const state: IRState = {
nextID: 0,
insns: [],
}
stmts.forEach(stmt => {
convertAssignStmt(state, stmt)
})
return state.insns
}
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): void => {
const threeAddress = convertExpr3(state, dest, expr)
threeAddress.forEach(ssa => {
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) },
)
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
}
})
}
export const convertExpr3 = (state: IRState, dest: Loc, expr: Expr): Array<AbsInsn3> => {
let expr_stmts: Array<AbsInsn3> = []
if (typeof expr === "number") {
expr_stmts = [{ type: "copy", dest, source: expr }]
} else if (typeof expr === "string") {
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,
})
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
}
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]
}