summary refs log tree commit diff stats
path: root/compiler/cgendata.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/cgendata.nim')
-rw-r--r--compiler/cgendata.nim218
1 files changed, 218 insertions, 0 deletions
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
new file mode 100644
index 000000000..5368e9dc7
--- /dev/null
+++ b/compiler/cgendata.nim
@@ -0,0 +1,218 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module contains the data structures for the C code generation phase.
+
+import
+  ast, ropes, options,
+  ndi, lineinfos, pathutils, modulegraphs
+
+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
+    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
+    cfsTypeInfo,              # section for type information (ag ABI checks)
+    cfsProcHeaders,           # section for C procs prototypes
+    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
+    cfsTypeInit3,             # section 3 for init of type information
+    cfsDynLibInit,            # section for init of dynamic library binding
+  TCTypeKind* = enum          # describes the type kind of a C type
+    ctVoid, ctChar, ctBool,
+    ctInt, ctInt8, ctInt16, ctInt32, ctInt64,
+    ctFloat, ctFloat32, ctFloat64, ctFloat128,
+    ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64,
+    ctArray, ctPtrToArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc,
+    ctCString
+  TCFileSections* = array[TCFileSection, Rope] # represents a generated C file
+  TCProcSection* = enum       # the sections a generated C proc consists of
+    cpsLocals,                # section of local variables for C proc
+    cpsInit,                  # section for init of variables for C proc
+    cpsStmts                  # section of local statements for C proc
+  TCProcSections* = array[TCProcSection, Rope] # represents a generated C proc
+  BModule* = ref TCGen
+  BProc* = ref TCProc
+  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 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
+
+  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
+    flags*: set[TCProcFlag]
+    lastLineInfo*: TLineInfo  # to avoid generating excessive 'nimln' statements
+    currLineInfo*: TLineInfo  # AST codegen will make this superfluous
+    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
+    blocks*: seq[TBlock]      # nested blocks
+    breakIdx*: int            # the block that will be exited
+                              # with a regular break
+    options*: TOptions        # options that should be used for code
+                              # generation; this is the same as prc.options
+                              # unless prc == nil
+    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)
+    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
+    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
+                        # a frame var twice in an init proc
+    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
+    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
+    typeInfoMarker*: TypeCacheWithOwner
+    typeInfoMarkerV2*: TypeCacheWithOwner
+    config*: ConfigRef
+    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]
+    module*: PSym
+    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
+    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
+    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
+    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
+
+proc s*(p: BProc, s: TCProcSection): var Rope {.inline.} =
+  # section in the current block
+  result = p.blocks[^1].sections[s]
+
+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 =
+  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 m in g.modulesClosed:
+    # iterate modules in the order they were closed
+    yield m