|
|
- import { R8 } from "../sm83/cpu"
- import { Loc, LocType } from "../ir/loc"
- import type { Operand, SSA, SSABinary, SSACopy, SSAUnary } from "../ir/ssa"
- import type { RegAlloc } from "../regalloc"
- import { BinaryOp, UnaryOp } from "../ast"
-
- export const generateBlock = (alloc: RegAlloc, block: Array<SSA>): Array<string> => {
- const output: Array<string> = []
-
- block.forEach(ssa => {
- output.push(...generateSSA(alloc, ssa))
- })
-
- return output
- }
-
- export const generateSSA = (alloc: RegAlloc, ssa: SSA): Array<string> => {
- let output: Array<string> = []
-
- if ("op" in ssa) {
- output = generateSSA_Unary(alloc, ssa)
- } else {
- output = generateSSA_Copy(alloc, ssa)
- }
-
- return output
- }
-
- export const generateSSA_Copy = (alloc: RegAlloc, ssa: SSACopy): 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 with peephole optimizer
- } else if (source !== ssa.dest.name) {
- output.push(`LD ${ssa.dest.name}, ${source}`)
- }
- break
-
- case LocType.VARIABLE:
- if (source !== R8.A) {
- console.log(source, ssa)
- throw new Error("unsupported")
- }
- 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: SSAUnary): 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}'`)
- }
- }
-
- /*
- export const generateSSA_Binary = (alloc: RegAlloc, ssa: SSABinary): Array<string> => {
- if (!isA(ssa.dest) || !isA(ssa.source)) {
- throw new Error("Unexpected form for binary operation")
- }
-
- const output: Array<string> = []
-
-
- switch (ssa.op) {
- case "add":
- output.push(`ADD ${source}`)
- break
-
- default:
- throw new Error(`unsupported binary op \`${ssa.op}'`)
- }
-
- return output
- } */
-
- const isA = (loc: Operand): boolean =>
- typeof loc === "object" && loc.type === LocType.REGISTER && loc.name === R8.A
|