import { R8 } from "../sm83/cpu"
|
|
import { Loc, LocType } from "../ir/loc"
|
|
import type { Operand, AbsInsn2, AbsInsnCopy, AbsInsn2Unary } from "../ir/insn"
|
|
import type { RegAlloc } from "../regalloc"
|
|
|
|
export const generateBlock = (alloc: RegAlloc, block: Array<AbsInsn2>): Array<string> => {
|
|
const output: Array<string> = []
|
|
|
|
block.forEach(ssa => {
|
|
output.push(...generateSSA(alloc, ssa))
|
|
})
|
|
|
|
return output
|
|
}
|
|
|
|
export const generateSSA = (alloc: RegAlloc, ssa: AbsInsn2): Array<string> => {
|
|
let output: Array<string> = []
|
|
|
|
switch (ssa.type) {
|
|
case 'copy':
|
|
output = generateSSA_Copy(alloc, ssa)
|
|
break
|
|
|
|
case 'unary':
|
|
output = generateSSA_Unary(alloc, ssa)
|
|
break
|
|
}
|
|
|
|
return output
|
|
}
|
|
|
|
export const generateSSA_Copy = (alloc: RegAlloc, ssa: AbsInsnCopy): Array<string> => {
|
|
const output: Array<string> = []
|
|
|
|
const source = typeof ssa.source === 'number'
|
|
? ssa.source.toString()
|
|
: getAlloc(alloc, ssa.source).name
|
|
|
|
switch (ssa.dest.type) {
|
|
case LocType.TEMPORARY:
|
|
const dest = getAlloc(alloc, ssa.dest)
|
|
// TODO: Remove later with peephole optimizer
|
|
if (dest.name !== source) {
|
|
output.push(`LD ${dest.name}, ${source}`)
|
|
}
|
|
break
|
|
|
|
case LocType.REGISTER:
|
|
if (isA(ssa.dest) && typeof ssa.source !== 'number' && ssa.source.type === LocType.VARIABLE) {
|
|
output.push(`LD A, (${ssa.source.name})`)
|
|
// TODO: Remove check later with peephole optimizer
|
|
} else if (source !== ssa.dest.name) {
|
|
output.push(`LD ${ssa.dest.name}, ${source}`)
|
|
}
|
|
break
|
|
|
|
case LocType.VARIABLE:
|
|
if (source !== R8.A) {
|
|
throw new Error(`can only deref address into A (had ${source})`)
|
|
}
|
|
output.push(`LD (${ssa.dest.name}), A`)
|
|
break
|
|
|
|
default:
|
|
throw new Error(`unsupported destination type \`${ssa.dest.type}'`)
|
|
}
|
|
|
|
return output
|
|
}
|
|
|
|
const getAlloc = (alloc: RegAlloc, loc: Loc): Loc => {
|
|
const destAlloc = alloc[loc.toString()]
|
|
if (typeof destAlloc === "object") {
|
|
throw new Error("stack variables not yet supported")
|
|
}
|
|
|
|
return Loc.reg(destAlloc)
|
|
}
|
|
|
|
export const generateSSA_Unary = (alloc: RegAlloc, ssa: AbsInsn2Unary): Array<string> => {
|
|
if (!isA(ssa.dest)) {
|
|
throw new Error("Unexpected form for unary operation")
|
|
}
|
|
|
|
const source = typeof ssa.source === 'number'
|
|
? ssa.source.toString()
|
|
: getAlloc(alloc, ssa.source).name
|
|
|
|
switch (ssa.op) {
|
|
case "add":
|
|
return [`ADD ${source}`]
|
|
|
|
case "arith_negate":
|
|
return ["CPL", "INC A"]
|
|
|
|
case "bit_negate":
|
|
return ["CPL"]
|
|
|
|
default:
|
|
throw new Error(`unsupported unary op \`${ssa.op}'`)
|
|
}
|
|
}
|
|
|
|
const isA = (loc: Operand): boolean =>
|
|
typeof loc === "object" && loc.type === LocType.REGISTER && loc.name === R8.A
|