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.

99 lines
2.6 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. last.forEach(loc => {
  17. if (loc.toString() === insn.dest.toString()) {
  18. return
  19. }
  20. info[i].add(loc)
  21. })
  22. }
  23. return info
  24. }
  25. export const locations = (block: Array<SSA>): Set<Loc> => {
  26. const ls: Set<Loc> = new Set()
  27. block.forEach(ssa => {
  28. ls.add(ssa.dest)
  29. if (typeof ssa.source !== "number") {
  30. ls.add(ssa.source)
  31. }
  32. })
  33. return ls
  34. }
  35. export const interference = (block: Array<SSA>, live: LivenessInfo): Graph<Loc> =>
  36. createGraph((v, e) => {
  37. const locs = locations(block)
  38. locs.forEach(loc => {
  39. v(loc.toString(), loc)
  40. })
  41. block.forEach((ssa, i) =>
  42. live[i + 1].forEach(u => {
  43. if (ssa.dest.toString() !== u.toString()) {
  44. e(ssa.dest.toString(), u.toString())
  45. }
  46. })
  47. )
  48. })
  49. export type RegAlloc = {
  50. [s: string]: string | StackOffset,
  51. }
  52. export const allocateRegisters = (block: Array<SSA>, registers: Array<string>): RegAlloc => {
  53. const info = liveness(block)
  54. const graph = interference(block, info)
  55. const ordering = maxCardinalitySearch(graph)
  56. const coloring = colorGreedy(graph, ordering)
  57. const allocation: RegAlloc = {}
  58. const availableRegisters = new Set(registers)
  59. const colorMap: { [c: number]: string | StackOffset } = {}
  60. let nextStackOffset = 0
  61. Object.entries(coloring.colors).forEach(([vertex, color]) => {
  62. if (typeof colorMap[color] !== 'undefined') {
  63. allocation[vertex] = colorMap[color]
  64. return
  65. }
  66. let value = null
  67. if (availableRegisters.size == 0) {
  68. value = { offset: nextStackOffset++ }
  69. } else {
  70. const result = availableRegisters.values().next()
  71. value = result.value
  72. availableRegisters.delete(value)
  73. }
  74. allocation[vertex] = value
  75. colorMap[color] = value
  76. })
  77. return allocation
  78. }