nirslots.nim 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2023 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## Management of slots. Similar to "register allocation"
  10. ## in lower level languages.
  11. import std / [assertions, tables]
  12. import nirtypes, nirinsts
  13. type
  14. SlotManagerFlag* = enum
  15. ReuseTemps,
  16. ReuseVars
  17. SlotKind* = enum
  18. Temp, Perm
  19. SlotManager* = object # "register allocator"
  20. live: Table[SymId, (SlotKind, TypeId)]
  21. dead: Table[TypeId, seq[SymId]]
  22. flags: set[SlotManagerFlag]
  23. inScope: seq[SymId]
  24. proc initSlotManager*(flags: set[SlotManagerFlag]): SlotManager {.inline.} =
  25. SlotManager(flags: flags)
  26. proc allocRaw(m: var SlotManager; t: TypeId; f: SlotManagerFlag; k: SlotKind;
  27. symIdgen: var int32): SymId {.inline.} =
  28. if f in m.flags and m.dead.hasKey(t) and m.dead[t].len > 0:
  29. result = m.dead[t].pop()
  30. else:
  31. inc symIdgen
  32. result = SymId(symIdgen)
  33. m.inScope.add result
  34. m.live[result] = (k, t)
  35. proc allocTemp*(m: var SlotManager; t: TypeId; symIdgen: var int32): SymId {.inline.} =
  36. result = allocRaw(m, t, ReuseTemps, Temp, symIdgen)
  37. proc allocVar*(m: var SlotManager; t: TypeId; symIdgen: var int32): SymId {.inline.} =
  38. result = allocRaw(m, t, ReuseVars, Perm, symIdgen)
  39. proc freeLoc*(m: var SlotManager; s: SymId) =
  40. let t = m.live.getOrDefault(s)
  41. assert t[1].int != 0
  42. m.live.del s
  43. m.dead.mgetOrPut(t[1], @[]).add s
  44. proc freeTemp*(m: var SlotManager; s: SymId) =
  45. let t = m.live.getOrDefault(s)
  46. if t[1].int != 0 and t[0] == Temp:
  47. m.live.del s
  48. m.dead.mgetOrPut(t[1], @[]).add s
  49. iterator stillAlive*(m: SlotManager): (SymId, TypeId) =
  50. for k, v in pairs(m.live):
  51. yield (k, v[1])
  52. proc getType*(m: SlotManager; s: SymId): TypeId {.inline.} = m.live[s][1]
  53. proc openScope*(m: var SlotManager) =
  54. m.inScope.add SymId(-1) # add marker
  55. proc closeScope*(m: var SlotManager) =
  56. var i = m.inScope.len - 1
  57. while i >= 0:
  58. if m.inScope[i] == SymId(-1):
  59. m.inScope.setLen i
  60. break
  61. dec i
  62. when isMainModule:
  63. var symIdgen: int32
  64. var m = initSlotManager({ReuseTemps})
  65. var g = initTypeGraph(Literals())
  66. let a = g.openType ArrayTy
  67. g.addBuiltinType Int8Id
  68. g.addArrayLen 5
  69. let finalArrayType = finishType(g, a)
  70. let obj = g.openType ObjectDecl
  71. g.addName "MyType"
  72. g.addField "p", finalArrayType, 0
  73. let objB = finishType(g, obj)
  74. let x = m.allocTemp(objB, symIdgen)
  75. assert x.int == 0
  76. let y = m.allocTemp(objB, symIdgen)
  77. assert y.int == 1
  78. let z = m.allocTemp(Int8Id, symIdgen)
  79. assert z.int == 2
  80. m.freeLoc y
  81. let y2 = m.allocTemp(objB, symIdgen)
  82. assert y2.int == 1