summary refs log tree commit diff stats
path: root/compiler/nir/ast2ir.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/nir/ast2ir.nim')
-rw-r--r--compiler/nir/ast2ir.nim2638
1 files changed, 0 insertions, 2638 deletions
diff --git a/compiler/nir/ast2ir.nim b/compiler/nir/ast2ir.nim
deleted file mode 100644
index 11bd711f9..000000000
--- a/compiler/nir/ast2ir.nim
+++ /dev/null
@@ -1,2638 +0,0 @@
-#
-#
-#           The Nim Compiler
-#        (c) Copyright 2023 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-import std / [assertions, tables, sets]
-import ".." / [ast, astalgo, types, options, lineinfos, msgs, magicsys,
-  modulegraphs, renderer, transf, bitsets, trees, nimsets,
-  expanddefaults]
-from ".." / lowerings import lowerSwap, lowerTupleUnpacking
-from ".." / pathutils import customPath
-import .. / ic / bitabs
-
-import nirtypes, nirinsts, nirlineinfos, nirslots, types2ir, nirfiles
-
-when defined(nimCompilerStacktraceHints):
-  import std/stackframes
-
-type
-  ModuleCon* = ref object
-    nirm*: ref NirModule
-    types: TypesCon
-    module*: PSym
-    graph*: ModuleGraph
-    nativeIntId, nativeUIntId: TypeId
-    strPayloadId: (TypeId, TypeId)
-    idgen: IdGenerator
-    processedProcs, pendingProcsAsSet: HashSet[ItemId]
-    pendingProcs: seq[PSym] # procs we still need to generate code for
-    pendingVarsAsSet: HashSet[ItemId]
-    pendingVars: seq[PSym]
-    noModularity*: bool
-    inProc: int
-    toSymId: Table[ItemId, SymId]
-    symIdCounter: int32
-
-  ProcCon* = object
-    config*: ConfigRef
-    lit: Literals
-    lastFileKey: FileIndex
-    lastFileVal: LitId
-    labelGen: int
-    exitLabel: LabelId
-    #code*: Tree
-    blocks: seq[(PSym, LabelId)]
-    sm: SlotManager
-    idgen: IdGenerator
-    m: ModuleCon
-    prc: PSym
-    options: TOptions
-
-template code(c: ProcCon): Tree = c.m.nirm.code
-
-proc initModuleCon*(graph: ModuleGraph; config: ConfigRef; idgen: IdGenerator; module: PSym;
-                    nirm: ref NirModule): ModuleCon =
-  #let lit = Literals() # must be shared
-  result = ModuleCon(graph: graph, types: initTypesCon(config), nirm: nirm,
-    idgen: idgen, module: module)
-  case config.target.intSize
-  of 2:
-    result.nativeIntId = Int16Id
-    result.nativeUIntId = UInt16Id
-  of 4:
-    result.nativeIntId = Int32Id
-    result.nativeUIntId = UInt16Id
-  else:
-    result.nativeIntId = Int64Id
-    result.nativeUIntId = UInt16Id
-  result.strPayloadId = strPayloadPtrType(result.types, result.nirm.types)
-  nirm.namespace = nirm.lit.strings.getOrIncl(customPath(toFullPath(config, module.info)))
-  nirm.intbits = uint32(config.target.intSize * 8)
-
-proc initProcCon*(m: ModuleCon; prc: PSym; config: ConfigRef): ProcCon =
-  result = ProcCon(m: m, sm: initSlotManager({}), prc: prc, config: config,
-    lit: m.nirm.lit, idgen: m.idgen,
-    options: if prc != nil: prc.options
-             else: config.options)
-  result.exitLabel = newLabel(result.labelGen)
-
-proc toLineInfo(c: var ProcCon; i: TLineInfo): PackedLineInfo =
-  var val: LitId
-  if c.lastFileKey == i.fileIndex:
-    val = c.lastFileVal
-  else:
-    val = c.lit.strings.getOrIncl(toFullPath(c.config, i.fileIndex))
-    # remember the entry:
-    c.lastFileKey = i.fileIndex
-    c.lastFileVal = val
-  result = pack(c.m.nirm.man, val, int32 i.line, int32 i.col)
-
-proc bestEffort(c: ProcCon): TLineInfo =
-  if c.prc != nil:
-    c.prc.info
-  else:
-    c.m.module.info
-
-proc popBlock(c: var ProcCon; oldLen: int) =
-  c.blocks.setLen(oldLen)
-
-template withBlock(labl: PSym; info: PackedLineInfo; asmLabl: LabelId; body: untyped) {.dirty.} =
-  var oldLen {.gensym.} = c.blocks.len
-  c.blocks.add (labl, asmLabl)
-  body
-  popBlock(c, oldLen)
-
-type
-  GenFlag = enum
-    gfAddrOf # load the address of the expression
-    gfToOutParam # the expression is passed to an `out` parameter
-  GenFlags = set[GenFlag]
-
-proc gen(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {})
-
-proc genScope(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) =
-  openScope c.sm
-  gen c, n, d, flags
-  closeScope c.sm
-
-proc freeTemp(c: var ProcCon; tmp: Value) =
-  let s = extractTemp(tmp)
-  if s != SymId(-1):
-    freeTemp(c.sm, s)
-
-proc freeTemps(c: var ProcCon; tmps: openArray[Value]) =
-  for t in tmps: freeTemp(c, t)
-
-proc typeToIr(m: ModuleCon; t: PType): TypeId =
-  typeToIr(m.types, m.nirm.types, t)
-
-proc allocTemp(c: var ProcCon; t: TypeId): SymId =
-  if c.m.noModularity:
-    result = allocTemp(c.sm, t, c.m.symIdCounter)
-  else:
-    result = allocTemp(c.sm, t, c.idgen.symId)
-
-const
-  ListSymId = -1
-
-proc toSymId(c: var ProcCon; s: PSym): SymId =
-  if c.m.noModularity:
-    result = c.m.toSymId.getOrDefault(s.itemId, SymId(-1))
-    if result.int < 0:
-      inc c.m.symIdCounter
-      result = SymId(c.m.symIdCounter)
-      c.m.toSymId[s.itemId] = result
-      when ListSymId != -1:
-        if result.int == ListSymId or s.name.s == "echoBinSafe":
-          echo result.int, " is ", s.name.s, " ", c.m.graph.config $ s.info, " ", s.flags
-          writeStackTrace()
-  else:
-    result = SymId(s.itemId.item)
-
-proc getTemp(c: var ProcCon; n: PNode): Value =
-  let info = toLineInfo(c, n.info)
-  let t = typeToIr(c.m, n.typ)
-  let tmp = allocTemp(c, t)
-  c.code.addSummon info, tmp, t
-  result = localToValue(info, tmp)
-
-proc getTemp(c: var ProcCon; t: TypeId; info: PackedLineInfo): Value =
-  let tmp = allocTemp(c, t)
-  c.code.addSummon info, tmp, t
-  result = localToValue(info, tmp)
-
-proc gen(c: var ProcCon; n: PNode; flags: GenFlags = {}) =
-  var tmp = default(Value)
-  gen(c, n, tmp, flags)
-  freeTemp c, tmp
-
-proc genScope(c: var ProcCon; n: PNode; flags: GenFlags = {}) =
-  openScope c.sm
-  gen c, n, flags
-  closeScope c.sm
-
-proc genx(c: var ProcCon; n: PNode; flags: GenFlags = {}): Value =
-  result = default(Value)
-  gen(c, n, result, flags)
-  assert Tree(result).len > 0, $n
-
-proc clearDest(c: var ProcCon; n: PNode; d: var Value) {.inline.} =
-  when false:
-    if n.typ.isNil or n.typ.kind == tyVoid:
-      let s = extractTemp(d)
-      if s != SymId(-1):
-        freeLoc(c.sm, s)
-
-proc isNotOpr(n: PNode): bool =
-  n.kind in nkCallKinds and n[0].kind == nkSym and n[0].sym.magic == mNot
-
-proc jmpBack(c: var ProcCon; n: PNode; lab: LabelId) =
-  c.code.gotoLabel toLineInfo(c, n.info), GotoLoop, lab
-
-type
-  JmpKind = enum opcFJmp, opcTJmp
-
-proc xjmp(c: var ProcCon; n: PNode; jk: JmpKind; v: Value): LabelId =
-  result = newLabel(c.labelGen)
-  let info = toLineInfo(c, n.info)
-  buildTyped c.code, info, Select, Bool8Id:
-    c.code.copyTree Tree(v)
-    build c.code, info, SelectPair:
-      build c.code, info, SelectValue:
-        c.code.boolVal(c.lit.numbers, info, jk == opcTJmp)
-      c.code.gotoLabel info, Goto, result
-
-proc patch(c: var ProcCon; n: PNode; L: LabelId) =
-  addLabel c.code, toLineInfo(c, n.info), Label, L
-
-proc genWhile(c: var ProcCon; n: PNode) =
-  # lab1:
-  #   cond, tmp
-  #   fjmp tmp, lab2
-  #   body
-  #   jmp lab1
-  # lab2:
-  let info = toLineInfo(c, n.info)
-  let lab1 = c.code.addNewLabel(c.labelGen, info, LoopLabel)
-  withBlock(nil, info, lab1):
-    if isTrue(n[0]):
-      c.gen(n[1])
-      c.jmpBack(n, lab1)
-    elif isNotOpr(n[0]):
-      var tmp = c.genx(n[0][1])
-      let lab2 = c.xjmp(n, opcTJmp, tmp)
-      c.freeTemp(tmp)
-      c.gen(n[1])
-      c.jmpBack(n, lab1)
-      c.patch(n, lab2)
-    else:
-      var tmp = c.genx(n[0])
-      let lab2 = c.xjmp(n, opcFJmp, tmp)
-      c.freeTemp(tmp)
-      c.gen(n[1])
-      c.jmpBack(n, lab1)
-      c.patch(n, lab2)
-
-proc genBlock(c: var ProcCon; n: PNode; d: var Value) =
-  openScope c.sm
-  let info = toLineInfo(c, n.info)
-  let lab1 = newLabel(c.labelGen)
-
-  withBlock(n[0].sym, info, lab1):
-    c.gen(n[1], d)
-
-  c.code.addLabel(info, Label, lab1)
-  closeScope c.sm
-  c.clearDest(n, d)
-
-proc jumpTo(c: var ProcCon; n: PNode; L: LabelId) =
-  c.code.addLabel(toLineInfo(c, n.info), Goto, L)
-
-proc genBreak(c: var ProcCon; n: PNode) =
-  if n[0].kind == nkSym:
-    for i in countdown(c.blocks.len-1, 0):
-      if c.blocks[i][0] == n[0].sym:
-        c.jumpTo n, c.blocks[i][1]
-        return
-    localError(c.config, n.info, "NIR problem: cannot find 'break' target")
-  else:
-    c.jumpTo n, c.blocks[c.blocks.high][1]
-
-proc genIf(c: var ProcCon; n: PNode; d: var Value) =
-  #  if (!expr1) goto lab1;
-  #    thenPart
-  #    goto LEnd
-  #  lab1:
-  #  if (!expr2) goto lab2;
-  #    thenPart2
-  #    goto LEnd
-  #  lab2:
-  #    elsePart
-  #  Lend:
-  if isEmpty(d) and not isEmptyType(n.typ): d = getTemp(c, n)
-  var ending = newLabel(c.labelGen)
-  for i in 0..<n.len:
-    var it = n[i]
-    if it.len == 2:
-      let info = toLineInfo(c, it[0].info)
-      var elsePos: LabelId
-      if isNotOpr(it[0]):
-        let tmp = c.genx(it[0][1])
-        elsePos = c.xjmp(it[0][1], opcTJmp, tmp) # if true
-        c.freeTemp tmp
-      else:
-        let tmp = c.genx(it[0])
-        elsePos = c.xjmp(it[0], opcFJmp, tmp) # if false
-        c.freeTemp tmp
-      c.clearDest(n, d)
-      if isEmptyType(it[1].typ): # maybe noreturn call, don't touch `d`
-        c.genScope(it[1])
-      else:
-        c.genScope(it[1], d) # then part
-      if i < n.len-1:
-        c.jumpTo it[1], ending
-      c.patch(it, elsePos)
-    else:
-      c.clearDest(n, d)
-      if isEmptyType(it[0].typ): # maybe noreturn call, don't touch `d`
-        c.genScope(it[0])
-      else:
-        c.genScope(it[0], d)
-  c.patch(n, ending)
-  c.clearDest(n, d)
-
-proc tempToDest(c: var ProcCon; n: PNode; d: var Value; tmp: Value) =
-  if isEmpty(d):
-    d = tmp
-  else:
-    let info = toLineInfo(c, n.info)
-    buildTyped c.code, info, Asgn, typeToIr(c.m, n.typ):
-      c.code.copyTree d
-      c.code.copyTree tmp
-    freeTemp(c, tmp)
-
-proc genAndOr(c: var ProcCon; n: PNode; opc: JmpKind; d: var Value) =
-  #   asgn d, a
-  #   tjmp|fjmp lab1
-  #   asgn d, b
-  # lab1:
-  var tmp = getTemp(c, n)
-  c.gen(n[1], tmp)
-  let lab1 = c.xjmp(n, opc, tmp)
-  c.gen(n[2], tmp)
-  c.patch(n, lab1)
-  tempToDest c, n, d, tmp
-
-proc unused(c: var ProcCon; n: PNode; x: Value) {.inline.} =
-  if hasValue(x):
-    #debug(n)
-    localError(c.config, n.info, "not unused")
-
-proc caseValue(c: var ProcCon; n: PNode) =
-  let info = toLineInfo(c, n.info)
-  build c.code, info, SelectValue:
-    let x = genx(c, n)
-    c.code.copyTree x
-    freeTemp(c, x)
-
-proc caseRange(c: var ProcCon; n: PNode) =
-  let info = toLineInfo(c, n.info)
-  build c.code, info, SelectRange:
-    let x = genx(c, n[0])
-    let y = genx(c, n[1])
-    c.code.copyTree x
-    c.code.copyTree y
-    freeTemp(c, y)
-    freeTemp(c, x)
-
-proc addUseCodegenProc(c: var ProcCon; dest: var Tree; name: string; info: PackedLineInfo) =
-  let cp = getCompilerProc(c.m.graph, name)
-  let theProc = c.genx newSymNode(cp)
-  copyTree c.code, theProc
-
-template buildCond(useNegation: bool; cond: typed; body: untyped) =
-  let lab = newLabel(c.labelGen)
-  buildTyped c.code, info, Select, Bool8Id:
-    c.code.copyTree cond
-    build c.code, info, SelectPair:
-      build c.code, info, SelectValue:
-        c.code.boolVal(c.lit.numbers, info, useNegation)
-      c.code.gotoLabel info, Goto, lab
-
-  body
-  c.code.addLabel info, Label, lab
-
-template buildIf(cond: typed; body: untyped) =
-  buildCond false, cond, body
-
-template buildIfNot(cond: typed; body: untyped) =
-  buildCond true, cond, body
-
-template buildIfThenElse(cond: typed; then, otherwise: untyped) =
-  let lelse = newLabel(c.labelGen)
-  let lend = newLabel(c.labelGen)
-  buildTyped c.code, info, Select, Bool8Id:
-    c.code.copyTree cond
-    build c.code, info, SelectPair:
-      build c.code, info, SelectValue:
-        c.code.boolVal(c.lit.numbers, info, false)
-      c.code.gotoLabel info, Goto, lelse
-
-  then()
-  c.code.gotoLabel info, Goto, lend
-  c.code.addLabel info, Label, lelse
-  otherwise()
-  c.code.addLabel info, Label, lend
-
-include stringcases
-
-proc genCase(c: var ProcCon; n: PNode; d: var Value) =
-  if not isEmptyType(n.typ):
-    if isEmpty(d): d = getTemp(c, n)
-  else:
-    unused(c, n, d)
-
-  if n[0].typ.skipTypes(abstractInst).kind == tyString:
-    genStringCase(c, n, d)
-    return
-
-  var sections = newSeqOfCap[LabelId](n.len-1)
-  let ending = newLabel(c.labelGen)
-  let info = toLineInfo(c, n.info)
-  let tmp = c.genx(n[0])
-  buildTyped c.code, info, Select, typeToIr(c.m, n[0].typ):
-    c.code.copyTree tmp
-    for i in 1..<n.len:
-      let section = newLabel(c.labelGen)
-      sections.add section
-      let it = n[i]
-      let itinfo = toLineInfo(c, it.info)
-      build c.code, itinfo, SelectPair:
-        build c.code, itinfo, SelectList:
-          for j in 0..<it.len-1:
-            if it[j].kind == nkRange:
-              caseRange c, it[j]
-            else:
-              caseValue c, it[j]
-        c.code.addLabel itinfo, Goto, section
-  c.freeTemp tmp
-  for i in 1..<n.len:
-    let it = n[i]
-    let itinfo = toLineInfo(c, it.info)
-    c.code.addLabel itinfo, Label, sections[i-1]
-    c.gen it.lastSon
-    if i != n.len-1:
-      c.code.addLabel itinfo, Goto, ending
-  c.code.addLabel info, Label, ending
-
-proc rawCall(c: var ProcCon; info: PackedLineInfo; opc: Opcode; t: TypeId; args: var openArray[Value]) =
-  buildTyped c.code, info, opc, t:
-    if opc in {CheckedCall, CheckedIndirectCall}:
-      c.code.addLabel info, CheckedGoto, c.exitLabel
-    for a in mitems(args):
-      c.code.copyTree a
-      freeTemp c, a
-
-proc canRaiseDisp(c: ProcCon; n: PNode): bool =
-  # we assume things like sysFatal cannot raise themselves
-  if n.kind == nkSym and {sfNeverRaises, sfImportc, sfCompilerProc} * n.sym.flags != {}:
-    result = false
-  elif optPanics in c.config.globalOptions or
-      (n.kind == nkSym and sfSystemModule in getModule(n.sym).flags and
-       sfSystemRaisesDefect notin n.sym.flags):
-    # we know we can be strict:
-    result = canRaise(n)
-  else:
-    # we have to be *very* conservative:
-    result = canRaiseConservative(n)
-
-proc genCall(c: var ProcCon; n: PNode; d: var Value) =
-  let canRaise = canRaiseDisp(c, n[0])
-
-  let opc = if n[0].kind == nkSym and n[0].sym.kind in routineKinds:
-              (if canRaise: CheckedCall else: Call)
-            else:
-              (if canRaise: CheckedIndirectCall else: IndirectCall)
-  let info = toLineInfo(c, n.info)
-
-  # In the IR we cannot nest calls. Thus we use two passes:
-  var args: seq[Value] = @[]
-  var t = n[0].typ
-  if t != nil: t = t.skipTypes(abstractInst)
-  args.add genx(c, n[0])
-  for i in 1..<n.len:
-    if t != nil and i < t.len:
-      if isCompileTimeOnly(t[i]): discard
-      elif isOutParam(t[i]): args.add genx(c, n[i], {gfToOutParam})
-      else: args.add genx(c, n[i])
-    else:
-      args.add genx(c, n[i])
-
-  let tb = typeToIr(c.m, n.typ)
-  if not isEmptyType(n.typ):
-    if isEmpty(d): d = getTemp(c, n)
-    # XXX Handle problematic aliasing here: `a = f_canRaise(a)`.
-    buildTyped c.code, info, Asgn, tb:
-      c.code.copyTree d
-      rawCall c, info, opc, tb, args
-  else:
-    rawCall c, info, opc, tb, args
-  freeTemps c, args
-
-proc genRaise(c: var ProcCon; n: PNode) =
-  let info = toLineInfo(c, n.info)
-  let tb = typeToIr(c.m, n[0].typ)
-
-  let d = genx(c, n[0])
-  buildTyped c.code, info, SetExc, tb:
-    c.code.copyTree d
-  c.freeTemp(d)
-  c.code.addLabel info, Goto, c.exitLabel
-
-proc genReturn(c: var ProcCon; n: PNode) =
-  if n[0].kind != nkEmpty:
-    gen(c, n[0])
-  # XXX Block leave actions?
-  let info = toLineInfo(c, n.info)
-  c.code.addLabel info, Goto, c.exitLabel
-
-proc genTry(c: var ProcCon; n: PNode; d: var Value) =
-  if isEmpty(d) and not isEmptyType(n.typ): d = getTemp(c, n)
-  var endings: seq[LabelId] = @[]
-  let ehPos = newLabel(c.labelGen)
-  let oldExitLab = c.exitLabel
-  c.exitLabel = ehPos
-  if isEmptyType(n[0].typ): # maybe noreturn call, don't touch `d`
-    c.gen(n[0])
-  else:
-    c.gen(n[0], d)
-  c.clearDest(n, d)
-
-  # Add a jump past the exception handling code
-  let jumpToFinally = newLabel(c.labelGen)
-  c.jumpTo n, jumpToFinally
-  # This signals where the body ends and where the exception handling begins
-  c.patch(n, ehPos)
-  c.exitLabel = oldExitLab
-  for i in 1..<n.len:
-    let it = n[i]
-    if it.kind != nkFinally:
-      # first opcExcept contains the end label of the 'except' block:
-      let endExcept = newLabel(c.labelGen)
-      for j in 0..<it.len - 1:
-        assert(it[j].kind == nkType)
-        let typ = it[j].typ.skipTypes(abstractPtrs-{tyTypeDesc})
-        let itinfo = toLineInfo(c, it[j].info)
-        build c.code, itinfo, TestExc:
-          c.code.addTyped itinfo, typeToIr(c.m, typ)
-      if it.len == 1:
-        let itinfo = toLineInfo(c, it.info)
-        build c.code, itinfo, TestExc:
-          c.code.addTyped itinfo, VoidId
-      let body = it.lastSon
-      if isEmptyType(body.typ): # maybe noreturn call, don't touch `d`
-        c.gen(body)
-      else:
-        c.gen(body, d)
-      c.clearDest(n, d)
-      if i < n.len:
-        endings.add newLabel(c.labelGen)
-      c.patch(it, endExcept)
-  let fin = lastSon(n)
-  # we always generate an 'opcFinally' as that pops the safepoint
-  # from the stack if no exception is raised in the body.
-  c.patch(fin, jumpToFinally)
-  #c.gABx(fin, opcFinally, 0, 0)
-  for endPos in endings: c.patch(n, endPos)
-  if fin.kind == nkFinally:
-    c.gen(fin[0])
-    c.clearDest(n, d)
-  #c.gABx(fin, opcFinallyEnd, 0, 0)
-
-template isGlobal(s: PSym): bool = sfGlobal in s.flags and s.kind != skForVar
-proc isGlobal(n: PNode): bool = n.kind == nkSym and isGlobal(n.sym)
-
-proc genField(c: var ProcCon; n: PNode; d: var Value) =
-  var pos: int
-  if n.kind != nkSym or n.sym.kind != skField:
-    localError(c.config, n.info, "no field symbol")
-    pos = 0
-  else:
-    pos = n.sym.position
-  d.addImmediateVal toLineInfo(c, n.info), pos
-
-proc genIndex(c: var ProcCon; n: PNode; arr: PType; d: var Value) =
-  let info = toLineInfo(c, n.info)
-  if arr.skipTypes(abstractInst).kind == tyArray and
-      (let offset = firstOrd(c.config, arr); offset != Zero):
-    let x = c.genx(n)
-    buildTyped d, info, Sub, c.m.nativeIntId:
-      copyTree d.Tree, x
-      d.addImmediateVal toLineInfo(c, n.info), toInt(offset)
-  else:
-    c.gen(n, d)
-  if optBoundsCheck in c.options:
-    let idx = move d
-    build d, info, CheckedIndex:
-      d.Tree.addLabel info, CheckedGoto, c.exitLabel
-      copyTree d.Tree, idx
-      let x = toInt64 lengthOrd(c.config, arr)
-      d.addIntVal c.lit.numbers, info, c.m.nativeIntId, x
-
-proc rawGenNew(c: var ProcCon; d: Value; refType: PType; ninfo: TLineInfo; needsInit: bool) =
-  assert refType.kind == tyRef
-  let baseType = refType.elementType
-
-  let info = toLineInfo(c, ninfo)
-  let codegenProc = magicsys.getCompilerProc(c.m.graph,
-    if needsInit: "nimNewObj" else: "nimNewObjUninit")
-  let refTypeIr = typeToIr(c.m, refType)
-  buildTyped c.code, info, Asgn, refTypeIr:
-    copyTree c.code, d
-    buildTyped c.code, info, Cast, refTypeIr:
-      buildTyped c.code, info, Call, VoidPtrId:
-        let theProc = c.genx newSymNode(codegenProc, ninfo)
-        copyTree c.code, theProc
-        c.code.addImmediateVal info, int(getSize(c.config, baseType))
-        c.code.addImmediateVal info, int(getAlign(c.config, baseType))
-
-proc genNew(c: var ProcCon; n: PNode; needsInit: bool) =
-  # If in doubt, always follow the blueprint of the C code generator for `mm:orc`.
-  let refType = n[1].typ.skipTypes(abstractInstOwned)
-  let d = genx(c, n[1])
-  rawGenNew c, d, refType, n.info, needsInit
-  freeTemp c, d
-
-proc genNewSeqOfCap(c: var ProcCon; n: PNode; d: var Value) =
-  let info = toLineInfo(c, n.info)
-  let seqtype = skipTypes(n.typ, abstractVarRange)
-  let baseType = seqtype.elementType
-  var a = c.genx(n[1])
-  if isEmpty(d): d = getTemp(c, n)
-  # $1.len = 0
-  buildTyped c.code, info, Asgn, c.m.nativeIntId:
-    buildTyped c.code, info, FieldAt, typeToIr(c.m, seqtype):
-      copyTree c.code, d
-      c.code.addImmediateVal info, 0
-    c.code.addImmediateVal info, 0
-  # $1.p = ($4*) #newSeqPayloadUninit($2, sizeof($3), NIM_ALIGNOF($3))
-  let payloadPtr = seqPayloadPtrType(c.m.types, c.m.nirm.types, seqtype)[0]
-  buildTyped c.code, info, Asgn, payloadPtr:
-    # $1.p
-    buildTyped c.code, info, FieldAt, typeToIr(c.m, seqtype):
-      copyTree c.code, d
-      c.code.addImmediateVal info, 1
-    # ($4*) #newSeqPayloadUninit($2, sizeof($3), NIM_ALIGNOF($3))
-    buildTyped c.code, info, Cast, payloadPtr:
-      buildTyped c.code, info, Call, VoidPtrId:
-        let codegenProc = magicsys.getCompilerProc(c.m.graph, "newSeqPayloadUninit")
-        let theProc = c.genx newSymNode(codegenProc, n.info)
-        copyTree c.code, theProc
-        copyTree c.code, a
-        c.code.addImmediateVal info, int(getSize(c.config, baseType))
-        c.code.addImmediateVal info, int(getAlign(c.config, baseType))
-  freeTemp c, a
-
-proc genNewSeqPayload(c: var ProcCon; info: PackedLineInfo; d, b: Value; seqtype: PType) =
-  let baseType = seqtype.elementType
-  # $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3))
-  let payloadPtr = seqPayloadPtrType(c.m.types, c.m.nirm.types, seqtype)[0]
-
-  # $1.len = $2
-  buildTyped c.code, info, Asgn, c.m.nativeIntId:
-    buildTyped c.code, info, FieldAt, typeToIr(c.m, seqtype):
-      copyTree c.code, d
-      c.code.addImmediateVal info, 0
-    copyTree c.code, b
-
-  buildTyped c.code, info, Asgn, payloadPtr:
-    # $1.p
-    buildTyped c.code, info, FieldAt, typeToIr(c.m, seqtype):
-      copyTree c.code, d
-      c.code.addImmediateVal info, 1
-    # ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3))
-    buildTyped c.code, info, Cast, payloadPtr:
-      buildTyped c.code, info, Call, VoidPtrId:
-        let codegenProc = magicsys.getCompilerProc(c.m.graph, "newSeqPayload")
-        let theProc = c.genx newSymNode(codegenProc)
-        copyTree c.code, theProc
-        copyTree c.code, b
-        c.code.addImmediateVal info, int(getSize(c.config, baseType))
-        c.code.addImmediateVal info, int(getAlign(c.config, baseType))
-
-proc genNewSeq(c: var ProcCon; n: PNode) =
-  let info = toLineInfo(c, n.info)
-  let seqtype = skipTypes(n[1].typ, abstractVarRange)
-  var d = c.genx(n[1])
-  var b = c.genx(n[2])
-
-  genNewSeqPayload(c, info, d, b, seqtype)
-
-  freeTemp c, b
-  freeTemp c, d
-
-template intoDest*(d: var Value; info: PackedLineInfo; typ: TypeId; body: untyped) =
-  if typ == VoidId:
-    body(c.code)
-  elif isEmpty(d):
-    body(Tree(d))
-  else:
-    buildTyped c.code, info, Asgn, typ:
-      copyTree c.code, d
-      body(c.code)
-
-template valueIntoDest(c: var ProcCon; info: PackedLineInfo; d: var Value; typ: PType; body: untyped) =
-  if isEmpty(d):
-    body(Tree d)
-  else:
-    buildTyped c.code, info, Asgn, typeToIr(c.m, typ):
-      copyTree c.code, d
-      body(c.code)
-
-template constrIntoDest(c: var ProcCon; info: PackedLineInfo; d: var Value; typ: PType; body: untyped) =
-  var tmp = default(Value)
-  body(Tree tmp)
-  if isEmpty(d):
-    d = tmp
-  else:
-    buildTyped c.code, info, Asgn, typeToIr(c.m, typ):
-      copyTree c.code, d
-      copyTree c.code, tmp
-
-proc genBinaryOp(c: var ProcCon; n: PNode; d: var Value; opc: Opcode) =
-  let info = toLineInfo(c, n.info)
-  let tmp = c.genx(n[1])
-  let tmp2 = c.genx(n[2])
-  let t = typeToIr(c.m, n.typ)
-  template body(target) =
-    buildTyped target, info, opc, t:
-      if opc in {CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, CheckedMod}:
-        target.addLabel info, CheckedGoto, c.exitLabel
-      copyTree target, tmp
-      copyTree target, tmp2
-  intoDest d, info, t, body
-  c.freeTemp(tmp)
-  c.freeTemp(tmp2)
-
-proc genCmpOp(c: var ProcCon; n: PNode; d: var Value; opc: Opcode) =
-  let info = toLineInfo(c, n.info)
-  let tmp = c.genx(n[1])
-  let tmp2 = c.genx(n[2])
-  let t = typeToIr(c.m, n[1].typ)
-  template body(target) =
-    buildTyped target, info, opc, t:
-      copyTree target, tmp
-      copyTree target, tmp2
-  intoDest d, info, Bool8Id, body
-  c.freeTemp(tmp)
-  c.freeTemp(tmp2)
-
-proc genUnaryOp(c: var ProcCon; n: PNode; d: var Value; opc: Opcode) =
-  let info = toLineInfo(c, n.info)
-  let tmp = c.genx(n[1])
-  let t = typeToIr(c.m, n.typ)
-  template body(target) =
-    buildTyped target, info, opc, t:
-      copyTree target, tmp
-  intoDest d, info, t, body
-  c.freeTemp(tmp)
-
-proc genIncDec(c: var ProcCon; n: PNode; opc: Opcode) =
-  let info = toLineInfo(c, n.info)
-  let t = typeToIr(c.m, skipTypes(n[1].typ, abstractVar))
-
-  let d = c.genx(n[1])
-  let tmp = c.genx(n[2])
-  # we produce code like:  i = i + 1
-  buildTyped c.code, info, Asgn, t:
-    copyTree c.code, d
-    buildTyped c.code, info, opc, t:
-      if opc in {CheckedAdd, CheckedSub}:
-        c.code.addLabel info, CheckedGoto, c.exitLabel
-      copyTree c.code, d
-      copyTree c.code, tmp
-  c.freeTemp(tmp)
-  #c.genNarrow(n[1], d)
-  c.freeTemp(d)
-
-proc genArrayLen(c: var ProcCon; n: PNode; d: var Value) =
-  #echo c.m.graph.config $ n.info, " ", n
-  let info = toLineInfo(c, n.info)
-  var a = n[1]
-  #if a.kind == nkHiddenAddr: a = a[0]
-  var typ = skipTypes(a.typ, abstractVar + tyUserTypeClasses)
-  case typ.kind
-  of tyOpenArray, tyVarargs:
-    let xa = c.genx(a)
-    template body(target) =
-      buildTyped target, info, FieldAt, typeToIr(c.m, typ):
-        copyTree target, xa
-        target.addImmediateVal info, 1 # (p, len)-pair so len is at index 1
-    intoDest d, info, c.m.nativeIntId, body
-
-  of tyCstring:
-    let xa = c.genx(a)
-    if isEmpty(d): d = getTemp(c, n)
-    buildTyped c.code, info, Call, c.m.nativeIntId:
-      let codegenProc = magicsys.getCompilerProc(c.m.graph, "nimCStrLen")
-      assert codegenProc != nil
-      let theProc = c.genx newSymNode(codegenProc, n.info)
-      copyTree c.code, theProc
-      copyTree c.code, xa
-
-  of tyString, tySequence:
-    let xa = c.genx(a)
-
-    if typ.kind == tySequence:
-      # we go through a temporary here because people write bullshit code.
-      if isEmpty(d): d = getTemp(c, n)
-
-    template body(target) =
-      buildTyped target, info, FieldAt, typeToIr(c.m, typ):
-        copyTree target, xa
-        target.addImmediateVal info, 0 # (len, p)-pair so len is at index 0
-    intoDest d, info, c.m.nativeIntId, body
-
-  of tyArray:
-    template body(target) =
-      target.addIntVal(c.lit.numbers, info, c.m.nativeIntId, toInt lengthOrd(c.config, typ))
-    intoDest d, info, c.m.nativeIntId, body
-  else: internalError(c.config, n.info, "genArrayLen()")
-
-proc genUnaryMinus(c: var ProcCon; n: PNode; d: var Value) =
-  let info = toLineInfo(c, n.info)
-  let tmp = c.genx(n[1])
-  let t = typeToIr(c.m, n.typ)
-  template body(target) =
-    buildTyped target, info, Sub, t:
-      # Little hack: This works because we know that `0.0` is all 0 bits:
-      target.addIntVal(c.lit.numbers, info, t, 0)
-      copyTree target, tmp
-  intoDest d, info, t, body
-  c.freeTemp(tmp)
-
-proc genHigh(c: var ProcCon; n: PNode; d: var Value) =
-  let info = toLineInfo(c, n.info)
-  let t = typeToIr(c.m, n.typ)
-  var x = default(Value)
-  genArrayLen(c, n, x)
-  template body(target) =
-    buildTyped target, info, Sub, t:
-      copyTree target, x
-      target.addIntVal(c.lit.numbers, info, t, 1)
-  intoDest d, info, t, body
-  c.freeTemp x
-
-proc genBinaryCp(c: var ProcCon; n: PNode; d: var Value; compilerProc: string) =
-  let info = toLineInfo(c, n.info)
-  let xa = c.genx(n[1])
-  let xb = c.genx(n[2])
-  if isEmpty(d) and not isEmptyType(n.typ): d = getTemp(c, n)
-
-  let t = typeToIr(c.m, n.typ)
-  template body(target) =
-    buildTyped target, info, Call, t:
-      let codegenProc = magicsys.getCompilerProc(c.m.graph, compilerProc)
-      #assert codegenProc != nil, $n & " " & (c.m.graph.config $ n.info)
-      let theProc = c.genx newSymNode(codegenProc, n.info)
-      copyTree target, theProc
-      copyTree target, xa
-      copyTree target, xb
-
-  intoDest d, info, t, body
-  c.freeTemp xb
-  c.freeTemp xa
-
-proc genUnaryCp(c: var ProcCon; n: PNode; d: var Value; compilerProc: string; argAt = 1) =
-  let info = toLineInfo(c, n.info)
-  let xa = c.genx(n[argAt])
-  if isEmpty(d) and not isEmptyType(n.typ): d = getTemp(c, n)
-
-  let t = typeToIr(c.m, n.typ)
-  template body(target) =
-    buildTyped target, info, Call, t:
-      let codegenProc = magicsys.getCompilerProc(c.m.graph, compilerProc)
-      let theProc = c.genx newSymNode(codegenProc, n.info)
-      copyTree target, theProc
-      copyTree target, xa
-
-  intoDest d, info, t, body
-  c.freeTemp xa
-
-proc genEnumToStr(c: var ProcCon; n: PNode; d: var Value) =
-  let t = n[1].typ.skipTypes(abstractInst+{tyRange})
-  let toStrProc = getToStringProc(c.m.graph, t)
-  # XXX need to modify this logic for IC.
-  var nb = copyTree(n)
-  nb[0] = newSymNode(toStrProc)
-  gen(c, nb, d)
-
-proc genOf(c: var ProcCon; n: PNode; d: var Value) =
-  genUnaryOp c, n, d, TestOf
-
-template sizeOfLikeMsg(name): string =
-  "'" & name & "' requires '.importc' types to be '.completeStruct'"
-
-proc genIsNil(c: var ProcCon; n: PNode; d: var Value) =
-  let info = toLineInfo(c, n.info)
-  let tmp = c.genx(n[1])
-  let t = typeToIr(c.m, n[1].typ)
-  template body(target) =
-    buildTyped target, info, Eq, t:
-      copyTree target, tmp
-      addNilVal target, info, t
-  intoDest d, info, Bool8Id, body
-  c.freeTemp(tmp)
-
-proc fewCmps(conf: ConfigRef; s: PNode): bool =
-  # this function estimates whether it is better to emit code
-  # for constructing the set or generating a bunch of comparisons directly
-  if s.kind != nkCurly:
-    result = false
-  elif (getSize(conf, s.typ) <= conf.target.intSize) and (nfAllConst in s.flags):
-    result = false            # it is better to emit the set generation code
-  elif elemType(s.typ).kind in {tyInt, tyInt16..tyInt64}:
-    result = true             # better not emit the set if int is basetype!
-  else:
-    result = s.len <= 8  # 8 seems to be a good value
-
-proc genInBitset(c: var ProcCon; n: PNode; d: var Value) =
-  let info = toLineInfo(c, n.info)
-  let a = c.genx(n[1])
-  let b = c.genx(n[2])
-
-  let t = bitsetBasetype(c.m.types, c.m.nirm.types, n[1].typ)
-  let setType = typeToIr(c.m, n[1].typ)
-  let mask =
-    case t
-    of UInt8Id: 7
-    of UInt16Id: 15
-    of UInt32Id: 31
-    else: 63
-  let expansion = if t == UInt64Id: UInt64Id else: c.m.nativeUIntId
-    # "(($1              &(1U<<((NU)($2)&7U)))!=0)"  - or -
-    # "(($1[(NU)($2)>>3] &(1U<<((NU)($2)&7U)))!=0)"
-
-  template body(target) =
-    buildTyped target, info, BoolNot, Bool8Id:
-      buildTyped target, info, Eq, t:
-        buildTyped target, info, BitAnd, t:
-          if c.m.nirm.types[setType].kind != ArrayTy:
-            copyTree target, a
-          else:
-            buildTyped target, info, ArrayAt, setType:
-              copyTree target, a
-              buildTyped target, info, BitShr, t:
-                buildTyped target, info, Cast, expansion:
-                  copyTree target, b
-                addIntVal target, c.lit.numbers, info, expansion, 3
-
-          buildTyped target, info, BitShl, t:
-            addIntVal target, c.lit.numbers, info, t, 1
-            buildTyped target, info, BitAnd, t:
-              buildTyped target, info, Cast, expansion:
-                copyTree target, b
-              addIntVal target, c.lit.numbers, info, expansion, mask
-        addIntVal target, c.lit.numbers, info, t, 0
-  intoDest d, info, t, body
-
-  c.freeTemp(b)
-  c.freeTemp(a)
-
-proc genInSet(c: var ProcCon; n: PNode; d: var Value) =
-  let g {.cursor.} = c.m.graph
-  if n[1].kind == nkCurly and fewCmps(g.config, n[1]):
-    # a set constructor but not a constant set:
-    # do not emit the set, but generate a bunch of comparisons; and if we do
-    # so, we skip the unnecessary range check: This is a semantical extension
-    # that code now relies on. :-/ XXX
-    let elem = if n[2].kind in {nkChckRange, nkChckRange64}: n[2][0]
-               else: n[2]
-    let curly = n[1]
-    var ex: PNode = nil
-    for it in curly:
-      var test: PNode
-      if it.kind == nkRange:
-        test = newTree(nkCall, g.operators.opAnd.newSymNode,
-          newTree(nkCall, g.operators.opLe.newSymNode, it[0], elem), # a <= elem
-          newTree(nkCall, g.operators.opLe.newSymNode, elem, it[1])
-        )
-      else:
-        test = newTree(nkCall, g.operators.opEq.newSymNode, elem, it)
-      test.typ = getSysType(g, it.info, tyBool)
-
-      if ex == nil: ex = test
-      else: ex = newTree(nkCall, g.operators.opOr.newSymNode, ex, test)
-
-    if ex == nil:
-      let info = toLineInfo(c, n.info)
-      template body(target) =
-        boolVal target, c.lit.numbers, info, false
-      intoDest d, info, Bool8Id, body
-    else:
-      gen c, ex, d
-  else:
-    genInBitset c, n, d
-
-proc genCard(c: var ProcCon; n: PNode; d: var Value) =
-  let info = toLineInfo(c, n.info)
-  let a = c.genx(n[1])
-  let t = typeToIr(c.m, n.typ)
-
-  let setType = typeToIr(c.m, n[1].typ)
-  if isEmpty(d): d = getTemp(c, n)
-
-  buildTyped c.code, info, Asgn, t:
-    copyTree c.code, d
-    buildTyped c.code, info, Call, t:
-      if c.m.nirm.types[setType].kind == ArrayTy:
-        let codegenProc = magicsys.getCompilerProc(c.m.graph, "cardSet")
-        let theProc = c.genx newSymNode(codegenProc, n.info)
-        copyTree c.code, theProc
-        buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.nirm.types, setType):
-          copyTree c.code, a
-        c.code.addImmediateVal info, int(getSize(c.config, n[1].typ))
-      elif t == UInt64Id:
-        let codegenProc = magicsys.getCompilerProc(c.m.graph, "countBits64")
-        let theProc = c.genx newSymNode(codegenProc, n.info)
-        copyTree c.code, theProc
-        copyTree c.code, a
-      else:
-        let codegenProc = magicsys.getCompilerProc(c.m.graph, "countBits32")
-        let theProc = c.genx newSymNode(codegenProc, n.info)
-        copyTree c.code, theProc
-        buildTyped c.code, info, Cast, UInt32Id:
-          copyTree c.code, a
-  freeTemp c, a
-
-proc genEqSet(c: var ProcCon; n: PNode; d: var Value) =
-  let info = toLineInfo(c, n.info)
-  let a = c.genx(n[1])
-  let b = c.genx(n[2])
-  let t = typeToIr(c.m, n.typ)
-
-  let setType = typeToIr(c.m, n[1].typ)
-
-  if c.m.nirm.types[setType].kind == ArrayTy:
-    if isEmpty(d): d = getTemp(c, n)
-
-    buildTyped c.code, info, Asgn, t:
-      copyTree c.code, d
-      buildTyped c.code, info, Eq, t:
-        buildTyped c.code, info, Call, t:
-          let codegenProc = magicsys.getCompilerProc(c.m.graph, "nimCmpMem")
-          let theProc = c.genx newSymNode(codegenProc, n.info)
-          copyTree c.code, theProc
-          buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.nirm.types, setType):
-            copyTree c.code, a
-          buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.nirm.types, setType):
-            copyTree c.code, b
-          c.code.addImmediateVal info, int(getSize(c.config, n[1].typ))
-        c.code.addIntVal c.lit.numbers, info, c.m.nativeIntId, 0
-
-  else:
-    template body(target) =
-      buildTyped target, info, Eq, setType:
-        copyTree target, a
-        copyTree target, b
-    intoDest d, info, Bool8Id, body
-
-  freeTemp c, b
-  freeTemp c, a
-
-proc beginCountLoop(c: var ProcCon; info: PackedLineInfo; first, last: int): (SymId, LabelId, LabelId) =
-  let tmp = allocTemp(c, c.m.nativeIntId)
-  c.code.addSummon info, tmp, c.m.nativeIntId
-  buildTyped c.code, info, Asgn, c.m.nativeIntId:
-    c.code.addSymUse info, tmp
-    c.code.addIntVal c.lit.numbers, info, c.m.nativeIntId, first
-  let lab1 = c.code.addNewLabel(c.labelGen, info, LoopLabel)
-  result = (tmp, lab1, newLabel(c.labelGen))
-
-  buildTyped c.code, info, Select, Bool8Id:
-    buildTyped c.code, info, Lt, c.m.nativeIntId:
-      c.code.addSymUse info, tmp
-      c.code.addIntVal c.lit.numbers, info, c.m.nativeIntId, last
-    build c.code, info, SelectPair:
-      build c.code, info, SelectValue:
-        c.code.boolVal(c.lit.numbers, info, false)
-      c.code.gotoLabel info, Goto, result[2]
-
-proc beginCountLoop(c: var ProcCon; info: PackedLineInfo; first, last: Value): (SymId, LabelId, LabelId) =
-  let tmp = allocTemp(c, c.m.nativeIntId)
-  c.code.addSummon info, tmp, c.m.nativeIntId
-  buildTyped c.code, info, Asgn, c.m.nativeIntId:
-    c.code.addSymUse info, tmp
-    copyTree c.code, first
-  let lab1 = c.code.addNewLabel(c.labelGen, info, LoopLabel)
-  result = (tmp, lab1, newLabel(c.labelGen))
-
-  buildTyped c.code, info, Select, Bool8Id:
-    buildTyped c.code, info, Le, c.m.nativeIntId:
-      c.code.addSymUse info, tmp
-      copyTree c.code, last
-    build c.code, info, SelectPair:
-      build c.code, info, SelectValue:
-        c.code.boolVal(c.lit.numbers, info, false)
-      c.code.gotoLabel info, Goto, result[2]
-
-proc endLoop(c: var ProcCon; info: PackedLineInfo; s: SymId; back, exit: LabelId) =
-  buildTyped c.code, info, Asgn, c.m.nativeIntId:
-    c.code.addSymUse info, s
-    buildTyped c.code, info, Add, c.m.nativeIntId:
-      c.code.addSymUse info, s
-      c.code.addIntVal c.lit.numbers, info, c.m.nativeIntId, 1
-  c.code.addLabel info, GotoLoop, back
-  c.code.addLabel info, Label, exit
-  freeTemp(c.sm, s)
-
-proc genLeSet(c: var ProcCon; n: PNode; d: var Value) =
-  let info = toLineInfo(c, n.info)
-  let a = c.genx(n[1])
-  let b = c.genx(n[2])
-  let t = typeToIr(c.m, n.typ)
-
-  let setType = typeToIr(c.m, n[1].typ)
-
-  if c.m.nirm.types[setType].kind == ArrayTy:
-    let elemType = bitsetBasetype(c.m.types, c.m.nirm.types, n[1].typ)
-    if isEmpty(d): d = getTemp(c, n)
-    #    "for ($1 = 0; $1 < $2; $1++):"
-    #    "  $3 = (($4[$1] & ~ $5[$1]) == 0)"
-    #    "  if (!$3) break;"
-    let (idx, backLabel, endLabel) = beginCountLoop(c, info, 0, int(getSize(c.config, n[1].typ)))
-    buildTyped c.code, info, Asgn, Bool8Id:
-      copyTree c.code, d
-      buildTyped c.code, info, Eq, elemType:
-        buildTyped c.code, info, BitAnd, elemType:
-          buildTyped c.code, info, ArrayAt, setType:
-            copyTree c.code, a
-            c.code.addSymUse info, idx
-          buildTyped c.code, info, BitNot, elemType:
-            buildTyped c.code, info, ArrayAt, setType:
-              copyTree c.code, b
-              c.code.addSymUse info, idx
-        c.code.addIntVal c.lit.numbers, info, elemType, 0
-
-    # if !$3: break
-    buildTyped c.code, info, Select, Bool8Id:
-      c.code.copyTree d
-      build c.code, info, SelectPair:
-        build c.code, info, SelectValue:
-          c.code.boolVal(c.lit.numbers, info, false)
-        c.code.gotoLabel info, Goto, endLabel
-
-    endLoop(c, info, idx, backLabel, endLabel)
-  else:
-    # "(($1 & ~ $2)==0)"
-    template body(target) =
-      buildTyped target, info, Eq, setType:
-        buildTyped target, info, BitAnd, setType:
-          copyTree target, a
-          buildTyped target, info, BitNot, setType:
-            copyTree target, b
-        target.addIntVal c.lit.numbers, info, setType, 0
-
-    intoDest d, info, Bool8Id, body
-
-  freeTemp c, b
-  freeTemp c, a
-
-proc genLtSet(c: var ProcCon; n: PNode; d: var Value) =
-  localError(c.m.graph.config, n.info, "`<` for sets not implemented")
-
-proc genBinarySet(c: var ProcCon; n: PNode; d: var Value; m: TMagic) =
-  let info = toLineInfo(c, n.info)
-  let a = c.genx(n[1])
-  let b = c.genx(n[2])
-  let t = typeToIr(c.m, n.typ)
-
-  let setType = typeToIr(c.m, n[1].typ)
-
-  if c.m.nirm.types[setType].kind == ArrayTy:
-    let elemType = bitsetBasetype(c.m.types, c.m.nirm.types, n[1].typ)
-    if isEmpty(d): d = getTemp(c, n)
-    #    "for ($1 = 0; $1 < $2; $1++):"
-    #    "  $3 = (($4[$1] & ~ $5[$1]) == 0)"
-    #    "  if (!$3) break;"
-    let (idx, backLabel, endLabel) = beginCountLoop(c, info, 0, int(getSize(c.config, n[1].typ)))
-    buildTyped c.code, info, Asgn, elemType:
-      buildTyped c.code, info, ArrayAt, setType:
-        copyTree c.code, d
-        c.code.addSymUse info, idx
-      buildTyped c.code, info, (if m == mPlusSet: BitOr else: BitAnd), elemType:
-        buildTyped c.code, info, ArrayAt, setType:
-          copyTree c.code, a
-          c.code.addSymUse info, idx
-        if m == mMinusSet:
-          buildTyped c.code, info, BitNot, elemType:
-            buildTyped c.code, info, ArrayAt, setType:
-              copyTree c.code, b
-              c.code.addSymUse info, idx
-        else:
-          buildTyped c.code, info, ArrayAt, setType:
-            copyTree c.code, b
-            c.code.addSymUse info, idx
-
-    endLoop(c, info, idx, backLabel, endLabel)
-  else:
-    # "(($1 & ~ $2)==0)"
-    template body(target) =
-      buildTyped target, info, (if m == mPlusSet: BitOr else: BitAnd), setType:
-        copyTree target, a
-        if m == mMinusSet:
-          buildTyped target, info, BitNot, setType:
-            copyTree target, b
-        else:
-          copyTree target, b
-
-    intoDest d, info, setType, body
-
-  freeTemp c, b
-  freeTemp c, a
-
-proc genInclExcl(c: var ProcCon; n: PNode; m: TMagic) =
-  let info = toLineInfo(c, n.info)
-  let a = c.genx(n[1])
-  let b = c.genx(n[2])
-
-  let setType = typeToIr(c.m, n[1].typ)
-
-  let t = bitsetBasetype(c.m.types, c.m.nirm.types, n[1].typ)
-  let mask =
-    case t
-    of UInt8Id: 7
-    of UInt16Id: 15
-    of UInt32Id: 31
-    else: 63
-
-  buildTyped c.code, info, Asgn, setType:
-    if c.m.nirm.types[setType].kind == ArrayTy:
-      if m == mIncl:
-        # $1[(NU)($2)>>3] |=(1U<<($2&7U))
-        buildTyped c.code, info, ArrayAt, setType:
-          copyTree c.code, a
-          buildTyped c.code, info, BitShr, t:
-            buildTyped c.code, info, Cast, c.m.nativeUIntId:
-              copyTree c.code, b
-            addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3
-        buildTyped c.code, info, BitOr, t:
-          buildTyped c.code, info, ArrayAt, setType:
-            copyTree c.code, a
-            buildTyped c.code, info, BitShr, t:
-              buildTyped c.code, info, Cast, c.m.nativeUIntId:
-                copyTree c.code, b
-              addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3
-          buildTyped c.code, info, BitShl, t:
-            c.code.addIntVal c.lit.numbers, info, t, 1
-            buildTyped c.code, info, BitAnd, t:
-              copyTree c.code, b
-              c.code.addIntVal c.lit.numbers, info, t, 7
-      else:
-        # $1[(NU)($2)>>3] &= ~(1U<<($2&7U))
-        buildTyped c.code, info, ArrayAt, setType:
-          copyTree c.code, a
-          buildTyped c.code, info, BitShr, t:
-            buildTyped c.code, info, Cast, c.m.nativeUIntId:
-              copyTree c.code, b
-            addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3
-        buildTyped c.code, info, BitAnd, t:
-          buildTyped c.code, info, ArrayAt, setType:
-            copyTree c.code, a
-            buildTyped c.code, info, BitShr, t:
-              buildTyped c.code, info, Cast, c.m.nativeUIntId:
-                copyTree c.code, b
-              addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3
-          buildTyped c.code, info, BitNot, t:
-            buildTyped c.code, info, BitShl, t:
-              c.code.addIntVal c.lit.numbers, info, t, 1
-              buildTyped c.code, info, BitAnd, t:
-                copyTree c.code, b
-                c.code.addIntVal c.lit.numbers, info, t, 7
-
-    else:
-      copyTree c.code, a
-      if m == mIncl:
-        # $1 |= ((NU8)1)<<(($2) & 7)
-        buildTyped c.code, info, BitOr, setType:
-          copyTree c.code, a
-          buildTyped c.code, info, BitShl, t:
-            c.code.addIntVal c.lit.numbers, info, t, 1
-            buildTyped c.code, info, BitAnd, t:
-              copyTree c.code, b
-              c.code.addIntVal c.lit.numbers, info, t, mask
-      else:
-        # $1 &= ~(((NU8)1) << (($2) & 7))
-        buildTyped c.code, info, BitAnd, setType:
-          copyTree c.code, a
-          buildTyped c.code, info, BitNot, t:
-            buildTyped c.code, info, BitShl, t:
-              c.code.addIntVal c.lit.numbers, info, t, 1
-              buildTyped c.code, info, BitAnd, t:
-                copyTree c.code, b
-                c.code.addIntVal c.lit.numbers, info, t, mask
-  freeTemp c, b
-  freeTemp c, a
-
-proc genSetConstrDyn(c: var ProcCon; n: PNode; d: var Value) =
-  # example: { a..b, c, d, e, f..g }
-  # we have to emit an expression of the form:
-  # nimZeroMem(tmp, sizeof(tmp)); inclRange(tmp, a, b); incl(tmp, c);
-  # incl(tmp, d); incl(tmp, e); inclRange(tmp, f, g);
-  let info = toLineInfo(c, n.info)
-  let setType = typeToIr(c.m, n.typ)
-  let size = int(getSize(c.config, n.typ))
-  let t = bitsetBasetype(c.m.types, c.m.nirm.types, n.typ)
-  let mask =
-    case t
-    of UInt8Id: 7
-    of UInt16Id: 15
-    of UInt32Id: 31
-    else: 63
-
-  if isEmpty(d): d = getTemp(c, n)
-  if c.m.nirm.types[setType].kind != ArrayTy:
-    buildTyped c.code, info, Asgn, setType:
-      copyTree c.code, d
-      c.code.addIntVal c.lit.numbers, info, t, 0
-
-    for it in n:
-      if it.kind == nkRange:
-        let a = genx(c, it[0])
-        let b = genx(c, it[1])
-        let (idx, backLabel, endLabel) = beginCountLoop(c, info, a, b)
-        buildTyped c.code, info, Asgn, setType:
-          copyTree c.code, d
-          buildTyped c.code, info, BitAnd, setType:
-            copyTree c.code, d
-            buildTyped c.code, info, BitNot, t:
-              buildTyped c.code, info, BitShl, t:
-                c.code.addIntVal c.lit.numbers, info, t, 1
-                buildTyped c.code, info, BitAnd, t:
-                  c.code.addSymUse info, idx
-                  c.code.addIntVal c.lit.numbers, info, t, mask
-
-        endLoop(c, info, idx, backLabel, endLabel)
-        freeTemp c, b
-        freeTemp c, a
-
-      else:
-        let a = genx(c, it)
-        buildTyped c.code, info, Asgn, setType:
-          copyTree c.code, d
-          buildTyped c.code, info, BitAnd, setType:
-            copyTree c.code, d
-            buildTyped c.code, info, BitNot, t:
-              buildTyped c.code, info, BitShl, t:
-                c.code.addIntVal c.lit.numbers, info, t, 1
-                buildTyped c.code, info, BitAnd, t:
-                  copyTree c.code, a
-                  c.code.addIntVal c.lit.numbers, info, t, mask
-        freeTemp c, a
-
-  else:
-    # init loop:
-    let (idx, backLabel, endLabel) = beginCountLoop(c, info, 0, size)
-    buildTyped c.code, info, Asgn, t:
-      copyTree c.code, d
-      c.code.addIntVal c.lit.numbers, info, t, 0
-    endLoop(c, info, idx, backLabel, endLabel)
-
-    # incl elements:
-    for it in n:
-      if it.kind == nkRange:
-        let a = genx(c, it[0])
-        let b = genx(c, it[1])
-        let (idx, backLabel, endLabel) = beginCountLoop(c, info, a, b)
-
-        buildTyped c.code, info, Asgn, t:
-          buildTyped c.code, info, ArrayAt, setType:
-            copyTree c.code, d
-            buildTyped c.code, info, BitShr, t:
-              buildTyped c.code, info, Cast, c.m.nativeUIntId:
-                c.code.addSymUse info, idx
-              addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3
-          buildTyped c.code, info, BitOr, t:
-            buildTyped c.code, info, ArrayAt, setType:
-              copyTree c.code, d
-              buildTyped c.code, info, BitShr, t:
-                buildTyped c.code, info, Cast, c.m.nativeUIntId:
-                  c.code.addSymUse info, idx
-                addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3
-            buildTyped c.code, info, BitShl, t:
-              c.code.addIntVal c.lit.numbers, info, t, 1
-              buildTyped c.code, info, BitAnd, t:
-                c.code.addSymUse info, idx
-                c.code.addIntVal c.lit.numbers, info, t, 7
-
-        endLoop(c, info, idx, backLabel, endLabel)
-        freeTemp c, b
-        freeTemp c, a
-
-      else:
-        let a = genx(c, it)
-        # $1[(NU)($2)>>3] |=(1U<<($2&7U))
-        buildTyped c.code, info, Asgn, t:
-          buildTyped c.code, info, ArrayAt, setType:
-            copyTree c.code, d
-            buildTyped c.code, info, BitShr, t:
-              buildTyped c.code, info, Cast, c.m.nativeUIntId:
-                copyTree c.code, a
-              addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3
-          buildTyped c.code, info, BitOr, t:
-            buildTyped c.code, info, ArrayAt, setType:
-              copyTree c.code, d
-              buildTyped c.code, info, BitShr, t:
-                buildTyped c.code, info, Cast, c.m.nativeUIntId:
-                  copyTree c.code, a
-                addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3
-            buildTyped c.code, info, BitShl, t:
-              c.code.addIntVal c.lit.numbers, info, t, 1
-              buildTyped c.code, info, BitAnd, t:
-                copyTree c.code, a
-                c.code.addIntVal c.lit.numbers, info, t, 7
-        freeTemp c, a
-
-proc genSetConstr(c: var ProcCon; n: PNode; d: var Value) =
-  if isDeepConstExpr(n):
-    let info = toLineInfo(c, n.info)
-    let setType = typeToIr(c.m, n.typ)
-    let size = int(getSize(c.config, n.typ))
-    let cs = toBitSet(c.config, n)
-
-    if c.m.nirm.types[setType].kind != ArrayTy:
-      template body(target) =
-        target.addIntVal c.lit.numbers, info, setType, cast[BiggestInt](bitSetToWord(cs, size))
-      intoDest d, info, setType, body
-    else:
-      let t = bitsetBasetype(c.m.types, c.m.nirm.types, n.typ)
-      template body(target) =
-        buildTyped target, info, ArrayConstr, setType:
-          for i in 0..high(cs):
-            target.addIntVal c.lit.numbers, info, t, int64 cs[i]
-      intoDest d, info, setType, body
-  else:
-    genSetConstrDyn c, n, d
-
-proc genStrConcat(c: var ProcCon; n: PNode; d: var Value) =
-  let info = toLineInfo(c, n.info)
-  #   <Nim code>
-  #   s = "Hello " & name & ", how do you feel?" & 'z'
-  #
-  #   <generated code>
-  #  {
-  #    string tmp0;
-  #    ...
-  #    tmp0 = rawNewString(6 + 17 + 1 + s2->len);
-  #    // we cannot generate s = rawNewString(...) here, because
-  #    // ``s`` may be used on the right side of the expression
-  #    appendString(tmp0, strlit_1);
-  #    appendString(tmp0, name);
-  #    appendString(tmp0, strlit_2);
-  #    appendChar(tmp0, 'z');
-  #    asgn(s, tmp0);
-  #  }
-  var args: seq[Value] = @[]
-  var argsRuntimeLen: seq[Value] = @[]
-
-  var precomputedLen = 0
-  for i in 1 ..< n.len:
-    let it = n[i]
-    args.add genx(c, it)
-    if skipTypes(it.typ, abstractVarRange).kind == tyChar:
-      inc precomputedLen
-    elif it.kind in {nkStrLit..nkTripleStrLit}:
-      inc precomputedLen, it.strVal.len
-    else:
-      argsRuntimeLen.add args[^1]
-
-  # generate length computation:
-  var tmpLen = allocTemp(c, c.m.nativeIntId)
-  buildTyped c.code, info, Asgn, c.m.nativeIntId:
-    c.code.addSymUse info, tmpLen
-    c.code.addIntVal c.lit.numbers, info, c.m.nativeIntId, precomputedLen
-  for a in mitems(argsRuntimeLen):
-    buildTyped c.code, info, Asgn, c.m.nativeIntId:
-      c.code.addSymUse info, tmpLen
-      buildTyped c.code, info, CheckedAdd, c.m.nativeIntId:
-        c.code.addLabel info, CheckedGoto, c.exitLabel
-        c.code.addSymUse info, tmpLen
-        buildTyped c.code, info, FieldAt, typeToIr(c.m, n.typ):
-          copyTree c.code, a
-          c.code.addImmediateVal info, 0 # (len, p)-pair so len is at index 0
-
-  var tmpStr = getTemp(c, n)
-  #    ^ because of aliasing, we always go through a temporary
-  let t = typeToIr(c.m, n.typ)
-  buildTyped c.code, info, Asgn, t:
-    copyTree c.code, tmpStr
-    buildTyped c.code, info, Call, t:
-      let codegenProc = magicsys.getCompilerProc(c.m.graph, "rawNewString")
-      #assert codegenProc != nil, $n & " " & (c.m.graph.config $ n.info)
-      let theProc = c.genx newSymNode(codegenProc, n.info)
-      copyTree c.code, theProc
-      c.code.addSymUse info, tmpLen
-  freeTemp c.sm, tmpLen
-
-  for i in 1 ..< n.len:
-    let it = n[i]
-    let isChar = skipTypes(it.typ, abstractVarRange).kind == tyChar
-    buildTyped c.code, info, Call, VoidId:
-      let codegenProc = magicsys.getCompilerProc(c.m.graph,
-        (if isChar: "appendChar" else: "appendString"))
-      #assert codegenProc != nil, $n & " " & (c.m.graph.config $ n.info)
-      let theProc = c.genx newSymNode(codegenProc, n.info)
-      copyTree c.code, theProc
-      buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.nirm.types, t):
-        copyTree c.code, tmpStr
-      copyTree c.code, args[i-1]
-    freeTemp c, args[i-1]
-
-  if isEmpty(d):
-    d = tmpStr
-  else:
-    # XXX Test that this does not cause memory leaks!
-    buildTyped c.code, info, Asgn, t:
-      copyTree c.code, d
-      copyTree c.code, tmpStr
-
-proc genDefault(c: var ProcCon; n: PNode; d: var Value) =
-  let m = expandDefault(n.typ, n.info)
-  gen c, m, d
-
-proc genWasMoved(c: var ProcCon; n: PNode) =
-  let n1 = n[1].skipAddr
-  # XXX We need a way to replicate this logic or better yet a better
-  # solution for injectdestructors.nim:
-  #if c.withinBlockLeaveActions > 0 and notYetAlive(n1):
-  var d = c.genx(n1)
-  assert not isEmpty(d)
-  let m = expandDefault(n1.typ, n1.info)
-  gen c, m, d
-
-proc genMove(c: var ProcCon; n: PNode; d: var Value) =
-  let info = toLineInfo(c, n.info)
-  let n1 = n[1].skipAddr
-  var a = c.genx(n1)
-  if n.len == 4:
-    # generated by liftdestructors:
-    let src = c.genx(n[2])
-    # if ($1.p == $2.p) goto lab1
-    let lab1 = newLabel(c.labelGen)
-
-    let n1t = typeToIr(c.m, n1.typ)
-    let payloadType = seqPayloadPtrType(c.m.types, c.m.nirm.types, n1.typ)[0]
-    buildTyped c.code, info, Select, Bool8Id:
-      buildTyped c.code, info, Eq, payloadType:
-        buildTyped c.code, info, FieldAt, n1t:
-          copyTree c.code, a
-          c.code.addImmediateVal info, 1 # (len, p)-pair
-        buildTyped c.code, info, FieldAt, n1t:
-          copyTree c.code, src
-          c.code.addImmediateVal info, 1 # (len, p)-pair
-
-      build c.code, info, SelectPair:
-        build c.code, info, SelectValue:
-          c.code.boolVal(c.lit.numbers, info, true)
-        c.code.gotoLabel info, Goto, lab1
-
-    gen(c, n[3])
-    c.patch n, lab1
-
-    buildTyped c.code, info, Asgn, typeToIr(c.m, n1.typ):
-      copyTree c.code, a
-      copyTree c.code, src
-
-  else:
-    if isEmpty(d): d = getTemp(c, n)
-    buildTyped c.code, info, Asgn, typeToIr(c.m, n1.typ):
-      copyTree c.code, d
-      copyTree c.code, a
-    var op = getAttachedOp(c.m.graph, n.typ, attachedWasMoved)
-    if op == nil or skipTypes(n1.typ, abstractVar+{tyStatic}).kind in {tyOpenArray, tyVarargs}:
-      let m = expandDefault(n1.typ, n1.info)
-      gen c, m, a
-    else:
-      var opB = c.genx(newSymNode(op))
-      buildTyped c.code, info, Call, typeToIr(c.m, n.typ):
-        copyTree c.code, opB
-        buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.nirm.types, typeToIr(c.m, n1.typ)):
-          copyTree c.code, a
-
-template fieldAt(x: Value; i: int; t: TypeId): Tree =
-  var result = default(Tree)
-  buildTyped result, info, FieldAt, t:
-    copyTree result, x
-    result.addImmediateVal info, i
-  result
-
-template eqNil(x: Tree; t: TypeId): Tree =
-  var result = default(Tree)
-  buildTyped result, info, Eq, t:
-    copyTree result, x
-    result.addNilVal info, t
-  result
-
-template eqZero(x: Tree): Tree =
-  var result = default(Tree)
-  buildTyped result, info, Eq, c.m.nativeIntId:
-    copyTree result, x
-    result.addIntVal c.lit.numbers, info, c.m.nativeIntId, 0
-  result
-
-template bitOp(x: Tree; opc: Opcode; y: int): Tree =
-  var result = default(Tree)
-  buildTyped result, info, opc, c.m.nativeIntId:
-    copyTree result, x
-    result.addIntVal c.lit.numbers, info, c.m.nativeIntId, y
-  result
-
-proc genDestroySeq(c: var ProcCon; n: PNode; t: PType) =
-  let info = toLineInfo(c, n.info)
-  let strLitFlag = 1 shl (c.m.graph.config.target.intSize * 8 - 2) # see also NIM_STRLIT_FLAG
-
-  let x = c.genx(n[1])
-  let baseType = t.elementType
-
-  let seqType = typeToIr(c.m, t)
-  let p = fieldAt(x, 0, seqType)
-
-  # if $1.p != nil and ($1.p.cap and NIM_STRLIT_FLAG) == 0:
-  #   alignedDealloc($1.p, NIM_ALIGNOF($2))
-  buildIfNot p.eqNil(seqType):
-    buildIf fieldAt(Value(p), 0, seqPayloadPtrType(c.m.types, c.m.nirm.types, t)[0]).bitOp(BitAnd, 0).eqZero():
-      let codegenProc = getCompilerProc(c.m.graph, "alignedDealloc")
-      buildTyped c.code, info, Call, VoidId:
-        let theProc = c.genx newSymNode(codegenProc, n.info)
-        copyTree c.code, theProc
-        copyTree c.code, p
-        c.code.addImmediateVal info, int(getAlign(c.config, baseType))
-
-  freeTemp c, x
-
-proc genDestroy(c: var ProcCon; n: PNode) =
-  let t = n[1].typ.skipTypes(abstractInst)
-  case t.kind
-  of tyString:
-    var unused = default(Value)
-    genUnaryCp(c, n, unused, "nimDestroyStrV1")
-  of tySequence:
-    genDestroySeq(c, n, t)
-  else: discard "nothing to do"
-
-type
-  IndexFor = enum
-    ForSeq, ForStr, ForOpenArray, ForArray
-
-proc genIndexCheck(c: var ProcCon; n: PNode; a: Value; kind: IndexFor; arr: PType): Value =
-  if optBoundsCheck in c.options:
-    let info = toLineInfo(c, n.info)
-    result = default(Value)
-    let idx = genx(c, n)
-    build result, info, CheckedIndex:
-      result.Tree.addLabel info, CheckedGoto, c.exitLabel
-      copyTree result.Tree, idx
-      case kind
-      of ForSeq, ForStr:
-        buildTyped result, info, FieldAt, typeToIr(c.m, arr):
-          copyTree result.Tree, a
-          result.addImmediateVal info, 0 # (len, p)-pair
-      of ForOpenArray:
-        buildTyped result, info, FieldAt, typeToIr(c.m, arr):
-          copyTree result.Tree, a
-          result.addImmediateVal info, 1 # (p, len)-pair
-      of ForArray:
-        let x = toInt64 lengthOrd(c.config, arr)
-        result.addIntVal c.lit.numbers, info, c.m.nativeIntId, x
-    freeTemp c, idx
-  else:
-    result = genx(c, n)
-
-proc addSliceFields(c: var ProcCon; target: var Tree; info: PackedLineInfo;
-                    x: Value; n: PNode; arrType: PType) =
-  let elemType = arrayPtrTypeOf(c.m.nirm.types, typeToIr(c.m, arrType.elementType))
-  case arrType.kind
-  of tyString, tySequence:
-    let checkKind = if arrType.kind == tyString: ForStr else: ForSeq
-    let pay = if checkKind == ForStr: c.m.strPayloadId
-              else: seqPayloadPtrType(c.m.types, c.m.nirm.types, arrType)
-
-    let y = genIndexCheck(c, n[2], x, checkKind, arrType)
-    let z = genIndexCheck(c, n[3], x, checkKind, arrType)
-
-    buildTyped target, info, ObjConstr, typeToIr(c.m, n.typ):
-      target.addImmediateVal info, 0
-      buildTyped target, info, AddrOf, elemType:
-        buildTyped target, info, DerefArrayAt, pay[1]:
-          buildTyped target, info, FieldAt, typeToIr(c.m, arrType):
-            copyTree target, x
-            target.addImmediateVal info, 1 # (len, p)-pair
-          copyTree target, y
-
-      # len:
-      target.addImmediateVal info, 1
-      buildTyped target, info, Add, c.m.nativeIntId:
-        buildTyped target, info, Sub, c.m.nativeIntId:
-          copyTree target, z
-          copyTree target, y
-        target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 1
-
-    freeTemp c, z
-    freeTemp c, y
-  of tyArray:
-    # XXX This evaluates the index check for `y` twice.
-    # This check is also still insufficient for non-zero based arrays.
-    let y = genIndexCheck(c, n[2], x, ForArray, arrType)
-    let z = genIndexCheck(c, n[3], x, ForArray, arrType)
-
-    buildTyped target, info, ObjConstr, typeToIr(c.m, n.typ):
-      target.addImmediateVal info, 0
-      buildTyped target, info, AddrOf, elemType:
-        buildTyped target, info, ArrayAt, typeToIr(c.m, arrType):
-          copyTree target, x
-          copyTree target, y
-
-      target.addImmediateVal info, 1
-      buildTyped target, info, Add, c.m.nativeIntId:
-        buildTyped target, info, Sub, c.m.nativeIntId:
-          copyTree target, z
-          copyTree target, y
-        target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 1
-
-    freeTemp c, z
-    freeTemp c, y
-  of tyOpenArray:
-    # XXX This evaluates the index check for `y` twice.
-    let y = genIndexCheck(c, n[2], x, ForOpenArray, arrType)
-    let z = genIndexCheck(c, n[3], x, ForOpenArray, arrType)
-    let pay = openArrayPayloadType(c.m.types, c.m.nirm.types, arrType)
-
-    buildTyped target, info, ObjConstr, typeToIr(c.m, n.typ):
-      target.addImmediateVal info, 0
-      buildTyped target, info, AddrOf, elemType:
-        buildTyped target, info, DerefArrayAt, pay:
-          buildTyped target, info, FieldAt, typeToIr(c.m, arrType):
-            copyTree target, x
-            target.addImmediateVal info, 0 # (p, len)-pair
-          copyTree target, y
-
-      target.addImmediateVal info, 1
-      buildTyped target, info, Add, c.m.nativeIntId:
-        buildTyped target, info, Sub, c.m.nativeIntId:
-          copyTree target, z
-          copyTree target, y
-        target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 1
-
-    freeTemp c, z
-    freeTemp c, y
-  else:
-    raiseAssert "addSliceFields: " & typeToString(arrType)
-
-proc genSlice(c: var ProcCon; n: PNode; d: var Value) =
-  let info = toLineInfo(c, n.info)
-
-  let x = c.genx(n[1])
-
-  let arrType = n[1].typ.skipTypes(abstractVar)
-
-  template body(target) =
-    c.addSliceFields target, info, x, n, arrType
-
-  valueIntoDest c, info, d, arrType, body
-  freeTemp c, x
-
-proc genMagic(c: var ProcCon; n: PNode; d: var Value; m: TMagic) =
-  case m
-  of mAnd: c.genAndOr(n, opcFJmp, d)
-  of mOr: c.genAndOr(n, opcTJmp, d)
-  of mPred, mSubI: c.genBinaryOp(n, d, if optOverflowCheck in c.options: CheckedSub else: Sub)
-  of mSucc, mAddI: c.genBinaryOp(n, d, if optOverflowCheck in c.options: CheckedAdd else: Add)
-  of mInc:
-    unused(c, n, d)
-    c.genIncDec(n, if optOverflowCheck in c.options: CheckedAdd else: Add)
-  of mDec:
-    unused(c, n, d)
-    c.genIncDec(n, if optOverflowCheck in c.options: CheckedSub else: Sub)
-  of mOrd, mChr, mUnown:
-    c.gen(n[1], d)
-  of generatedMagics:
-    genCall(c, n, d)
-  of mNew, mNewFinalize:
-    unused(c, n, d)
-    c.genNew(n, needsInit = true)
-  of mNewSeq:
-    unused(c, n, d)
-    c.genNewSeq(n)
-  of mNewSeqOfCap: c.genNewSeqOfCap(n, d)
-  of mNewString, mNewStringOfCap, mExit: c.genCall(n, d)
-  of mLengthOpenArray, mLengthArray, mLengthSeq, mLengthStr:
-    genArrayLen(c, n, d)
-  of mMulI: genBinaryOp(c, n, d, if optOverflowCheck in c.options: CheckedMul else: Mul)
-  of mDivI: genBinaryOp(c, n, d, if optOverflowCheck in c.options: CheckedDiv else: Div)
-  of mModI: genBinaryOp(c, n, d, if optOverflowCheck in c.options: CheckedMod else: Mod)
-  of mAddF64: genBinaryOp(c, n, d, Add)
-  of mSubF64: genBinaryOp(c, n, d, Sub)
-  of mMulF64: genBinaryOp(c, n, d, Mul)
-  of mDivF64: genBinaryOp(c, n, d, Div)
-  of mShrI: genBinaryOp(c, n, d, BitShr)
-  of mShlI: genBinaryOp(c, n, d, BitShl)
-  of mAshrI: genBinaryOp(c, n, d, BitShr)
-  of mBitandI: genBinaryOp(c, n, d, BitAnd)
-  of mBitorI: genBinaryOp(c, n, d, BitOr)
-  of mBitxorI: genBinaryOp(c, n, d, BitXor)
-  of mAddU: genBinaryOp(c, n, d, Add)
-  of mSubU: genBinaryOp(c, n, d, Sub)
-  of mMulU: genBinaryOp(c, n, d, Mul)
-  of mDivU: genBinaryOp(c, n, d, Div)
-  of mModU: genBinaryOp(c, n, d, Mod)
-  of mEqI, mEqB, mEqEnum, mEqCh:
-    genCmpOp(c, n, d, Eq)
-  of mLeI, mLeEnum, mLeCh, mLeB:
-    genCmpOp(c, n, d, Le)
-  of mLtI, mLtEnum, mLtCh, mLtB:
-    genCmpOp(c, n, d, Lt)
-  of mEqF64: genCmpOp(c, n, d, Eq)
-  of mLeF64: genCmpOp(c, n, d, Le)
-  of mLtF64: genCmpOp(c, n, d, Lt)
-  of mLePtr, mLeU: genCmpOp(c, n, d, Le)
-  of mLtPtr, mLtU: genCmpOp(c, n, d, Lt)
-  of mEqProc, mEqRef:
-    genCmpOp(c, n, d, Eq)
-  of mXor: genBinaryOp(c, n, d, BitXor)
-  of mNot: genUnaryOp(c, n, d, BoolNot)
-  of mUnaryMinusI, mUnaryMinusI64:
-    genUnaryMinus(c, n, d)
-    #genNarrow(c, n, d)
-  of mUnaryMinusF64: genUnaryMinus(c, n, d)
-  of mUnaryPlusI, mUnaryPlusF64: gen(c, n[1], d)
-  of mBitnotI:
-    genUnaryOp(c, n, d, BitNot)
-    when false:
-      # XXX genNarrowU modified, do not narrow signed types
-      let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
-      let size = getSize(c.config, t)
-      if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8):
-        c.gABC(n, opcNarrowU, d, TRegister(size*8))
-  of mStrToStr, mEnsureMove: c.gen n[1], d
-  of mBoolToStr: genUnaryCp(c, n, d, "nimBoolToStr")
-  of mCharToStr: genUnaryCp(c, n, d, "nimCharToStr")
-  of mCStrToStr: genUnaryCp(c, n, d, "cstrToNimstr")
-  of mEnumToStr: genEnumToStr(c, n, d)
-
-  of mEqStr: genBinaryCp(c, n, d, "eqStrings")
-  of mEqCString: genCall(c, n, d)
-  of mLeStr: genBinaryCp(c, n, d, "leStrings")
-  of mLtStr: genBinaryCp(c, n, d, "ltStrings")
-
-  of mSetLengthStr:
-    unused(c, n, d)
-    let nb = copyTree(n)
-    nb[1] = makeAddr(nb[1], c.m.idgen)
-    genBinaryCp(c, nb, d, "setLengthStrV2")
-
-  of mSetLengthSeq:
-    unused(c, n, d)
-    let nb = copyTree(n)
-    nb[1] = makeAddr(nb[1], c.m.idgen)
-    genCall(c, nb, d)
-
-  of mSwap:
-    unused(c, n, d)
-    c.gen(lowerSwap(c.m.graph, n, c.m.idgen,
-      if c.prc == nil: c.m.module else: c.prc), d)
-  of mParseBiggestFloat:
-    genCall c, n, d
-  of mHigh:
-    c.genHigh n, d
-
-  of mEcho:
-    unused(c, n, d)
-    genUnaryCp c, n, d, "echoBinSafe"
-
-  of mAppendStrCh:
-    unused(c, n, d)
-    let nb = copyTree(n)
-    nb[1] = makeAddr(nb[1], c.m.idgen)
-    genBinaryCp(c, nb, d, "nimAddCharV1")
-  of mMinI, mMaxI, mAbsI, mDotDot:
-    c.genCall(n, d)
-  of mSizeOf:
-    localError(c.config, n.info, sizeOfLikeMsg("sizeof"))
-  of mAlignOf:
-    localError(c.config, n.info, sizeOfLikeMsg("alignof"))
-  of mOffsetOf:
-    localError(c.config, n.info, sizeOfLikeMsg("offsetof"))
-  of mRunnableExamples:
-    discard "just ignore any call to runnableExamples"
-  of mOf: genOf(c, n, d)
-  of mAppendStrStr:
-    unused(c, n, d)
-    let nb = copyTree(n)
-    nb[1] = makeAddr(nb[1], c.m.idgen)
-    genBinaryCp(c, nb, d, "nimAddStrV1")
-  of mAppendSeqElem:
-    unused(c, n, d)
-    let nb = copyTree(n)
-    nb[1] = makeAddr(nb[1], c.m.idgen)
-    genCall(c, nb, d)
-  of mIsNil: genIsNil(c, n, d)
-  of mInSet: genInSet(c, n, d)
-  of mCard: genCard(c, n, d)
-  of mEqSet: genEqSet(c, n, d)
-  of mLeSet: genLeSet(c, n, d)
-  of mLtSet: genLtSet(c, n, d)
-  of mMulSet: genBinarySet(c, n, d, m)
-  of mPlusSet: genBinarySet(c, n, d, m)
-  of mMinusSet: genBinarySet(c, n, d, m)
-  of mIncl, mExcl:
-    unused(c, n, d)
-    genInclExcl(c, n, m)
-  of mConStrStr: genStrConcat(c, n, d)
-  of mDefault, mZeroDefault:
-    genDefault c, n, d
-  of mMove: genMove(c, n, d)
-  of mWasMoved:
-    unused(c, n, d)
-    genWasMoved(c, n)
-  of mDestroy: genDestroy(c, n)
-  #of mAccessEnv: unaryExpr(d, n, d, "$1.ClE_0")
-  #of mAccessTypeField: genAccessTypeField(c, n, d)
-  of mSlice: genSlice(c, n, d)
-  of mTrace: discard "no code to generate"
-  else:
-    # mGCref, mGCunref: unused by ORC
-    globalError(c.config, n.info, "cannot generate code for: " & $m)
-
-proc canElimAddr(n: PNode; idgen: IdGenerator): PNode =
-  result = nil
-  case n[0].kind
-  of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
-    var m = n[0][0]
-    if m.kind in {nkDerefExpr, nkHiddenDeref}:
-      # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
-      result = copyNode(n[0])
-      result.add m[0]
-      if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
-        result.typ = n.typ
-      elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
-        result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind, idgen)
-  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
-    var m = n[0][1]
-    if m.kind in {nkDerefExpr, nkHiddenDeref}:
-      # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
-      result = copyNode(n[0])
-      result.add n[0][0]
-      result.add m[0]
-      if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
-        result.typ = n.typ
-      elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
-        result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind, idgen)
-  else:
-    if n[0].kind in {nkDerefExpr, nkHiddenDeref}:
-      # addr ( deref ( x )) --> x
-      result = n[0][0]
-
-proc genAddr(c: var ProcCon; n: PNode; d: var Value, flags: GenFlags) =
-  if (let m = canElimAddr(n, c.m.idgen); m != nil):
-    gen(c, m, d, flags)
-    return
-
-  let info = toLineInfo(c, n.info)
-  let tmp = c.genx(n[0], flags)
-  template body(target) =
-    buildTyped target, info, AddrOf, typeToIr(c.m, n.typ):
-      copyTree target, tmp
-
-  valueIntoDest c, info, d, n.typ, body
-  freeTemp c, tmp
-
-proc genDeref(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
-  let info = toLineInfo(c, n.info)
-  let tmp = c.genx(n[0], flags)
-  template body(target) =
-    buildTyped target, info, Load, typeToIr(c.m, n.typ):
-      copyTree target, tmp
-
-  valueIntoDest c, info, d, n.typ, body
-  freeTemp c, tmp
-
-proc addAddrOfFirstElem(c: var ProcCon; target: var Tree; info: PackedLineInfo; tmp: Value; typ: PType) =
-  let arrType = typ.skipTypes(abstractVar)
-  let elemType = arrayPtrTypeOf(c.m.nirm.types, typeToIr(c.m, arrType.elementType))
-  case arrType.kind
-  of tyString:
-    let t = typeToIr(c.m, typ)
-    target.addImmediateVal info, 0
-    buildTyped target, info, AddrOf, elemType:
-      buildTyped target, info, DerefArrayAt, c.m.strPayloadId[1]:
-        buildTyped target, info, FieldAt, typeToIr(c.m, arrType):
-          copyTree target, tmp
-          target.addImmediateVal info, 1 # (len, p)-pair
-        target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 0
-    # len:
-    target.addImmediateVal info, 1
-    buildTyped target, info, FieldAt, typeToIr(c.m, arrType):
-      copyTree target, tmp
-      target.addImmediateVal info, 0 # (len, p)-pair so len is at index 0
-
-  of tySequence:
-    let t = typeToIr(c.m, typ)
-    target.addImmediateVal info, 0
-    buildTyped target, info, AddrOf, elemType:
-      buildTyped target, info, DerefArrayAt, seqPayloadPtrType(c.m.types, c.m.nirm.types, typ)[1]:
-        buildTyped target, info, FieldAt, typeToIr(c.m, arrType):
-          copyTree target, tmp
-          target.addImmediateVal info, 1 # (len, p)-pair
-        target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 0
-    # len:
-    target.addImmediateVal info, 1
-    buildTyped target, info, FieldAt, typeToIr(c.m, arrType):
-      copyTree target, tmp
-      target.addImmediateVal info, 0 # (len, p)-pair so len is at index 0
-
-  of tyArray:
-    let t = typeToIr(c.m, arrType)
-    target.addImmediateVal info, 0
-    buildTyped target, info, AddrOf, elemType:
-      buildTyped target, info, ArrayAt, t:
-        copyTree target, tmp
-        target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 0
-    target.addImmediateVal info, 1
-    target.addIntVal(c.lit.numbers, info, c.m.nativeIntId, toInt lengthOrd(c.config, arrType))
-  else:
-    raiseAssert "addAddrOfFirstElem: " & typeToString(typ)
-
-proc genToOpenArrayConv(c: var ProcCon; arg: PNode; d: var Value; flags: GenFlags; destType: PType) =
-  let info = toLineInfo(c, arg.info)
-  let tmp = c.genx(arg, flags)
-  let arrType = destType.skipTypes(abstractVar)
-  template body(target) =
-    buildTyped target, info, ObjConstr, typeToIr(c.m, arrType):
-      c.addAddrOfFirstElem target, info, tmp, arg.typ
-
-  valueIntoDest c, info, d, arrType, body
-  freeTemp c, tmp
-
-proc genConv(c: var ProcCon; n, arg: PNode; d: var Value; flags: GenFlags; opc: Opcode) =
-  let targetType = n.typ.skipTypes({tyDistinct})
-  let argType = arg.typ.skipTypes({tyDistinct})
-
-  if sameBackendType(targetType, argType) or (
-      argType.kind == tyProc and targetType.kind == argType.kind):
-    # don't do anything for lambda lifting conversions:
-    gen c, arg, d
-    return
-
-  if opc != Cast and targetType.skipTypes({tyVar, tyLent}).kind in {tyOpenArray, tyVarargs} and
-      argType.skipTypes({tyVar, tyLent}).kind notin {tyOpenArray, tyVarargs}:
-    genToOpenArrayConv c, arg, d, flags, n.typ
-    return
-
-  let info = toLineInfo(c, n.info)
-  let tmp = c.genx(arg, flags)
-  template body(target) =
-    buildTyped target, info, opc, typeToIr(c.m, n.typ):
-      if opc == CheckedObjConv:
-        target.addLabel info, CheckedGoto, c.exitLabel
-      copyTree target, tmp
-
-  valueIntoDest c, info, d, n.typ, body
-  freeTemp c, tmp
-
-proc genObjOrTupleConstr(c: var ProcCon; n: PNode; d: var Value; t: PType) =
-  # XXX x = (x.old, 22)  produces wrong code ... stupid self assignments
-  let info = toLineInfo(c, n.info)
-  template body(target) =
-    buildTyped target, info, ObjConstr, typeToIr(c.m, t):
-      for i in ord(n.kind == nkObjConstr)..<n.len:
-        let it = n[i]
-        if it.kind == nkExprColonExpr:
-          genField(c, it[0], Value target)
-          let tmp = c.genx(it[1])
-          copyTree target, tmp
-          c.freeTemp(tmp)
-        else:
-          let tmp = c.genx(it)
-          target.addImmediateVal info, i
-          copyTree target, tmp
-          c.freeTemp(tmp)
-
-      if isException(t):
-        target.addImmediateVal info, 1 # "name" field is at position after the "parent". See system.nim
-        target.addStrVal c.lit.strings, info, t.skipTypes(abstractInst).sym.name.s
-
-  constrIntoDest c, info, d, t, body
-
-proc genRefObjConstr(c: var ProcCon; n: PNode; d: var Value) =
-  if isEmpty(d): d = getTemp(c, n)
-  let info = toLineInfo(c, n.info)
-  let refType = n.typ.skipTypes(abstractInstOwned)
-  let objType = refType.elementType
-
-  rawGenNew(c, d, refType, n.info, needsInit = nfAllFieldsSet notin n.flags)
-  var deref = default(Value)
-  deref.buildTyped info, Load, typeToIr(c.m, objType):
-    deref.Tree.copyTree d
-  genObjOrTupleConstr c, n, deref, objType
-
-proc genSeqConstr(c: var ProcCon; n: PNode; d: var Value) =
-  if isEmpty(d): d = getTemp(c, n)
-
-  let info = toLineInfo(c, n.info)
-  let seqtype = skipTypes(n.typ, abstractVarRange)
-  let baseType = seqtype.elementType
-
-  var b = default(Value)
-  b.addIntVal c.lit.numbers, info, c.m.nativeIntId, n.len
-
-  genNewSeqPayload(c, info, d, b, seqtype)
-
-  for i in 0..<n.len:
-    var dd = default(Value)
-    buildTyped dd, info, DerefArrayAt, seqPayloadPtrType(c.m.types, c.m.nirm.types, seqtype)[1]:
-      buildTyped dd, info, FieldAt, typeToIr(c.m, seqtype):
-        copyTree Tree(dd), d
-        dd.addImmediateVal info, 1 # (len, p)-pair
-      dd.addIntVal c.lit.numbers, info, c.m.nativeIntId, i
-    gen(c, n[i], dd)
-
-  freeTemp c, d
-
-proc genArrayConstr(c: var ProcCon; n: PNode, d: var Value) =
-  let seqType = n.typ.skipTypes(abstractVar-{tyTypeDesc})
-  if seqType.kind == tySequence:
-    genSeqConstr(c, n, d)
-    return
-
-  let info = toLineInfo(c, n.info)
-  template body(target) =
-    buildTyped target, info, ArrayConstr, typeToIr(c.m, n.typ):
-      for i in 0..<n.len:
-        let tmp = c.genx(n[i])
-        copyTree target, tmp
-        c.freeTemp(tmp)
-
-  constrIntoDest c, info, d, n.typ, body
-
-proc genAsgn2(c: var ProcCon; a, b: PNode) =
-  assert a != nil
-  assert b != nil
-  var d = c.genx(a)
-  c.gen b, d
-
-proc irModule(c: var ProcCon; owner: PSym): string =
-  #if owner == c.m.module: "" else:
-  customPath(toFullPath(c.config, owner.info))
-
-proc fromForeignModule(c: ProcCon; s: PSym): bool {.inline.} =
-  result = ast.originatingModule(s) != c.m.module and not c.m.noModularity
-
-proc genForeignVar(c: var ProcCon; s: PSym) =
-  var opc: Opcode
-  if s.kind == skConst:
-    opc = SummonConst
-  elif sfThread in s.flags:
-    opc = SummonThreadLocal
-  else:
-    assert sfGlobal in s.flags
-    opc = SummonGlobal
-  let t = typeToIr(c.m, s.typ)
-  let info = toLineInfo(c, s.info)
-  build c.code, info, ForeignDecl:
-    buildTyped c.code, info, opc, t:
-      build c.code, info, ModuleSymUse:
-        c.code.addStrVal c.lit.strings, info, irModule(c, ast.originatingModule(s))
-        c.code.addImmediateVal info, s.itemId.item.int
-
-proc genVarSection(c: var ProcCon; n: PNode) =
-  for a in n:
-    if a.kind == nkCommentStmt: continue
-    #assert(a[0].kind == nkSym) can happen for transformed vars
-    if a.kind == nkVarTuple:
-      c.gen(lowerTupleUnpacking(c.m.graph, a, c.m.idgen, c.prc))
-    else:
-      var vn = a[0]
-      if vn.kind == nkPragmaExpr: vn = vn[0]
-      if vn.kind == nkSym:
-        let s = vn.sym
-        if s.kind == skConst:
-          if dontInlineConstant(n, s.astdef):
-            let symId = toSymId(c, s)
-            c.m.nirm.symnames[symId] = c.lit.strings.getOrIncl(s.name.s)
-            let val = c.genx(s.astdef)
-            let info = toLineInfo(c, a.info)
-            buildTyped c.code, info, SummonConst, typeToIr(c.m, s.typ):
-              c.code.addSymDef info, symId
-              c.code.copyTree val
-            freeTemp c, val
-        else:
-          var opc: Opcode
-          if sfThread in s.flags:
-            opc = SummonThreadLocal
-          elif sfGlobal in s.flags:
-            opc = SummonGlobal
-          else:
-            opc = Summon
-          #assert t.int >= 0, typeToString(s.typ) & (c.config $ n.info)
-          let symId = toSymId(c, s)
-          c.code.addSummon toLineInfo(c, a.info), symId, typeToIr(c.m, s.typ), opc
-          c.m.nirm.symnames[symId] = c.lit.strings.getOrIncl(s.name.s)
-          if a[2].kind != nkEmpty:
-            genAsgn2(c, vn, a[2])
-      else:
-        if a[2].kind == nkEmpty:
-          genAsgn2(c, vn, expandDefault(vn.typ, vn.info))
-        else:
-          genAsgn2(c, vn, a[2])
-
-proc genAsgn(c: var ProcCon; n: PNode) =
-  var d = c.genx(n[0])
-  c.gen n[1], d
-
-proc convStrToCStr(c: var ProcCon; n: PNode; d: var Value) =
-  genUnaryCp(c, n, d, "nimToCStringConv", argAt = 0)
-
-proc convCStrToStr(c: var ProcCon; n: PNode; d: var Value) =
-  genUnaryCp(c, n, d, "cstrToNimstr", argAt = 0)
-
-proc genRdVar(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
-  let info = toLineInfo(c, n.info)
-  let s = n.sym
-  if fromForeignModule(c, s):
-    if s.kind in {skVar, skConst, skLet} and not c.m.pendingVarsAsSet.containsOrIncl(s.itemId):
-      c.m.pendingVars.add s
-
-    template body(target) =
-      build target, info, ModuleSymUse:
-        target.addStrVal c.lit.strings, info, irModule(c, ast.originatingModule(s))
-        target.addImmediateVal info, s.itemId.item.int
-
-    valueIntoDest c, info, d, s.typ, body
-  else:
-    template body(target) =
-      target.addSymUse info, toSymId(c, s)
-    valueIntoDest c, info, d, s.typ, body
-
-proc genSym(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) =
-  let s = n.sym
-  case s.kind
-  of skConst:
-    if dontInlineConstant(n, s.astdef):
-      genRdVar(c, n, d, flags)
-    else:
-      gen(c, s.astdef, d, flags)
-  of skVar, skForVar, skTemp, skLet, skResult, skParam:
-    genRdVar(c, n, d, flags)
-  of skProc, skFunc, skConverter, skMethod, skIterator:
-    if not c.m.noModularity:
-      # anon and generic procs have no AST so we need to remember not to forget
-      # to emit these:
-      if not c.m.processedProcs.contains(s.itemId):
-        if not c.m.pendingProcsAsSet.containsOrIncl(s.itemId):
-          c.m.pendingProcs.add s
-    genRdVar(c, n, d, flags)
-  of skEnumField:
-    let info = toLineInfo(c, n.info)
-    template body(target) =
-      target.addIntVal c.lit.numbers, info, typeToIr(c.m, n.typ), s.position
-    valueIntoDest c, info, d, n.typ, body
-  else:
-    localError(c.config, n.info, "cannot generate code for: " & s.name.s)
-
-proc genNumericLit(c: var ProcCon; n: PNode; d: var Value; bits: int64) =
-  let info = toLineInfo(c, n.info)
-  template body(target) =
-    target.addIntVal c.lit.numbers, info, typeToIr(c.m, n.typ), bits
-  valueIntoDest c, info, d, n.typ, body
-
-proc genStringLit(c: var ProcCon; n: PNode; d: var Value) =
-  let info = toLineInfo(c, n.info)
-  template body(target) =
-    target.addStrVal c.lit.strings, info, n.strVal
-  valueIntoDest c, info, d, n.typ, body
-
-proc genNilLit(c: var ProcCon; n: PNode; d: var Value) =
-  let info = toLineInfo(c, n.info)
-  template body(target) =
-    target.addNilVal info, typeToIr(c.m, n.typ)
-  valueIntoDest c, info, d, n.typ, body
-
-proc genRangeCheck(c: var ProcCon; n: PNode; d: var Value) =
-  if optRangeCheck in c.options:
-    let info = toLineInfo(c, n.info)
-    let tmp = c.genx n[0]
-    let a = c.genx n[1]
-    let b = c.genx n[2]
-    template body(target) =
-      buildTyped target, info, CheckedRange, typeToIr(c.m, n.typ):
-        target.addLabel info, CheckedGoto, c.exitLabel
-        copyTree target, tmp
-        copyTree target, a
-        copyTree target, b
-    valueIntoDest c, info, d, n.typ, body
-    freeTemp c, tmp
-    freeTemp c, a
-    freeTemp c, b
-  else:
-    gen c, n[0], d
-
-proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
-  let arrayType = n[0].typ.skipTypes(abstractVarRange-{tyTypeDesc})
-  let arrayKind = arrayType.kind
-  let info = toLineInfo(c, n.info)
-  case arrayKind
-  of tyString:
-    let a = genx(c, n[0], flags)
-    let b = genIndexCheck(c, n[1], a, ForStr, arrayType)
-    let t = typeToIr(c.m, n.typ)
-    template body(target) =
-      buildTyped target, info, DerefArrayAt, c.m.strPayloadId[1]:
-        buildTyped target, info, FieldAt, typeToIr(c.m, arrayType):
-          copyTree target, a
-          target.addImmediateVal info, 1 # (len, p)-pair
-        copyTree target, b
-    intoDest d, info, t, body
-    freeTemp c, b
-    freeTemp c, a
-
-  of tyCstring, tyPtr, tyUncheckedArray:
-    let a = genx(c, n[0], flags)
-    let b = genx(c, n[1])
-    template body(target) =
-      buildTyped target, info, DerefArrayAt, typeToIr(c.m, arrayType):
-        copyTree target, a
-        copyTree target, b
-    valueIntoDest c, info, d, n.typ, body
-
-    freeTemp c, b
-    freeTemp c, a
-  of tyTuple:
-    let a = genx(c, n[0], flags)
-    let b = int n[1].intVal
-    template body(target) =
-      buildTyped target, info, FieldAt, typeToIr(c.m, arrayType):
-        copyTree target, a
-        target.addImmediateVal info, b
-    valueIntoDest c, info, d, n.typ, body
-
-    freeTemp c, a
-  of tyOpenArray, tyVarargs:
-    let a = genx(c, n[0], flags)
-    let b = genIndexCheck(c, n[1], a, ForOpenArray, arrayType)
-    let t = typeToIr(c.m, n.typ)
-    template body(target) =
-      buildTyped target, info, DerefArrayAt, openArrayPayloadType(c.m.types, c.m.nirm.types, n[0].typ):
-        buildTyped target, info, FieldAt, typeToIr(c.m, arrayType):
-          copyTree target, a
-          target.addImmediateVal info, 0 # (p, len)-pair
-        copyTree target, b
-    intoDest d, info, t, body
-
-    freeTemp c, b
-    freeTemp c, a
-  of tyArray:
-    let a = genx(c, n[0], flags)
-    var b = default(Value)
-    genIndex(c, n[1], n[0].typ, b)
-
-    template body(target) =
-      buildTyped target, info, ArrayAt, typeToIr(c.m, arrayType):
-        copyTree target, a
-        copyTree target, b
-    valueIntoDest c, info, d, n.typ, body
-    freeTemp c, b
-    freeTemp c, a
-  of tySequence:
-    let a = genx(c, n[0], flags)
-    let b = genIndexCheck(c, n[1], a, ForSeq, arrayType)
-    let t = typeToIr(c.m, n.typ)
-    template body(target) =
-      buildTyped target, info, DerefArrayAt, seqPayloadPtrType(c.m.types, c.m.nirm.types, n[0].typ)[1]:
-        buildTyped target, info, FieldAt, t:
-          copyTree target, a
-          target.addImmediateVal info, 1 # (len, p)-pair
-        copyTree target, b
-    intoDest d, info, t, body
-    freeTemp c, b
-    freeTemp c, a
-  else:
-    localError c.config, n.info, "invalid type for nkBracketExpr: " & $arrayKind
-
-proc genObjAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
-  let info = toLineInfo(c, n.info)
-
-  var n0 = n[0]
-  var opc = FieldAt
-  if n0.kind == nkDotExpr:
-    # obj[].a --> DerefFieldAt instead of FieldAt:
-    n0 = n[0]
-    opc = DerefFieldAt
-
-  let a = genx(c, n0, flags)
-
-  template body(target) =
-    buildTyped target, info, opc, typeToIr(c.m, n0.typ):
-      copyTree target, a
-      genField c, n[1], Value(target)
-
-  valueIntoDest c, info, d, n.typ, body
-  freeTemp c, a
-
-proc genParams(c: var ProcCon; params: PNode; prc: PSym): PSym =
-  result = nil
-  if params.len > 0 and resultPos < prc.ast.len:
-    let resNode = prc.ast[resultPos]
-    result = resNode.sym # get result symbol
-    c.code.addSummon toLineInfo(c, result.info), toSymId(c, result),
-      typeToIr(c.m, result.typ), SummonResult
-  elif prc.typ.len > 0 and not isEmptyType(prc.typ.returnType) and not isCompileTimeOnly(prc.typ.returnType):
-    # happens for procs without bodies:
-    let t = typeToIr(c.m, prc.typ.returnType)
-    let tmp = allocTemp(c, t)
-    c.code.addSummon toLineInfo(c, params.info), tmp, t, SummonResult
-
-  for i in 1..<params.len:
-    let s = params[i].sym
-    if not isCompileTimeOnly(s.typ):
-      let t = typeToIr(c.m, s.typ)
-      assert t.int != -1, typeToString(s.typ)
-      let symId = toSymId(c, s)
-      c.code.addSummon toLineInfo(c, params[i].info), symId, t, SummonParam
-      c.m.nirm.symnames[symId] = c.lit.strings.getOrIncl(s.name.s)
-
-proc addCallConv(c: var ProcCon; info: PackedLineInfo; callConv: TCallingConvention) =
-  template ann(s: untyped) = c.code.addPragmaId info, s
-  case callConv
-  of ccNimCall, ccFastCall, ccClosure: ann FastCall
-  of ccStdCall: ann StdCall
-  of ccCDecl: ann CDeclCall
-  of ccSafeCall: ann SafeCall
-  of ccSysCall: ann SysCall
-  of ccInline: ann InlineCall
-  of ccNoInline: ann NoinlineCall
-  of ccThisCall: ann ThisCall
-  of ccNoConvention, ccMember: ann NoCall
-
-proc genProc(cOuter: var ProcCon; prc: PSym) =
-  if prc.magic notin generatedMagics: return
-  if cOuter.m.processedProcs.containsOrIncl(prc.itemId):
-    return
-  #assert cOuter.m.inProc == 0, " in nested proc! " & prc.name.s
-  if cOuter.m.inProc > 0:
-    if not cOuter.m.pendingProcsAsSet.containsOrIncl(prc.itemId):
-      cOuter.m.pendingProcs.add prc
-    return
-  inc cOuter.m.inProc
-
-  var c = initProcCon(cOuter.m, prc, cOuter.m.graph.config)
-  let body =
-    if not fromForeignModule(c, prc):
-      transformBody(c.m.graph, c.m.idgen, prc, {useCache, keepOpenArrayConversions})
-    else:
-      nil
-
-  let info = toLineInfo(c, prc.info)
-  build c.code, info, (if body != nil: ProcDecl else: ForeignProcDecl):
-    if body != nil:
-      let symId = toSymId(c, prc)
-      addSymDef c.code, info, symId
-      c.m.nirm.symnames[symId] = c.lit.strings.getOrIncl(prc.name.s)
-    else:
-      build c.code, info, ModuleSymUse:
-        c.code.addStrVal c.lit.strings, info, irModule(c, ast.originatingModule(prc))
-        c.code.addImmediateVal info, prc.itemId.item.int
-    addCallConv c, info, prc.typ.callConv
-    if sfCompilerProc in prc.flags:
-      build c.code, info, PragmaPair:
-        c.code.addPragmaId info, CoreName
-        c.code.addStrVal c.lit.strings, info, prc.name.s
-    if {sfImportc, sfExportc} * prc.flags != {}:
-      build c.code, info, PragmaPair:
-        c.code.addPragmaId info, ExternName
-        c.code.addStrVal c.lit.strings, info, prc.loc.r
-      if sfImportc in prc.flags:
-        if lfHeader in prc. loc.flags:
-          assert(prc. annex != nil)
-          let str = getStr(prc. annex.path)
-          build c.code, info, PragmaPair:
-            c.code.addPragmaId info, HeaderImport
-            c.code.addStrVal c.lit.strings, info, str
-        elif lfDynamicLib in prc. loc.flags:
-          assert(prc. annex != nil)
-          let str = getStr(prc. annex.path)
-          build c.code, info, PragmaPair:
-            c.code.addPragmaId info, DllImport
-            c.code.addStrVal c.lit.strings, info, str
-      elif sfExportc in prc.flags:
-        if lfDynamicLib in prc. loc.flags:
-          c.code.addPragmaId info, DllExport
-        else:
-          c.code.addPragmaId info, ObjExport
-
-    let resultSym = genParams(c, prc.typ.n, prc)
-    if body != nil:
-      gen(c, body)
-      patch c, body, c.exitLabel
-      if resultSym != nil:
-        build c.code, info, Ret:
-          c.code.addSymUse info, toSymId(c, resultSym)
-      else:
-        build c.code, info, Ret:
-          c.code.addNop info
-
-  #copyTree cOuter.code, c.code
-  dec cOuter.m.inProc
-
-proc genProc(cOuter: var ProcCon; n: PNode) =
-  if n.len == 0 or n[namePos].kind != nkSym: return
-  let prc = n[namePos].sym
-  if isGenericRoutineStrict(prc) or isCompileTimeProc(prc) or sfForward in prc.flags: return
-  genProc cOuter, prc
-
-proc genClosureCall(c: var ProcCon; n: PNode; d: var Value) =
-  let typ = skipTypes(n[0].typ, abstractInstOwned)
-  if tfIterator in typ.flags:
-    const PatIter = "$1.ClP_0($3, $1.ClE_0)" # we know the env exists
-
-  else:
-    const PatProc = "$1.ClE_0? $1.ClP_0($3, $1.ClE_0):(($4)($1.ClP_0))($2)"
-
-
-proc genComplexCall(c: var ProcCon; n: PNode; d: var Value) =
-  if n[0].typ != nil and n[0].typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure:
-    # XXX genClosureCall p, n, d
-    genCall c, n, d
-  else:
-    genCall c, n, d
-
-proc gen(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) =
-  when defined(nimCompilerStacktraceHints):
-    setFrameMsg c.config$n.info & " " & $n.kind & " " & $flags
-  case n.kind
-  of nkSym: genSym(c, n, d, flags)
-  of nkCallKinds:
-    if n[0].kind == nkSym:
-      let s = n[0].sym
-      if s.magic != mNone:
-        genMagic(c, n, d, s.magic)
-      elif s.kind == skMethod:
-        localError(c.config, n.info, "cannot call method " & s.name.s &
-          " at compile time")
-      else:
-        genComplexCall(c, n, d)
-    else:
-      genComplexCall(c, n, d)
-  of nkCharLit..nkInt64Lit, nkUIntLit..nkUInt64Lit:
-    genNumericLit(c, n, d, n.intVal)
-  of nkFloatLit..nkFloat128Lit:
-    genNumericLit(c, n, d, cast[int64](n.floatVal))
-  of nkStrLit..nkTripleStrLit:
-    genStringLit(c, n, d)
-  of nkNilLit:
-    if not n.typ.isEmptyType: genNilLit(c, n, d)
-    else: unused(c, n, d)
-  of nkAsgn, nkFastAsgn, nkSinkAsgn:
-    unused(c, n, d)
-    genAsgn(c, n)
-  of nkDotExpr: genObjAccess(c, n, d, flags)
-  of nkCheckedFieldExpr: genObjAccess(c, n[0], d, flags)
-  of nkBracketExpr: genArrAccess(c, n, d, flags)
-  of nkDerefExpr, nkHiddenDeref: genDeref(c, n, d, flags)
-  of nkAddr, nkHiddenAddr: genAddr(c, n, d, flags)
-  of nkIfStmt, nkIfExpr: genIf(c, n, d)
-  of nkWhenStmt:
-    # This is "when nimvm" node. Chose the first branch.
-    gen(c, n[0][1], d)
-  of nkCaseStmt: genCase(c, n, d)
-  of nkWhileStmt:
-    unused(c, n, d)
-    genWhile(c, n)
-  of nkBlockExpr, nkBlockStmt: genBlock(c, n, d)
-  of nkReturnStmt: genReturn(c, n)
-  of nkRaiseStmt: genRaise(c, n)
-  of nkBreakStmt: genBreak(c, n)
-  of nkTryStmt, nkHiddenTryStmt: genTry(c, n, d)
-  of nkStmtList:
-    #unused(c, n, d)
-    # XXX Fix this bug properly, lexim triggers it
-    for x in n: gen(c, x)
-  of nkStmtListExpr:
-    for i in 0..<n.len-1: gen(c, n[i])
-    gen(c, n[^1], d, flags)
-  of nkPragmaBlock:
-    gen(c, n.lastSon, d, flags)
-  of nkDiscardStmt:
-    unused(c, n, d)
-    gen(c, n[0], d)
-  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
-    genConv(c, n, n[1], d, flags, NumberConv) # misnomer?
-  of nkObjDownConv:
-    genConv(c, n, n[0], d, flags, ObjConv)
-  of nkObjUpConv:
-    genConv(c, n, n[0], d, flags, CheckedObjConv)
-  of nkVarSection, nkLetSection, nkConstSection:
-    unused(c, n, d)
-    genVarSection(c, n)
-  of nkLambdaKinds:
-    #let s = n[namePos].sym
-    #discard genProc(c, s)
-    gen(c, newSymNode(n[namePos].sym), d)
-  of nkChckRangeF, nkChckRange64, nkChckRange:
-    genRangeCheck(c, n, d)
-  of declarativeDefs - {nkIteratorDef}:
-    unused(c, n, d)
-    genProc(c, n)
-  of nkEmpty, nkCommentStmt, nkTypeSection, nkPragma,
-     nkTemplateDef, nkIncludeStmt, nkImportStmt, nkFromStmt, nkExportStmt,
-     nkMixinStmt, nkBindStmt, nkMacroDef, nkIteratorDef:
-    unused(c, n, d)
-  of nkStringToCString: convStrToCStr(c, n, d)
-  of nkCStringToString: convCStrToStr(c, n, d)
-  of nkBracket: genArrayConstr(c, n, d)
-  of nkCurly: genSetConstr(c, n, d)
-  of nkObjConstr:
-    if n.typ.skipTypes(abstractInstOwned).kind == tyRef:
-      genRefObjConstr(c, n, d)
-    else:
-      genObjOrTupleConstr(c, n, d, n.typ)
-  of nkPar, nkClosure, nkTupleConstr:
-    genObjOrTupleConstr(c, n, d, n.typ)
-  of nkCast:
-    genConv(c, n, n[1], d, flags, Cast)
-  of nkComesFrom:
-    discard "XXX to implement for better stack traces"
-  #of nkState: genState(c, n)
-  #of nkGotoState: genGotoState(c, n)
-  #of nkBreakState: genBreakState(c, n, d)
-  else:
-    localError(c.config, n.info, "cannot generate IR code for " & $n)
-
-proc genPendingProcs(c: var ProcCon) =
-  while c.m.pendingProcs.len > 0 or c.m.pendingVars.len > 0:
-    let procs = move(c.m.pendingProcs)
-    for v in procs:
-      genProc(c, v)
-    let vars = move(c.m.pendingVars)
-    for v in vars:
-      genForeignVar(c, v)
-
-proc genStmt*(c: var ProcCon; n: PNode): NodePos =
-  result = NodePos c.code.len
-  var d = default(Value)
-  c.gen(n, d)
-  unused c, n, d
-  genPendingProcs c
-
-proc genExpr*(c: var ProcCon; n: PNode, requiresValue = true): int =
-  result = c.code.len
-  var d = default(Value)
-  c.gen(n, d)
-  genPendingProcs c
-  if isEmpty d:
-    if requiresValue:
-      globalError(c.config, n.info, "VM problem: d register is not set")