cgendata.nim 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2012 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## This module contains the data structures for the C code generation phase.
  10. import
  11. ast, ropes, options, intsets,
  12. tables, ndi, lineinfos, pathutils, modulegraphs, sets
  13. type
  14. TLabel* = Rope # for the C generator a label is just a rope
  15. TCFileSection* = enum # the sections a generated C file consists of
  16. cfsMergeInfo, # section containing merge information
  17. cfsHeaders, # section for C include file headers
  18. cfsFrameDefines # section for nim frame macros
  19. cfsForwardTypes, # section for C forward typedefs
  20. cfsTypes, # section for C typedefs
  21. cfsSeqTypes, # section for sequence types only
  22. # this is needed for strange type generation
  23. # reasons
  24. cfsFieldInfo, # section for field information
  25. cfsTypeInfo, # section for type information (ag ABI checks)
  26. cfsProcHeaders, # section for C procs prototypes
  27. cfsStrData, # section for constant string literals
  28. cfsData, # section for C constant data
  29. cfsVars, # section for C variable declarations
  30. cfsProcs, # section for C procs that are not inline
  31. cfsInitProc, # section for the C init proc
  32. cfsDatInitProc, # section for the C datInit proc
  33. cfsTypeInit1, # section 1 for declarations of type information
  34. cfsTypeInit2, # section 2 for init of type information
  35. cfsTypeInit3, # section 3 for init of type information
  36. cfsDebugInit, # section for init of debug information
  37. cfsDynLibInit, # section for init of dynamic library binding
  38. cfsDynLibDeinit # section for deinitialization of dynamic
  39. # libraries
  40. TCTypeKind* = enum # describes the type kind of a C type
  41. ctVoid, ctChar, ctBool,
  42. ctInt, ctInt8, ctInt16, ctInt32, ctInt64,
  43. ctFloat, ctFloat32, ctFloat64, ctFloat128,
  44. ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64,
  45. ctArray, ctPtrToArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc,
  46. ctCString
  47. TCFileSections* = array[TCFileSection, Rope] # represents a generated C file
  48. TCProcSection* = enum # the sections a generated C proc consists of
  49. cpsLocals, # section of local variables for C proc
  50. cpsInit, # section for init of variables for C proc
  51. cpsStmts # section of local statements for C proc
  52. TCProcSections* = array[TCProcSection, Rope] # represents a generated C proc
  53. BModule* = ref TCGen
  54. BProc* = ref TCProc
  55. TBlock* = object
  56. id*: int # the ID of the label; positive means that it
  57. label*: Rope # generated text for the label
  58. # nil if label is not used
  59. sections*: TCProcSections # the code belonging
  60. isLoop*: bool # whether block is a loop
  61. nestedTryStmts*: int16 # how many try statements is it nested into
  62. nestedExceptStmts*: int16 # how many except statements is it nested into
  63. frameLen*: int16
  64. TCProcFlag* = enum
  65. beforeRetNeeded,
  66. threadVarAccessed,
  67. hasCurFramePointer,
  68. noSafePoints,
  69. nimErrorFlagAccessed,
  70. nimErrorFlagDeclared,
  71. nimErrorFlagDisabled
  72. TCProc = object # represents C proc that is currently generated
  73. prc*: PSym # the Nim proc that this C proc belongs to
  74. flags*: set[TCProcFlag]
  75. lastLineInfo*: TLineInfo # to avoid generating excessive 'nimln' statements
  76. currLineInfo*: TLineInfo # AST codegen will make this superfluous
  77. nestedTryStmts*: seq[tuple[fin: PNode, inExcept: bool, label: Natural]]
  78. # in how many nested try statements we are
  79. # (the vars must be volatile then)
  80. # bool is true when are in the except part of a try block
  81. finallySafePoints*: seq[Rope] # For correctly cleaning up exceptions when
  82. # using return in finally statements
  83. labels*: Natural # for generating unique labels in the C proc
  84. blocks*: seq[TBlock] # nested blocks
  85. breakIdx*: int # the block that will be exited
  86. # with a regular break
  87. options*: TOptions # options that should be used for code
  88. # generation; this is the same as prc.options
  89. # unless prc == nil
  90. module*: BModule # used to prevent excessive parameter passing
  91. withinLoop*: int # > 0 if we are within a loop
  92. splitDecls*: int # > 0 if we are in some context for C++ that
  93. # requires 'T x = T()' to become 'T x; x = T()'
  94. # (yes, C++ is weird like that)
  95. withinTryWithExcept*: int # required for goto based exception handling
  96. withinBlockLeaveActions*: int # complex to explain
  97. sigConflicts*: CountTable[string]
  98. inUncheckedAssignSection*: int
  99. TTypeSeq* = seq[PType]
  100. TypeCache* = Table[SigHash, Rope]
  101. TypeCacheWithOwner* = Table[SigHash, tuple[str: Rope, owner: int32]]
  102. CodegenFlag* = enum
  103. preventStackTrace, # true if stack traces need to be prevented
  104. usesThreadVars, # true if the module uses a thread var
  105. frameDeclared, # hack for ROD support so that we don't declare
  106. # a frame var twice in an init proc
  107. isHeaderFile, # C source file is the header file
  108. includesStringh, # C source file already includes ``<string.h>``
  109. objHasKidsValid # whether we can rely on tfObjHasKids
  110. useAliveDataFromDce # use the `alive: IntSet` field instead of
  111. # computing alive data on our own.
  112. BModuleList* = ref object of RootObj
  113. mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Rope
  114. mapping*: Rope # the generated mapping file (if requested)
  115. modules*: seq[BModule] # list of all compiled modules
  116. modulesClosed*: seq[BModule] # list of the same compiled modules, but in the order they were closed
  117. forwardedProcs*: seq[PSym] # proc:s that did not yet have a body
  118. generatedHeader*: BModule
  119. typeInfoMarker*: TypeCacheWithOwner
  120. typeInfoMarkerV2*: TypeCacheWithOwner
  121. config*: ConfigRef
  122. graph*: ModuleGraph
  123. strVersion*, seqVersion*: int # version of the string/seq implementation to use
  124. nimtv*: Rope # Nim thread vars; the struct body
  125. nimtvDeps*: seq[PType] # type deps: every module needs whole struct
  126. nimtvDeclared*: IntSet # so that every var/field exists only once
  127. # in the struct
  128. # 'nimtv' is incredibly hard to modularize! Best
  129. # effort is to store all thread vars in a ROD
  130. # section and with their type deps and load them
  131. # unconditionally...
  132. # nimtvDeps is VERY hard to cache because it's
  133. # not a list of IDs nor can it be made to be one.
  134. TCGen = object of PPassContext # represents a C source file
  135. s*: TCFileSections # sections of the C file
  136. flags*: set[CodegenFlag]
  137. module*: PSym
  138. filename*: AbsoluteFile
  139. cfilename*: AbsoluteFile # filename of the module (including path,
  140. # without extension)
  141. tmpBase*: Rope # base for temp identifier generation
  142. typeCache*: TypeCache # cache the generated types
  143. typeABICache*: HashSet[SigHash] # cache for ABI checks; reusing typeCache
  144. # would be ideal but for some reason enums
  145. # don't seem to get cached so it'd generate
  146. # 1 ABI check per occurence in code
  147. forwTypeCache*: TypeCache # cache for forward declarations of types
  148. declaredThings*: IntSet # things we have declared in this .c file
  149. declaredProtos*: IntSet # prototypes we have declared in this .c file
  150. alive*: IntSet # symbol IDs of alive data as computed by `dce.nim`
  151. headerFiles*: seq[string] # needed headers to include
  152. typeInfoMarker*: TypeCache # needed for generating type information
  153. typeInfoMarkerV2*: TypeCache
  154. initProc*: BProc # code for init procedure
  155. preInitProc*: BProc # code executed before the init proc
  156. hcrCreateTypeInfosProc*: Rope # type info globals are in here when HCR=on
  157. inHcrInitGuard*: bool # We are currently within a HCR reloading guard.
  158. typeStack*: TTypeSeq # used for type generation
  159. dataCache*: TNodeTable
  160. typeNodes*, nimTypes*: int # used for type info generation
  161. typeNodesName*, nimTypesName*: Rope # used for type info generation
  162. labels*: Natural # for generating unique module-scope names
  163. extensionLoaders*: array['0'..'9', Rope] # special procs for the
  164. # OpenGL wrapper
  165. sigConflicts*: CountTable[SigHash]
  166. g*: BModuleList
  167. ndi*: NdiFile
  168. template config*(m: BModule): ConfigRef = m.g.config
  169. template config*(p: BProc): ConfigRef = p.module.g.config
  170. proc includeHeader*(this: BModule; header: string) =
  171. if not this.headerFiles.contains header:
  172. this.headerFiles.add header
  173. proc s*(p: BProc, s: TCProcSection): var Rope {.inline.} =
  174. # section in the current block
  175. result = p.blocks[^1].sections[s]
  176. proc procSec*(p: BProc, s: TCProcSection): var Rope {.inline.} =
  177. # top level proc sections
  178. result = p.blocks[0].sections[s]
  179. proc initBlock*(): TBlock =
  180. result = TBlock()
  181. for i in low(result.sections)..high(result.sections):
  182. result.sections[i] = newRopeAppender()
  183. proc newProc*(prc: PSym, module: BModule): BProc =
  184. new(result)
  185. result.prc = prc
  186. result.module = module
  187. result.options = if prc != nil: prc.options
  188. else: module.config.options
  189. result.blocks = @[initBlock()]
  190. result.nestedTryStmts = @[]
  191. result.finallySafePoints = @[]
  192. result.sigConflicts = initCountTable[string]()
  193. proc newModuleList*(g: ModuleGraph): BModuleList =
  194. BModuleList(typeInfoMarker: initTable[SigHash, tuple[str: Rope, owner: int32]](),
  195. config: g.config, graph: g, nimtvDeclared: initIntSet())
  196. iterator cgenModules*(g: BModuleList): BModule =
  197. for m in g.modulesClosed:
  198. # iterate modules in the order they were closed
  199. yield m