From 1a944de1a192893e3862912ff379afbdd04c73fe Mon Sep 17 00:00:00 2001 From: Forest Belton Date: Wed, 15 Sep 2021 15:43:05 -0400 Subject: [PATCH] Finish basic register allocation --- lib/data/graph.ts | 2 +- lib/data/set.ts | 2 +- lib/live.ts | 33 ------------------------- lib/regalloc.ts | 56 ++++++++++++++++++++++++++++++++++++++----- lib/sm83/cpu.ts | 12 ++++++++++ test/regalloc.spec.ts | 18 +++++++++++++- 6 files changed, 81 insertions(+), 42 deletions(-) delete mode 100644 lib/live.ts create mode 100644 lib/sm83/cpu.ts diff --git a/lib/data/graph.ts b/lib/data/graph.ts index ada175a..55a0414 100644 --- a/lib/data/graph.ts +++ b/lib/data/graph.ts @@ -111,7 +111,7 @@ export const colorGreedy = (g: Graph, vertexOrdering: Array): Grap } const coloring: GraphColoring = { numColors: 0, colors: {} } - const usedColors = {} + const usedColors: { [c: number]: boolean } = {} vertexOrdering.forEach(v => { const ns = neighbors(g, v) diff --git a/lib/data/set.ts b/lib/data/set.ts index 668dc93..c2c7302 100644 --- a/lib/data/set.ts +++ b/lib/data/set.ts @@ -15,7 +15,7 @@ export const setEquals = (xs: Set, ys: Set): boolean => { return false } - for (const x of xs) { + for (const x of Array.from(xs)) { if (!ys.has(x)) { return false } diff --git a/lib/live.ts b/lib/live.ts deleted file mode 100644 index ac5c6a0..0000000 --- a/lib/live.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { Loc } from "./ir/loc" -import type { SSA } from "./ir/ssa" - -export type LivenessInfo = Array> - -export const liveness = (block: Array): LivenessInfo => { - const info: LivenessInfo = [] - - for (let i = block.length - 1; i >= 0; --i) { - const insn = block[i] - const last = info[i + 1] || new Set() - - info[i] = new Set() - - if (typeof insn.source !== "number") { - info[i].add(insn.source) - } - - if ("source1" in insn && typeof insn.source1 !== "number") { - info[i].add(insn.source1) - } - - last.forEach(loc => { - if (loc === insn.dest) { - return - } - - info[i].add(loc) - }) - } - - return info -} diff --git a/lib/regalloc.ts b/lib/regalloc.ts index c108df3..91fe19e 100644 --- a/lib/regalloc.ts +++ b/lib/regalloc.ts @@ -1,5 +1,5 @@ -import { createGraph, Graph } from "./data/graph" - +import { colorGreedy, createGraph, Graph, maxCardinalitySearch } from "./data/graph" +import { R8, StackOffset } from "./sm83/cpu" import type { Loc } from "./ir/loc" import type { SSA } from "./ir/ssa" @@ -39,10 +39,14 @@ export const locations = (block: Array): Set => { const ls: Set = new Set() block.forEach(ssa => { + ls.add(ssa.dest) + + if (typeof ssa.source !== "number") { + ls.add(ssa.source) + } + if ("source1" in ssa && typeof ssa.source1 !== "number") { ls.add(ssa.source1) - } else if (typeof ssa.source !== "number") { - ls.add(ssa.source) } }) @@ -51,13 +55,53 @@ export const locations = (block: Array): Set => { export const interference = (block: Array, live: LivenessInfo): Graph => createGraph((v, e) => { + const locs = locations(block) + locs.forEach(loc => { + v(loc.toString(), loc) + }) + block.forEach((ssa, i) => live[i + 1].forEach(u => { if (ssa.dest.toString() !== u.toString()) { - v(ssa.dest.toString(), ssa.dest) - v(u.toString(), u) e(ssa.dest.toString(), u.toString()) } }) ) }) + +type RegAlloc = { + [s: string]: R8 | StackOffset, +} + +export const allocateRegisters = (block: 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(Object.values(R8)) + const colorMap: { [c: number]: R8 | 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 +} diff --git a/lib/sm83/cpu.ts b/lib/sm83/cpu.ts new file mode 100644 index 0000000..112b948 --- /dev/null +++ b/lib/sm83/cpu.ts @@ -0,0 +1,12 @@ +export enum R8 { + A = "A", + B = "B", + C = "C", + D = "D", + E = "E", + H = "H", + L = "L", + HL = "(HL)", +} + +export type StackOffset = { offset: number } diff --git a/test/regalloc.spec.ts b/test/regalloc.spec.ts index 8e684f1..cbaa17d 100644 --- a/test/regalloc.spec.ts +++ b/test/regalloc.spec.ts @@ -3,7 +3,7 @@ import { edgeConnects } from "../lib/data/graph" import { Loc } from "../lib/ir/loc" import type { SSA } from "../lib/ir/ssa" -import { interference, liveness } from "../lib/regalloc" +import { allocateRegisters, interference, liveness } from "../lib/regalloc" describe("liveness", () => { it("computes liveness", () => { @@ -42,3 +42,19 @@ describe("interference", () => { expect(edgeConnects(g, "a", "b")).to.be.true }) }) + +describe("allocateRegisters", () => { + it("allocates registers", () => { + const block: Array = [ + { dest: Loc.vari("a"), source: 7 }, + { dest: Loc.vari("b"), source: 3 }, + { dest: Loc.vari("x"), source: Loc.vari("a") } + ] + + const alloc = allocateRegisters(block) + + expect(alloc.a).to.equal("A") + expect(alloc.b).to.equal("B") + expect(alloc.x).to.equal("A") + }) +})