summary refs log tree commit diff stats
path: root/compiler/cgen.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/cgen.nim')
-rwxr-xr-xcompiler/cgen.nim1032
1 files changed, 1032 insertions, 0 deletions
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
new file mode 100755
index 000000000..a15c4c4ca
--- /dev/null
+++ b/compiler/cgen.nim
@@ -0,0 +1,1032 @@
+#
+#
+#           The Nimrod Compiler
+#        (c) Copyright 2011 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This is the new C code generator; much cleaner and faster
+# than the old one. It also generates better code.
+
+import 
+  ast, astalgo, strutils, nhashes, trees, platform, magicsys, extccomp,
+  options, 
+  nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os, 
+  times, ropes, math, passes, rodread, wordrecg, rnimsyn, treetab, cgmeth,
+  rodutils
+
+when options.hasTinyCBackend:
+  import tccgen
+
+proc cgenPass*(): TPass
+# implementation
+
+type 
+  TLabel = PRope              # 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
+    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
+    cfsProcHeaders,           # section for C procs prototypes
+    cfsData,                  # section for C constant data
+    cfsVars,                  # section for C variable declarations
+    cfsProcs,                 # section for C procs that are not inline
+    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, ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64, 
+    ctInt, ctInt8, ctInt16, ctInt32, ctInt64, ctFloat, ctFloat32, ctFloat64, 
+    ctFloat128, ctArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc, ctCString
+  TCFileSections = array[TCFileSection, PRope] # 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, PRope] # represents a generated C proc
+  BModule = ref TCGen
+  BProc = ref TCProc
+  TBlock{.final.} = object 
+    id*: int                  # the ID of the label; positive means that it
+                              # has been used (i.e. the label should be emitted)
+    nestedTryStmts*: int      # how many try statements is it nested into
+  
+  TCProc{.final.} = object   # represents C proc that is currently generated
+    s: TCProcSections        # the procs sections; short name for readability
+    prc: PSym                # the Nimrod proc that this C proc belongs to
+    BeforeRetNeeded: bool    # true iff 'BeforeRet' label for proc is needed
+    nestedTryStmts: seq[PNode] # in how many nested try statements we are
+                               # (the vars must be volatile then)
+    labels: Natural          # for generating unique labels in the C proc
+    blocks: seq[TBlock]      # nested blocks
+    options: TOptions        # options that should be used for code
+                             # generation; this is the same as prc.options
+                             # unless prc == nil
+    frameLen: int            # current length of frame descriptor
+    sendClosure: PType       # closure record type that we pass
+    receiveClosure: PType    # closure record type that we get
+    module: BModule          # used to prevent excessive parameter passing
+    withinLoop: int          # > 0 if we are within a loop
+  
+  TTypeSeq = seq[PType]
+  TCGen = object of TPassContext # represents a C source file
+    module*: PSym
+    filename*: string
+    s*: TCFileSections        # sections of the C file
+    cfilename*: string        # filename of the module (including path,
+                              # without extension)
+    typeCache*: TIdTable      # cache the generated types
+    forwTypeCache*: TIdTable  # cache for forward declarations of types
+    declaredThings*: TIntSet  # things we have declared in this .c file
+    declaredProtos*: TIntSet  # prototypes we have declared in this .c file
+    headerFiles*: TLinkedList # needed headers to include
+    typeInfoMarker*: TIntSet  # needed for generating type information
+    initProc*: BProc          # code for init procedure
+    typeStack*: TTypeSeq      # used for type generation
+    dataCache*: TNodeTable
+    forwardedProcs*: TSymSeq  # keep forwarded procs here
+    typeNodes*, nimTypes*: int # used for type info generation
+    typeNodesName*, nimTypesName*: PRope # used for type info generation
+    labels*: natural          # for generating unique module-scope names
+  
+
+var 
+  mainModProcs, mainModInit: PRope # parts of the main module
+  gMapping: PRope             # the generated mapping file (if requested)
+  gProcProfile: Natural       # proc profile counter
+  gGeneratedSyms: TIntSet     # set of ID's of generated symbols
+  gPendingModules: seq[BModule] = @[] # list of modules that are not
+                                      # finished with code generation
+  gForwardedProcsCounter: int = 0
+  gNimDat: BModule            # generated global data
+
+proc ropeff(cformat, llvmformat: string, args: openarray[PRope]): PRope = 
+  if gCmd == cmdCompileToLLVM: result = ropef(llvmformat, args)
+  else: result = ropef(cformat, args)
+  
+proc appff(dest: var PRope, cformat, llvmformat: string, 
+           args: openarray[PRope]) = 
+  if gCmd == cmdCompileToLLVM: appf(dest, llvmformat, args)
+  else: appf(dest, cformat, args)
+  
+proc addForwardedProc(m: BModule, prc: PSym) = 
+  m.forwardedProcs.add(prc)
+  inc(gForwardedProcsCounter)
+
+proc addPendingModule(m: BModule) = 
+  for i in countup(0, high(gPendingModules)): 
+    if gPendingModules[i] == m: 
+      InternalError("module already pending: " & m.module.name.s)
+  gPendingModules.add(m)
+
+proc findPendingModule(m: BModule, s: PSym): BModule = 
+  var ms = getModule(s)
+  if ms.id == m.module.id: return m
+  for i in countup(0, high(gPendingModules)): 
+    result = gPendingModules[i]
+    if result.module.id == ms.id: return 
+  InternalError(s.info, "no pending module found for: " & s.name.s)
+
+proc initLoc(result: var TLoc, k: TLocKind, typ: PType, s: TStorageLoc) = 
+  result.k = k
+  result.s = s
+  result.t = GetUniqueType(typ)
+  result.r = nil
+  result.a = - 1
+  result.flags = {}
+
+proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: PRope, s: TStorageLoc) = 
+  # fills the loc if it is not already initialized
+  if a.k == locNone: 
+    a.k = k
+    a.t = getUniqueType(typ)
+    a.a = - 1
+    a.s = s
+    if a.r == nil: a.r = r
+  
+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
+  result.blocks = @[]
+  result.nestedTryStmts = @[]
+
+proc isSimpleConst(typ: PType): bool = 
+  result = not (skipTypes(typ, abstractVar).kind in
+      {tyTuple, tyObject, tyArray, tyArrayConstr, tySet, tySequence})
+
+proc useHeader(m: BModule, sym: PSym) = 
+  if lfHeader in sym.loc.Flags: 
+    assert(sym.annex != nil)
+    discard lists.IncludeStr(m.headerFiles, getStr(sym.annex.path))
+
+proc cgsym(m: BModule, name: string): PRope
+
+proc ropecg(m: BModule, frmt: TFormatStr, args: openarray[PRope]): PRope = 
+  var i, j, length, start, num: int
+  i = 0
+  length = len(frmt)
+  result = nil
+  num = 0
+  while i < length: 
+    if frmt[i] == '$': 
+      inc(i)                  # skip '$'
+      case frmt[i]
+      of '$': 
+        app(result, "$")
+        inc(i)
+      of '#': 
+        inc(i)
+        app(result, args[num])
+        inc(num)
+      of '0'..'9': 
+        j = 0
+        while true: 
+          j = (j * 10) + Ord(frmt[i]) - ord('0')
+          inc(i)
+          if i >= length or not (frmt[i] in {'0'..'9'}): break 
+        num = j
+        if j > high(args) + 1: 
+          internalError("ropes: invalid format string $" & $(j))
+        app(result, args[j - 1])
+      of 'N', 'n': 
+        app(result, tnl)
+        inc(i)
+      else: InternalError("ropes: invalid format string $" & frmt[i])
+    elif frmt[i] == '#' and frmt[i+1] in IdentStartChars:
+      inc(i)
+      var j = i
+      while frmt[j] in IdentChars: inc(j)
+      var ident = copy(frmt, i, j-1)
+      i = j
+      app(result, cgsym(m, ident))
+    elif frmt[i] == '#' and frmt[i+1] == '$':
+      inc(i, 2)
+      var j = 0
+      while frmt[i] in Digits: 
+        j = (j * 10) + Ord(frmt[i]) - ord('0')
+        inc(i)
+      app(result, cgsym(m, args[j-1].ropeToStr))
+    start = i
+    while i < length: 
+      if frmt[i] != '$' and frmt[i] != '#': inc(i)
+      else: break 
+    if i - 1 >= start: 
+      app(result, copy(frmt, start, i - 1))
+
+proc appcg(m: BModule, c: var PRope, frmt: TFormatStr, 
+           args: openarray[PRope]) = 
+  app(c, ropecg(m, frmt, args))
+
+proc appcg(m: BModule, s: TCFileSection, frmt: TFormatStr, 
+           args: openarray[PRope]) = 
+  app(m.s[s], ropecg(m, frmt, args))
+
+proc appcg(p: BProc, s: TCProcSection, frmt: TFormatStr, 
+           args: openarray[PRope]) = 
+  app(p.s[s], ropecg(p.module, frmt, args))
+
+
+include "ccgtypes.nim"
+
+# ------------------------------ Manager of temporaries ------------------
+
+proc rdLoc(a: TLoc): PRope =
+  # 'read' location (deref if indirect)
+  result = a.r
+  if lfIndirect in a.flags: result = ropef("(*$1)", [result])
+
+proc addrLoc(a: TLoc): PRope =
+  result = a.r
+  if lfIndirect notin a.flags: result = con("&", result)
+
+proc rdCharLoc(a: TLoc): PRope =
+  # read a location that may need a char-cast:
+  result = rdLoc(a)
+  if skipTypes(a.t, abstractRange).kind == tyChar:
+    result = ropef("((NU8)($1))", [result])
+
+proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc, 
+                   takeAddr: bool) =
+  case analyseObjectWithTypeField(t)
+  of frNone:
+    nil
+  of frHeader:
+    var r = rdLoc(a)
+    if not takeAddr: r = ropef("(*$1)", [r])
+    var s = skipTypes(t, abstractInst)
+    while (s.kind == tyObject) and (s.sons[0] != nil):
+      app(r, ".Sup")
+      s = skipTypes(s.sons[0], abstractInst)
+    appcg(p, section, "$1.m_type = $2;$n", [r, genTypeInfo(p.module, t)])
+  of frEmbedded:
+    # worst case for performance:
+    var r = if takeAddr: addrLoc(a) else: rdLoc(a)
+    appcg(p, section, "#objectInit($1, $2);$n", [r, genTypeInfo(p.module, t)])
+
+type
+  TAssignmentFlag = enum
+    needToCopy, needForSubtypeCheck, afDestIsNil, afDestIsNotNil, afSrcIsNil,
+    afSrcIsNotNil
+  TAssignmentFlags = set[TAssignmentFlag]
+
+proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags)
+
+proc zeroVar(p: BProc, loc: TLoc, containsGCref: bool) = 
+  if skipTypes(loc.t, abstractVarRange).Kind notin
+      {tyArray, tyArrayConstr, tySet, tyTuple, tyObject}: 
+    if containsGcref and p.WithInLoop > 0:
+      appf(p.s[cpsInit], "$1 = 0;$n", [rdLoc(loc)])
+      var nilLoc: TLoc
+      initLoc(nilLoc, locTemp, loc.t, onStack)
+      nilLoc.r = toRope("NIM_NIL")
+      # puts ``unsureAsgnRef`` etc to ``p.s[cpsStmts]``:
+      genRefAssign(p, loc, nilLoc, {afSrcIsNil})
+    else:
+      appf(p.s[cpsStmts], "$1 = 0;$n", [rdLoc(loc)])
+  else: 
+    if containsGcref and p.WithInLoop > 0:
+      appf(p.s[cpsInit], "memset((void*)$1, 0, sizeof($2));$n", 
+           [addrLoc(loc), rdLoc(loc)])
+      appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n", 
+           [addrLoc(loc), genTypeInfo(p.module, loc.t)])
+    else:
+      appf(p.s[cpsStmts], "memset((void*)$1, 0, sizeof($2));$n", 
+           [addrLoc(loc), rdLoc(loc)])
+    genObjectInit(p, cpsInit, loc.t, loc, true)
+
+proc zeroTemp(p: BProc, loc: TLoc) = 
+  if skipTypes(loc.t, abstractVarRange).Kind notin
+      {tyArray, tyArrayConstr, tySet, tyTuple, tyObject}: 
+    appf(p.s[cpsStmts], "$1 = 0;$n", [rdLoc(loc)])
+    when false:
+      var nilLoc: TLoc
+      initLoc(nilLoc, locTemp, loc.t, onStack)
+      nilLoc.r = toRope("NIM_NIL")
+      # puts ``unsureAsgnRef`` etc to ``p.s[cpsStmts]``:
+      genRefAssign(p, loc, nilLoc, {afSrcIsNil})
+  else: 
+    appf(p.s[cpsStmts], "memset((void*)$1, 0, sizeof($2));$n", 
+         [addrLoc(loc), rdLoc(loc)])
+    when false:
+      appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n", 
+           [addrLoc(loc), genTypeInfo(p.module, loc.t)])
+
+proc initVariable(p: BProc, v: PSym) = 
+  var b = containsGarbageCollectedRef(v.typ)
+  if b or v.ast == nil: 
+    zeroVar(p, v.loc, b)
+    
+proc initTemp(p: BProc, tmp: var TLoc) = 
+  if containsGarbageCollectedRef(tmp.t):
+    zeroTemp(p, tmp)
+
+proc getTemp(p: BProc, t: PType, result: var TLoc) = 
+  inc(p.labels)
+  if gCmd == cmdCompileToLLVM: 
+    result.r = con("%LOC", toRope(p.labels))
+  else: 
+    result.r = con("LOC", toRope(p.labels))
+    appf(p.s[cpsLocals], "$1 $2;$n", [getTypeDesc(p.module, t), result.r])
+  result.k = locTemp
+  result.a = - 1
+  result.t = getUniqueType(t)
+  result.s = OnStack
+  result.flags = {}
+  initTemp(p, result)
+
+proc cstringLit(p: BProc, r: var PRope, s: string): PRope = 
+  if gCmd == cmdCompileToLLVM: 
+    inc(p.module.labels)
+    inc(p.labels)
+    result = ropef("%LOC$1", [toRope(p.labels)])
+    appf(p.module.s[cfsData], "@C$1 = private constant [$2 x i8] $3$n", 
+         [toRope(p.module.labels), toRope(len(s)), makeLLVMString(s)])
+    appf(r, "$1 = getelementptr [$2 x i8]* @C$3, %NI 0, %NI 0$n", 
+         [result, toRope(len(s)), toRope(p.module.labels)])
+  else: 
+    result = makeCString(s)
+  
+proc cstringLit(m: BModule, r: var PRope, s: string): PRope = 
+  if gCmd == cmdCompileToLLVM: 
+    inc(m.labels, 2)
+    result = ropef("%MOC$1", [toRope(m.labels - 1)])
+    appf(m.s[cfsData], "@MOC$1 = private constant [$2 x i8] $3$n", 
+         [toRope(m.labels), toRope(len(s)), makeLLVMString(s)])
+    appf(r, "$1 = getelementptr [$2 x i8]* @MOC$3, %NI 0, %NI 0$n", 
+         [result, toRope(len(s)), toRope(m.labels)])
+  else: 
+    result = makeCString(s)
+  
+proc allocParam(p: BProc, s: PSym) = 
+  assert(s.kind == skParam)
+  if lfParamCopy notin s.loc.flags: 
+    inc(p.labels)
+    var tmp = con("%LOC", toRope(p.labels))
+    incl(s.loc.flags, lfParamCopy)
+    incl(s.loc.flags, lfIndirect)
+    appf(p.s[cpsInit], "$1 = alloca $3$n" & "store $3 $2, $3* $1$n", 
+         [tmp, s.loc.r, getTypeDesc(p.module, s.loc.t)])
+    s.loc.r = tmp
+
+proc localDebugInfo(p: BProc, s: PSym) = 
+  if {optStackTrace, optEndb} * p.options != {optStackTrace, optEndb}: return 
+  # XXX work around a bug: No type information for open arrays possible:
+  if skipTypes(s.typ, abstractVar).kind == tyOpenArray: return
+  if gCmd == cmdCompileToLLVM: 
+    # "address" is the 0th field
+    # "typ" is the 1rst field
+    # "name" is the 2nd field
+    var name = cstringLit(p, p.s[cpsInit], normalize(s.name.s))
+    if (s.kind == skParam) and not ccgIntroducedPtr(s): allocParam(p, s)
+    inc(p.labels, 3)
+    appf(p.s[cpsInit], "%LOC$6 = getelementptr %TF* %F, %NI 0, $1, %NI 0$n" &
+        "%LOC$7 = getelementptr %TF* %F, %NI 0, $1, %NI 1$n" &
+        "%LOC$8 = getelementptr %TF* %F, %NI 0, $1, %NI 2$n" &
+        "store i8* $2, i8** %LOC$6$n" & "store $3* $4, $3** %LOC$7$n" &
+        "store i8* $5, i8** %LOC$8$n", [toRope(p.frameLen), s.loc.r, 
+                                        getTypeDesc(p.module, "TNimType"), 
+                                        genTypeInfo(p.module, s.loc.t), name, 
+                                        toRope(p.labels), toRope(p.labels - 1), 
+                                        toRope(p.labels - 2)])
+  else: 
+    var a = con("&", s.loc.r)
+    if (s.kind == skParam) and ccgIntroducedPtr(s): a = s.loc.r
+    appf(p.s[cpsInit], 
+         "F.s[$1].address = (void*)$3; F.s[$1].typ = $4; F.s[$1].name = $2;$n",
+         [toRope(p.frameLen), makeCString(normalize(s.name.s)), a, 
+          genTypeInfo(p.module, s.loc.t)])
+  inc(p.frameLen)
+
+proc assignLocalVar(p: BProc, s: PSym) = 
+  #assert(s.loc.k == locNone) // not yet assigned
+  # this need not be fullfilled for inline procs; they are regenerated
+  # for each module that uses them!
+  if s.loc.k == locNone: 
+    fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack)
+  if gCmd == cmdCompileToLLVM: 
+    appf(p.s[cpsLocals], "$1 = alloca $2$n", 
+         [s.loc.r, getTypeDesc(p.module, s.loc.t)])
+    incl(s.loc.flags, lfIndirect)
+  else: 
+    app(p.s[cpsLocals], getTypeDesc(p.module, s.loc.t))
+    if sfRegister in s.flags: app(p.s[cpsLocals], " register")
+    if (sfVolatile in s.flags) or (p.nestedTryStmts.len > 0): 
+      app(p.s[cpsLocals], " volatile")
+    appf(p.s[cpsLocals], " $1;$n", [s.loc.r])
+  localDebugInfo(p, s)
+
+proc declareThreadVar(m: BModule, s: PSym) =
+  if optThreads in gGlobalOptions:
+    app(m.s[cfsVars], "NIM_THREADVAR ")
+  app(m.s[cfsVars], getTypeDesc(m, s.loc.t))
+  
+
+proc assignGlobalVar(p: BProc, s: PSym) = 
+  if s.loc.k == locNone: 
+    fillLoc(s.loc, locGlobalVar, s.typ, mangleName(s), OnHeap)
+  useHeader(p.module, s)
+  if lfNoDecl in s.loc.flags: return 
+  if sfImportc in s.flags: app(p.module.s[cfsVars], "extern ")
+  if sfThreadVar in s.flags: declareThreadVar(p.module, s)
+  else: app(p.module.s[cfsVars], getTypeDesc(p.module, s.loc.t))
+  if sfRegister in s.flags: app(p.module.s[cfsVars], " register")
+  if sfVolatile in s.flags: app(p.module.s[cfsVars], " volatile")
+  appf(p.module.s[cfsVars], " $1;$n", [s.loc.r])
+  if {optStackTrace, optEndb} * p.module.module.options ==
+      {optStackTrace, optEndb}: 
+    appcg(p.module, p.module.s[cfsDebugInit], 
+          "#dbgRegisterGlobal($1, &$2, $3);$n", 
+         [cstringLit(p, p.module.s[cfsDebugInit], 
+          normalize(s.owner.name.s & '.' & s.name.s)), 
+          s.loc.r, genTypeInfo(p.module, s.typ)])
+
+proc iff(cond: bool, the, els: PRope): PRope = 
+  if cond: result = the
+  else: result = els
+  
+proc assignParam(p: BProc, s: PSym) = 
+  assert(s.loc.r != nil)
+  if sfAddrTaken in s.flags and gCmd == cmdCompileToLLVM: allocParam(p, s)
+  localDebugInfo(p, s)
+
+proc fillProcLoc(sym: PSym) = 
+  if sym.loc.k == locNone: 
+    fillLoc(sym.loc, locProc, sym.typ, mangleName(sym), OnStack)
+  
+proc getLabel(p: BProc): TLabel = 
+  inc(p.labels)
+  result = con("LA", toRope(p.labels))
+
+proc fixLabel(p: BProc, labl: TLabel) = 
+  appf(p.s[cpsStmts], "$1: ;$n", [labl])
+
+proc genVarPrototype(m: BModule, sym: PSym)
+proc genConstPrototype(m: BModule, sym: PSym)
+proc genProc(m: BModule, prc: PSym)
+proc genStmts(p: BProc, t: PNode)
+proc genProcPrototype(m: BModule, sym: PSym)
+
+include "ccgexprs.nim", "ccgstmts.nim"
+
+# ----------------------------- dynamic library handling -----------------
+# We don't finalize dynamic libs as this does the OS for us.
+
+proc libCandidates(s: string, dest: var TStringSeq) = 
+  var le = strutils.find(s, '(')
+  var ri = strutils.find(s, ')', le+1)
+  if le >= 0 and ri > le: 
+    var prefix = copy(s, 0, le - 1)
+    var suffix = copy(s, ri + 1)
+    for middle in split(copy(s, le + 1, ri - 1), '|'):
+      libCandidates(prefix & middle & suffix, dest)
+  else: 
+    add(dest, s)
+
+proc loadDynamicLib(m: BModule, lib: PLib) = 
+  assert(lib != nil)
+  if not lib.generated: 
+    lib.generated = true
+    var tmp = getGlobalTempName()
+    assert(lib.name == nil)
+    lib.name = tmp # BUGFIX: cgsym has awful side-effects
+    appf(m.s[cfsVars], "static void* $1;$n", [tmp])
+    if lib.path.kind in {nkStrLit..nkTripleStrLit}:
+      var s: TStringSeq = @[]
+      libCandidates(lib.path.strVal, s)
+      var loadlib: PRope = nil
+      for i in countup(0, high(s)): 
+        inc(m.labels)
+        if i > 0: app(loadlib, "||")
+        appcg(m, loadlib, "($1 = #nimLoadLibrary((#NimStringDesc*) &$2))$n", 
+              [tmp, getStrLit(m, s[i])])
+      appcg(m, m.s[cfsDynLibInit], 
+            "if (!($1)) #nimLoadLibraryError((#NimStringDesc*) &$2);$n", 
+            [loadlib, getStrLit(m, lib.path.strVal)]) 
+    else:
+      var p = newProc(nil, m)
+      var dest: TLoc
+      initLocExpr(p, lib.path, dest)
+      app(m.s[cfsVars], p.s[cpsLocals])
+      app(m.s[cfsDynLibInit], p.s[cpsInit])
+      app(m.s[cfsDynLibInit], p.s[cpsStmts])
+      appcg(m, m.s[cfsDynLibInit], 
+           "if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n", 
+           [tmp, rdLoc(dest)])
+      
+  if lib.name == nil: InternalError("loadDynamicLib")
+  
+proc mangleDynLibProc(sym: PSym): PRope =
+  if sfCompilerProc in sym.flags: 
+    # NOTE: sym.loc.r is the external name!
+    result = toRope(sym.name.s)
+  else:
+    result = ropef("Dl_$1", [toRope(sym.id)])
+  
+proc SymInDynamicLib(m: BModule, sym: PSym) = 
+  var lib = sym.annex
+  var extname = sym.loc.r
+  loadDynamicLib(m, lib)
+  #discard cgsym(m, "nimGetProcAddr")
+  if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect)
+  var tmp = mangleDynLibProc(sym)
+  sym.loc.r = tmp             # from now on we only need the internal name
+  sym.typ.sym = nil           # generate a new name
+  inc(m.labels, 2)
+  appcg(m, m.s[cfsDynLibInit], 
+      "$1 = ($2) #nimGetProcAddr($3, $4);$n", 
+      [tmp, getTypeDesc(m, sym.typ), 
+      lib.name, cstringLit(m, m.s[cfsDynLibInit], ropeToStr(extname))])
+  appff(m.s[cfsVars], "$2 $1;$n", 
+      "$1 = linkonce global $2 zeroinitializer$n", 
+      [sym.loc.r, getTypeDesc(m, sym.loc.t)])
+
+proc cgsym(m: BModule, name: string): PRope = 
+  var sym = magicsys.getCompilerProc(name)
+  if sym != nil: 
+    case sym.kind
+    of skProc, skMethod, skConverter: genProc(m, sym)
+    of skVar: genVarPrototype(m, sym)
+    of skType: discard getTypeDesc(m, sym.typ)
+    else: InternalError("cgsym: " & name)
+  else:
+    # we used to exclude the system module from this check, but for DLL
+    # generation support this sloppyness leads to hard to detect bugs, so
+    # we're picky here for the system module too:
+    rawMessage(errSystemNeeds, name)
+  result = sym.loc.r
+  
+proc generateHeaders(m: BModule) = 
+  app(m.s[cfsHeaders], "#include \"nimbase.h\"" & tnl & tnl)
+  var it = PStrEntry(m.headerFiles.head)
+  while it != nil: 
+    if it.data[0] notin {'\"', '<'}: 
+      appf(m.s[cfsHeaders], "#include \"$1\"$n", [toRope(it.data)])
+    else: 
+      appf(m.s[cfsHeaders], "#include $1$n", [toRope(it.data)])
+    it = PStrEntry(it.Next)
+
+proc getFrameDecl(p: BProc) = 
+  var slots: PRope
+  if p.frameLen > 0: 
+    discard cgsym(p.module, "TVarSlot")
+    slots = ropeff("  TVarSlot s[$1];$n", ", [$1 x %TVarSlot]", 
+                   [toRope(p.frameLen)])
+  else: 
+    slots = nil
+  appff(p.s[cpsLocals], "volatile struct {TFrame* prev;" &
+      "NCSTRING procname;NI line;NCSTRING filename;" & 
+      "NI len;$n$1} F;$n", 
+      "%TF = type {%TFrame*, i8*, %NI, %NI$1}$n" & 
+      "%F = alloca %TF$n", [slots])
+  inc(p.labels)
+  prepend(p.s[cpsInit], ropeff("F.len = $1;$n", 
+      "%LOC$2 = getelementptr %TF %F, %NI 4$n" &
+      "store %NI $1, %NI* %LOC$2$n", [toRope(p.frameLen), toRope(p.labels)]))
+
+proc retIsNotVoid(s: PSym): bool = 
+  result = (s.typ.sons[0] != nil) and not isInvalidReturnType(s.typ.sons[0])
+
+proc initFrame(p: BProc, procname, filename: PRope): PRope = 
+  result = ropecg(p.module, 
+    "F.procname = $1;$n" &
+    "F.prev = #framePtr;$n" &
+    "F.filename = $2;$n" & 
+    "F.line = 0;$n" & 
+    "framePtr = (TFrame*)&F;$n", [procname, filename])
+
+proc deinitFrame(p: BProc): PRope = 
+  inc(p.labels, 3)
+  result = ropeff("framePtr = framePtr->prev;$n", 
+      "%LOC$1 = load %TFrame* @framePtr$n" &
+      "%LOC$2 = getelementptr %TFrame* %LOC$1, %NI 0$n" &
+      "%LOC$3 = load %TFrame** %LOC$2$n" &
+      "store %TFrame* $LOC$3, %TFrame** @framePtr", [toRope(p.labels), 
+      toRope(p.labels - 1), toRope(p.labels - 2)])
+
+proc genProcAux(m: BModule, prc: PSym) = 
+  var 
+    p: BProc
+    generatedProc, header, returnStmt, procname, filename: PRope
+    res, param: PSym
+  p = newProc(prc, m)
+  header = genProcHeader(m, prc)
+  if (gCmd != cmdCompileToLLVM) and (lfExportLib in prc.loc.flags): 
+    header = con("N_LIB_EXPORT ", header)
+  returnStmt = nil
+  assert(prc.ast != nil)
+  if not (sfPure in prc.flags) and (prc.typ.sons[0] != nil): 
+    res = prc.ast.sons[resultPos].sym # get result symbol
+    if not isInvalidReturnType(prc.typ.sons[0]): 
+      # declare the result symbol:
+      assignLocalVar(p, res)
+      assert(res.loc.r != nil)
+      returnStmt = ropeff("return $1;$n", "ret $1$n", [rdLoc(res.loc)])
+      initVariable(p, res)
+    else: 
+      fillResult(res)
+      assignParam(p, res)
+      if skipTypes(res.typ, abstractInst).kind == tyArray: 
+        incl(res.loc.flags, lfIndirect)
+        res.loc.s = OnUnknown
+  for i in countup(1, sonsLen(prc.typ.n) - 1): 
+    param = prc.typ.n.sons[i].sym
+    assignParam(p, param)
+  genStmts(p, prc.ast.sons[codePos]) # modifies p.locals, p.init, etc.
+  if sfPure in prc.flags: 
+    generatedProc = ropeff("$1 {$n$2$3$4}$n", "define $1 {$n$2$3$4}$n", [header, 
+        p.s[cpsLocals], p.s[cpsInit], p.s[cpsStmts]])
+  else: 
+    generatedProc = ropeff("$1 {$n", "define $1 {$n", [header])
+    if optStackTrace in prc.options: 
+      getFrameDecl(p)
+      app(generatedProc, p.s[cpsLocals])
+      procname = CStringLit(p, generatedProc, prc.name.s)
+      filename = CStringLit(p, generatedProc, toFilename(prc.info))
+      app(generatedProc, initFrame(p, procname, filename))
+    else: 
+      app(generatedProc, p.s[cpsLocals])
+    if (optProfiler in prc.options) and (gCmd != cmdCompileToLLVM): 
+      if gProcProfile >= 64 * 1024: 
+        InternalError(prc.info, "too many procedures for profiling")
+      discard cgsym(m, "profileData")
+      app(p.s[cpsLocals], "ticks NIM_profilingStart;" & tnl)
+      if prc.loc.a < 0: 
+        appf(m.s[cfsDebugInit], "profileData[$1].procname = $2;$n", [
+            toRope(gProcProfile), 
+            makeCString(prc.name.s)])
+        prc.loc.a = gProcProfile
+        inc(gProcProfile)
+      prepend(p.s[cpsInit], toRope("NIM_profilingStart = getticks();" & tnl))
+    app(generatedProc, p.s[cpsInit])
+    app(generatedProc, p.s[cpsStmts])
+    if p.beforeRetNeeded: app(generatedProc, "BeforeRet: ;" & tnl)
+    if optStackTrace in prc.options: app(generatedProc, deinitFrame(p))
+    if (optProfiler in prc.options) and (gCmd != cmdCompileToLLVM): 
+      appf(generatedProc, 
+          "profileData[$1].total += elapsed(getticks(), NIM_profilingStart);$n", 
+           [toRope(prc.loc.a)])
+    app(generatedProc, returnStmt)
+    app(generatedProc, '}' & tnl)
+  app(m.s[cfsProcs], generatedProc)
+  
+proc genProcPrototype(m: BModule, sym: PSym) = 
+  useHeader(m, sym)
+  if lfNoDecl in sym.loc.Flags: return 
+  if lfDynamicLib in sym.loc.Flags: 
+    if sym.owner.id != m.module.id and
+        not intSetContainsOrIncl(m.declaredThings, sym.id): 
+      appff(m.s[cfsVars], "extern $1 $2;$n", 
+            "@$2 = linkonce global $1 zeroinitializer$n", 
+            [getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)])
+      if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect)
+  elif not IntSetContainsOrIncl(m.declaredProtos, sym.id): 
+    appf(m.s[cfsProcHeaders], "$1;$n", [genProcHeader(m, sym)])
+
+proc genProcNoForward(m: BModule, prc: PSym) = 
+  fillProcLoc(prc)
+  useHeader(m, prc)
+  genProcPrototype(m, prc)
+  if lfNoDecl in prc.loc.Flags: return 
+  if prc.typ.callConv == ccInline: 
+    # We add inline procs to the calling module to enable C based inlining.
+    # This also means that a check with ``gGeneratedSyms`` is wrong, we need
+    # a check for ``m.declaredThings``.
+    if not intSetContainsOrIncl(m.declaredThings, prc.id): genProcAux(m, prc)
+  elif lfDynamicLib in prc.loc.flags: 
+    if not IntSetContainsOrIncl(gGeneratedSyms, prc.id): 
+      SymInDynamicLib(findPendingModule(m, prc), prc)
+  elif not (sfImportc in prc.flags): 
+    if not IntSetContainsOrIncl(gGeneratedSyms, prc.id): 
+      genProcAux(findPendingModule(m, prc), prc)
+  
+proc genProc(m: BModule, prc: PSym) = 
+  if sfBorrow in prc.flags: return 
+  fillProcLoc(prc)
+  if {sfForward, sfFromGeneric} * prc.flags != {}: addForwardedProc(m, prc)
+  else: genProcNoForward(m, prc)
+  
+proc genVarPrototype(m: BModule, sym: PSym) = 
+  assert(sfGlobal in sym.flags)
+  useHeader(m, sym)
+  fillLoc(sym.loc, locGlobalVar, sym.typ, mangleName(sym), OnHeap)
+  if (lfNoDecl in sym.loc.Flags) or
+      intSetContainsOrIncl(m.declaredThings, sym.id): 
+    return 
+  if sym.owner.id != m.module.id: 
+    # else we already have the symbol generated!
+    assert(sym.loc.r != nil)
+    if gCmd == cmdCompileToLLVM: 
+      incl(sym.loc.flags, lfIndirect)
+      appf(m.s[cfsVars], "$1 = linkonce global $2 zeroinitializer$n", 
+           [sym.loc.r, getTypeDesc(m, sym.loc.t)])
+    else: 
+      app(m.s[cfsVars], "extern ")
+      if sfThreadVar in sym.flags: declareThreadVar(m, sym)
+      else: app(m.s[cfsVars], getTypeDesc(m, sym.loc.t))
+      if sfRegister in sym.flags: app(m.s[cfsVars], " register")
+      if sfVolatile in sym.flags: app(m.s[cfsVars], " volatile")
+      appf(m.s[cfsVars], " $1;$n", [sym.loc.r])
+
+proc genConstPrototype(m: BModule, sym: PSym) = 
+  useHeader(m, sym)
+  if sym.loc.k == locNone: 
+    fillLoc(sym.loc, locData, sym.typ, mangleName(sym), OnUnknown)
+  if (lfNoDecl in sym.loc.Flags) or
+      intSetContainsOrIncl(m.declaredThings, sym.id): 
+    return 
+  if sym.owner.id != m.module.id: 
+    # else we already have the symbol generated!
+    assert(sym.loc.r != nil)
+    appff(m.s[cfsData], "extern NIM_CONST $1 $2;$n", 
+          "$1 = linkonce constant $2 zeroinitializer", 
+          [getTypeDesc(m, sym.loc.t), sym.loc.r])
+
+proc getFileHeader(cfilenoext: string): PRope = 
+  if optCompileOnly in gGlobalOptions: 
+    result = ropeff("/* Generated by Nimrod Compiler v$1 */$n" &
+        "/*   (c) 2011 Andreas Rumpf */$n", 
+        "; Generated by Nimrod Compiler v$1$n" &
+        ";   (c) 2011 Andreas Rumpf$n", [toRope(versionAsString)])
+  else: 
+    result = ropeff("/* Generated by Nimrod Compiler v$1 */$n" &
+        "/*   (c) 2011 Andreas Rumpf */$n" & "/* Compiled for: $2, $3, $4 */$n" &
+        "/* Command for C compiler:$n   $5 */$n", 
+        "; Generated by Nimrod Compiler v$1$n" &
+        ";   (c) 2011 Andreas Rumpf$n" & "; Compiled for: $2, $3, $4$n" &
+        "; Command for LLVM compiler:$n   $5$n", [toRope(versionAsString), 
+        toRope(platform.OS[targetOS].name), 
+        toRope(platform.CPU[targetCPU].name), 
+        toRope(extccomp.CC[extccomp.ccompiler].name), 
+        toRope(getCompileCFileCmd(cfilenoext))])
+  case platform.CPU[targetCPU].intSize
+  of 16: 
+    appff(result, 
+          "$ntypedef short int NI;$n" & "typedef unsigned short int NU;$n", 
+          "$n%NI = type i16$n", [])
+  of 32: 
+    appff(result, 
+          "$ntypedef long int NI;$n" & "typedef unsigned long int NU;$n", 
+          "$n%NI = type i32$n", [])
+  of 64: 
+    appff(result, "$ntypedef long long int NI;$n" &
+        "typedef unsigned long long int NU;$n", "$n%NI = type i64$n", [])
+  else: 
+    nil
+
+proc genMainProc(m: BModule) = 
+  const 
+    CommonMainBody = 
+        "  nim__datInit();$n" &
+        "  systemInit();$n" & 
+        "$1" & 
+        "$2"
+    PosixNimMain = 
+        "int cmdCount;$n" & 
+        "char** cmdLine;$n" & 
+        "char** gEnv;$n" &
+        "N_CDECL(void, NimMain)(void) {$n" &
+        CommonMainBody & "}$n"
+    PosixCMain = "int main(int argc, char** args, char** env) {$n" &
+        "  cmdLine = args;$n" & "  cmdCount = argc;$n" & "  gEnv = env;$n" &
+        "  NimMain();$n" & "  return 0;$n" & "}$n"
+    WinNimMain = "N_CDECL(void, NimMain)(void) {$n" &
+        CommonMainBody & "}$n"
+    WinCMain = "N_STDCALL(int, WinMain)(HINSTANCE hCurInstance, $n" &
+        "                        HINSTANCE hPrevInstance, $n" &
+        "                        LPSTR lpCmdLine, int nCmdShow) {$n" &
+        "  NimMain();$n" & "  return 0;$n" & "}$n"
+    WinNimDllMain = "N_LIB_EXPORT N_CDECL(void, NimMain)(void) {$n" &
+        CommonMainBody & "}$n"
+    WinCDllMain = 
+        "BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $n" &
+        "                    LPVOID lpvReserved) {$n" & "  NimMain();$n" &
+        "  return 1;$n" & "}$n"
+    PosixNimDllMain = WinNimDllMain
+    PosixCDllMain = 
+        "void NIM_POSIX_INIT NimMainInit(void) {$n" &
+        "  NimMain();$n}$n"
+  var nimMain, otherMain: TFormatStr
+  if platform.targetOS == osWindows and
+      gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}: 
+    if optGenGuiApp in gGlobalOptions: 
+      nimMain = WinNimMain
+      otherMain = WinCMain
+    else: 
+      nimMain = WinNimDllMain
+      otherMain = WinCDllMain
+    discard lists.IncludeStr(m.headerFiles, "<windows.h>")
+  elif optGenDynLib in gGlobalOptions:
+    nimMain = posixNimDllMain
+    otherMain = posixCDllMain
+  else: 
+    nimMain = PosixNimMain
+    otherMain = PosixCMain
+  if gBreakpoints != nil: discard cgsym(m, "dbgRegisterBreakpoint")
+  inc(m.labels)
+  appcg(m, m.s[cfsProcs], nimMain, [
+        gBreakpoints, mainModInit, toRope(m.labels)])
+  if not (optNoMain in gGlobalOptions): 
+    appcg(m, m.s[cfsProcs], otherMain, [])
+  
+proc getInitName(m: PSym): PRope = 
+  result = ropeff("$1Init", "@$1Init", [toRope(m.name.s)])
+
+proc registerModuleToMain(m: PSym) = 
+  var initname = getInitName(m)
+  appff(mainModProcs, "N_NOINLINE(void, $1)(void);$n", 
+        "declare void $1() noinline$n", [initname])
+  if not (sfSystemModule in m.flags): 
+    appff(mainModInit, "$1();$n", "call void ()* $1$n", [initname])
+  
+proc genInitCode(m: BModule) = 
+  var initname, prc, procname, filename: PRope
+  if optProfiler in m.initProc.options: 
+    # This does not really belong here, but there is no good place for this
+    # code. I don't want to put this to the proc generation as the
+    # ``IncludeStr`` call is quite slow.
+    discard lists.IncludeStr(m.headerFiles, "<cycle.h>")
+  initname = getInitName(m.module)
+  prc = ropeff("N_NOINLINE(void, $1)(void) {$n", 
+               "define void $1() noinline {$n", [initname])
+  if m.typeNodes > 0: 
+    appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n", 
+          [m.typeNodesName, toRope(m.typeNodes)])
+  if m.nimTypes > 0: 
+    appcg(m, m.s[cfsTypeInit1], "static #TNimType $1[$2];$n", 
+          [m.nimTypesName, toRope(m.nimTypes)])
+  if optStackTrace in m.initProc.options: 
+    getFrameDecl(m.initProc)
+    app(prc, m.initProc.s[cpsLocals])
+    app(prc, m.s[cfsTypeInit1])
+    procname = CStringLit(m.initProc, prc, m.module.name.s)
+    filename = CStringLit(m.initProc, prc, toFilename(m.module.info))
+    app(prc, initFrame(m.initProc, procname, filename))
+  else: 
+    app(prc, m.initProc.s[cpsLocals])
+    app(prc, m.s[cfsTypeInit1])
+  app(prc, m.s[cfsTypeInit2])
+  app(prc, m.s[cfsTypeInit3])
+  app(prc, m.s[cfsDebugInit])
+  app(prc, m.s[cfsDynLibInit])
+  app(prc, m.initProc.s[cpsInit])
+  app(prc, m.initProc.s[cpsStmts])
+  if optStackTrace in m.initProc.options: app(prc, deinitFrame(m.initProc))
+  app(prc, '}' & tnl & tnl)
+  app(m.s[cfsProcs], prc)
+
+proc genModule(m: BModule, cfilenoext: string): PRope = 
+  result = getFileHeader(cfilenoext)
+  generateHeaders(m)
+  for i in countup(low(TCFileSection), cfsProcs): app(result, m.s[i])
+  
+proc rawNewModule(module: PSym, filename: string): BModule = 
+  new(result)
+  InitLinkedList(result.headerFiles)
+  intSetInit(result.declaredThings)
+  intSetInit(result.declaredProtos)
+  result.cfilename = filename
+  result.filename = filename
+  initIdTable(result.typeCache)
+  initIdTable(result.forwTypeCache)
+  result.module = module
+  intSetInit(result.typeInfoMarker)
+  result.initProc = newProc(nil, result)
+  result.initProc.options = gOptions
+  initNodeTable(result.dataCache)
+  result.typeStack = @[]
+  result.forwardedProcs = @[]
+  result.typeNodesName = getTempName()
+  result.nimTypesName = getTempName()
+
+proc newModule(module: PSym, filename: string): BModule = 
+  result = rawNewModule(module, filename)
+  if (optDeadCodeElim in gGlobalOptions): 
+    if (sfDeadCodeElim in module.flags): 
+      InternalError("added pending module twice: " & filename)
+    addPendingModule(result)
+
+proc registerTypeInfoModule() = 
+  const moduleName = "nim__dat"
+  var s = NewSym(skModule, getIdent(moduleName), nil)
+  gNimDat = rawNewModule(s, joinPath(options.projectPath, moduleName) & ".nim")
+  addPendingModule(gNimDat)
+  appff(mainModProcs, "N_NOINLINE(void, $1)(void);$n", 
+        "declare void $1() noinline$n", [getInitName(s)])
+
+proc myOpen(module: PSym, filename: string): PPassContext = 
+  if gNimDat == nil: registerTypeInfoModule()
+  result = newModule(module, filename)
+
+proc myOpenCached(module: PSym, filename: string, 
+                  rd: PRodReader): PPassContext = 
+  if gNimDat == nil: 
+    registerTypeInfoModule()
+    #MessageOut('cgen.myOpenCached has been called ' + filename)
+  var cfile = changeFileExt(completeCFilePath(filename), cExt)
+  var cfilenoext = changeFileExt(cfile, "")
+  addFileToLink(cfilenoext)
+  registerModuleToMain(module)
+  # XXX: this cannot be right here, initalization has to be appended during
+  # the ``myClose`` call
+  result = nil
+
+proc shouldRecompile(code: PRope, cfile, cfilenoext: string): bool = 
+  result = true
+  if not (optForceFullMake in gGlobalOptions): 
+    var objFile = toObjFile(cfilenoext)
+    if writeRopeIfNotEqual(code, cfile): return 
+    if ExistsFile(objFile) and os.FileNewer(objFile, cfile): result = false
+  else: 
+    writeRope(code, cfile)
+  
+proc myProcess(b: PPassContext, n: PNode): PNode = 
+  result = n
+  if b == nil or passes.skipCodegen(n): return
+  var m = BModule(b)
+  m.initProc.options = gOptions
+  genStmts(m.initProc, n)
+
+proc finishModule(m: BModule) = 
+  var i = 0
+  while i <= high(m.forwardedProcs): 
+    # Note: ``genProc`` may add to ``m.forwardedProcs``, so we cannot use
+    # a ``for`` loop here
+    var prc = m.forwardedProcs[i]
+    if sfForward in prc.flags: InternalError(prc.info, "still forwarded")
+    genProcNoForward(m, prc)
+    inc(i)
+  assert(gForwardedProcsCounter >= i)
+  dec(gForwardedProcsCounter, i)
+  setlen(m.forwardedProcs, 0)
+
+proc writeModule(m: BModule) = 
+  # generate code for the init statements of the module:
+  genInitCode(m)
+  finishTypeDescriptions(m)
+  var cfile = completeCFilePath(m.cfilename)
+  var cfilenoext = changeFileExt(cfile, "")
+  if sfMainModule in m.module.flags: 
+    # generate main file:
+    app(m.s[cfsProcHeaders], mainModProcs)
+  var code = genModule(m, cfilenoext)
+  
+  when hasTinyCBackend:
+    if gCmd == cmdRun:
+      tccgen.compileCCode(ropeToStr(code))
+      return
+  
+  if shouldRecompile(code, changeFileExt(cfile, cExt), cfilenoext): 
+    addFileToCompile(cfilenoext)
+  addFileToLink(cfilenoext)
+
+proc myClose(b: PPassContext, n: PNode): PNode = 
+  result = n
+  if b == nil or passes.skipCodegen(n): return 
+  var m = BModule(b)
+  if n != nil: 
+    m.initProc.options = gOptions
+    genStmts(m.initProc, n)
+  registerModuleToMain(m.module)
+  if not (optDeadCodeElim in gGlobalOptions) and
+      not (sfDeadCodeElim in m.module.flags): 
+    finishModule(m)
+  if sfMainModule in m.module.flags: 
+    var disp = generateMethodDispatchers()
+    for i in 0..sonsLen(disp)-1: genProcAux(gNimDat, disp.sons[i].sym)
+    genMainProc(m) 
+    # we need to process the transitive closure because recursive module
+    # deps are allowed (and the system module is processed in the wrong
+    # order anyway)
+    while gForwardedProcsCounter > 0: 
+      for i in countup(0, high(gPendingModules)): 
+        finishModule(gPendingModules[i])
+    for i in countup(0, high(gPendingModules)): writeModule(gPendingModules[i])
+    setlen(gPendingModules, 0)
+  if not (optDeadCodeElim in gGlobalOptions) and
+      not (sfDeadCodeElim in m.module.flags): 
+    writeModule(m)
+  if sfMainModule in m.module.flags: writeMapping(gMapping)
+  
+proc cgenPass(): TPass = 
+  initPass(result)
+  result.open = myOpen
+  result.openCached = myOpenCached
+  result.process = myProcess
+  result.close = myClose
+
+InitIiTable(gToTypeInfoId)
+IntSetInit(gGeneratedSyms)