types2ir.nim 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  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. import std / [assertions, tables, sets]
  10. import ".." / [ast, types, options, sighashes, modulegraphs]
  11. import nirtypes
  12. type
  13. TypesCon* = object
  14. processed: Table[ItemId, TypeId]
  15. processedByName: Table[string, TypeId]
  16. recursionCheck: HashSet[ItemId]
  17. conf: ConfigRef
  18. stringType: TypeId
  19. proc initTypesCon*(conf: ConfigRef): TypesCon =
  20. TypesCon(conf: conf, stringType: TypeId(-1))
  21. proc mangle(c: var TypesCon; t: PType): string =
  22. result = $sighashes.hashType(t, c.conf)
  23. template cached(c: var TypesCon; t: PType; body: untyped) =
  24. result = c.processed.getOrDefault(t.itemId)
  25. if result.int == 0:
  26. body
  27. c.processed[t.itemId] = result
  28. template cachedByName(c: var TypesCon; t: PType; body: untyped) =
  29. let key = mangle(c, t)
  30. result = c.processedByName.getOrDefault(key)
  31. if result.int == 0:
  32. body
  33. c.processedByName[key] = result
  34. proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId
  35. proc collectFieldTypes(c: var TypesCon; g: var TypeGraph; n: PNode; dest: var Table[ItemId, TypeId]) =
  36. case n.kind
  37. of nkRecList:
  38. for i in 0..<n.len:
  39. collectFieldTypes(c, g, n[i], dest)
  40. of nkRecCase:
  41. assert(n[0].kind == nkSym)
  42. collectFieldTypes(c, g, n[0], dest)
  43. for i in 1..<n.len:
  44. case n[i].kind
  45. of nkOfBranch, nkElse:
  46. collectFieldTypes c, g, lastSon(n[i]), dest
  47. else: discard
  48. of nkSym:
  49. dest[n.sym.itemId] = typeToIr(c, g, n.sym.typ)
  50. else:
  51. assert false, "unknown node kind: " & $n.kind
  52. proc objectToIr(c: var TypesCon; g: var TypeGraph; n: PNode; fieldTypes: Table[ItemId, TypeId]; unionId: var int) =
  53. case n.kind
  54. of nkRecList:
  55. for i in 0..<n.len:
  56. objectToIr(c, g, n[i], fieldTypes, unionId)
  57. of nkRecCase:
  58. assert(n[0].kind == nkSym)
  59. objectToIr(c, g, n[0], fieldTypes, unionId)
  60. let u = openType(g, UnionDecl)
  61. g.addName "u_" & $unionId
  62. inc unionId
  63. for i in 1..<n.len:
  64. case n[i].kind
  65. of nkOfBranch, nkElse:
  66. let subObj = openType(g, ObjectDecl)
  67. g.addName "uo_" & $unionId & "_" & $i
  68. objectToIr c, g, lastSon(n[i]), fieldTypes, unionId
  69. sealType(g, subObj)
  70. else: discard
  71. sealType(g, u)
  72. of nkSym:
  73. g.addField n.sym.name.s & "_" & $n.sym.position, fieldTypes[n.sym.itemId], n.sym.offset
  74. else:
  75. assert false, "unknown node kind: " & $n.kind
  76. proc objectToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
  77. if t.baseClass != nil:
  78. # ensure we emitted the base type:
  79. discard typeToIr(c, g, t.baseClass)
  80. var unionId = 0
  81. var fieldTypes = initTable[ItemId, TypeId]()
  82. collectFieldTypes c, g, t.n, fieldTypes
  83. let obj = openType(g, ObjectDecl)
  84. g.addName mangle(c, t)
  85. g.addSize c.conf.getSize(t)
  86. g.addAlign c.conf.getAlign(t)
  87. if t.baseClass != nil:
  88. g.addNominalType(ObjectTy, mangle(c, t.baseClass))
  89. else:
  90. g.addBuiltinType VoidId # object does not inherit
  91. if not lacksMTypeField(t):
  92. let f2 = g.openType FieldDecl
  93. let voidPtr = openType(g, APtrTy)
  94. g.addBuiltinType(VoidId)
  95. sealType(g, voidPtr)
  96. g.addOffset 0 # type field is always at offset 0
  97. g.addName "m_type"
  98. sealType(g, f2) # FieldDecl
  99. objectToIr c, g, t.n, fieldTypes, unionId
  100. result = finishType(g, obj)
  101. proc objectHeaderToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
  102. result = g.nominalType(ObjectTy, mangle(c, t))
  103. proc tupleToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
  104. var fieldTypes = newSeq[TypeId](t.len)
  105. for i in 0..<t.len:
  106. fieldTypes[i] = typeToIr(c, g, t[i])
  107. let obj = openType(g, ObjectDecl)
  108. g.addName mangle(c, t)
  109. g.addSize c.conf.getSize(t)
  110. g.addAlign c.conf.getAlign(t)
  111. var accum = OffsetAccum(maxAlign: 1)
  112. for i in 0..<t.len:
  113. let child = t[i]
  114. g.addField "f_" & $i, fieldTypes[i], accum.offset
  115. computeSizeAlign(c.conf, child)
  116. accum.align(child.align)
  117. accum.inc(int32(child.size))
  118. result = finishType(g, obj)
  119. proc procToIr(c: var TypesCon; g: var TypeGraph; t: PType; addEnv = false): TypeId =
  120. var fieldTypes = newSeq[TypeId](0)
  121. for i in 0..<t.len:
  122. if t[i] == nil or not isCompileTimeOnly(t[i]):
  123. fieldTypes.add typeToIr(c, g, t[i])
  124. let obj = openType(g, ProcTy)
  125. case t.callConv
  126. of ccNimCall, ccFastCall, ccClosure: g.addAnnotation "__fastcall"
  127. of ccStdCall: g.addAnnotation "__stdcall"
  128. of ccCDecl: g.addAnnotation "__cdecl"
  129. of ccSafeCall: g.addAnnotation "__safecall"
  130. of ccSysCall: g.addAnnotation "__syscall"
  131. of ccInline: g.addAnnotation "__inline"
  132. of ccNoInline: g.addAnnotation "__noinline"
  133. of ccThisCall: g.addAnnotation "__thiscall"
  134. of ccNoConvention: g.addAnnotation ""
  135. for i in 0..<fieldTypes.len:
  136. g.addType fieldTypes[i]
  137. if addEnv:
  138. let a = openType(g, APtrTy)
  139. g.addBuiltinType(VoidId)
  140. sealType(g, a)
  141. if tfVarargs in t.flags:
  142. g.addVarargs()
  143. result = finishType(g, obj)
  144. proc nativeInt(c: TypesCon): TypeId =
  145. case c.conf.target.intSize
  146. of 2: result = Int16Id
  147. of 4: result = Int32Id
  148. else: result = Int64Id
  149. proc openArrayPayloadType*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
  150. let e = elementType(t)
  151. let elementType = typeToIr(c, g, e)
  152. let arr = g.openType AArrayPtrTy
  153. g.addType elementType
  154. result = finishType(g, arr) # LastArrayTy
  155. proc openArrayToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
  156. # object (a: ArrayPtr[T], len: int)
  157. let e = elementType(t)
  158. let mangledBase = mangle(c, e)
  159. let typeName = "NimOpenArray" & mangledBase
  160. let elementType = typeToIr(c, g, e)
  161. #assert elementType.int >= 0, typeToString(t)
  162. let p = openType(g, ObjectDecl)
  163. g.addName typeName
  164. g.addSize c.conf.target.ptrSize*2
  165. g.addAlign c.conf.target.ptrSize
  166. let f = g.openType FieldDecl
  167. let arr = g.openType AArrayPtrTy
  168. g.addType elementType
  169. sealType(g, arr) # LastArrayTy
  170. g.addOffset 0
  171. g.addName "data"
  172. sealType(g, f) # FieldDecl
  173. g.addField "len", c.nativeInt, c.conf.target.ptrSize
  174. result = finishType(g, p) # ObjectDecl
  175. proc strPayloadType(c: var TypesCon; g: var TypeGraph): (string, TypeId) =
  176. result = ("NimStrPayload", TypeId(-1))
  177. let p = openType(g, ObjectDecl)
  178. g.addName result[0]
  179. g.addSize c.conf.target.ptrSize*2
  180. g.addAlign c.conf.target.ptrSize
  181. g.addField "cap", c.nativeInt, 0
  182. let f = g.openType FieldDecl
  183. let arr = g.openType LastArrayTy
  184. g.addBuiltinType Char8Id
  185. result[1] = finishType(g, arr) # LastArrayTy
  186. g.addOffset c.conf.target.ptrSize # comes after the len field
  187. g.addName "data"
  188. sealType(g, f) # FieldDecl
  189. sealType(g, p)
  190. proc strPayloadPtrType*(c: var TypesCon; g: var TypeGraph): (TypeId, TypeId) =
  191. let (mangled, arrayType) = strPayloadType(c, g)
  192. let ffp = g.openType APtrTy
  193. g.addNominalType ObjectTy, mangled
  194. result = (finishType(g, ffp), arrayType) # APtrTy
  195. proc stringToIr(c: var TypesCon; g: var TypeGraph): TypeId =
  196. #[
  197. NimStrPayload = object
  198. cap: int
  199. data: UncheckedArray[char]
  200. NimStringV2 = object
  201. len: int
  202. p: ptr NimStrPayload
  203. ]#
  204. let payload = strPayloadType(c, g)
  205. let str = openType(g, ObjectDecl)
  206. g.addName "NimStringV2"
  207. g.addSize c.conf.target.ptrSize*2
  208. g.addAlign c.conf.target.ptrSize
  209. g.addField "len", c.nativeInt, 0
  210. let fp = g.openType FieldDecl
  211. let ffp = g.openType APtrTy
  212. g.addNominalType ObjectTy, "NimStrPayload"
  213. sealType(g, ffp) # APtrTy
  214. g.addOffset c.conf.target.ptrSize # comes after 'len' field
  215. g.addName "p"
  216. sealType(g, fp) # FieldDecl
  217. result = finishType(g, str) # ObjectDecl
  218. proc seqPayloadType(c: var TypesCon; g: var TypeGraph; t: PType): (string, TypeId) =
  219. #[
  220. NimSeqPayload[T] = object
  221. cap: int
  222. data: UncheckedArray[T]
  223. ]#
  224. let e = elementType(t)
  225. result = (mangle(c, e), TypeId(-1))
  226. let payloadName = "NimSeqPayload" & result[0]
  227. let elementType = typeToIr(c, g, e)
  228. let p = openType(g, ObjectDecl)
  229. g.addName payloadName
  230. g.addSize c.conf.target.intSize
  231. g.addAlign c.conf.target.intSize
  232. g.addField "cap", c.nativeInt, 0
  233. let f = g.openType FieldDecl
  234. let arr = g.openType LastArrayTy
  235. g.addType elementType
  236. # DO NOT USE `finishType` here as it is an inner type. This is subtle and we
  237. # probably need an even better API here.
  238. sealType(g, arr)
  239. result[1] = TypeId(arr)
  240. g.addOffset c.conf.target.ptrSize
  241. g.addName "data"
  242. sealType(g, f) # FieldDecl
  243. sealType(g, p)
  244. proc seqPayloadPtrType*(c: var TypesCon; g: var TypeGraph; t: PType): (TypeId, TypeId) =
  245. let (mangledBase, arrayType) = seqPayloadType(c, g, t)
  246. let ffp = g.openType APtrTy
  247. g.addNominalType ObjectTy, "NimSeqPayload" & mangledBase
  248. result = (finishType(g, ffp), arrayType) # APtrTy
  249. proc seqToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
  250. #[
  251. NimSeqV2*[T] = object
  252. len: int
  253. p: ptr NimSeqPayload[T]
  254. ]#
  255. let (mangledBase, _) = seqPayloadType(c, g, t)
  256. let sq = openType(g, ObjectDecl)
  257. g.addName "NimSeqV2" & mangledBase
  258. g.addSize c.conf.getSize(t)
  259. g.addAlign c.conf.getAlign(t)
  260. g.addField "len", c.nativeInt, 0
  261. let fp = g.openType FieldDecl
  262. let ffp = g.openType APtrTy
  263. g.addNominalType ObjectTy, "NimSeqPayload" & mangledBase
  264. sealType(g, ffp) # APtrTy
  265. g.addOffset c.conf.target.ptrSize
  266. g.addName "p"
  267. sealType(g, fp) # FieldDecl
  268. result = finishType(g, sq) # ObjectDecl
  269. proc closureToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
  270. # struct {fn(args, void* env), env}
  271. # typedef struct {$n" &
  272. # "N_NIMCALL_PTR($2, ClP_0) $3;$n" &
  273. # "void* ClE_0;$n} $1;$n"
  274. let mangledBase = mangle(c, t)
  275. let typeName = "NimClosure" & mangledBase
  276. let procType = procToIr(c, g, t, addEnv=true)
  277. let p = openType(g, ObjectDecl)
  278. g.addName typeName
  279. g.addSize c.conf.getSize(t)
  280. g.addAlign c.conf.getAlign(t)
  281. let f = g.openType FieldDecl
  282. g.addType procType
  283. g.addOffset 0
  284. g.addName "ClP_0"
  285. sealType(g, f) # FieldDecl
  286. let f2 = g.openType FieldDecl
  287. let voidPtr = openType(g, APtrTy)
  288. g.addBuiltinType(VoidId)
  289. sealType(g, voidPtr)
  290. g.addOffset c.conf.target.ptrSize
  291. g.addName "ClE_0"
  292. sealType(g, f2) # FieldDecl
  293. result = finishType(g, p) # ObjectDecl
  294. proc bitsetBasetype*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
  295. let s = int(getSize(c.conf, t))
  296. case s
  297. of 1: result = UInt8Id
  298. of 2: result = UInt16Id
  299. of 4: result = UInt32Id
  300. of 8: result = UInt64Id
  301. else: result = UInt8Id
  302. proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
  303. if t == nil: return VoidId
  304. case t.kind
  305. of tyInt:
  306. case int(getSize(c.conf, t))
  307. of 2: result = Int16Id
  308. of 4: result = Int32Id
  309. else: result = Int64Id
  310. of tyInt8: result = Int8Id
  311. of tyInt16: result = Int16Id
  312. of tyInt32: result = Int32Id
  313. of tyInt64: result = Int64Id
  314. of tyFloat:
  315. case int(getSize(c.conf, t))
  316. of 4: result = Float32Id
  317. else: result = Float64Id
  318. of tyFloat32: result = Float32Id
  319. of tyFloat64: result = Float64Id
  320. of tyFloat128: result = getFloat128Type(g)
  321. of tyUInt:
  322. case int(getSize(c.conf, t))
  323. of 2: result = UInt16Id
  324. of 4: result = UInt32Id
  325. else: result = UInt64Id
  326. of tyUInt8: result = UInt8Id
  327. of tyUInt16: result = UInt16Id
  328. of tyUInt32: result = UInt32Id
  329. of tyUInt64: result = UInt64Id
  330. of tyBool: result = Bool8Id
  331. of tyChar: result = Char8Id
  332. of tyVoid: result = VoidId
  333. of tySink, tyGenericInst, tyDistinct, tyAlias, tyOwned, tyRange:
  334. result = typeToIr(c, g, t.skipModifier)
  335. of tyEnum:
  336. if firstOrd(c.conf, t) < 0:
  337. result = Int32Id
  338. else:
  339. case int(getSize(c.conf, t))
  340. of 1: result = UInt8Id
  341. of 2: result = UInt16Id
  342. of 4: result = Int32Id
  343. of 8: result = Int64Id
  344. else: result = Int32Id
  345. of tyOrdinal, tyGenericBody, tyGenericParam, tyInferred, tyStatic:
  346. if t.len > 0:
  347. result = typeToIr(c, g, t.skipModifier)
  348. else:
  349. result = TypeId(-1)
  350. of tyFromExpr:
  351. if t.n != nil and t.n.typ != nil:
  352. result = typeToIr(c, g, t.n.typ)
  353. else:
  354. result = TypeId(-1)
  355. of tyArray:
  356. cached(c, t):
  357. var n = toInt64(lengthOrd(c.conf, t))
  358. if n <= 0: n = 1 # make an array of at least one element
  359. let elemType = typeToIr(c, g, t.elementType)
  360. let a = openType(g, ArrayTy)
  361. g.addType(elemType)
  362. g.addArrayLen n
  363. g.addName mangle(c, t)
  364. result = finishType(g, a)
  365. of tyPtr, tyRef:
  366. cached(c, t):
  367. let e = t.elementType
  368. if e.kind == tyUncheckedArray:
  369. let elemType = typeToIr(c, g, e.elementType)
  370. let a = openType(g, AArrayPtrTy)
  371. g.addType(elemType)
  372. result = finishType(g, a)
  373. else:
  374. let elemType = typeToIr(c, g, t.elementType)
  375. let a = openType(g, APtrTy)
  376. g.addType(elemType)
  377. result = finishType(g, a)
  378. of tyVar, tyLent:
  379. cached(c, t):
  380. let e = t.elementType
  381. if e.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}:
  382. # skip the modifier, `var openArray` is a (ptr, len) pair too:
  383. result = typeToIr(c, g, e)
  384. else:
  385. let elemType = typeToIr(c, g, e)
  386. let a = openType(g, APtrTy)
  387. g.addType(elemType)
  388. result = finishType(g, a)
  389. of tySet:
  390. let s = int(getSize(c.conf, t))
  391. case s
  392. of 1: result = UInt8Id
  393. of 2: result = UInt16Id
  394. of 4: result = UInt32Id
  395. of 8: result = UInt64Id
  396. else:
  397. # array[U8, s]
  398. cached(c, t):
  399. let a = openType(g, ArrayTy)
  400. g.addType(UInt8Id)
  401. g.addArrayLen s
  402. g.addName mangle(c, t)
  403. result = finishType(g, a)
  404. of tyPointer, tyNil:
  405. # tyNil can happen for code like: `const CRAP = nil` which we have in posix.nim
  406. let a = openType(g, APtrTy)
  407. g.addBuiltinType(VoidId)
  408. result = finishType(g, a)
  409. of tyObject:
  410. # Objects are special as they can be recursive in Nim. This is easily solvable.
  411. # We check if we are already "processing" t. If so, we produce `ObjectTy`
  412. # instead of `ObjectDecl`.
  413. cached(c, t):
  414. if not c.recursionCheck.containsOrIncl(t.itemId):
  415. result = objectToIr(c, g, t)
  416. else:
  417. result = objectHeaderToIr(c, g, t)
  418. of tyTuple:
  419. cachedByName(c, t):
  420. result = tupleToIr(c, g, t)
  421. of tyProc:
  422. cached(c, t):
  423. if t.callConv == ccClosure:
  424. result = closureToIr(c, g, t)
  425. else:
  426. result = procToIr(c, g, t)
  427. of tyVarargs, tyOpenArray:
  428. cached(c, t):
  429. result = openArrayToIr(c, g, t)
  430. of tyString:
  431. if c.stringType.int < 0:
  432. result = stringToIr(c, g)
  433. c.stringType = result
  434. else:
  435. result = c.stringType
  436. of tySequence:
  437. cachedByName(c, t):
  438. result = seqToIr(c, g, t)
  439. of tyCstring:
  440. cached(c, t):
  441. let a = openType(g, AArrayPtrTy)
  442. g.addBuiltinType Char8Id
  443. result = finishType(g, a)
  444. of tyUncheckedArray:
  445. # We already handled the `ptr UncheckedArray` in a special way.
  446. cached(c, t):
  447. let elemType = typeToIr(c, g, t.elementType)
  448. let a = openType(g, LastArrayTy)
  449. g.addType(elemType)
  450. result = finishType(g, a)
  451. of tyUntyped, tyTyped:
  452. # this avoids a special case for system.echo which is not a generic but
  453. # uses `varargs[typed]`:
  454. result = VoidId
  455. of tyNone, tyEmpty, tyTypeDesc,
  456. tyGenericInvocation, tyProxy, tyBuiltInTypeClass,
  457. tyUserTypeClass, tyUserTypeClassInst, tyCompositeTypeClass,
  458. tyAnd, tyOr, tyNot, tyAnything, tyConcept, tyIterable, tyForward:
  459. result = TypeId(-1)