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.
 
 

108 lines
2.9 KiB

import { colorGreedy, createGraph, Graph, maxCardinalitySearch } from "./data/graph"
import { R8, StackOffset } from "./sm83/cpu"
import { Loc } from "./ir/loc"
import type { AbsInsn2 } from "./ir/insn"
export type LivenessInfo = Array<Set<Loc>>
export const liveness = (block: Array<AbsInsn2>): LivenessInfo => {
const info: LivenessInfo = []
info[block.length] = new Set()
for (let i = block.length - 1; i >= 0; --i) {
const insn = block[i]
const last = info[i + 1]
info[i] = new Set()
// TODO: Add support for goto
if (insn.type === "goto") {
throw new Error("goto not supported in liveness analysis yet")
}
if ("source" in insn && typeof insn.source !== "number") {
info[i].add(insn.source)
}
last.forEach(loc => {
if (insn.dest instanceof Loc && loc.ppName() === insn.dest.ppName()) {
return
}
info[i].add(loc)
})
}
return info
}
export const locations = (block: Array<AbsInsn2>): Set<Loc> => {
const ls: Set<Loc> = new Set()
block.forEach(ssa => {
if (ssa.type === "goto" || ssa.type === "label") {
return
}
ls.add(ssa.dest)
if (typeof ssa.source !== "number") {
ls.add(ssa.source)
}
})
return ls
}
export const interference = (block: Array<AbsInsn2>, live: LivenessInfo): Graph<Loc> =>
createGraph((v, e) => {
const locs = locations(block)
locs.forEach(loc => {
v(loc.ppName(), loc)
})
block.forEach((insn, i) =>
live[i + 1].forEach(u => {
if (insn.dest instanceof Loc && insn.dest.ppName() !== u.ppName()) {
e(insn.dest.ppName(), u.ppName())
}
})
)
})
export type RegAlloc = {
[s: string]: string | StackOffset,
}
export const allocateRegisters = (block: Array<AbsInsn2>, registers: Array<string>): RegAlloc => {
const info = liveness(block)
const graph = interference(block, info)
const ordering = maxCardinalitySearch(graph)
const coloring = colorGreedy(graph, ordering)
const allocation: RegAlloc = {}
const availableRegisters = new Set(registers)
const colorMap: { [c: number]: string | StackOffset } = {}
let nextStackOffset = 0
Object.entries(coloring.colors).forEach(([vertex, color]) => {
if (typeof colorMap[color] !== 'undefined') {
allocation[vertex] = colorMap[color]
return
}
let value = null
if (availableRegisters.size == 0) {
value = { offset: nextStackOffset++ }
} else {
const result = availableRegisters.values().next()
value = result.value
availableRegisters.delete(value)
}
allocation[vertex] = value
colorMap[color] = value
})
return allocation
}