diff options
Diffstat (limited to 'compiler/cgendata.nim')
-rw-r--r-- | compiler/cgendata.nim | 148 |
1 files changed, 92 insertions, 56 deletions
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index be087095f..5368e9dc7 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -10,35 +10,32 @@ ## This module contains the data structures for the C code generation phase. import - ast, astalgo, ropes, passes, options, intsets, platform, sighashes, - tables, ndi + ast, ropes, options, + ndi, lineinfos, pathutils, modulegraphs -from msgs import TLineInfo +import std/[intsets, tables, sets] type TLabel* = Rope # for the C generator a label is just a rope TCFileSection* = enum # the sections a generated C file consists of - cfsMergeInfo, # section containing merge information cfsHeaders, # section for C include file headers + cfsFrameDefines # section for nim frame macros cfsForwardTypes, # section for C forward typedefs cfsTypes, # section for C typedefs cfsSeqTypes, # section for sequence types only # this is needed for strange type generation # reasons - cfsFieldInfo, # section for field information - cfsTypeInfo, # section for type information + cfsTypeInfo, # section for type information (ag ABI checks) cfsProcHeaders, # section for C procs prototypes - cfsVars, # section for C variable declarations + cfsStrData, # section for constant string literals cfsData, # section for C constant data + cfsVars, # section for C variable declarations cfsProcs, # section for C procs that are not inline cfsInitProc, # section for the C init proc + cfsDatInitProc, # section for the C datInit proc cfsTypeInit1, # section 1 for declarations of type information - cfsTypeInit2, # section 2 for init of type information cfsTypeInit3, # section 3 for init of type information - cfsDebugInit, # section for init of debug information cfsDynLibInit, # section for init of dynamic library binding - cfsDynLibDeinit # section for deinitialization of dynamic - # libraries TCTypeKind* = enum # describes the type kind of a C type ctVoid, ctChar, ctBool, ctInt, ctInt8, ctInt16, ctInt32, ctInt64, @@ -54,27 +51,34 @@ type TCProcSections* = array[TCProcSection, Rope] # represents a generated C proc BModule* = ref TCGen BProc* = ref TCProc - TBlock*{.final.} = object + TBlock* = object id*: int # the ID of the label; positive means that it label*: Rope # generated text for the label # nil if label is not used - sections*: TCProcSections # the code beloging + sections*: TCProcSections # the code belonging isLoop*: bool # whether block is a loop nestedTryStmts*: int16 # how many try statements is it nested into nestedExceptStmts*: int16 # how many except statements is it nested into frameLen*: int16 - TCProc{.final.} = object # represents C proc that is currently generated + TCProcFlag* = enum + beforeRetNeeded, + threadVarAccessed, + hasCurFramePointer, + noSafePoints, + nimErrorFlagAccessed, + nimErrorFlagDeclared, + nimErrorFlagDisabled + + TCProc = object # represents C proc that is currently generated prc*: PSym # the Nim proc that this C proc belongs to - beforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed - threadVarAccessed*: bool # true if the proc already accessed some threadvar + flags*: set[TCProcFlag] lastLineInfo*: TLineInfo # to avoid generating excessive 'nimln' statements currLineInfo*: TLineInfo # AST codegen will make this superfluous - nestedTryStmts*: seq[PNode] # in how many nested try statements we are - # (the vars must be volatile then) - inExceptBlock*: int # are we currently inside an except block? - # leaving such scopes by raise or by return must - # execute any applicable finally blocks + nestedTryStmts*: seq[tuple[fin: PNode, inExcept: bool, label: Natural]] + # in how many nested try statements we are + # (the vars must be volatile then) + # bool is true when are in the except part of a try block finallySafePoints*: seq[Rope] # For correctly cleaning up exceptions when # using return in finally statements labels*: Natural # for generating unique labels in the C proc @@ -84,20 +88,22 @@ type options*: TOptions # options that should be used for code # generation; this is the same as prc.options # unless prc == nil - maxFrameLen*: int # max length of frame descriptor + optionsStack*: seq[(TOptions, TNoteKinds)] module*: BModule # used to prevent excessive parameter passing withinLoop*: int # > 0 if we are within a loop splitDecls*: int # > 0 if we are in some context for C++ that # requires 'T x = T()' to become 'T x; x = T()' # (yes, C++ is weird like that) - gcFrameId*: Natural # for the GC stack marking - gcFrameType*: Rope # the struct {} we put the GC markers into + withinTryWithExcept*: int # required for goto based exception handling + withinBlockLeaveActions*: int # complex to explain sigConflicts*: CountTable[string] + inUncheckedAssignSection*: int TTypeSeq* = seq[PType] TypeCache* = Table[SigHash, Rope] + TypeCacheWithOwner* = Table[SigHash, tuple[str: Rope, owner: int32]] - Codegenflag* = enum + CodegenFlag* = enum preventStackTrace, # true if stack traces need to be prevented usesThreadVars, # true if the module uses a thread var frameDeclared, # hack for ROD support so that we don't declare @@ -105,49 +111,73 @@ type isHeaderFile, # C source file is the header file includesStringh, # C source file already includes ``<string.h>`` objHasKidsValid # whether we can rely on tfObjHasKids - + useAliveDataFromDce # use the `alive: IntSet` field instead of + # computing alive data on our own. BModuleList* = ref object of RootObj mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Rope mapping*: Rope # the generated mapping file (if requested) modules*: seq[BModule] # list of all compiled modules - forwardedProcsCounter*: int + modulesClosed*: seq[BModule] # list of the same compiled modules, but in the order they were closed + forwardedProcs*: seq[PSym] # proc:s that did not yet have a body generatedHeader*: BModule - breakPointId*: int - breakpoints*: Rope # later the breakpoints are inserted into the main proc - typeInfoMarker*: TypeCache + typeInfoMarker*: TypeCacheWithOwner + typeInfoMarkerV2*: TypeCacheWithOwner config*: ConfigRef - - TCGen = object of TPassContext # represents a C source file + graph*: ModuleGraph + strVersion*, seqVersion*: int # version of the string/seq implementation to use + + nimtv*: Rope # Nim thread vars; the struct body + nimtvDeps*: seq[PType] # type deps: every module needs whole struct + nimtvDeclared*: IntSet # so that every var/field exists only once + # in the struct + # 'nimtv' is incredibly hard to modularize! Best + # effort is to store all thread vars in a ROD + # section and with their type deps and load them + # unconditionally... + # nimtvDeps is VERY hard to cache because it's + # not a list of IDs nor can it be made to be one. + mangledPrcs*: HashSet[string] + + TCGen = object of PPassContext # represents a C source file s*: TCFileSections # sections of the C file - flags*: set[Codegenflag] + flags*: set[CodegenFlag] module*: PSym - filename*: string - cfilename*: string # filename of the module (including path, + filename*: AbsoluteFile + cfilename*: AbsoluteFile # filename of the module (including path, # without extension) tmpBase*: Rope # base for temp identifier generation typeCache*: TypeCache # cache the generated types + typeABICache*: HashSet[SigHash] # cache for ABI checks; reusing typeCache + # would be ideal but for some reason enums + # don't seem to get cached so it'd generate + # 1 ABI check per occurrence in code forwTypeCache*: TypeCache # cache for forward declarations of types declaredThings*: IntSet # things we have declared in this .c file declaredProtos*: IntSet # prototypes we have declared in this .c file + alive*: IntSet # symbol IDs of alive data as computed by `dce.nim` headerFiles*: seq[string] # needed headers to include typeInfoMarker*: TypeCache # needed for generating type information + typeInfoMarkerV2*: TypeCache initProc*: BProc # code for init procedure - postInitProc*: BProc # code to be executed after the init proc preInitProc*: BProc # code executed before the init proc + hcrCreateTypeInfosProc*: Rope # type info globals are in here when HCR=on + inHcrInitGuard*: bool # We are currently within a HCR reloading guard. typeStack*: TTypeSeq # used for type generation dataCache*: TNodeTable - forwardedProcs*: TSymSeq # keep forwarded procs here typeNodes*, nimTypes*: int # used for type info generation typeNodesName*, nimTypesName*: Rope # used for type info generation labels*: Natural # for generating unique module-scope names extensionLoaders*: array['0'..'9', Rope] # special procs for the - # OpenGL wrapper - injectStmt*: Rope + # OpenGL wrapper sigConflicts*: CountTable[SigHash] g*: BModuleList ndi*: NdiFile +template config*(m: BModule): ConfigRef = m.g.config +template config*(p: BProc): ConfigRef = p.module.g.config +template vccAndC*(p: BProc): bool = p.module.config.cCompiler == ccVcc and p.module.config.backend == backendC + proc includeHeader*(this: BModule; header: string) = if not this.headerFiles.contains header: this.headerFiles.add header @@ -160,23 +190,29 @@ proc procSec*(p: BProc, s: TCProcSection): var Rope {.inline.} = # top level proc sections result = p.blocks[0].sections[s] +proc initBlock*(): TBlock = + result = TBlock() + for i in low(result.sections)..high(result.sections): + result.sections[i] = newRopeAppender() + proc newProc*(prc: PSym, module: BModule): BProc = - new(result) - result.prc = prc - result.module = module - if prc != nil: result.options = prc.options - else: result.options = gOptions - newSeq(result.blocks, 1) - result.nestedTryStmts = @[] - result.finallySafePoints = @[] - result.sigConflicts = initCountTable[string]() - -proc newModuleList*(config: ConfigRef): BModuleList = - BModuleList(modules: @[], typeInfoMarker: initTable[SigHash, Rope](), config: config) + result = BProc( + prc: prc, + module: module, + optionsStack: if module.initProc != nil: module.initProc.optionsStack + else: @[], + options: if prc != nil: prc.options + else: module.config.options, + blocks: @[initBlock()], + sigConflicts: initCountTable[string]()) + if optQuirky in result.options: + result.flags = {nimErrorFlagDisabled} + +proc newModuleList*(g: ModuleGraph): BModuleList = + BModuleList(typeInfoMarker: initTable[SigHash, tuple[str: Rope, owner: int32]](), + config: g.config, graph: g, nimtvDeclared: initIntSet()) iterator cgenModules*(g: BModuleList): BModule = - for i in 0..high(g.modules): - # ultimately, we are iterating over the file ids here. - # some "files" won't have an associated cgen module (like stdin) - # and we must skip over them. - if g.modules[i] != nil: yield g.modules[i] + for m in g.modulesClosed: + # iterate modules in the order they were closed + yield m |