nirtypes.nim 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  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. ## Type system for NIR. Close to C's type system but without its quirks.
  10. import std / [assertions, hashes]
  11. import .. / ic / [bitabs, rodfiles]
  12. type
  13. NirTypeKind* = enum
  14. VoidTy, IntTy, UIntTy, FloatTy, BoolTy, CharTy, NameVal,
  15. IntVal, SizeVal, AlignVal, OffsetVal,
  16. AnnotationVal,
  17. ObjectTy,
  18. UnionTy,
  19. VarargsTy, # the `...` in a C prototype; also the last "atom"
  20. APtrTy, # pointer to aliasable memory
  21. UPtrTy, # pointer to unique/unaliasable memory
  22. AArrayPtrTy, # pointer to array of aliasable memory
  23. UArrayPtrTy, # pointer to array of unique/unaliasable memory
  24. ArrayTy,
  25. LastArrayTy, # array of unspecified size as a last field inside an object
  26. ProcTy,
  27. ObjectDecl,
  28. UnionDecl,
  29. FieldDecl
  30. const
  31. TypeKindBits = 8'u32
  32. TypeKindMask = (1'u32 shl TypeKindBits) - 1'u32
  33. type
  34. TypeNode* = object # 4 bytes
  35. x: uint32
  36. template kind*(n: TypeNode): NirTypeKind = NirTypeKind(n.x and TypeKindMask)
  37. template operand(n: TypeNode): uint32 = (n.x shr TypeKindBits)
  38. proc integralBits*(n: TypeNode): int {.inline.} =
  39. # Number of bits in the IntTy, etc. Only valid for integral types.
  40. assert n.kind in {IntTy, UIntTy, FloatTy, BoolTy, CharTy}
  41. result = int(n.operand)
  42. template toX(k: NirTypeKind; operand: uint32): uint32 =
  43. uint32(k) or (operand shl TypeKindBits)
  44. template toX(k: NirTypeKind; operand: LitId): uint32 =
  45. uint32(k) or (operand.uint32 shl TypeKindBits)
  46. type
  47. TypeId* = distinct int
  48. proc `==`*(a, b: TypeId): bool {.borrow.}
  49. proc hash*(a: TypeId): Hash {.borrow.}
  50. type
  51. Literals* = ref object
  52. strings*: BiTable[string]
  53. numbers*: BiTable[int64]
  54. TypeGraph* = object
  55. nodes: seq[TypeNode]
  56. lit: Literals
  57. const
  58. VoidId* = TypeId 0
  59. Bool8Id* = TypeId 1
  60. Char8Id* = TypeId 2
  61. Int8Id* = TypeId 3
  62. Int16Id* = TypeId 4
  63. Int32Id* = TypeId 5
  64. Int64Id* = TypeId 6
  65. UInt8Id* = TypeId 7
  66. UInt16Id* = TypeId 8
  67. UInt32Id* = TypeId 9
  68. UInt64Id* = TypeId 10
  69. Float32Id* = TypeId 11
  70. Float64Id* = TypeId 12
  71. VoidPtrId* = TypeId 13
  72. LastBuiltinId* = 13
  73. proc initTypeGraph*(lit: Literals): TypeGraph =
  74. result = TypeGraph(nodes: @[
  75. TypeNode(x: toX(VoidTy, 0'u32)),
  76. TypeNode(x: toX(BoolTy, 8'u32)),
  77. TypeNode(x: toX(CharTy, 8'u32)),
  78. TypeNode(x: toX(IntTy, 8'u32)),
  79. TypeNode(x: toX(IntTy, 16'u32)),
  80. TypeNode(x: toX(IntTy, 32'u32)),
  81. TypeNode(x: toX(IntTy, 64'u32)),
  82. TypeNode(x: toX(UIntTy, 8'u32)),
  83. TypeNode(x: toX(UIntTy, 16'u32)),
  84. TypeNode(x: toX(UIntTy, 32'u32)),
  85. TypeNode(x: toX(UIntTy, 64'u32)),
  86. TypeNode(x: toX(FloatTy, 32'u32)),
  87. TypeNode(x: toX(FloatTy, 64'u32)),
  88. TypeNode(x: toX(APtrTy, 2'u32)),
  89. TypeNode(x: toX(VoidTy, 0'u32))
  90. ], lit: lit)
  91. assert result.nodes.len == LastBuiltinId+2
  92. type
  93. TypePatchPos* = distinct int
  94. const
  95. InvalidTypePatchPos* = TypePatchPos(-1)
  96. LastAtomicValue = VarargsTy
  97. proc isValid(p: TypePatchPos): bool {.inline.} = p.int != -1
  98. proc prepare(tree: var TypeGraph; kind: NirTypeKind): TypePatchPos =
  99. result = TypePatchPos tree.nodes.len
  100. tree.nodes.add TypeNode(x: toX(kind, 1'u32))
  101. proc isAtom(tree: TypeGraph; pos: int): bool {.inline.} = tree.nodes[pos].kind <= LastAtomicValue
  102. proc isAtom(tree: TypeGraph; pos: TypeId): bool {.inline.} = tree.nodes[pos.int].kind <= LastAtomicValue
  103. proc patch(tree: var TypeGraph; pos: TypePatchPos) =
  104. let pos = pos.int
  105. let k = tree.nodes[pos].kind
  106. assert k > LastAtomicValue
  107. let distance = int32(tree.nodes.len - pos)
  108. assert distance > 0
  109. tree.nodes[pos].x = toX(k, cast[uint32](distance))
  110. proc len*(tree: TypeGraph): int {.inline.} = tree.nodes.len
  111. template rawSpan(n: TypeNode): int = int(operand(n))
  112. proc nextChild(tree: TypeGraph; pos: var int) {.inline.} =
  113. if tree.nodes[pos].kind > LastAtomicValue:
  114. assert tree.nodes[pos].operand > 0'u32
  115. inc pos, tree.nodes[pos].rawSpan
  116. else:
  117. inc pos
  118. iterator sons*(tree: TypeGraph; n: TypeId): TypeId =
  119. var pos = n.int
  120. assert tree.nodes[pos].kind > LastAtomicValue
  121. let last = pos + tree.nodes[pos].rawSpan
  122. inc pos
  123. while pos < last:
  124. yield TypeId pos
  125. nextChild tree, pos
  126. template `[]`*(t: TypeGraph; n: TypeId): TypeNode = t.nodes[n.int]
  127. proc elementType*(tree: TypeGraph; n: TypeId): TypeId {.inline.} =
  128. assert tree[n].kind in {APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy, ArrayTy, LastArrayTy}
  129. result = TypeId(n.int+1)
  130. proc litId*(n: TypeNode): LitId {.inline.} =
  131. assert n.kind in {NameVal, IntVal, SizeVal, AlignVal, OffsetVal, AnnotationVal, ObjectTy, UnionTy}
  132. result = LitId(n.operand)
  133. proc kind*(tree: TypeGraph; n: TypeId): NirTypeKind {.inline.} = tree[n].kind
  134. proc span(tree: TypeGraph; pos: int): int {.inline.} =
  135. if tree.nodes[pos].kind <= LastAtomicValue: 1 else: int(tree.nodes[pos].operand)
  136. proc sons2(tree: TypeGraph; n: TypeId): (TypeId, TypeId) =
  137. assert(not isAtom(tree, n.int))
  138. let a = n.int+1
  139. let b = a + span(tree, a)
  140. result = (TypeId a, TypeId b)
  141. proc sons3(tree: TypeGraph; n: TypeId): (TypeId, TypeId, TypeId) =
  142. assert(not isAtom(tree, n.int))
  143. let a = n.int+1
  144. let b = a + span(tree, a)
  145. let c = b + span(tree, b)
  146. result = (TypeId a, TypeId b, TypeId c)
  147. proc arrayName*(tree: TypeGraph; n: TypeId): TypeId {.inline.} =
  148. assert tree[n].kind == ArrayTy
  149. let (_, _, c) = sons3(tree, n)
  150. result = c
  151. proc arrayLen*(tree: TypeGraph; n: TypeId): BiggestInt =
  152. assert tree[n].kind == ArrayTy
  153. let (_, b) = sons2(tree, n)
  154. result = tree.lit.numbers[LitId tree[b].operand]
  155. proc returnType*(tree: TypeGraph; n: TypeId): (TypeId, TypeId) =
  156. # Returns the positions of the return type + calling convention.
  157. var pos = n.int
  158. assert tree.nodes[pos].kind == ProcTy
  159. let a = n.int+1
  160. let b = a + span(tree, a)
  161. result = (TypeId b, TypeId a) # not a typo, order is reversed
  162. iterator params*(tree: TypeGraph; n: TypeId): TypeId =
  163. var pos = n.int
  164. assert tree.nodes[pos].kind == ProcTy
  165. let last = pos + tree.nodes[pos].rawSpan
  166. inc pos
  167. nextChild tree, pos
  168. nextChild tree, pos
  169. while pos < last:
  170. yield TypeId pos
  171. nextChild tree, pos
  172. proc openType*(tree: var TypeGraph; kind: NirTypeKind): TypePatchPos =
  173. assert kind in {APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy,
  174. ArrayTy, LastArrayTy, ProcTy, ObjectDecl, UnionDecl,
  175. FieldDecl}
  176. result = prepare(tree, kind)
  177. template typeInvariant(p: TypePatchPos) =
  178. when false:
  179. if tree[TypeId(p)].kind == FieldDecl:
  180. var k = 0
  181. for ch in sons(tree, TypeId(p)):
  182. inc k
  183. assert k > 2, "damn! " & $k
  184. proc sealType*(tree: var TypeGraph; p: TypePatchPos) =
  185. patch tree, p
  186. typeInvariant(p)
  187. proc finishType*(tree: var TypeGraph; p: TypePatchPos): TypeId =
  188. # Search for an existing instance of this type in
  189. # order to reduce memory consumption:
  190. patch tree, p
  191. typeInvariant(p)
  192. let s = span(tree, p.int)
  193. var i = 0
  194. while i < p.int:
  195. if tree.nodes[i].x == tree.nodes[p.int].x:
  196. var isMatch = true
  197. for j in 1..<s:
  198. if tree.nodes[j+i].x == tree.nodes[j+p.int].x:
  199. discard "still a match"
  200. else:
  201. isMatch = false
  202. break
  203. if isMatch:
  204. if p.int+s == tree.len:
  205. setLen tree.nodes, p.int
  206. return TypeId(i)
  207. nextChild tree, i
  208. result = TypeId(p)
  209. proc nominalType*(tree: var TypeGraph; kind: NirTypeKind; name: string): TypeId =
  210. assert kind in {ObjectTy, UnionTy}
  211. let content = TypeNode(x: toX(kind, tree.lit.strings.getOrIncl(name)))
  212. for i in 0..<tree.len:
  213. if tree.nodes[i].x == content.x:
  214. return TypeId(i)
  215. result = TypeId tree.nodes.len
  216. tree.nodes.add content
  217. proc addNominalType*(tree: var TypeGraph; kind: NirTypeKind; name: string) =
  218. assert kind in {ObjectTy, UnionTy}
  219. tree.nodes.add TypeNode(x: toX(kind, tree.lit.strings.getOrIncl(name)))
  220. proc getTypeTag*(tree: TypeGraph; t: TypeId): string =
  221. assert tree[t].kind in {ObjectTy, UnionTy}
  222. result = tree.lit.strings[LitId tree[t].operand]
  223. proc addVarargs*(tree: var TypeGraph) =
  224. tree.nodes.add TypeNode(x: toX(VarargsTy, 0'u32))
  225. proc getFloat128Type*(tree: var TypeGraph): TypeId =
  226. result = TypeId tree.nodes.len
  227. tree.nodes.add TypeNode(x: toX(FloatTy, 128'u32))
  228. proc addBuiltinType*(g: var TypeGraph; id: TypeId) =
  229. g.nodes.add g[id]
  230. template firstSon*(n: TypeId): TypeId = TypeId(n.int+1)
  231. proc addType*(g: var TypeGraph; t: TypeId) =
  232. # We cannot simply copy `*Decl` nodes. We have to introduce `*Ty` nodes instead:
  233. if g[t].kind in {ObjectDecl, UnionDecl}:
  234. assert g[t.firstSon].kind == NameVal
  235. let name = LitId g[t.firstSon].operand
  236. if g[t].kind == ObjectDecl:
  237. g.nodes.add TypeNode(x: toX(ObjectTy, name))
  238. else:
  239. g.nodes.add TypeNode(x: toX(UnionTy, name))
  240. else:
  241. let pos = t.int
  242. let L = span(g, pos)
  243. let d = g.nodes.len
  244. g.nodes.setLen(d + L)
  245. assert L > 0
  246. for i in 0..<L:
  247. g.nodes[d+i] = g.nodes[pos+i]
  248. proc addArrayLen*(g: var TypeGraph; len: int64) =
  249. g.nodes.add TypeNode(x: toX(IntVal, g.lit.numbers.getOrIncl(len)))
  250. proc addSize*(g: var TypeGraph; s: int64) =
  251. g.nodes.add TypeNode(x: toX(SizeVal, g.lit.numbers.getOrIncl(s)))
  252. proc addOffset*(g: var TypeGraph; offset: int64) =
  253. g.nodes.add TypeNode(x: toX(OffsetVal, g.lit.numbers.getOrIncl(offset)))
  254. proc addAlign*(g: var TypeGraph; a: int64) =
  255. g.nodes.add TypeNode(x: toX(AlignVal, g.lit.numbers.getOrIncl(a)))
  256. proc addName*(g: var TypeGraph; name: string) =
  257. g.nodes.add TypeNode(x: toX(NameVal, g.lit.strings.getOrIncl(name)))
  258. proc addAnnotation*(g: var TypeGraph; name: string) =
  259. g.nodes.add TypeNode(x: toX(NameVal, g.lit.strings.getOrIncl(name)))
  260. proc addField*(g: var TypeGraph; name: string; typ: TypeId; offset: int64) =
  261. let f = g.openType FieldDecl
  262. g.addType typ
  263. g.addOffset offset
  264. g.addName name
  265. sealType(g, f)
  266. proc ptrTypeOf*(g: var TypeGraph; t: TypeId): TypeId =
  267. let f = g.openType APtrTy
  268. g.addType t
  269. result = finishType(g, f)
  270. proc arrayPtrTypeOf*(g: var TypeGraph; t: TypeId): TypeId =
  271. let f = g.openType AArrayPtrTy
  272. g.addType t
  273. result = finishType(g, f)
  274. proc store*(r: var RodFile; g: TypeGraph) =
  275. storeSeq r, g.nodes
  276. proc load*(r: var RodFile; g: var TypeGraph) =
  277. loadSeq r, g.nodes
  278. proc toString*(dest: var string; g: TypeGraph; i: TypeId) =
  279. case g[i].kind
  280. of VoidTy: dest.add "void"
  281. of IntTy:
  282. dest.add "i"
  283. dest.addInt g[i].operand
  284. of UIntTy:
  285. dest.add "u"
  286. dest.addInt g[i].operand
  287. of FloatTy:
  288. dest.add "f"
  289. dest.addInt g[i].operand
  290. of BoolTy:
  291. dest.add "b"
  292. dest.addInt g[i].operand
  293. of CharTy:
  294. dest.add "c"
  295. dest.addInt g[i].operand
  296. of NameVal, AnnotationVal:
  297. dest.add g.lit.strings[LitId g[i].operand]
  298. of IntVal, SizeVal, AlignVal, OffsetVal:
  299. dest.add $g[i].kind
  300. dest.add ' '
  301. dest.add $g.lit.numbers[LitId g[i].operand]
  302. of VarargsTy:
  303. dest.add "..."
  304. of APtrTy:
  305. dest.add "aptr["
  306. toString(dest, g, g.elementType(i))
  307. dest.add "]"
  308. of UPtrTy:
  309. dest.add "uptr["
  310. toString(dest, g, g.elementType(i))
  311. dest.add "]"
  312. of AArrayPtrTy:
  313. dest.add "aArrayPtr["
  314. toString(dest, g, g.elementType(i))
  315. dest.add "]"
  316. of UArrayPtrTy:
  317. dest.add "uArrayPtr["
  318. toString(dest, g, g.elementType(i))
  319. dest.add "]"
  320. of ArrayTy:
  321. dest.add "Array["
  322. let (elems, len, name) = g.sons3(i)
  323. toString(dest, g, elems)
  324. dest.add ", "
  325. toString(dest, g, len)
  326. dest.add ", "
  327. toString(dest, g, name)
  328. dest.add "]"
  329. of LastArrayTy:
  330. # array of unspecified size as a last field inside an object
  331. dest.add "LastArrayTy["
  332. toString(dest, g, g.elementType(i))
  333. dest.add "]"
  334. of ObjectTy:
  335. dest.add "object "
  336. dest.add g.lit.strings[LitId g[i].operand]
  337. of UnionTy:
  338. dest.add "union "
  339. dest.add g.lit.strings[LitId g[i].operand]
  340. of ProcTy:
  341. dest.add "proc["
  342. for t in sons(g, i):
  343. dest.add ' '
  344. toString(dest, g, t)
  345. dest.add "]"
  346. of ObjectDecl:
  347. dest.add "object["
  348. for t in sons(g, i):
  349. toString(dest, g, t)
  350. dest.add '\n'
  351. dest.add "]"
  352. of UnionDecl:
  353. dest.add "union["
  354. for t in sons(g, i):
  355. toString(dest, g, t)
  356. dest.add '\n'
  357. dest.add "]"
  358. of FieldDecl:
  359. dest.add "field["
  360. for t in sons(g, i):
  361. toString(dest, g, t)
  362. dest.add ' '
  363. dest.add "]"
  364. when false:
  365. let (typ, offset, name) = g.sons3(i)
  366. toString(dest, g, typ)
  367. dest.add ' '
  368. toString(dest, g, offset)
  369. dest.add ' '
  370. toString(dest, g, name)
  371. proc toString*(dest: var string; g: TypeGraph) =
  372. var i = 0
  373. while i < g.len:
  374. dest.add "T<"
  375. dest.addInt i
  376. dest.add "> "
  377. toString(dest, g, TypeId i)
  378. dest.add '\n'
  379. nextChild g, i
  380. iterator allTypes*(g: TypeGraph; start = 0): TypeId =
  381. var i = start
  382. while i < g.len:
  383. yield TypeId i
  384. nextChild g, i
  385. iterator allTypesIncludingInner*(g: TypeGraph; start = 0): TypeId =
  386. var i = start
  387. while i < g.len:
  388. yield TypeId i
  389. inc i
  390. proc `$`(g: TypeGraph): string =
  391. result = ""
  392. toString(result, g)
  393. when isMainModule:
  394. var g = initTypeGraph(Literals())
  395. let a = g.openType ArrayTy
  396. g.addBuiltinType Int8Id
  397. g.addArrayLen 5
  398. g.addName "SomeArray"
  399. let finalArrayType = finishType(g, a)
  400. let obj = g.openType ObjectDecl
  401. g.nodes.add TypeNode(x: toX(NameVal, g.lit.strings.getOrIncl("MyType")))
  402. g.addField "p", finalArrayType, 0
  403. sealType(g, obj)
  404. echo g