|
|
- import type { SSA, SSABinary, SSACopy, SSAUnary } from "./ir"
-
- const reg8 = ["B", "C", "D", "E"] as const
-
- type R8 = typeof reg8[number]
-
- class ASMState {
- regs: { [r in R8]: string | null }
- syms: { [s: string]: R8 }
- stack_offsets: { [s: string]: number }
- cur_offset: number
- insns: Array<string>
-
- constructor() {
- this.regs = { "B": null, "C": null, "D": null, "E": null }
- this.syms = {}
- this.stack_offsets = {}
- this.cur_offset = 0
- this.insns = []
- }
-
- // TODO: Generalize for u16
- get_sym_loc(sym: string): R8 | number | null {
- // return register if already allocated
- if (typeof this.syms[sym] !== "undefined") {
- return this.syms[sym]
- }
-
- // return stack offset if already allocated
- if (typeof this.stack_offsets[sym] !== "undefined") {
- return this.cur_offset - this.stack_offsets[sym]
- }
-
- return null
- }
-
- alloc_sym_loc(sym: string): R8 | number {
- const existing_loc = this.get_sym_loc(sym)
- if (existing_loc !== null) {
- return existing_loc
- }
-
- // look for free register
- for (const r8 of reg8) {
- if (this.regs[r8] === null) {
- this.regs[r8] = sym
- this.syms[sym] = r8
- return r8
- }
- }
-
- // allocate space on stack
- this.cur_offset++
- this.stack_offsets[sym] = this.cur_offset
-
- this.insns.push("ADD SP, -1")
- return this.stack_offsets[sym]
- }
- }
-
- export const convertASM = (ir: Array<SSA>): Array<string> => {
- const state = new ASMState()
-
- ir.forEach(ssa => convertASM_SSA(state, ssa))
-
- for (let sym of Object.keys(state.syms)) {
- if (sym.startsWith("temp")) {
- continue
- }
-
- state.insns.push(
- `LD A, ${state.syms[sym]}`,
- `LD (${sym}), A`
- )
- }
-
- for (let sym of Object.keys(state.stack_offsets)) {
- if (sym.startsWith("temp")) {
- continue
- }
-
- state.insns.push(
- `LD HL, SP + (${state.cur_offset - state.stack_offsets[sym]})`,
- `LD A, (HL)`,
- `LD (${sym}), A`
- )
- }
-
- if (state.cur_offset !== 0) {
- state.insns.push(`ADD SP, ${state.cur_offset}`)
- }
-
- return state.insns
- }
-
- // TODO: Track liveness
- const convertASM_SSA = (state: ASMState, ssa: SSA): void => {
- if ("source1" in ssa) { // Binary
- convertASM_SSA_Binary(state, ssa)
- } else if ("op" in ssa) { // Unary
- convertASM_SSA_Unary(state, ssa)
- } else { // Copy
- convertASM_SSA_Copy(state, ssa)
- }
- }
-
- export const convertASM_SSA_Binary = (state: ASMState, ssa: SSABinary): void => {
- const dest = state.alloc_sym_loc(ssa.dest)
-
- if (typeof ssa.source === "number") {
- state.insns.push(`LD A, ${ssa.source}`)
- } else {
- const loc = state.get_sym_loc(ssa.source)
-
- if (loc === null) {
- state.insns.push(`LD A, (${ssa.source})`)
- } else if (typeof loc === "string") {
- state.insns.push(`LD A, ${loc}`)
- } else {
- state.insns.push(
- `LD HL, SP + (${loc})`,
- `LD A, (HL)`
- )
- }
- }
-
- switch (ssa.op) {
- case "add":
- if (typeof ssa.source1 === "number") {
- state.insns.push(`ADD ${ssa.source1}`)
- } else {
- const loc = state.get_sym_loc(ssa.source1)
- if (loc === null) {
- throw new Error('fuck')
- } else if (typeof loc === "string") {
- state.insns.push(`ADD ${loc}`)
- } else {
- throw new Error('fuck')
- state.insns.push(
- `LD HL, SP + (${loc})`
- )
- }
- }
- break
-
- default:
- throw new Error(`unsupported binary op \`${ssa.op}'`)
- }
-
- if (typeof dest === "string") {
- state.insns.push(`LD ${dest}, A`)
- } else {
- state.insns.push(
- `LD HL, SP + (${dest})`,
- `LD (HL), A`
- )
- }
- }
-
- export const convertASM_SSA_Unary = (state: ASMState, ssa: SSAUnary): void => {
- const dest = state.alloc_sym_loc(ssa.dest)
-
- if (typeof ssa.source == "number") {
- state.insns.push(`LD A, ${ssa.source}`)
- } else {
- const loc = state.get_sym_loc(ssa.source)
-
- if (loc === null) {
- state.insns.push(`LD A, (${ssa.source})`)
- } else if (typeof loc === "string") {
- state.insns.push(`LD A, ${loc}`)
- } else {
- state.insns.push(
- `LD HL, SP + (${loc})`,
- `LD A, (HL)`
- )
- }
- }
-
- switch (ssa.op) {
- case 'arith_negate':
- state.insns.push(
- `CPL`,
- `INC A`,
- )
- break
-
- case 'bit_negate':
- state.insns.push(
- `CPL`
- )
- break
-
- default:
- throw new Error(`unsupported unary op \`'${ssa.op}`)
- }
-
- if (typeof dest === "string") {
- state.insns.push(`LD ${dest}, A`)
- } else {
- state.insns.push(
- `LD HL, SP + (${dest})`,
- `LD (HL), A`
- )
- }
- }
-
-
- export const convertASM_SSA_Copy = (state: ASMState, ssa: SSACopy): void => {
- const dest = state.alloc_sym_loc(ssa.dest)
-
- let source = ""
- if (typeof ssa.source == "number") {
- source = ssa.source.toString()
- } else {
- const loc = state.get_sym_loc(ssa.source)
-
- if (loc === null) {
- state.insns.push(`LD A, (${ssa.source})`)
- source = "A"
- } else if (typeof loc === "string") {
- source = loc
- } else {
- state.insns.push(
- `LD HL, SP + (${loc})`,
- `LD A, (HL)`
- )
- source = "A"
- }
- }
-
- if (typeof dest === "string") {
- state.insns.push(`LD ${dest}, ${source}`)
- } else {
- state.insns.push(
- `LD HL, SP + (${dest})`,
- `LD (HL), ${source}`
- )
- }
- }
|