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> export const liveness = (block: Array): 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): Set => { const ls: Set = 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, live: LivenessInfo): Graph => 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, registers: Array): 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 }