|
|
- import { colorGreedy, createGraph, Graph, maxCardinalitySearch } from "./data/graph"
- import { setEquals, union } from "./data/set"
- import { BasicBlock } from "./ir/block"
- import { Loc } from "./ir/loc"
- import { StackOffset } from "./sm83/cpu"
-
- export type LivenessInfo = Array<Set<Loc>>
-
- export const liveness = (block: BasicBlock): LivenessInfo => {
- const info: LivenessInfo = []
-
- info[block.insns.length] = new Set()
- for (let i = block.insns.length - 1; i >= 0; --i) {
- const insn = block.insns[i]
- const last = info[i + 1]
-
- info[i] = new Set()
-
- if (insn.type === "goto") {
- continue
- }
-
- 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)
- })
- }
-
- let dirty = true
- while (dirty) {
- dirty = false
- for (let i = block.insns.length - 1; i >= 0; --i) {
- if (block.insns[i].type !== "goto") {
- continue
- }
-
- const labelSet = info[getLabelIndex(block, block.insns[i].dest as string)]
- if (setEquals(info[i], labelSet)) {
- continue
- }
-
- dirty = true
- info[i] = union(info[i], labelSet)
- }
- }
-
- return info
- }
-
- export const getLabelIndex = (block: BasicBlock, label: string): number => {
- let idx = -1
-
- for (let i = 0; i < block.insns.length; ++i) {
- if (block.insns[i].type === "label" && block.insns[i].dest === label) {
- idx = i
- break
- }
- }
-
- return idx
- }
-
- export const interference = (block: BasicBlock, live: LivenessInfo): Graph<Loc> =>
- createGraph((v, e) => {
- block.locs().forEach(loc => {
- v(loc.ppName(), loc)
- })
-
- block.insns.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: BasicBlock, 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
- }
|