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.

107 lines
2.8 KiB

  1. import { colorGreedy, createGraph, Graph, maxCardinalitySearch } from "./data/graph"
  2. import { R8, StackOffset } from "./sm83/cpu"
  3. import type { Loc } from "./ir/loc"
  4. import type { SSA } from "./ir/ssa"
  5. export type LivenessInfo = Array<Set<Loc>>
  6. export const liveness = (block: Array<SSA>): LivenessInfo => {
  7. const info: LivenessInfo = []
  8. info[block.length] = new Set()
  9. for (let i = block.length - 1; i >= 0; --i) {
  10. const insn = block[i]
  11. const last = info[i + 1]
  12. info[i] = new Set()
  13. if (typeof insn.source !== "number") {
  14. info[i].add(insn.source)
  15. }
  16. if ("source1" in insn && typeof insn.source1 !== "number") {
  17. info[i].add(insn.source1)
  18. }
  19. last.forEach(loc => {
  20. if (loc.toString() === insn.dest.toString()) {
  21. return
  22. }
  23. info[i].add(loc)
  24. })
  25. }
  26. return info
  27. }
  28. export const locations = (block: Array<SSA>): Set<Loc> => {
  29. const ls: Set<Loc> = new Set()
  30. block.forEach(ssa => {
  31. ls.add(ssa.dest)
  32. if (typeof ssa.source !== "number") {
  33. ls.add(ssa.source)
  34. }
  35. if ("source1" in ssa && typeof ssa.source1 !== "number") {
  36. ls.add(ssa.source1)
  37. }
  38. })
  39. return ls
  40. }
  41. export const interference = (block: Array<SSA>, live: LivenessInfo): Graph<Loc> =>
  42. createGraph((v, e) => {
  43. const locs = locations(block)
  44. locs.forEach(loc => {
  45. v(loc.toString(), loc)
  46. })
  47. block.forEach((ssa, i) =>
  48. live[i + 1].forEach(u => {
  49. if (ssa.dest.toString() !== u.toString()) {
  50. e(ssa.dest.toString(), u.toString())
  51. }
  52. })
  53. )
  54. })
  55. export type RegAlloc = {
  56. [s: string]: string | StackOffset,
  57. }
  58. export const allocateRegisters = (block: Array<SSA>, registers: Array<string>): RegAlloc => {
  59. const info = liveness(block)
  60. const graph = interference(block, info)
  61. const ordering = maxCardinalitySearch(graph)
  62. const coloring = colorGreedy(graph, ordering)
  63. const allocation: RegAlloc = {}
  64. const availableRegisters = new Set(registers)
  65. const colorMap: { [c: number]: string | StackOffset } = {}
  66. let nextStackOffset = 0
  67. Object.entries(coloring.colors).forEach(([vertex, color]) => {
  68. if (typeof colorMap[color] !== 'undefined') {
  69. allocation[vertex] = colorMap[color]
  70. return
  71. }
  72. let value = null
  73. if (availableRegisters.size == 0) {
  74. value = { offset: nextStackOffset++ }
  75. } else {
  76. const result = availableRegisters.values().next()
  77. value = result.value
  78. availableRegisters.delete(value)
  79. }
  80. allocation[vertex] = value
  81. colorMap[color] = value
  82. })
  83. return allocation
  84. }