cgen

Search:
Group by:
Source   Edit  

This module implements the C code generator.This include file contains the logic to produce constant string and seq literals. The code here is responsible that const x = ["a", "b"] works without hidden runtime creation code. The price is that seqs and strings are not purely a library implementation.Generates traversal procs for the C backend.Code specialization instead of the old, incredibly slow 'genericReset' implementation.Thread var support for architectures that lack native support for thread local storage.

Procs

proc cgenWriteModules(backend: RootRef; config: ConfigRef) {....raises: [KeyError,
    OSError, Exception, ValueError, IOError, ERecoverableError], tags: [
    ReadEnvEffect, ReadIOEffect, ReadDirEffect, RootEffect, WriteIOEffect,
    TimeEffect, WriteDirEffect], forbids: [].}
Source   Edit  
proc fillObjectFields(m: BModule; typ: PType) {....raises: [Exception, ValueError,
    OSError, KeyError, IOError, ERecoverableError], tags: [RootEffect,
    ReadDirEffect, WriteIOEffect, ReadIOEffect, ReadEnvEffect], forbids: [].}
Source   Edit  
proc finalCodegenActions(graph: ModuleGraph; m: BModule; n: PNode) {....raises: [
    KeyError, OSError, Exception, ValueError, IOError, ERecoverableError], tags: [
    ReadEnvEffect, ReadIOEffect, ReadDirEffect, RootEffect, WriteIOEffect,
    TimeEffect], forbids: [].}
Also called from IC. Source   Edit  
proc genIcModuleDestroyGlobals(graph: ModuleGraph; m: BModule): string {....raises: [
    KeyError, OSError, Exception, ValueError, IOError, ERecoverableError], tags: [
    ReadEnvEffect, ReadIOEffect, ReadDirEffect, RootEffect, WriteIOEffect,
    TimeEffect], forbids: [].}

Per-module backend (cg stage), non-main module: wrap this module's accumulated top-level global destructors in a nullary exported proc and return its C name ("" when there are none).

graph.globalDestructors is filled while a module's own cg process injects destructors into its top level, but the teardown code is emitted by the MAIN module's cg — a different process, whose graph only ever sees its own entries. So each module emits its own teardown here and records the name in its .c.nif meta head; the main module's cg reads the heads (like it already does for init/datInit) and calls them.

Source   Edit  
proc genProcLvl3(m: BModule; prc: PSym) {....raises: [KeyError, OSError, Exception,
    ValueError, IOError, ERecoverableError], tags: [ReadEnvEffect, ReadIOEffect,
    ReadDirEffect, RootEffect, WriteIOEffect, TimeEffect], forbids: [].}
Source   Edit  
proc genTopLevelStmt(m: BModule; n: PNode) {....raises: [KeyError, OSError,
    Exception, ValueError, IOError, ERecoverableError], tags: [ReadEnvEffect,
    ReadIOEffect, ReadDirEffect, RootEffect, WriteIOEffect, TimeEffect],
    forbids: [].}
Also called from ic/cbackend.nim. Source   Edit  
proc genTypeInfo(config: ConfigRef; m: BModule; t: PType; info: TLineInfo): Rope {....raises: [
    KeyError, OSError, Exception, ValueError, IOError, ERecoverableError], tags: [
    ReadEnvEffect, ReadIOEffect, ReadDirEffect, RootEffect, WriteIOEffect],
    forbids: [].}
Source   Edit  
proc getCFile(m: BModule): AbsoluteFile {.
    ...raises: [KeyError, OSError, Exception, ValueError, IOError], tags: [
    ReadEnvEffect, ReadIOEffect, ReadDirEffect, RootEffect, WriteDirEffect],
    forbids: [].}
Source   Edit  
proc getSomeNameForModule(m: BModule): Rope {.
    ...raises: [KeyError, OSError, Exception, ValueError],
    tags: [ReadEnvEffect, ReadIOEffect, ReadDirEffect, RootEffect], forbids: [].}
Returns a mangled module name. Source   Edit  
proc homeEmitsInstance(s: PSym; modPos: int; g: ModuleGraph; exportcOnly = false): bool {.
    ...raises: [KeyError, OSError, Exception, ValueError],
    tags: [ReadEnvEffect, ReadIOEffect, ReadDirEffect, RootEffect], forbids: [].}

Whether the cg of the module at modPos emits the generic instance s ITSELF, so that every other demander only prototypes it. That module is the instance's HOME: the module that created it and serializes it, and whose (offer) makes every importer reuse this very symbol instead of minting its own. Emitting it once there restores the original one-definition semantics; emit-everywhere + merge remains the fallback for what does not qualify.

The predicate reads only the symbol as its home serialized it, so the home's cg (which seeds it) and every demander's cg (which then skips the body) agree without talking to each other. It excludes:

  • BACKEND-MINTED syms (rttiDestroy/rttiTrace wrappers, lifted hooks): no module's index lists them, so no home would seed them;
  • generated type-bound ops (sfGeneratedOp): same reason — they are produced per process, not serialized by a home;
  • instances the home does not OFFER: the ones minted inside a compiles() probe. Such an instance can survive with a body that never resolved ($ of a CountTable[PIdent] with a raw nkDotExpr callee); nothing demands it, and codegen of it crashes. The home always loads its own header, so it sees its offers; a demander that did not load the home's header just emits the body as before, which merge dedups;
  • everything isSeedableRoutine rejects (metatypes, unused, forward, ...).

cg transforms a seeded instance in its own process, exactly as a demander did before, so the lower stage still never sees one.

Source   Edit  
proc multiFormat(frmt: var string; chars: static openArray[char];
                 args: openArray[seq[string]])
Source   Edit  
proc newModule(g: BModuleList; module: PSym; conf: ConfigRef; idgen: IdGenerator): BModule {.
    ...raises: [KeyError, OSError, Exception, ValueError],
    tags: [ReadEnvEffect, ReadIOEffect, ReadDirEffect, RootEffect], forbids: [].}
Source   Edit  
proc ownsRuntimeRoutine(s: PSym; modPos: int; exportcOnly = false): bool {.
    ...raises: [KeyError, OSError, Exception, ValueError],
    tags: [ReadEnvEffect, ReadIOEffect, ReadDirEffect, RootEffect], forbids: [].}
A used or exported, concrete, non-generic runtime routine with a body, OWNED by the module at modPos. Shared by the cg stage's owned-routine seeding (so a routine called only from other modules is still emitted by its owner, next to the owner's emits and C options) and the lower stage's owned-routine enumeration, so both stages see exactly the same set. An unused private routine is left alone: classic codegen never visits it, and transforming it can reject a valid program (for example, an unused helper that captures its owner's result). Exported routines are kept even when the module does not use them itself, because a use by an importer is only recorded in the importer's process, never in this module's NIF. With exportcOnly (see seedsOnlyExportcRoutines) only {.exportc.} routines qualify. The other exclusions:
  • nested/closure procs (owner is a proc, not a module): emitted via their enclosing routine's lambda-lifting, never standalone;
  • generic instances (sfFromGeneric): seeded by their home module instead, see homeEmitsInstance;
  • importc/compileTime/error/forward sentinels and meta signatures: not real codegen targets.
  • method DISPATCHERS (sfDispatcher): their bodies are (re)synthesized into the main TU by emitMethodDispatchers/generateIfMethodDispatchers, never per module. A dispatcher is a copySym clone of the method that shares the method's body sub-tree (incl. its closure iterator); transforming it here would lambda-lift that SHARED iterator a SECOND time under a different owner identity, baking a conflicting up field → "up references do not agree" (the divergence is impossible in non-IC, where the dispatcher body is empty at lift time). So a dispatcher is never an owned runtime routine.

A {.closure.} iterator IS a standalone runtime routine (unlike an inline iterator, which is expanded at each call site) and must be emitted by its owner — else a cross-module for over it links to nothing.

Generic INSTANCES (sfFromGeneric) are NEVER an owned runtime routine, so the lower stage never transforms one; cg seeds them separately through homeEmitsInstance and transforms them itself. The lower stage must not transform an instance: a not-fully-concrete instance (a closure factory over a static param, or a $/= op instance whose body resolves only at its further-specialised use sites) still carries unresolved overload choices and crashes transformBody (empty-namePos lambda, nil-typed const-fold).

Source   Edit  
proc registerReusedModuleToMain(g: BModuleList; m: BModule;
                                initRequired, datInitRequired: bool) {....raises: [
    KeyError, OSError, Exception, ValueError, IOError, ERecoverableError], tags: [
    ReadEnvEffect, ReadIOEffect, ReadDirEffect, RootEffect, WriteIOEffect],
    forbids: [].}
registerModuleToMain for a module whose cached translation unit is reused: the init/datInit presence comes from the artifact's meta head instead of the (never generated) sections. Mirrors the non-hcr path of registerModuleToMain — reuse is disabled when hcr is on. Source   Edit  
proc requestProcDef(m: BModule; prc: PSym) {....raises: [KeyError, OSError,
    Exception, ValueError, IOError, ERecoverableError], tags: [ReadEnvEffect,
    ReadIOEffect, ReadDirEffect, RootEffect, WriteIOEffect, TimeEffect],
    forbids: [].}
Public demand entry: request prc's definition; it is routed to the module that owns it and generated once, exactly as if some generated code had referenced it. Source   Edit  
proc seedsOnlyExportcRoutines(conf: ConfigRef): bool {....raises: [], tags: [],
    forbids: [].}
Standalone builds without a GC leave parts of the runtime out. A routine that sem marked used (because some unreachable routine refers to it) can then need a compilerproc this configuration does not have ("system module needs: appendString"). Classic codegen only generates reachable routines and never notices, so the per-module backend seeds only the {.exportc.} entry points there and leaves everything else to demand. Source   Edit  
proc setupCgen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.
    ...raises: [KeyError, OSError, Exception, ValueError, IOError], tags: [
    ReadEnvEffect, ReadIOEffect, ReadDirEffect, RootEffect, WriteDirEffect],
    forbids: [].}
Source   Edit  
proc signatureHasMetaType(t: PType; depth: int = 0): bool {.
    ...raises: [KeyError, OSError, Exception, ValueError],
    tags: [ReadEnvEffect, ReadIOEffect, ReadDirEffect, RootEffect], forbids: [].}
Whether a routine signature mentions a compile-time/meta element type (typed/untyped — e.g. echo's varargs[typed] — typedesc, static, generic param). Such routines are expanded at their call sites and never emitted standalone, so the per-module owned-routine seeding must skip them (getTypeDescAux(tyTyped) otherwise). tfHasMeta alone misses the varargs element case, hence the explicit scan. Source   Edit  

Templates

template cgDeclFrmt(s: PSym): string
Source   Edit