summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorringabout <43030857+ringabout@users.noreply.github.com>2024-07-09 15:29:45 +0800
committerGitHub <noreply@github.com>2024-07-09 09:29:45 +0200
commit732f7752a954bb33a92e839304006ba5d865400a (patch)
tree8ad5d283cba3570b5916cfe81ac388116faed881 /compiler
parent14f86b3965bfe096b5fed81caa0cc1570f7e7fdf (diff)
downloadNim-732f7752a954bb33a92e839304006ba5d865400a.tar.gz
remove nir; succeeded by nif (#23809)
ref https://github.com/nim-lang/nif
Diffstat (limited to 'compiler')
-rw-r--r--compiler/commands.nim2
-rw-r--r--compiler/extccomp.nim2
-rw-r--r--compiler/ic/ic.nim2
-rw-r--r--compiler/ic/iclineinfos.nim (renamed from compiler/nir/nirlineinfos.nim)2
-rw-r--r--compiler/ic/navigator.nim2
-rw-r--r--compiler/ic/packed_ast.nim2
-rw-r--r--compiler/main.nim39
-rw-r--r--compiler/modulegraphs.nim2
-rw-r--r--compiler/nim.nim3
-rw-r--r--compiler/nir/ast2ir.nim2638
-rw-r--r--compiler/nir/cir.nim983
-rw-r--r--compiler/nir/nir.nim105
-rw-r--r--compiler/nir/nirc.nim52
-rw-r--r--compiler/nir/nirfiles.nim83
-rw-r--r--compiler/nir/nirinsts.nim582
-rw-r--r--compiler/nir/nirslots.nim104
-rw-r--r--compiler/nir/nirtypes.nim475
-rw-r--r--compiler/nir/nirvm.nim1175
-rw-r--r--compiler/nir/stringcases.nim200
-rw-r--r--compiler/nir/types2ir.nim525
-rw-r--r--compiler/options.nim4
-rw-r--r--compiler/pipelines.nim13
22 files changed, 11 insertions, 6984 deletions
diff --git a/compiler/commands.nim b/compiler/commands.nim
index 176b73044..5b261b3e8 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -462,7 +462,6 @@ proc handleCmdInput*(conf: ConfigRef) =
 proc parseCommand*(command: string): Command =
   case command.normalize
   of "c", "cc", "compile", "compiletoc": cmdCompileToC
-  of "nir": cmdCompileToNir
   of "cpp", "compiletocpp": cmdCompileToCpp
   of "objc", "compiletooc": cmdCompileToOC
   of "js", "compiletojs": cmdCompileToJS
@@ -500,7 +499,6 @@ proc setCmd*(conf: ConfigRef, cmd: Command) =
   of cmdCompileToCpp: conf.backend = backendCpp
   of cmdCompileToOC: conf.backend = backendObjc
   of cmdCompileToJS: conf.backend = backendJs
-  of cmdCompileToNir: conf.backend = backendNir
   else: discard
 
 proc setCommandEarly*(conf: ConfigRef, command: string) =
diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim
index dc9b43514..a8b6489b8 100644
--- a/compiler/extccomp.nim
+++ b/compiler/extccomp.nim
@@ -337,7 +337,7 @@ proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string =
   var fullSuffix = suffix
   case conf.backend
   of backendCpp, backendJs, backendObjc: fullSuffix = "." & $conf.backend & suffix
-  of backendC, backendNir: discard
+  of backendC: discard
   of backendInvalid:
     # during parsing of cfg files; we don't know the backend yet, no point in
     # guessing wrong thing
diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim
index 22b886ff4..f59a53a16 100644
--- a/compiler/ic/ic.nim
+++ b/compiler/ic/ic.nim
@@ -16,7 +16,7 @@ from std/os import removeFile, isAbsolute
 
 import ../../dist/checksums/src/checksums/sha1
 
-import ".." / nir / nirlineinfos
+import iclineinfos
 
 when defined(nimPreviewSlimSystem):
   import std/[syncio, assertions, formatfloat]
diff --git a/compiler/nir/nirlineinfos.nim b/compiler/ic/iclineinfos.nim
index f11ef7c42..74a7d971b 100644
--- a/compiler/nir/nirlineinfos.nim
+++ b/compiler/ic/iclineinfos.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2023 Andreas Rumpf
+#        (c) Copyright 2024 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
diff --git a/compiler/ic/navigator.nim b/compiler/ic/navigator.nim
index ca2f981a1..39037b94f 100644
--- a/compiler/ic/navigator.nim
+++ b/compiler/ic/navigator.nim
@@ -20,7 +20,7 @@ when defined(nimPreviewSlimSystem):
   import std/assertions
 
 import ".." / [ast, modulegraphs, msgs, options]
-import ".." / nir / nirlineinfos
+import iclineinfos
 import packed_ast, bitabs, ic
 
 type
diff --git a/compiler/ic/packed_ast.nim b/compiler/ic/packed_ast.nim
index 392f6b325..a39bb7adf 100644
--- a/compiler/ic/packed_ast.nim
+++ b/compiler/ic/packed_ast.nim
@@ -16,7 +16,7 @@ import std/[hashes, tables, strtabs]
 import bitabs, rodfiles
 import ".." / [ast, options]
 
-import ".." / nir / nirlineinfos
+import iclineinfos
 
 when defined(nimPreviewSlimSystem):
   import std/assertions
diff --git a/compiler/main.nim b/compiler/main.nim
index 0b74162a9..4c52317cf 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -22,8 +22,6 @@ import
   modules,
   modulegraphs, lineinfos, pathutils, vmprofiler
 
-# ensure NIR compiles:
-import nir / nir
 
 when defined(nimPreviewSlimSystem):
   import std/[syncio, assertions]
@@ -48,9 +46,6 @@ proc writeDepsFile(g: ModuleGraph) =
       f.writeLine(toFullPath(g.config, k))
   f.close()
 
-proc writeNinjaFile(g: ModuleGraph) =
-  discard "to implement"
-
 proc writeCMakeDepsFile(conf: ConfigRef) =
   ## write a list of C files for build systems like CMake.
   ## only updated when the C file list changes.
@@ -161,26 +156,6 @@ proc commandCompileToC(graph: ModuleGraph) =
     if optGenCDeps in graph.config.globalOptions:
       writeCMakeDepsFile(conf)
 
-proc commandCompileToNir(graph: ModuleGraph) =
-  let conf = graph.config
-  extccomp.initVars(conf)
-  if conf.symbolFiles == disabledSf:
-    if {optRun, optForceFullMake} * conf.globalOptions == {optRun}:
-      if not changeDetectedViaJsonBuildInstructions(conf, conf.jsonBuildInstructionsFile):
-        # nothing changed
-        graph.config.notes = graph.config.mainPackageNotes
-        return
-
-  if not extccomp.ccHasSaneOverflow(conf):
-    conf.symbols.defineSymbol("nimEmulateOverflowChecks")
-
-  if conf.symbolFiles == disabledSf:
-    setPipeLinePass(graph, NirPass)
-  else:
-    setPipeLinePass(graph, SemPass)
-  compilePipelineProject(graph)
-  writeNinjaFile(graph)
-
 proc commandJsonScript(graph: ModuleGraph) =
   extccomp.runJsonBuildInstructions(graph.config, graph.config.jsonBuildInstructionsFile)
 
@@ -197,16 +172,13 @@ proc commandCompileToJS(graph: ModuleGraph) =
     if optGenScript in conf.globalOptions:
       writeDepsFile(graph)
 
-proc commandInteractive(graph: ModuleGraph; useNir: bool) =
+proc commandInteractive(graph: ModuleGraph) =
   graph.config.setErrorMaxHighMaybe
   initDefines(graph.config.symbols)
-  if useNir:
-    defineSymbol(graph.config.symbols, "noSignalHandler")
-  else:
-    defineSymbol(graph.config.symbols, "nimscript")
+  defineSymbol(graph.config.symbols, "nimscript")
   # note: seems redundant with -d:nimHasLibFFI
   when hasFFI: defineSymbol(graph.config.symbols, "nimffi")
-  setPipeLinePass(graph, if useNir: NirReplPass else: InterpreterPass)
+  setPipeLinePass(graph, InterpreterPass)
   compilePipelineSystemModule(graph)
   if graph.config.commandArgs.len > 0:
     discard graph.compilePipelineModule(fileInfoIdx(graph.config, graph.config.projectFull), {})
@@ -293,8 +265,6 @@ proc mainCommand*(graph: ModuleGraph) =
         # and it has added this define implictly, so we must undo that here.
         # A better solution might be to fix system.nim
         undefSymbol(conf.symbols, "useNimRtl")
-    of backendNir:
-      if conf.exc == excNone: conf.exc = excGoto
     of backendInvalid: raiseAssert "unreachable"
 
   proc compileToBackend() =
@@ -305,7 +275,6 @@ proc mainCommand*(graph: ModuleGraph) =
     of backendCpp: commandCompileToC(graph)
     of backendObjc: commandCompileToC(graph)
     of backendJs: commandCompileToJS(graph)
-    of backendNir: commandCompileToNir(graph)
     of backendInvalid: raiseAssert "unreachable"
 
   template docLikeCmd(body) =
@@ -444,7 +413,7 @@ proc mainCommand*(graph: ModuleGraph) =
     wantMainModule(conf)
     commandView(graph)
     #msgWriteln(conf, "Beware: Indentation tokens depend on the parser's state!")
-  of cmdInteractive: commandInteractive(graph, isDefined(conf, "nir"))
+  of cmdInteractive: commandInteractive(graph)
   of cmdNimscript:
     if conf.projectIsCmd or conf.projectIsStdin: discard
     elif not fileExists(conf.projectFull):
diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim
index 75f3a3c70..a2b69a7e8 100644
--- a/compiler/modulegraphs.nim
+++ b/compiler/modulegraphs.nim
@@ -62,8 +62,6 @@ type
     CgenPass
     EvalPass
     InterpreterPass
-    NirPass
-    NirReplPass
     GenDependPass
     Docgen2TexPass
     Docgen2JsonPass
diff --git a/compiler/nim.nim b/compiler/nim.nim
index 3473ea443..1d499a50d 100644
--- a/compiler/nim.nim
+++ b/compiler/nim.nim
@@ -116,8 +116,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
     conf.backend = backendC
 
   if conf.selectedGC == gcUnselected:
-    if conf.backend in {backendC, backendCpp, backendObjc, backendNir} or
-        (conf.cmd == cmdInteractive and isDefined(conf, "nir")) or
+    if conf.backend in {backendC, backendCpp, backendObjc} or
         (conf.cmd in cmdDocLike and conf.backend != backendJs):
       initOrcDefines(conf)
 
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")
diff --git a/compiler/nir/cir.nim b/compiler/nir/cir.nim
deleted file mode 100644
index 01f9c4c9a..000000000
--- a/compiler/nir/cir.nim
+++ /dev/null
@@ -1,983 +0,0 @@
-#
-#
-#           The Nim Compiler
-#        (c) Copyright 2023 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-# We produce C code as a list of tokens.
-
-import std / [assertions, syncio, tables, intsets, formatfloat]
-from std / strutils import toOctal
-import .. / ic / [bitabs, rodfiles]
-import nirtypes, nirinsts, nirfiles
-import ../../dist/checksums/src/checksums/md5
-
-type
-  Token = LitId # indexing into the tokens BiTable[string]
-
-  PredefinedToken = enum
-    IgnoreMe = "<unused>"
-    EmptyToken = ""
-    CurlyLe = "{"
-    CurlyRi = "}"
-    ParLe = "("
-    ParRi = ")"
-    BracketLe = "["
-    BracketRi = "]"
-    NewLine = "\n"
-    Semicolon = ";"
-    Comma = ", "
-    Space = " "
-    Colon = ": "
-    Dot = "."
-    Arrow = "->"
-    Star = "*"
-    Amp = "&"
-    AsgnOpr = " = "
-    ScopeOpr = "::"
-    ConstKeyword = "const "
-    StaticKeyword = "static "
-    ExternKeyword = "extern "
-    WhileKeyword = "while "
-    IfKeyword = "if ("
-    ElseKeyword = "else "
-    SwitchKeyword = "switch "
-    CaseKeyword = "case "
-    DefaultKeyword = "default:"
-    BreakKeyword = "break"
-    NullPtr = "nullptr"
-    IfNot = "if (!("
-    ReturnKeyword = "return "
-    TypedefStruct = "typedef struct "
-    TypedefUnion = "typedef union "
-    IncludeKeyword = "#include "
-
-proc fillTokenTable(tab: var BiTable[string]) =
-  for e in EmptyToken..high(PredefinedToken):
-    let id = tab.getOrIncl $e
-    assert id == LitId(e), $(id, " ", ord(e))
-
-type
-  GeneratedCode* = object
-    m: NirModule
-    includes: seq[LitId]
-    includedHeaders: IntSet
-    data: seq[LitId]
-    protos: seq[LitId]
-    code: seq[LitId]
-    init: seq[LitId]
-    tokens: BiTable[string]
-    emittedStrings: IntSet
-    needsPrefix: IntSet
-    generatedTypes: IntSet
-    mangledModules: Table[LitId, LitId]
-
-proc initGeneratedCode*(m: sink NirModule): GeneratedCode =
-  result = GeneratedCode(m: m, code: @[], tokens: initBiTable[string]())
-  fillTokenTable(result.tokens)
-
-proc add*(g: var GeneratedCode; t: PredefinedToken) {.inline.} =
-  g.code.add Token(t)
-
-proc add*(g: var GeneratedCode; s: string) {.inline.} =
-  g.code.add g.tokens.getOrIncl(s)
-
-proc mangleModuleName(c: var GeneratedCode; key: LitId): LitId =
-  result = c.mangledModules.getOrDefault(key, LitId(0))
-  if result == LitId(0):
-    let u {.cursor.} = c.m.lit.strings[key]
-    var last = u.len - len(".nim") - 1
-    var start = last
-    while start >= 0 and u[start] != '/': dec start
-    var sum = getMD5(u)
-    sum.setLen(8)
-    let dest = u.substr(start+1, last) & sum
-    result = c.tokens.getOrIncl(dest)
-    c.mangledModules[key] = result
-
-type
-  CppFile = object
-    f: File
-
-proc write(f: var CppFile; s: string) = write(f.f, s)
-proc write(f: var CppFile; c: char) = write(f.f, c)
-
-proc writeTokenSeq(f: var CppFile; s: seq[Token]; c: GeneratedCode) =
-  var indent = 0
-  for i in 0..<s.len:
-    let x = s[i]
-    case x
-    of Token(CurlyLe):
-      inc indent
-      write f, c.tokens[x]
-      write f, "\n"
-      for i in 1..indent*2: write f, ' '
-    of Token(CurlyRi):
-      dec indent
-      write f, c.tokens[x]
-      if i+1 < s.len and s[i+1] == Token(CurlyRi):
-        discard
-      else:
-        write f, "\n"
-        for i in 1..indent*2: write f, ' '
-    of Token(Semicolon):
-      write f, c.tokens[x]
-      if i+1 < s.len and s[i+1] == Token(CurlyRi):
-        discard "no newline before }"
-      else:
-        write f, "\n"
-        for i in 1..indent*2: write f, ' '
-    of Token(NewLine):
-      write f, c.tokens[x]
-      for i in 1..indent*2: write f, ' '
-    else:
-      write f, c.tokens[x]
-
-
-# Type graph
-
-type
-  TypeList = object
-    processed: IntSet
-    s: seq[(TypeId, PredefinedToken)]
-
-proc add(dest: var TypeList; elem: TypeId; decl: PredefinedToken) =
-  if not containsOrIncl(dest.processed, int(elem)):
-    dest.s.add (elem, decl)
-
-type
-  TypeOrder = object
-    forwardedDecls, ordered: TypeList
-    typeImpls: Table[string, TypeId]
-    lookedAt: IntSet
-
-proc traverseObject(types: TypeGraph; lit: Literals; c: var TypeOrder; t: TypeId)
-
-proc recordDependency(types: TypeGraph; lit: Literals; c: var TypeOrder; parent, child: TypeId) =
-  var ch = child
-  var viaPointer = false
-  while true:
-    case types[ch].kind
-    of APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy:
-      viaPointer = true
-      ch = elementType(types, ch)
-    of LastArrayTy:
-      ch = elementType(types, ch)
-    else:
-      break
-
-  case types[ch].kind
-  of ObjectTy, UnionTy:
-    let decl = if types[ch].kind == ObjectTy: TypedefStruct else: TypedefUnion
-    let obj = c.typeImpls.getOrDefault(lit.strings[types[ch].litId])
-    if viaPointer:
-      c.forwardedDecls.add obj, decl
-    else:
-      if not containsOrIncl(c.lookedAt, obj.int):
-        traverseObject(types, lit, c, obj)
-      c.ordered.add obj, decl
-  of ArrayTy:
-    if viaPointer:
-      c.forwardedDecls.add ch, TypedefStruct
-    else:
-      if not containsOrIncl(c.lookedAt, ch.int):
-        traverseObject(types, lit, c, ch)
-      c.ordered.add ch, TypedefStruct
-  else:
-    discard "uninteresting type as we only focus on the required struct declarations"
-
-proc traverseObject(types: TypeGraph; lit: Literals; c: var TypeOrder; t: TypeId) =
-  for x in sons(types, t):
-    case types[x].kind
-    of FieldDecl:
-      recordDependency types, lit, c, t, x.firstSon
-    of ObjectTy:
-      # inheritance
-      recordDependency types, lit, c, t, x
-    else: discard
-
-proc traverseTypes(types: TypeGraph; lit: Literals; c: var TypeOrder) =
-  for t in allTypes(types):
-    if types[t].kind in {ObjectDecl, UnionDecl}:
-      assert types[t.firstSon].kind == NameVal
-      c.typeImpls[lit.strings[types[t.firstSon].litId]] = t
-
-  for t in allTypesIncludingInner(types):
-    case types[t].kind
-    of ObjectDecl, UnionDecl:
-      traverseObject types, lit, c, t
-      let decl = if types[t].kind == ObjectDecl: TypedefStruct else: TypedefUnion
-      c.ordered.add t, decl
-    of ArrayTy:
-      traverseObject types, lit, c, t
-      c.ordered.add t, TypedefStruct
-    else: discard
-
-when false:
-  template emitType(s: string) = c.types.add c.tokens.getOrIncl(s)
-  template emitType(t: Token) = c.types.add t
-  template emitType(t: PredefinedToken) = c.types.add Token(t)
-
-proc genType(g: var GeneratedCode; types: TypeGraph; lit: Literals; t: TypeId; name = "") =
-  template maybeAddName =
-    if name != "":
-      g.add Space
-      g.add name
-
-  template atom(s: string) =
-    g.add s
-    maybeAddName()
-  case types[t].kind
-  of VoidTy: atom "void"
-  of IntTy: atom "NI" & $types[t].integralBits
-  of UIntTy: atom "NU" & $types[t].integralBits
-  of FloatTy: atom "NF" & $types[t].integralBits
-  of BoolTy: atom "NB" & $types[t].integralBits
-  of CharTy: atom "NC" & $types[t].integralBits
-  of ObjectTy, UnionTy, NameVal, AnnotationVal:
-    atom lit.strings[types[t].litId]
-  of VarargsTy:
-    g.add "..."
-  of APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy:
-    genType g, types, lit, elementType(types, t)
-    g.add Star
-    maybeAddName()
-  of ArrayTy:
-    genType g, types, lit, arrayName(types, t)
-    maybeAddName()
-  of LastArrayTy:
-    genType g, types, lit, elementType(types, t)
-    maybeAddName()
-    g.add BracketLe
-    g.add BracketRi
-  of ProcTy:
-    let (retType, callConv) = returnType(types, t)
-    genType g, types, lit, retType
-    g.add Space
-    g.add ParLe
-    genType g, types, lit, callConv
-    g.add Star # "(*fn)"
-    maybeAddName()
-    g.add ParRi
-    g.add ParLe
-    var i = 0
-    for ch in params(types, t):
-      if i > 0: g.add Comma
-      genType g, types, lit, ch
-      inc i
-    g.add ParRi
-  of ObjectDecl, UnionDecl:
-    atom lit.strings[types[t.firstSon].litId]
-  of IntVal, SizeVal, AlignVal, OffsetVal, FieldDecl:
-    #raiseAssert "did not expect: " & $types[t].kind
-    g.add "BUG "
-    atom $types[t].kind
-
-proc generateTypes(g: var GeneratedCode; types: TypeGraph; lit: Literals; c: TypeOrder) =
-  for (t, declKeyword) in c.forwardedDecls.s:
-    let name = if types[t].kind == ArrayTy: arrayName(types, t) else: t.firstSon
-    let s {.cursor.} = lit.strings[types[name].litId]
-    g.add declKeyword
-    g.add s
-    g.add Space
-    g.add s
-    g.add Semicolon
-
-  for (t, declKeyword) in c.ordered.s:
-    let name = if types[t].kind == ArrayTy: arrayName(types, t) else: t.firstSon
-    let litId = types[name].litId
-    if not g.generatedTypes.containsOrIncl(litId.int):
-      let s {.cursor.} = lit.strings[litId]
-      g.add declKeyword
-      g.add CurlyLe
-      if types[t].kind == ArrayTy:
-        genType g, types, lit, elementType(types, t), "a"
-        g.add BracketLe
-        g.add $arrayLen(types, t)
-        g.add BracketRi
-        g.add Semicolon
-      else:
-        var i = 0
-        for x in sons(types, t):
-          case types[x].kind
-          of FieldDecl:
-            genType g, types, lit, x.firstSon, "F" & $i
-            g.add Semicolon
-            inc i
-          of ObjectTy:
-            genType g, types, lit, x, "P"
-            g.add Semicolon
-          else: discard
-      g.add CurlyRi
-      g.add s
-      g.add Semicolon
-
-# Procs
-
-proc toCChar*(c: char; result: var string) {.inline.} =
-  case c
-  of '\0'..'\x1F', '\x7F'..'\xFF':
-    result.add '\\'
-    result.add toOctal(c)
-  of '\'', '\"', '\\', '?':
-    result.add '\\'
-    result.add c
-  else:
-    result.add c
-
-proc makeCString(s: string): string =
-  result = newStringOfCap(s.len + 10)
-  result.add('"')
-  for c in s: toCChar(c, result)
-  result.add('"')
-
-template emitData(s: string) = c.data.add c.tokens.getOrIncl(s)
-template emitData(t: Token) = c.data.add t
-template emitData(t: PredefinedToken) = c.data.add Token(t)
-
-proc genStrLit(c: var GeneratedCode; lit: Literals; litId: LitId): Token =
-  result = Token(c.tokens.getOrIncl "QStr" & $litId)
-  if not containsOrIncl(c.emittedStrings, int(litId)):
-    let s {.cursor.} = lit.strings[litId]
-    emitData "static const struct "
-    emitData CurlyLe
-    emitData "NI cap"
-    emitData Semicolon
-    emitData "NC8 data"
-    emitData BracketLe
-    emitData $s.len
-    emitData "+1"
-    emitData BracketRi
-    emitData Semicolon
-    emitData CurlyRi
-    emitData result
-    emitData AsgnOpr
-    emitData CurlyLe
-    emitData $s.len
-    emitData " | NIM_STRLIT_FLAG"
-    emitData Comma
-    emitData makeCString(s)
-    emitData CurlyRi
-    emitData Semicolon
-
-proc genIntLit(c: var GeneratedCode; lit: Literals; litId: LitId) =
-  let i = lit.numbers[litId]
-  if i > low(int32) and i <= high(int32):
-    c.add $i
-  elif i == low(int32):
-    # Nim has the same bug for the same reasons :-)
-    c.add "(-2147483647 -1)"
-  elif i > low(int64):
-    c.add "IL64("
-    c.add $i
-    c.add ")"
-  else:
-    c.add "(IL64(-9223372036854775807) - IL64(1))"
-
-proc gen(c: var GeneratedCode; t: Tree; n: NodePos)
-
-proc genDisplayName(c: var GeneratedCode; symId: SymId) =
-  let displayName = c.m.symnames[symId]
-  if displayName != LitId(0):
-    c.add "/*"
-    c.add c.m.lit.strings[displayName]
-    c.add "*/"
-
-proc genSymDef(c: var GeneratedCode; t: Tree; n: NodePos) =
-  if t[n].kind == SymDef:
-    let symId = t[n].symId
-    c.needsPrefix.incl symId.int
-    genDisplayName c, symId
-  gen c, t, n
-
-proc genGlobal(c: var GeneratedCode; t: Tree; name, typ: NodePos; annotation: string) =
-  c.add annotation
-  let m: string
-  if t[name].kind == SymDef:
-    let symId = t[name].symId
-    m = c.tokens[mangleModuleName(c, c.m.namespace)] & "__" & $symId
-    genDisplayName c, symId
-  else:
-    assert t[name].kind == ModuleSymUse
-    let (x, y) = sons2(t, name)
-    m = c.tokens[mangleModuleName(c, t[x].litId)] & "__" & $t[y].immediateVal
-  genType c, c.m.types, c.m.lit, t[typ].typeId, m
-
-proc genLocal(c: var GeneratedCode; t: Tree; name, typ: NodePos; annotation: string) =
-  assert t[name].kind == SymDef
-  c.add annotation
-  let symId = t[name].symId
-  genType c, c.m.types, c.m.lit, t[typ].typeId, "q" & $symId
-  genDisplayName c, symId
-
-proc genProcDecl(c: var GeneratedCode; t: Tree; n: NodePos; isExtern: bool) =
-  let signatureBegin = c.code.len
-  let name = n.firstSon
-
-  var prc = n.firstSon
-  next t, prc
-
-  while true:
-    case t[prc].kind
-    of PragmaPair:
-      let (x, y) = sons2(t, prc)
-      let key = cast[PragmaKey](t[x].rawOperand)
-      case key
-      of HeaderImport:
-        let lit = t[y].litId
-        let headerAsStr {.cursor.} = c.m.lit.strings[lit]
-        let header = c.tokens.getOrIncl(headerAsStr)
-        # headerAsStr can be empty, this has the semantics of the `nodecl` pragma:
-        if headerAsStr.len > 0 and not c.includedHeaders.containsOrIncl(int header):
-          if headerAsStr[0] == '#':
-            discard "skip the #include"
-          else:
-            c.includes.add Token(IncludeKeyword)
-          c.includes.add header
-          c.includes.add Token NewLine
-        # do not generate code for importc'ed procs:
-        return
-      of DllImport:
-        let lit = t[y].litId
-        raiseAssert "cannot eval: " & c.m.lit.strings[lit]
-      else: discard
-    of PragmaId: discard
-    else: break
-    next t, prc
-
-  var resultDeclPos = NodePos(-1)
-  if t[prc].kind == SummonResult:
-    resultDeclPos = prc
-    gen c, t, prc.firstSon
-    next t, prc
-  else:
-    c.add "void"
-  c.add Space
-  genSymDef c, t, name
-  c.add ParLe
-  var params = 0
-  while t[prc].kind == SummonParam:
-    if params > 0: c.add Comma
-    let (typ, sym) = sons2(t, prc)
-    genLocal c, t, sym, typ, ""
-    next t, prc
-    inc params
-  if params == 0:
-    c.add "void"
-  c.add ParRi
-
-  for i in signatureBegin ..< c.code.len:
-    c.protos.add c.code[i]
-  c.protos.add Token Semicolon
-
-  if isExtern:
-    c.code.setLen signatureBegin
-  else:
-    c.add CurlyLe
-    if resultDeclPos.int >= 0:
-      gen c, t, resultDeclPos
-    for ch in sonsRest(t, n, prc):
-      gen c, t, ch
-    c.add CurlyRi
-
-template triop(opr) =
-  let (typ, a, b) = sons3(t, n)
-  c.add ParLe
-  c.add ParLe
-  gen c, t, typ
-  c.add ParRi
-  gen c, t, a
-  c.add opr
-  gen c, t, b
-  c.add ParRi
-
-template cmpop(opr) =
-  let (_, a, b) = sons3(t, n)
-  c.add ParLe
-  gen c, t, a
-  c.add opr
-  gen c, t, b
-  c.add ParRi
-
-template binaryop(opr) =
-  let (typ, a) = sons2(t, n)
-  c.add ParLe
-  c.add ParLe
-  gen c, t, typ
-  c.add ParRi
-  c.add opr
-  gen c, t, a
-  c.add ParRi
-
-template checkedBinaryop(opr) =
-  let (typ, labIdx, a, b) = sons4(t, n)
-  let bits = integralBits(c.m.types[t[typ].typeId])
-  let lab = t[labIdx].label
-
-  c.add (opr & $bits)
-  c.add ParLe
-  c.gen t, a
-  c.add Comma
-  c.gen t, b
-  c.add Comma
-  c.add "L" & $lab.int
-  c.add ParRi
-
-proc genNumberConv(c: var GeneratedCode; t: Tree; n: NodePos) =
-  let (typ, arg) = sons2(t, n)
-  if t[arg].kind == IntVal:
-    let litId = t[arg].litId
-    c.add ParLe
-    c.add ParLe
-    gen c, t, typ
-    c.add ParRi
-    case c.m.types[t[typ].typeId].kind
-    of UIntTy:
-      let x = cast[uint64](c.m.lit.numbers[litId])
-      c.add $x
-    of FloatTy:
-      let x = cast[float64](c.m.lit.numbers[litId])
-      c.add $x
-    else:
-      gen c, t, arg
-    c.add ParRi
-  else:
-    binaryop ""
-
-template moveToDataSection(body: untyped) =
-  let oldLen = c.code.len
-  body
-  for i in oldLen ..< c.code.len:
-    c.data.add c.code[i]
-  setLen c.code, oldLen
-
-proc gen(c: var GeneratedCode; t: Tree; n: NodePos) =
-  case t[n].kind
-  of Nop:
-    discard "nothing to emit"
-  of ImmediateVal:
-    c.add $t[n].immediateVal
-  of IntVal:
-    genIntLit c, c.m.lit, t[n].litId
-  of StrVal:
-    c.code.add genStrLit(c, c.m.lit, t[n].litId)
-  of Typed:
-    genType c, c.m.types, c.m.lit, t[n].typeId
-  of SymDef, SymUse:
-    let s = t[n].symId
-    if c.needsPrefix.contains(s.int):
-      c.code.add mangleModuleName(c, c.m.namespace)
-      c.add "__"
-      c.add $s
-    else:
-      # XXX Use proper names here
-      c.add "q"
-      c.add $s
-
-  of ModuleSymUse:
-    let (x, y) = sons2(t, n)
-    let u = mangleModuleName(c, t[x].litId)
-    let s = t[y].immediateVal
-    c.code.add u
-    c.add "__"
-    c.add $s
-
-  of NilVal:
-    c.add NullPtr
-  of LoopLabel:
-    c.add WhileKeyword
-    c.add ParLe
-    c.add "1"
-    c.add ParRi
-    c.add CurlyLe
-  of GotoLoop:
-    c.add CurlyRi
-  of Label:
-    let lab = t[n].label
-    c.add "L"
-    c.add $lab.int
-    c.add Colon
-    c.add Semicolon
-  of Goto:
-    let lab = t[n].label
-    c.add "goto L"
-    c.add $lab.int
-    c.add Semicolon
-  of CheckedGoto:
-    discard "XXX todo"
-  of ArrayConstr:
-    c.add CurlyLe
-    c.add ".a = "
-    c.add CurlyLe
-    var i = 0
-    for ch in sonsFrom1(t, n):
-      if i > 0: c.add Comma
-      c.gen t, ch
-      inc i
-    c.add CurlyRi
-    c.add CurlyRi
-  of ObjConstr:
-    c.add CurlyLe
-    var i = 0
-    for ch in sonsFrom1(t, n):
-      if i mod 2 == 0:
-        if i > 0: c.add Comma
-        c.add ".F" & $t[ch].immediateVal
-        c.add AsgnOpr
-      else:
-        c.gen t, ch
-      inc i
-    c.add CurlyRi
-  of Ret:
-    c.add ReturnKeyword
-    c.gen t, n.firstSon
-    c.add Semicolon
-  of Select:
-    c.add SwitchKeyword
-    c.add ParLe
-    let (_, selector) = sons2(t, n)
-    c.gen t, selector
-    c.add ParRi
-    c.add CurlyLe
-    for ch in sonsFromN(t, n, 2):
-      c.gen t, ch
-    c.add CurlyRi
-  of SelectPair:
-    let (le, ri) = sons2(t, n)
-    c.gen t, le
-    c.gen t, ri
-  of SelectList:
-    for ch in sons(t, n):
-      c.gen t, ch
-  of SelectValue:
-    c.add CaseKeyword
-    c.gen t, n.firstSon
-    c.add Colon
-  of SelectRange:
-    let (le, ri) = sons2(t, n)
-    c.add CaseKeyword
-    c.gen t, le
-    c.add " ... "
-    c.gen t, ri
-    c.add Colon
-  of ForeignDecl:
-    c.data.add LitId(ExternKeyword)
-    c.gen t, n.firstSon
-  of SummonGlobal:
-    moveToDataSection:
-      let (typ, sym) = sons2(t, n)
-      c.genGlobal t, sym, typ, ""
-      c.add Semicolon
-  of SummonThreadLocal:
-    moveToDataSection:
-      let (typ, sym) = sons2(t, n)
-      c.genGlobal t, sym, typ, "__thread "
-      c.add Semicolon
-  of SummonConst:
-    moveToDataSection:
-      let (typ, sym, val) = sons3(t, n)
-      c.genGlobal t, sym, typ, "const "
-      c.add AsgnOpr
-      c.gen t, val
-      c.add Semicolon
-  of Summon, SummonResult:
-    let (typ, sym) = sons2(t, n)
-    c.genLocal t, sym, typ, ""
-    c.add Semicolon
-
-  of SummonParam:
-    raiseAssert "SummonParam should have been handled in genProc"
-  of Kill:
-    discard "we don't care about Kill instructions"
-  of AddrOf:
-    let (_, arg) = sons2(t, n)
-    c.add "&"
-    gen c, t, arg
-  of DerefArrayAt:
-    let (_, a, i) = sons3(t, n)
-    gen c, t, a
-    c.add BracketLe
-    gen c, t, i
-    c.add BracketRi
-  of ArrayAt:
-    let (_, a, i) = sons3(t, n)
-    gen c, t, a
-    c.add Dot
-    c.add "a"
-    c.add BracketLe
-    gen c, t, i
-    c.add BracketRi
-  of FieldAt:
-    let (_, a, b) = sons3(t, n)
-    gen c, t, a
-    let field = t[b].immediateVal
-    c.add Dot
-    c.add "F" & $field
-  of DerefFieldAt:
-    let (_, a, b) = sons3(t, n)
-    gen c, t, a
-    let field = t[b].immediateVal
-    c.add Arrow
-    c.add "F" & $field
-  of Load:
-    let (_, arg) = sons2(t, n)
-    c.add ParLe
-    c.add "*"
-    gen c, t, arg
-    c.add ParRi
-  of Store:
-    raiseAssert "Assumption was that Store is unused!"
-  of Asgn:
-    let (_, dest, src) = sons3(t, n)
-    gen c, t, dest
-    c.add AsgnOpr
-    gen c, t, src
-    c.add Semicolon
-  of CheckedRange:
-    c.add "nimCheckRange"
-    c.add ParLe
-    let (_, gotoInstr, x, a, b) = sons5(t, n)
-    gen c, t, x
-    c.add Comma
-    gen c, t, a
-    c.add Comma
-    gen c, t, b
-    c.add Comma
-    c.add "L" & $t[gotoInstr].label.int
-    c.add ParRi
-  of CheckedIndex:
-    c.add "nimCheckIndex"
-    c.add ParLe
-    let (gotoInstr, x, a) = sons3(t, n)
-    gen c, t, x
-    c.add Comma
-    gen c, t, a
-    c.add Comma
-    c.add "L" & $t[gotoInstr].label.int
-    c.add ParRi
-  of Call, IndirectCall:
-    let (typ, fn) = sons2(t, n)
-    gen c, t, fn
-    c.add ParLe
-    var i = 0
-    for ch in sonsFromN(t, n, 2):
-      if i > 0: c.add Comma
-      gen c, t, ch
-      inc i
-    c.add ParRi
-    if c.m.types[t[typ].typeId].kind == VoidTy:
-      c.add Semicolon
-  of CheckedCall, CheckedIndirectCall:
-    let (typ, gotoInstr, fn) = sons3(t, n)
-    gen c, t, fn
-    c.add ParLe
-    var i = 0
-    for ch in sonsFromN(t, n, 3):
-      if i > 0: c.add Comma
-      gen c, t, ch
-      inc i
-    c.add ParRi
-    if c.m.types[t[typ].typeId].kind == VoidTy:
-      c.add Semicolon
-
-  of CheckedAdd: checkedBinaryop "nimAddInt"
-  of CheckedSub: checkedBinaryop "nimSubInt"
-  of CheckedMul: checkedBinaryop "nimMulInt"
-  of CheckedDiv: checkedBinaryop "nimDivInt"
-  of CheckedMod: checkedBinaryop "nimModInt"
-  of Add: triop " + "
-  of Sub: triop " - "
-  of Mul: triop " * "
-  of Div: triop " / "
-  of Mod: triop " % "
-  of BitShl: triop " << "
-  of BitShr: triop " >> "
-  of BitAnd: triop " & "
-  of BitOr: triop " | "
-  of BitXor: triop " ^ "
-  of BitNot: binaryop " ~ "
-  of BoolNot: binaryop " !"
-  of Eq: cmpop " == "
-  of Le: cmpop " <= "
-  of Lt: cmpop " < "
-  of Cast: binaryop ""
-  of NumberConv: genNumberConv c, t, n
-  of CheckedObjConv: binaryop ""
-  of ObjConv: binaryop ""
-  of Emit: raiseAssert "cannot interpret: Emit"
-  of ProcDecl: genProcDecl c, t, n, false
-  of ForeignProcDecl: genProcDecl c, t, n, true
-  of PragmaPair, PragmaId, TestOf, Yld, SetExc, TestExc:
-    c.add "cannot interpret: " & $t[n].kind
-
-const
-  Prelude = """
-/* GENERATED CODE. DO NOT EDIT. */
-
-#ifdef __cplusplus
-#define NB8 bool
-#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901)
-// see #13798: to avoid conflicts for code emitting `#include <stdbool.h>`
-#define NB8 _Bool
-#else
-typedef unsigned char NB8; // best effort
-#endif
-
-typedef unsigned char NC8;
-
-typedef float NF32;
-typedef double NF64;
-#if defined(__BORLANDC__) || defined(_MSC_VER)
-typedef signed char NI8;
-typedef signed short int NI16;
-typedef signed int NI32;
-typedef __int64 NI64;
-/* XXX: Float128? */
-typedef unsigned char NU8;
-typedef unsigned short int NU16;
-typedef unsigned int NU32;
-typedef unsigned __int64 NU64;
-#elif defined(HAVE_STDINT_H)
-#ifndef USE_NIM_NAMESPACE
-#  include <stdint.h>
-#endif
-typedef int8_t NI8;
-typedef int16_t NI16;
-typedef int32_t NI32;
-typedef int64_t NI64;
-typedef uint8_t NU8;
-typedef uint16_t NU16;
-typedef uint32_t NU32;
-typedef uint64_t NU64;
-#elif defined(HAVE_CSTDINT)
-#ifndef USE_NIM_NAMESPACE
-#  include <cstdint>
-#endif
-typedef std::int8_t NI8;
-typedef std::int16_t NI16;
-typedef std::int32_t NI32;
-typedef std::int64_t NI64;
-typedef std::uint8_t NU8;
-typedef std::uint16_t NU16;
-typedef std::uint32_t NU32;
-typedef std::uint64_t NU64;
-#else
-/* Unknown compiler/version, do our best */
-#ifdef __INT8_TYPE__
-typedef __INT8_TYPE__ NI8;
-#else
-typedef signed char NI8;
-#endif
-#ifdef __INT16_TYPE__
-typedef __INT16_TYPE__ NI16;
-#else
-typedef signed short int NI16;
-#endif
-#ifdef __INT32_TYPE__
-typedef __INT32_TYPE__ NI32;
-#else
-typedef signed int NI32;
-#endif
-#ifdef __INT64_TYPE__
-typedef __INT64_TYPE__ NI64;
-#else
-typedef long long int NI64;
-#endif
-/* XXX: Float128? */
-#ifdef __UINT8_TYPE__
-typedef __UINT8_TYPE__ NU8;
-#else
-typedef unsigned char NU8;
-#endif
-#ifdef __UINT16_TYPE__
-typedef __UINT16_TYPE__ NU16;
-#else
-typedef unsigned short int NU16;
-#endif
-#ifdef __UINT32_TYPE__
-typedef __UINT32_TYPE__ NU32;
-#else
-typedef unsigned int NU32;
-#endif
-#ifdef __UINT64_TYPE__
-typedef __UINT64_TYPE__ NU64;
-#else
-typedef unsigned long long int NU64;
-#endif
-#endif
-
-#ifdef NIM_INTBITS
-#  if NIM_INTBITS == 64
-typedef NI64 NI;
-typedef NU64 NU;
-#  elif NIM_INTBITS == 32
-typedef NI32 NI;
-typedef NU32 NU;
-#  elif NIM_INTBITS == 16
-typedef NI16 NI;
-typedef NU16 NU;
-#  elif NIM_INTBITS == 8
-typedef NI8 NI;
-typedef NU8 NU;
-#  else
-#    error "invalid bit width for int"
-#  endif
-#endif
-
-#define NIM_STRLIT_FLAG ((NU)(1) << ((NIM_INTBITS) - 2)) /* This has to be the same as system.strlitFlag! */
-
-#define nimAddInt64(a, b, L) ({long long int res; if(__builtin_saddll_overflow(a, b, &res)) goto L; res})
-#define nimSubInt64(a, b, L) ({long long int res; if(__builtin_ssubll_overflow(a, b, &res)) goto L; res})
-#define nimMulInt64(a, b, L) ({long long int res; if(__builtin_smulll_overflow(a, b, &res)) goto L; res})
-
-#define nimAddInt32(a, b, L) ({long int res; if(__builtin_sadd_overflow(a, b, &res)) goto L; res})
-#define nimSubInt32(a, b, L) ({long int res; if(__builtin_ssub_overflow(a, b, &res)) goto L; res})
-#define nimMulInt32(a, b, L) ({long int res; if(__builtin_smul_overflow(a, b, &res)) goto L; res})
-
-#define nimCheckRange(x, a, b, L) ({if (x < a || x > b) goto L; x})
-#define nimCheckIndex(x, a, L) ({if (x >= a) goto L; x})
-
-"""
-
-proc traverseCode(c: var GeneratedCode) =
-  const AllowedInToplevelC = {SummonConst, SummonGlobal, SummonThreadLocal,
-                              ProcDecl, ForeignDecl, ForeignProcDecl}
-  var i = NodePos(0)
-  while i.int < c.m.code.len:
-    let oldLen = c.code.len
-    let moveToInitSection = c.m.code[NodePos(i)].kind notin AllowedInToplevelC
-
-    gen c, c.m.code, NodePos(i)
-    next c.m.code, i
-
-    if moveToInitSection:
-      for i in oldLen ..< c.code.len:
-        c.init.add c.code[i]
-      setLen c.code, oldLen
-
-proc generateCode*(inp, outp: string) =
-  var c = initGeneratedCode(load(inp))
-
-  var co = TypeOrder()
-  traverseTypes(c.m.types, c.m.lit, co)
-
-  generateTypes(c, c.m.types, c.m.lit, co)
-  let typeDecls = move c.code
-
-  traverseCode c
-  var f = CppFile(f: open(outp, fmWrite))
-  f.write "#define NIM_INTBITS " & $c.m.intbits & "\n"
-  f.write Prelude
-  writeTokenSeq f, c.includes, c
-  writeTokenSeq f, typeDecls, c
-  writeTokenSeq f, c.data, c
-  writeTokenSeq f, c.protos, c
-  writeTokenSeq f, c.code, c
-  if c.init.len > 0:
-    f.write "void __attribute__((constructor)) init(void) {"
-    writeTokenSeq f, c.init, c
-    f.write "}\n\n"
-  f.f.close
diff --git a/compiler/nir/nir.nim b/compiler/nir/nir.nim
deleted file mode 100644
index 6f7077fb0..000000000
--- a/compiler/nir/nir.nim
+++ /dev/null
@@ -1,105 +0,0 @@
-#
-#
-#           The Nim Compiler
-#        (c) Copyright 2023 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## Nim Intermediate Representation, designed to capture all of Nim's semantics without losing too much
-## precious information. Can easily be translated into C. And to JavaScript, hopefully.
-
-from std/os import addFileExt, `/`, createDir
-
-import std / assertions
-import ".." / [ast, modulegraphs, renderer, transf, options, msgs, lineinfos]
-import nirtypes, nirinsts, ast2ir, nirlineinfos, nirfiles, nirvm
-
-import ".." / ic / [rodfiles, bitabs]
-
-type
-  PCtx* = ref object of TPassContext
-    m: ModuleCon
-    c: ProcCon
-    oldErrorCount: int
-    bytecode: Bytecode
-
-proc newCtx*(module: PSym; g: ModuleGraph; idgen: IdGenerator): PCtx =
-  var lit = Literals()
-  var nirm = (ref NirModule)(types: initTypeGraph(lit), lit: lit)
-  var m = initModuleCon(g, g.config, idgen, module, nirm)
-  m.noModularity = true
-  PCtx(m: m, c: initProcCon(m, nil, g.config), idgen: idgen, bytecode: initBytecode(nirm))
-
-proc refresh*(c: PCtx; module: PSym; idgen: IdGenerator) =
-  #c.m = initModuleCon(c.m.graph, c.m.graph.config, idgen, module, c.m.nirm)
-  #c.m.noModularity = true
-  c.c = initProcCon(c.m, nil, c.m.graph.config)
-  c.idgen = idgen
-
-proc setupGlobalCtx*(module: PSym; graph: ModuleGraph; idgen: IdGenerator) =
-  if graph.repl.isNil:
-    graph.repl = newCtx(module, graph, idgen)
-    #registerAdditionalOps(PCtx graph.repl)
-  else:
-    refresh(PCtx graph.repl, module, idgen)
-
-proc setupNirReplGen*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
-  setupGlobalCtx(module, graph, idgen)
-  result = PCtx graph.repl
-
-proc evalStmt(c: PCtx; n: PNode) =
-  let n = transformExpr(c.m.graph, c.idgen, c.m.module, n)
-  let pc = genStmt(c.c, n)
-  #var res = ""
-  #toString c.m.nirm.code, NodePos(pc), c.m.nirm.lit.strings, c.m.nirm.lit.numbers, c.m.symnames, res
-  #res.add "\n--------------------------\n"
-  #toString res, c.m.types.g
-  if pc.int < c.m.nirm.code.len:
-    c.bytecode.interactive = c.m.graph.interactive
-    execCode c.bytecode, c.m.nirm.code, pc
-  #echo res
-
-proc runCode*(c: PPassContext; n: PNode): PNode =
-  let c = PCtx(c)
-  # don't eval errornous code:
-  if c.oldErrorCount == c.m.graph.config.errorCounter:
-    evalStmt(c, n)
-    result = newNodeI(nkEmpty, n.info)
-  else:
-    result = n
-  c.oldErrorCount = c.m.graph.config.errorCounter
-
-type
-  NirPassContext* = ref object of TPassContext
-    m: ModuleCon
-    c: ProcCon
-
-proc openNirBackend*(g: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
-  var lit = Literals()
-  var nirm = (ref NirModule)(types: initTypeGraph(lit), lit: lit)
-  let m = initModuleCon(g, g.config, idgen, module, nirm)
-  NirPassContext(m: m, c: initProcCon(m, nil, g.config), idgen: idgen)
-
-proc gen(c: NirPassContext; n: PNode) =
-  let n = transformExpr(c.m.graph, c.idgen, c.m.module, n)
-  let pc = genStmt(c.c, n)
-
-proc nirBackend*(c: PPassContext; n: PNode): PNode =
-  gen(NirPassContext(c), n)
-  result = n
-
-proc closeNirBackend*(c: PPassContext; finalNode: PNode) =
-  discard nirBackend(c, finalNode)
-
-  let c = NirPassContext(c)
-  let nimcache = getNimcacheDir(c.c.config).string
-  createDir nimcache
-  let outp = nimcache / c.m.module.name.s.addFileExt("nir")
-  #c.m.nirm.code = move c.c.code
-  try:
-    store c.m.nirm[], outp
-    echo "created: ", outp
-  except IOError:
-    rawMessage(c.c.config, errFatal, "serialization failed: " & outp)
diff --git a/compiler/nir/nirc.nim b/compiler/nir/nirc.nim
deleted file mode 100644
index a2cf69988..000000000
--- a/compiler/nir/nirc.nim
+++ /dev/null
@@ -1,52 +0,0 @@
-#
-#
-#           The Nim Compiler
-#        (c) Copyright 2023 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## Nir Compiler.
-
-import ".." / ic / [bitabs, rodfiles]
-import nirinsts, nirtypes, nirlineinfos, nirfiles, cir
-
-proc view(filename: string) =
-  let m = load(filename)
-  var res = ""
-  allTreesToString m.code, m.lit.strings, m.lit.numbers, m.symnames, res
-  res.add "\n# TYPES\n"
-  nirtypes.toString res, m.types
-  echo res
-
-import std / [syncio, parseopt]
-
-proc writeHelp =
-  echo """Usage: nirc view|c <file.nir>"""
-  quit 0
-
-proc main =
-  var inp = ""
-  var cmd = ""
-  for kind, key, val in getopt():
-    case kind
-    of cmdArgument:
-      if cmd.len == 0: cmd = key
-      elif inp.len == 0: inp = key
-      else: quit "Error: too many arguments"
-    of cmdLongOption, cmdShortOption:
-      case key
-      of "help", "h": writeHelp()
-      of "version", "v": stdout.write "1.0\n"
-    of cmdEnd: discard
-  if inp.len == 0:
-    quit "Error: no input file specified"
-  case cmd
-  of "", "view":
-    view inp
-  of "c":
-    let outp = inp & ".c"
-    cir.generateCode inp, outp
-
-main()
diff --git a/compiler/nir/nirfiles.nim b/compiler/nir/nirfiles.nim
deleted file mode 100644
index cd5a79f06..000000000
--- a/compiler/nir/nirfiles.nim
+++ /dev/null
@@ -1,83 +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 ".." / ic / [bitabs, rodfiles]
-import nirinsts, nirtypes, nirlineinfos
-
-type
-  NirModule* = object
-    code*: Tree
-    man*: LineInfoManager
-    types*: TypeGraph
-    lit*: Literals
-    namespace*: LitId
-    intbits*: uint32
-    symnames*: SymNames
-
-proc load*(filename: string): NirModule =
-  let lit = Literals()
-  result = NirModule(lit: lit, types: initTypeGraph(lit))
-  var r = rodfiles.open(filename)
-  try:
-    r.loadHeader(nirCookie)
-    r.loadSection stringsSection
-    r.load result.lit.strings
-
-    r.loadSection numbersSection
-    r.load result.lit.numbers
-
-    r.loadSection bodiesSection
-    r.load result.code
-
-    r.loadSection typesSection
-    r.load result.types
-
-    r.loadSection sideChannelSection
-    r.load result.man
-
-    r.loadSection namespaceSection
-    r.loadPrim result.namespace
-    r.loadPrim result.intbits
-
-    r.loadSection symnamesSection
-    r.load result.symnames
-
-  finally:
-    r.close()
-
-proc store*(m: NirModule; outp: string) =
-  var r = rodfiles.create(outp)
-  try:
-    r.storeHeader(nirCookie)
-    r.storeSection stringsSection
-    r.store m.lit.strings
-
-    r.storeSection numbersSection
-    r.store m.lit.numbers
-
-    r.storeSection bodiesSection
-    r.store m.code
-
-    r.storeSection typesSection
-    r.store m.types
-
-    r.storeSection sideChannelSection
-    r.store m.man
-
-    r.storeSection namespaceSection
-    r.storePrim m.namespace
-    r.storePrim m.intbits
-
-    r.storeSection symnamesSection
-    r.store m.symnames
-
-  finally:
-    r.close()
-  if r.err != ok:
-    raise newException(IOError, "could store into: " & outp)
diff --git a/compiler/nir/nirinsts.nim b/compiler/nir/nirinsts.nim
deleted file mode 100644
index 6cffc1a89..000000000
--- a/compiler/nir/nirinsts.nim
+++ /dev/null
@@ -1,582 +0,0 @@
-#
-#
-#           The Nim Compiler
-#        (c) Copyright 2023 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## NIR instructions. Somewhat inspired by LLVM's instructions.
-
-import std / [assertions, hashes]
-import .. / ic / [bitabs, rodfiles]
-import nirlineinfos, nirtypes
-
-const
-  NirVersion = 1
-  nirCookie* = [byte(0), byte('N'), byte('I'), byte('R'),
-            byte(sizeof(int)*8), byte(system.cpuEndian), byte(0), byte(NirVersion)]
-
-type
-  SymId* = distinct int
-
-proc `$`*(s: SymId): string {.borrow.}
-proc hash*(s: SymId): Hash {.borrow.}
-proc `==`*(a, b: SymId): bool {.borrow.}
-
-type
-  Opcode* = enum
-    Nop,
-    ImmediateVal,
-    IntVal,
-    StrVal,
-    SymDef,
-    SymUse,
-    Typed,   # with type ID
-    PragmaId, # with Pragma ID, possible values: see PragmaKey enum
-    NilVal,
-    Label,
-    Goto,
-    CheckedGoto,
-    LoopLabel,
-    GotoLoop,  # last atom
-
-    ModuleSymUse, # `"module".x`
-
-    ArrayConstr,
-    ObjConstr,
-    Ret,
-    Yld,
-
-    Select,
-    SelectPair,  # ((values...), Label)
-    SelectList,  # (values...)
-    SelectValue, # (value)
-    SelectRange, # (valueA..valueB)
-    ForeignDecl, # Can wrap SummonGlobal, SummonThreadLocal, SummonConst
-    SummonGlobal,
-    SummonThreadLocal,
-    Summon, # x = Summon Typed <Type ID>; x begins to live
-    SummonResult,
-    SummonParam,
-    SummonConst,
-    Kill, # `Kill x`: scope end for `x`
-
-    AddrOf,
-    ArrayAt, # a[i]
-    DerefArrayAt, # a[i] where `a` is a PtrArray; `a[][i]`
-    FieldAt, # obj.field
-    DerefFieldAt, # obj[].field
-
-    Load, # a[]
-    Store, # a[] = b
-    Asgn,  # a = b
-    SetExc,
-    TestExc,
-
-    CheckedRange,
-    CheckedIndex,
-
-    Call,
-    IndirectCall,
-    CheckedCall, # call that can raise
-    CheckedIndirectCall, # call that can raise
-    CheckedAdd, # with overflow checking etc.
-    CheckedSub,
-    CheckedMul,
-    CheckedDiv,
-    CheckedMod,
-    Add,
-    Sub,
-    Mul,
-    Div,
-    Mod,
-    BitShl,
-    BitShr,
-    BitAnd,
-    BitOr,
-    BitXor,
-    BitNot,
-    BoolNot,
-    Eq,
-    Le,
-    Lt,
-    Cast,
-    NumberConv,
-    CheckedObjConv,
-    ObjConv,
-    TestOf,
-    Emit,
-    ProcDecl,
-    ForeignProcDecl,
-    PragmaPair
-
-type
-  PragmaKey* = enum
-    FastCall, StdCall, CDeclCall, SafeCall, SysCall, InlineCall, NoinlineCall, ThisCall, NoCall,
-    CoreName,
-    ExternName,
-    HeaderImport,
-    DllImport,
-    DllExport,
-    ObjExport
-
-const
-  LastAtomicValue = GotoLoop
-
-  OpcodeBits = 8'u32
-  OpcodeMask = (1'u32 shl OpcodeBits) - 1'u32
-
-  ValueProducingAtoms = {ImmediateVal, IntVal, StrVal, SymUse, NilVal}
-
-  ValueProducing* = {
-    ImmediateVal,
-    IntVal,
-    StrVal,
-    SymUse,
-    NilVal,
-    ModuleSymUse,
-    ArrayConstr,
-    ObjConstr,
-    CheckedAdd,
-    CheckedSub,
-    CheckedMul,
-    CheckedDiv,
-    CheckedMod,
-    Add,
-    Sub,
-    Mul,
-    Div,
-    Mod,
-    BitShl,
-    BitShr,
-    BitAnd,
-    BitOr,
-    BitXor,
-    BitNot,
-    BoolNot,
-    Eq,
-    Le,
-    Lt,
-    Cast,
-    NumberConv,
-    CheckedObjConv,
-    ObjConv,
-    AddrOf,
-    Load,
-    ArrayAt,
-    DerefArrayAt,
-    FieldAt,
-    DerefFieldAt,
-    TestOf
-  }
-
-type
-  Instr* = object     # 8 bytes
-    x: uint32
-    info*: PackedLineInfo
-
-template kind*(n: Instr): Opcode = Opcode(n.x and OpcodeMask)
-template operand(n: Instr): uint32 = (n.x shr OpcodeBits)
-
-template rawOperand*(n: Instr): uint32 = (n.x shr OpcodeBits)
-
-template toX(k: Opcode; operand: uint32): uint32 =
-  uint32(k) or (operand shl OpcodeBits)
-
-template toX(k: Opcode; operand: LitId): uint32 =
-  uint32(k) or (operand.uint32 shl OpcodeBits)
-
-type
-  Tree* = object
-    nodes: seq[Instr]
-
-  Values* = object
-    numbers: BiTable[int64]
-    strings: BiTable[string]
-
-type
-  PatchPos* = distinct int
-  NodePos* = distinct int
-
-const
-  InvalidPatchPos* = PatchPos(-1)
-
-proc isValid(p: PatchPos): bool {.inline.} = p.int != -1
-
-proc prepare*(tree: var Tree; info: PackedLineInfo; kind: Opcode): PatchPos =
-  result = PatchPos tree.nodes.len
-  tree.nodes.add Instr(x: toX(kind, 1'u32), info: info)
-
-proc isAtom(tree: Tree; pos: int): bool {.inline.} = tree.nodes[pos].kind <= LastAtomicValue
-proc isAtom(tree: Tree; pos: NodePos): bool {.inline.} = tree.nodes[pos.int].kind <= LastAtomicValue
-
-proc patch*(tree: var Tree; pos: PatchPos) =
-  let pos = pos.int
-  let k = tree.nodes[pos].kind
-  assert k > LastAtomicValue
-  let distance = int32(tree.nodes.len - pos)
-  assert distance > 0
-  tree.nodes[pos].x = toX(k, cast[uint32](distance))
-
-template build*(tree: var Tree; info: PackedLineInfo; kind: Opcode; body: untyped) =
-  let pos = prepare(tree, info, kind)
-  body
-  patch(tree, pos)
-
-template buildTyped*(tree: var Tree; info: PackedLineInfo; kind: Opcode; typ: TypeId; body: untyped) =
-  let pos = prepare(tree, info, kind)
-  tree.addTyped info, typ
-  body
-  patch(tree, pos)
-
-proc len*(tree: Tree): int {.inline.} = tree.nodes.len
-
-template rawSpan(n: Instr): int = int(operand(n))
-
-proc nextChild(tree: Tree; pos: var int) {.inline.} =
-  if tree.nodes[pos].kind > LastAtomicValue:
-    assert tree.nodes[pos].operand > 0'u32
-    inc pos, tree.nodes[pos].rawSpan
-  else:
-    inc pos
-
-proc next*(tree: Tree; pos: var NodePos) {.inline.} = nextChild tree, int(pos)
-
-template firstSon*(n: NodePos): NodePos = NodePos(n.int+1)
-
-template skipTyped*(n: NodePos): NodePos = NodePos(n.int+2)
-
-iterator sons*(tree: Tree; n: NodePos): NodePos =
-  var pos = n.int
-  assert tree.nodes[pos].kind > LastAtomicValue
-  let last = pos + tree.nodes[pos].rawSpan
-  inc pos
-  while pos < last:
-    yield NodePos pos
-    nextChild tree, pos
-
-iterator sonsFrom1*(tree: Tree; n: NodePos): NodePos =
-  var pos = n.int
-  assert tree.nodes[pos].kind > LastAtomicValue
-  let last = pos + tree.nodes[pos].rawSpan
-  inc pos
-  nextChild tree, pos
-  while pos < last:
-    yield NodePos pos
-    nextChild tree, pos
-
-iterator sonsFromN*(tree: Tree; n: NodePos; toSkip = 2): NodePos =
-  var pos = n.int
-  assert tree.nodes[pos].kind > LastAtomicValue
-  let last = pos + tree.nodes[pos].rawSpan
-  inc pos
-  for i in 1..toSkip:
-    nextChild tree, pos
-  while pos < last:
-    yield NodePos pos
-    nextChild tree, pos
-
-template `[]`*(t: Tree; n: NodePos): Instr = t.nodes[n.int]
-
-iterator sonsRest*(tree: Tree; parent, n: NodePos): NodePos =
-  var pos = n.int
-  assert tree[parent].kind > LastAtomicValue
-  let last = parent.int + tree[parent].rawSpan
-  while pos < last:
-    yield NodePos pos
-    nextChild tree, pos
-
-proc span(tree: Tree; pos: int): int {.inline.} =
-  if tree.nodes[pos].kind <= LastAtomicValue: 1 else: int(tree.nodes[pos].operand)
-
-proc copyTree*(dest: var Tree; src: Tree) =
-  let pos = 0
-  let L = span(src, pos)
-  let d = dest.nodes.len
-  dest.nodes.setLen(d + L)
-  assert L > 0
-  for i in 0..<L:
-    dest.nodes[d+i] = src.nodes[pos+i]
-
-proc sons2*(tree: Tree; n: NodePos): (NodePos, NodePos) {.inline.} =
-  assert(not isAtom(tree, n.int))
-  let a = n.int+1
-  let b = a + span(tree, a)
-  result = (NodePos a, NodePos b)
-
-proc sons3*(tree: Tree; n: NodePos): (NodePos, NodePos, NodePos) {.inline.} =
-  assert(not isAtom(tree, n.int))
-  let a = n.int+1
-  let b = a + span(tree, a)
-  let c = b + span(tree, b)
-  result = (NodePos a, NodePos b, NodePos c)
-
-proc sons4*(tree: Tree; n: NodePos): (NodePos, NodePos, NodePos, NodePos) {.inline.} =
-  assert(not isAtom(tree, n.int))
-  let a = n.int+1
-  let b = a + span(tree, a)
-  let c = b + span(tree, b)
-  let d = c + span(tree, c)
-  result = (NodePos a, NodePos b, NodePos c, NodePos d)
-
-proc sons5*(tree: Tree; n: NodePos): (NodePos, NodePos, NodePos, NodePos, NodePos) {.inline.} =
-  assert(not isAtom(tree, n.int))
-  let a = n.int+1
-  let b = a + span(tree, a)
-  let c = b + span(tree, b)
-  let d = c + span(tree, c)
-  let e = d + span(tree, d)
-  result = (NodePos a, NodePos b, NodePos c, NodePos d, NodePos e)
-
-proc typeId*(ins: Instr): TypeId {.inline.} =
-  assert ins.kind == Typed
-  result = TypeId(ins.operand)
-
-proc symId*(ins: Instr): SymId {.inline.} =
-  assert ins.kind in {SymUse, SymDef}
-  result = SymId(ins.operand)
-
-proc immediateVal*(ins: Instr): int {.inline.} =
-  assert ins.kind == ImmediateVal
-  result = cast[int](ins.operand)
-
-proc litId*(ins: Instr): LitId {.inline.} =
-  assert ins.kind in {StrVal, IntVal}
-  result = LitId(ins.operand)
-
-
-type
-  LabelId* = distinct int
-
-proc `==`*(a, b: LabelId): bool {.borrow.}
-proc hash*(a: LabelId): Hash {.borrow.}
-
-proc label*(ins: Instr): LabelId {.inline.} =
-  assert ins.kind in {Label, LoopLabel, Goto, GotoLoop, CheckedGoto}
-  result = LabelId(ins.operand)
-
-proc newLabel*(labelGen: var int): LabelId {.inline.} =
-  result = LabelId labelGen
-  inc labelGen
-
-proc newLabels*(labelGen: var int; n: int): LabelId {.inline.} =
-  result = LabelId labelGen
-  inc labelGen, n
-
-proc addNewLabel*(t: var Tree; labelGen: var int; info: PackedLineInfo; k: Opcode): LabelId =
-  assert k in {Label, LoopLabel}
-  result = LabelId labelGen
-  t.nodes.add Instr(x: toX(k, uint32(result)), info: info)
-  inc labelGen
-
-proc gotoLabel*(t: var Tree; info: PackedLineInfo; k: Opcode; L: LabelId) =
-  assert k in {Goto, GotoLoop, CheckedGoto}
-  t.nodes.add Instr(x: toX(k, uint32(L)), info: info)
-
-proc addLabel*(t: var Tree; info: PackedLineInfo; k: Opcode; L: LabelId) {.inline.} =
-  assert k in {Label, LoopLabel, Goto, GotoLoop, CheckedGoto}
-  t.nodes.add Instr(x: toX(k, uint32(L)), info: info)
-
-proc addSymUse*(t: var Tree; info: PackedLineInfo; s: SymId) {.inline.} =
-  t.nodes.add Instr(x: toX(SymUse, uint32(s)), info: info)
-
-proc addSymDef*(t: var Tree; info: PackedLineInfo; s: SymId) {.inline.} =
-  t.nodes.add Instr(x: toX(SymDef, uint32(s)), info: info)
-
-proc addNop*(t: var Tree; info: PackedLineInfo) {.inline.} =
-  t.nodes.add Instr(x: toX(Nop, 0'u32), info: info)
-
-proc addTyped*(t: var Tree; info: PackedLineInfo; typ: TypeId) {.inline.} =
-  assert typ.int >= 0
-  t.nodes.add Instr(x: toX(Typed, uint32(typ)), info: info)
-
-proc addSummon*(t: var Tree; info: PackedLineInfo; s: SymId; typ: TypeId; opc = Summon) {.inline.} =
-  assert typ.int >= 0
-  assert opc in {Summon, SummonConst, SummonGlobal, SummonThreadLocal, SummonParam, SummonResult}
-  let x = prepare(t, info, opc)
-  t.nodes.add Instr(x: toX(Typed, uint32(typ)), info: info)
-  t.nodes.add Instr(x: toX(SymDef, uint32(s)), info: info)
-  patch t, x
-
-proc addImmediateVal*(t: var Tree; info: PackedLineInfo; x: int) =
-  assert x >= 0 and x < ((1 shl 32) - OpcodeBits.int)
-  t.nodes.add Instr(x: toX(ImmediateVal, uint32(x)), info: info)
-
-proc addPragmaId*(t: var Tree; info: PackedLineInfo; x: PragmaKey) =
-  t.nodes.add Instr(x: toX(PragmaId, uint32(x)), info: info)
-
-proc addIntVal*(t: var Tree; integers: var BiTable[int64]; info: PackedLineInfo; typ: TypeId; x: int64) =
-  buildTyped t, info, NumberConv, typ:
-    t.nodes.add Instr(x: toX(IntVal, uint32(integers.getOrIncl(x))), info: info)
-
-proc boolVal*(t: var Tree; integers: var BiTable[int64]; info: PackedLineInfo; b: bool) =
-  buildTyped t, info, NumberConv, Bool8Id:
-    t.nodes.add Instr(x: toX(IntVal, uint32(integers.getOrIncl(ord b))), info: info)
-
-proc addStrVal*(t: var Tree; strings: var BiTable[string]; info: PackedLineInfo; s: string) =
-  t.nodes.add Instr(x: toX(StrVal, uint32(strings.getOrIncl(s))), info: info)
-
-proc addStrLit*(t: var Tree; info: PackedLineInfo; s: LitId) =
-  t.nodes.add Instr(x: toX(StrVal, uint32(s)), info: info)
-
-proc addNilVal*(t: var Tree; info: PackedLineInfo; typ: TypeId) =
-  buildTyped t, info, NumberConv, typ:
-    t.nodes.add Instr(x: toX(NilVal, uint32(0)), info: info)
-
-proc store*(r: var RodFile; t: Tree) = storeSeq r, t.nodes
-proc load*(r: var RodFile; t: var Tree) = loadSeq r, t.nodes
-
-proc escapeToNimLit*(s: string; result: var string) =
-  result.add '"'
-  for c in items s:
-    if c < ' ' or int(c) >= 128:
-      result.add '\\'
-      result.addInt int(c)
-    elif c == '\\':
-      result.add r"\\"
-    elif c == '\n':
-      result.add r"\n"
-    elif c == '\r':
-      result.add r"\r"
-    elif c == '\t':
-      result.add r"\t"
-    else:
-      result.add c
-  result.add '"'
-
-type
-  SymNames* = object
-    s: seq[LitId]
-
-proc `[]=`*(t: var SymNames; key: SymId; val: LitId) =
-  let k = int(key)
-  if k >= t.s.len: t.s.setLen k+1
-  t.s[k] = val
-
-proc `[]`*(t: SymNames; key: SymId): LitId =
-  let k = int(key)
-  if k < t.s.len: result = t.s[k]
-  else: result = LitId(0)
-
-template localName(s: SymId): string =
-  let name = names[s]
-  if name != LitId(0):
-    strings[name]
-  else:
-    $s.int
-
-proc store*(r: var RodFile; t: SymNames) = storeSeq(r, t.s)
-proc load*(r: var RodFile; t: var SymNames) = loadSeq(r, t.s)
-
-proc toString*(t: Tree; pos: NodePos; strings: BiTable[string]; integers: BiTable[int64];
-               names: SymNames;
-               r: var string; nesting = 0) =
-  if r.len > 0 and r[r.len-1] notin {' ', '\n', '(', '[', '{'}:
-    r.add ' '
-
-  case t[pos].kind
-  of Nop: r.add "Nop"
-  of ImmediateVal:
-    r.add $t[pos].operand
-  of IntVal:
-    r.add "IntVal "
-    r.add $integers[LitId t[pos].operand]
-  of StrVal:
-    escapeToNimLit(strings[LitId t[pos].operand], r)
-  of SymDef:
-    r.add "SymDef "
-    r.add localName(SymId t[pos].operand)
-  of SymUse:
-    r.add "SymUse "
-    r.add localName(SymId t[pos].operand)
-  of PragmaId:
-    r.add $cast[PragmaKey](t[pos].operand)
-  of Typed:
-    r.add "T<"
-    r.add $t[pos].operand
-    r.add ">"
-  of NilVal:
-    r.add "NilVal"
-  of Label:
-    # undo the nesting:
-    var spaces = r.len-1
-    while spaces >= 0 and r[spaces] == ' ': dec spaces
-    r.setLen spaces+1
-    r.add "\n  L"
-    r.add $t[pos].operand
-  of Goto, CheckedGoto, LoopLabel, GotoLoop:
-    r.add $t[pos].kind
-    r.add " L"
-    r.add $t[pos].operand
-  else:
-    r.add $t[pos].kind
-    r.add "{\n"
-    for i in 0..<(nesting+1)*2: r.add ' '
-    for p in sons(t, pos):
-      toString t, p, strings, integers, names, r, nesting+1
-    r.add "\n"
-    for i in 0..<nesting*2: r.add ' '
-    r.add "}"
-
-proc allTreesToString*(t: Tree; strings: BiTable[string]; integers: BiTable[int64];
-                       names: SymNames;
-                       r: var string) =
-  var i = 0
-  while i < t.len:
-    toString t, NodePos(i), strings, integers, names, r
-    nextChild t, i
-
-type
-  Value* = distinct Tree
-
-proc prepare*(dest: var Value; info: PackedLineInfo; k: Opcode): PatchPos {.inline.} =
-  assert k in ValueProducing - ValueProducingAtoms
-  result = prepare(Tree(dest), info, k)
-
-proc patch*(dest: var Value; pos: PatchPos) {.inline.} =
-  patch(Tree(dest), pos)
-
-proc localToValue*(info: PackedLineInfo; s: SymId): Value =
-  result = Value(Tree())
-  Tree(result).addSymUse info, s
-
-proc hasValue*(v: Value): bool {.inline.} = Tree(v).len > 0
-
-proc isEmpty*(v: Value): bool {.inline.} = Tree(v).len == 0
-
-proc extractTemp*(v: Value): SymId =
-  if hasValue(v) and Tree(v)[NodePos 0].kind == SymUse:
-    result = SymId(Tree(v)[NodePos 0].operand)
-  else:
-    result = SymId(-1)
-
-proc copyTree*(dest: var Tree; src: Value) = copyTree dest, Tree(src)
-
-proc addImmediateVal*(t: var Value; info: PackedLineInfo; x: int) =
-  assert x >= 0 and x < ((1 shl 32) - OpcodeBits.int)
-  Tree(t).nodes.add Instr(x: toX(ImmediateVal, uint32(x)), info: info)
-
-template build*(tree: var Value; info: PackedLineInfo; kind: Opcode; body: untyped) =
-  let pos = prepare(Tree(tree), info, kind)
-  body
-  patch(tree, pos)
-
-proc addTyped*(t: var Value; info: PackedLineInfo; typ: TypeId) {.inline.} =
-  addTyped(Tree(t), info, typ)
-
-template buildTyped*(tree: var Value; info: PackedLineInfo; kind: Opcode; typ: TypeId; body: untyped) =
-  let pos = prepare(tree, info, kind)
-  tree.addTyped info, typ
-  body
-  patch(tree, pos)
-
-proc addStrVal*(t: var Value; strings: var BiTable[string]; info: PackedLineInfo; s: string) =
-  addStrVal(Tree(t), strings, info, s)
-
-proc addNilVal*(t: var Value; info: PackedLineInfo; typ: TypeId) =
-  addNilVal Tree(t), info, typ
-
-proc addIntVal*(t: var Value; integers: var BiTable[int64]; info: PackedLineInfo; typ: TypeId; x: int64) =
-  addIntVal Tree(t), integers, info, typ, x
diff --git a/compiler/nir/nirslots.nim b/compiler/nir/nirslots.nim
deleted file mode 100644
index a01e7a633..000000000
--- a/compiler/nir/nirslots.nim
+++ /dev/null
@@ -1,104 +0,0 @@
-#
-#
-#           The Nim Compiler
-#        (c) Copyright 2023 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## Management of slots. Similar to "register allocation"
-## in lower level languages.
-
-import std / [assertions, tables]
-import nirtypes, nirinsts
-
-type
-  SlotManagerFlag* = enum
-    ReuseTemps,
-    ReuseVars
-  SlotKind* = enum
-    Temp, Perm
-  SlotManager* = object # "register allocator"
-    live: Table[SymId, (SlotKind, TypeId)]
-    dead: Table[TypeId, seq[SymId]]
-    flags: set[SlotManagerFlag]
-    inScope: seq[SymId]
-
-proc initSlotManager*(flags: set[SlotManagerFlag]): SlotManager {.inline.} =
-  SlotManager(flags: flags)
-
-proc allocRaw(m: var SlotManager; t: TypeId; f: SlotManagerFlag; k: SlotKind;
-              symIdgen: var int32): SymId {.inline.} =
-  if f in m.flags and m.dead.hasKey(t) and m.dead[t].len > 0:
-    result = m.dead[t].pop()
-  else:
-    inc symIdgen
-    result = SymId(symIdgen)
-    m.inScope.add result
-  m.live[result] = (k, t)
-
-proc allocTemp*(m: var SlotManager; t: TypeId; symIdgen: var int32): SymId {.inline.} =
-  result = allocRaw(m, t, ReuseTemps, Temp, symIdgen)
-
-proc allocVar*(m: var SlotManager; t: TypeId; symIdgen: var int32): SymId {.inline.} =
-  result = allocRaw(m, t, ReuseVars, Perm, symIdgen)
-
-proc freeLoc*(m: var SlotManager; s: SymId) =
-  let t = m.live.getOrDefault(s)
-  assert t[1].int != 0
-  m.live.del s
-  m.dead.mgetOrPut(t[1], @[]).add s
-
-proc freeTemp*(m: var SlotManager; s: SymId) =
-  let t = m.live.getOrDefault(s)
-  if t[1].int != 0 and t[0] == Temp:
-    m.live.del s
-    m.dead.mgetOrPut(t[1], @[]).add s
-
-iterator stillAlive*(m: SlotManager): (SymId, TypeId) =
-  for k, v in pairs(m.live):
-    yield (k, v[1])
-
-proc getType*(m: SlotManager; s: SymId): TypeId {.inline.} = m.live[s][1]
-
-proc openScope*(m: var SlotManager) =
-  m.inScope.add SymId(-1) # add marker
-
-proc closeScope*(m: var SlotManager) =
-  var i = m.inScope.len - 1
-  while i >= 0:
-    if m.inScope[i] == SymId(-1):
-      m.inScope.setLen i
-      break
-    dec i
-
-when isMainModule:
-  var symIdgen: int32
-  var m = initSlotManager({ReuseTemps})
-
-  var g = initTypeGraph(Literals())
-
-  let a = g.openType ArrayTy
-  g.addBuiltinType Int8Id
-  g.addArrayLen 5
-  let finalArrayType = finishType(g, a)
-
-  let obj = g.openType ObjectDecl
-  g.addName "MyType"
-
-  g.addField "p", finalArrayType, 0
-  let objB = finishType(g, obj)
-
-  let x = m.allocTemp(objB, symIdgen)
-  assert x.int == 0
-
-  let y = m.allocTemp(objB, symIdgen)
-  assert y.int == 1
-
-  let z = m.allocTemp(Int8Id, symIdgen)
-  assert z.int == 2
-
-  m.freeLoc y
-  let y2 = m.allocTemp(objB, symIdgen)
-  assert y2.int == 1
diff --git a/compiler/nir/nirtypes.nim b/compiler/nir/nirtypes.nim
deleted file mode 100644
index a79bf6d01..000000000
--- a/compiler/nir/nirtypes.nim
+++ /dev/null
@@ -1,475 +0,0 @@
-#
-#
-#           The Nim Compiler
-#        (c) Copyright 2023 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## Type system for NIR. Close to C's type system but without its quirks.
-
-import std / [assertions, hashes]
-import .. / ic / [bitabs, rodfiles]
-
-type
-  NirTypeKind* = enum
-    VoidTy, IntTy, UIntTy, FloatTy, BoolTy, CharTy, NameVal,
-    IntVal, SizeVal, AlignVal, OffsetVal,
-    AnnotationVal,
-    ObjectTy,
-    UnionTy,
-    VarargsTy, # the `...` in a C prototype; also the last "atom"
-    APtrTy, # pointer to aliasable memory
-    UPtrTy, # pointer to unique/unaliasable memory
-    AArrayPtrTy, # pointer to array of aliasable memory
-    UArrayPtrTy, # pointer to array of unique/unaliasable memory
-    ArrayTy,
-    LastArrayTy, # array of unspecified size as a last field inside an object
-    ProcTy,
-    ObjectDecl,
-    UnionDecl,
-    FieldDecl
-
-const
-  TypeKindBits = 8'u32
-  TypeKindMask = (1'u32 shl TypeKindBits) - 1'u32
-
-type
-  TypeNode* = object     # 4 bytes
-    x: uint32
-
-template kind*(n: TypeNode): NirTypeKind = NirTypeKind(n.x and TypeKindMask)
-template operand(n: TypeNode): uint32 = (n.x shr TypeKindBits)
-
-proc integralBits*(n: TypeNode): int {.inline.} =
-  # Number of bits in the IntTy, etc. Only valid for integral types.
-  assert n.kind in {IntTy, UIntTy, FloatTy, BoolTy, CharTy}
-  result = int(n.operand)
-
-template toX(k: NirTypeKind; operand: uint32): uint32 =
-  uint32(k) or (operand shl TypeKindBits)
-
-template toX(k: NirTypeKind; operand: LitId): uint32 =
-  uint32(k) or (operand.uint32 shl TypeKindBits)
-
-type
-  TypeId* = distinct int
-
-proc `==`*(a, b: TypeId): bool {.borrow.}
-proc hash*(a: TypeId): Hash {.borrow.}
-
-type
-  Literals* = ref object
-    strings*: BiTable[string]
-    numbers*: BiTable[int64]
-
-  TypeGraph* = object
-    nodes: seq[TypeNode]
-    lit: Literals
-
-const
-  VoidId* = TypeId 0
-  Bool8Id* = TypeId 1
-  Char8Id* = TypeId 2
-  Int8Id* = TypeId 3
-  Int16Id* = TypeId 4
-  Int32Id* = TypeId 5
-  Int64Id* = TypeId 6
-  UInt8Id* = TypeId 7
-  UInt16Id* = TypeId 8
-  UInt32Id* = TypeId 9
-  UInt64Id* = TypeId 10
-  Float32Id* = TypeId 11
-  Float64Id* = TypeId 12
-  VoidPtrId* = TypeId 13
-  LastBuiltinId* = 13
-
-proc initTypeGraph*(lit: Literals): TypeGraph =
-  result = TypeGraph(nodes: @[
-    TypeNode(x: toX(VoidTy, 0'u32)),
-    TypeNode(x: toX(BoolTy, 8'u32)),
-    TypeNode(x: toX(CharTy, 8'u32)),
-    TypeNode(x: toX(IntTy, 8'u32)),
-    TypeNode(x: toX(IntTy, 16'u32)),
-    TypeNode(x: toX(IntTy, 32'u32)),
-    TypeNode(x: toX(IntTy, 64'u32)),
-    TypeNode(x: toX(UIntTy, 8'u32)),
-    TypeNode(x: toX(UIntTy, 16'u32)),
-    TypeNode(x: toX(UIntTy, 32'u32)),
-    TypeNode(x: toX(UIntTy, 64'u32)),
-    TypeNode(x: toX(FloatTy, 32'u32)),
-    TypeNode(x: toX(FloatTy, 64'u32)),
-    TypeNode(x: toX(APtrTy, 2'u32)),
-    TypeNode(x: toX(VoidTy, 0'u32))
-  ], lit: lit)
-  assert result.nodes.len == LastBuiltinId+2
-
-type
-  TypePatchPos* = distinct int
-
-const
-  InvalidTypePatchPos* = TypePatchPos(-1)
-  LastAtomicValue = VarargsTy
-
-proc isValid(p: TypePatchPos): bool {.inline.} = p.int != -1
-
-proc prepare(tree: var TypeGraph; kind: NirTypeKind): TypePatchPos =
-  result = TypePatchPos tree.nodes.len
-  tree.nodes.add TypeNode(x: toX(kind, 1'u32))
-
-proc isAtom(tree: TypeGraph; pos: int): bool {.inline.} = tree.nodes[pos].kind <= LastAtomicValue
-proc isAtom(tree: TypeGraph; pos: TypeId): bool {.inline.} = tree.nodes[pos.int].kind <= LastAtomicValue
-
-proc patch(tree: var TypeGraph; pos: TypePatchPos) =
-  let pos = pos.int
-  let k = tree.nodes[pos].kind
-  assert k > LastAtomicValue
-  let distance = int32(tree.nodes.len - pos)
-  assert distance > 0
-  tree.nodes[pos].x = toX(k, cast[uint32](distance))
-
-proc len*(tree: TypeGraph): int {.inline.} = tree.nodes.len
-
-template rawSpan(n: TypeNode): int = int(operand(n))
-
-proc nextChild(tree: TypeGraph; pos: var int) {.inline.} =
-  if tree.nodes[pos].kind > LastAtomicValue:
-    assert tree.nodes[pos].operand > 0'u32
-    inc pos, tree.nodes[pos].rawSpan
-  else:
-    inc pos
-
-iterator sons*(tree: TypeGraph; n: TypeId): TypeId =
-  var pos = n.int
-  assert tree.nodes[pos].kind > LastAtomicValue
-  let last = pos + tree.nodes[pos].rawSpan
-  inc pos
-  while pos < last:
-    yield TypeId pos
-    nextChild tree, pos
-
-template `[]`*(t: TypeGraph; n: TypeId): TypeNode = t.nodes[n.int]
-
-proc elementType*(tree: TypeGraph; n: TypeId): TypeId {.inline.} =
-  assert tree[n].kind in {APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy, ArrayTy, LastArrayTy}
-  result = TypeId(n.int+1)
-
-proc litId*(n: TypeNode): LitId {.inline.} =
-  assert n.kind in {NameVal, IntVal, SizeVal, AlignVal, OffsetVal, AnnotationVal, ObjectTy, UnionTy}
-  result = LitId(n.operand)
-
-proc kind*(tree: TypeGraph; n: TypeId): NirTypeKind {.inline.} = tree[n].kind
-
-proc span(tree: TypeGraph; pos: int): int {.inline.} =
-  if tree.nodes[pos].kind <= LastAtomicValue: 1 else: int(tree.nodes[pos].operand)
-
-proc sons2(tree: TypeGraph; n: TypeId): (TypeId, TypeId) =
-  assert(not isAtom(tree, n.int))
-  let a = n.int+1
-  let b = a + span(tree, a)
-  result = (TypeId a, TypeId b)
-
-proc sons3(tree: TypeGraph; n: TypeId): (TypeId, TypeId, TypeId) =
-  assert(not isAtom(tree, n.int))
-  let a = n.int+1
-  let b = a + span(tree, a)
-  let c = b + span(tree, b)
-  result = (TypeId a, TypeId b, TypeId c)
-
-proc arrayName*(tree: TypeGraph; n: TypeId): TypeId {.inline.} =
-  assert tree[n].kind == ArrayTy
-  let (_, _, c) = sons3(tree, n)
-  result = c
-
-proc arrayLen*(tree: TypeGraph; n: TypeId): BiggestInt =
-  assert tree[n].kind == ArrayTy
-  let (_, b) = sons2(tree, n)
-  result = tree.lit.numbers[LitId tree[b].operand]
-
-proc returnType*(tree: TypeGraph; n: TypeId): (TypeId, TypeId) =
-  # Returns the positions of the return type + calling convention.
-  var pos = n.int
-  assert tree.nodes[pos].kind == ProcTy
-  let a = n.int+1
-  let b = a + span(tree, a)
-  result = (TypeId b, TypeId a) # not a typo, order is reversed
-
-iterator params*(tree: TypeGraph; n: TypeId): TypeId =
-  var pos = n.int
-  assert tree.nodes[pos].kind == ProcTy
-  let last = pos + tree.nodes[pos].rawSpan
-  inc pos
-  nextChild tree, pos
-  nextChild tree, pos
-  while pos < last:
-    yield TypeId pos
-    nextChild tree, pos
-
-proc openType*(tree: var TypeGraph; kind: NirTypeKind): TypePatchPos =
-  assert kind in {APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy,
-    ArrayTy, LastArrayTy, ProcTy, ObjectDecl, UnionDecl,
-    FieldDecl}
-  result = prepare(tree, kind)
-
-template typeInvariant(p: TypePatchPos) =
-  when false:
-    if tree[TypeId(p)].kind == FieldDecl:
-      var k = 0
-      for ch in sons(tree, TypeId(p)):
-        inc k
-      assert k > 2, "damn! " & $k
-
-proc sealType*(tree: var TypeGraph; p: TypePatchPos) =
-  patch tree, p
-  typeInvariant(p)
-
-proc finishType*(tree: var TypeGraph; p: TypePatchPos): TypeId =
-  # Search for an existing instance of this type in
-  # order to reduce memory consumption:
-  patch tree, p
-  typeInvariant(p)
-
-  let s = span(tree, p.int)
-  var i = 0
-  while i < p.int:
-    if tree.nodes[i].x == tree.nodes[p.int].x:
-      var isMatch = true
-      for j in 1..<s:
-        if tree.nodes[j+i].x == tree.nodes[j+p.int].x:
-          discard "still a match"
-        else:
-          isMatch = false
-          break
-      if isMatch:
-        if p.int+s == tree.len:
-          setLen tree.nodes, p.int
-        return TypeId(i)
-    nextChild tree, i
-  result = TypeId(p)
-
-proc nominalType*(tree: var TypeGraph; kind: NirTypeKind; name: string): TypeId =
-  assert kind in {ObjectTy, UnionTy}
-  let content = TypeNode(x: toX(kind, tree.lit.strings.getOrIncl(name)))
-  for i in 0..<tree.len:
-    if tree.nodes[i].x == content.x:
-      return TypeId(i)
-  result = TypeId tree.nodes.len
-  tree.nodes.add content
-
-proc addNominalType*(tree: var TypeGraph; kind: NirTypeKind; name: string) =
-  assert kind in {ObjectTy, UnionTy}
-  tree.nodes.add TypeNode(x: toX(kind, tree.lit.strings.getOrIncl(name)))
-
-proc getTypeTag*(tree: TypeGraph; t: TypeId): string =
-  assert tree[t].kind in {ObjectTy, UnionTy}
-  result = tree.lit.strings[LitId tree[t].operand]
-
-proc addVarargs*(tree: var TypeGraph) =
-  tree.nodes.add TypeNode(x: toX(VarargsTy, 0'u32))
-
-proc getFloat128Type*(tree: var TypeGraph): TypeId =
-  result = TypeId tree.nodes.len
-  tree.nodes.add TypeNode(x: toX(FloatTy, 128'u32))
-
-proc addBuiltinType*(g: var TypeGraph; id: TypeId) =
-  g.nodes.add g[id]
-
-template firstSon*(n: TypeId): TypeId = TypeId(n.int+1)
-
-proc addType*(g: var TypeGraph; t: TypeId) =
-  # We cannot simply copy `*Decl` nodes. We have to introduce `*Ty` nodes instead:
-  if g[t].kind in {ObjectDecl, UnionDecl}:
-    assert g[t.firstSon].kind == NameVal
-    let name = LitId g[t.firstSon].operand
-    if g[t].kind == ObjectDecl:
-      g.nodes.add TypeNode(x: toX(ObjectTy, name))
-    else:
-      g.nodes.add TypeNode(x: toX(UnionTy, name))
-  else:
-    let pos = t.int
-    let L = span(g, pos)
-    let d = g.nodes.len
-    g.nodes.setLen(d + L)
-    assert L > 0
-    for i in 0..<L:
-      g.nodes[d+i] = g.nodes[pos+i]
-
-proc addArrayLen*(g: var TypeGraph; len: int64) =
-  g.nodes.add TypeNode(x: toX(IntVal, g.lit.numbers.getOrIncl(len)))
-
-proc addSize*(g: var TypeGraph; s: int64) =
-  g.nodes.add TypeNode(x: toX(SizeVal, g.lit.numbers.getOrIncl(s)))
-
-proc addOffset*(g: var TypeGraph; offset: int64) =
-  g.nodes.add TypeNode(x: toX(OffsetVal, g.lit.numbers.getOrIncl(offset)))
-
-proc addAlign*(g: var TypeGraph; a: int64) =
-  g.nodes.add TypeNode(x: toX(AlignVal, g.lit.numbers.getOrIncl(a)))
-
-proc addName*(g: var TypeGraph; name: string) =
-  g.nodes.add TypeNode(x: toX(NameVal, g.lit.strings.getOrIncl(name)))
-
-proc addAnnotation*(g: var TypeGraph; name: string) =
-  g.nodes.add TypeNode(x: toX(NameVal, g.lit.strings.getOrIncl(name)))
-
-proc addField*(g: var TypeGraph; name: string; typ: TypeId; offset: int64) =
-  let f = g.openType FieldDecl
-  g.addType typ
-  g.addOffset offset
-  g.addName name
-  sealType(g, f)
-
-proc ptrTypeOf*(g: var TypeGraph; t: TypeId): TypeId =
-  let f = g.openType APtrTy
-  g.addType t
-  result = finishType(g, f)
-
-proc arrayPtrTypeOf*(g: var TypeGraph; t: TypeId): TypeId =
-  let f = g.openType AArrayPtrTy
-  g.addType t
-  result = finishType(g, f)
-
-proc store*(r: var RodFile; g: TypeGraph) =
-  storeSeq r, g.nodes
-
-proc load*(r: var RodFile; g: var TypeGraph) =
-  loadSeq r, g.nodes
-
-proc toString*(dest: var string; g: TypeGraph; i: TypeId) =
-  case g[i].kind
-  of VoidTy: dest.add "void"
-  of IntTy:
-    dest.add "i"
-    dest.addInt g[i].operand
-  of UIntTy:
-    dest.add "u"
-    dest.addInt g[i].operand
-  of FloatTy:
-    dest.add "f"
-    dest.addInt g[i].operand
-  of BoolTy:
-    dest.add "b"
-    dest.addInt g[i].operand
-  of CharTy:
-    dest.add "c"
-    dest.addInt g[i].operand
-  of NameVal, AnnotationVal:
-    dest.add g.lit.strings[LitId g[i].operand]
-  of IntVal, SizeVal, AlignVal, OffsetVal:
-    dest.add $g[i].kind
-    dest.add ' '
-    dest.add $g.lit.numbers[LitId g[i].operand]
-  of VarargsTy:
-    dest.add "..."
-  of APtrTy:
-    dest.add "aptr["
-    toString(dest, g, g.elementType(i))
-    dest.add "]"
-  of UPtrTy:
-    dest.add "uptr["
-    toString(dest, g, g.elementType(i))
-    dest.add "]"
-  of AArrayPtrTy:
-    dest.add "aArrayPtr["
-    toString(dest, g, g.elementType(i))
-    dest.add "]"
-  of UArrayPtrTy:
-    dest.add "uArrayPtr["
-    toString(dest, g, g.elementType(i))
-    dest.add "]"
-  of ArrayTy:
-    dest.add "Array["
-    let (elems, len, name) = g.sons3(i)
-    toString(dest, g, elems)
-    dest.add ", "
-    toString(dest, g, len)
-    dest.add ", "
-    toString(dest, g, name)
-    dest.add "]"
-  of LastArrayTy:
-    # array of unspecified size as a last field inside an object
-    dest.add "LastArrayTy["
-    toString(dest, g, g.elementType(i))
-    dest.add "]"
-  of ObjectTy:
-    dest.add "object "
-    dest.add g.lit.strings[LitId g[i].operand]
-  of UnionTy:
-    dest.add "union "
-    dest.add g.lit.strings[LitId g[i].operand]
-  of ProcTy:
-    dest.add "proc["
-    for t in sons(g, i):
-      dest.add ' '
-      toString(dest, g, t)
-    dest.add "]"
-  of ObjectDecl:
-    dest.add "object["
-    for t in sons(g, i):
-      toString(dest, g, t)
-      dest.add '\n'
-    dest.add "]"
-  of UnionDecl:
-    dest.add "union["
-    for t in sons(g, i):
-      toString(dest, g, t)
-      dest.add '\n'
-    dest.add "]"
-  of FieldDecl:
-    dest.add "field["
-    for t in sons(g, i):
-      toString(dest, g, t)
-      dest.add ' '
-    dest.add "]"
-
-    when false:
-      let (typ, offset, name) = g.sons3(i)
-      toString(dest, g, typ)
-      dest.add ' '
-      toString(dest, g, offset)
-      dest.add ' '
-      toString(dest, g, name)
-
-proc toString*(dest: var string; g: TypeGraph) =
-  var i = 0
-  while i < g.len:
-    dest.add "T<"
-    dest.addInt i
-    dest.add "> "
-    toString(dest, g, TypeId i)
-    dest.add '\n'
-    nextChild g, i
-
-iterator allTypes*(g: TypeGraph; start = 0): TypeId =
-  var i = start
-  while i < g.len:
-    yield TypeId i
-    nextChild g, i
-
-iterator allTypesIncludingInner*(g: TypeGraph; start = 0): TypeId =
-  var i = start
-  while i < g.len:
-    yield TypeId i
-    inc i
-
-proc `$`(g: TypeGraph): string =
-  result = ""
-  toString(result, g)
-
-when isMainModule:
-  var g = initTypeGraph(Literals())
-
-  let a = g.openType ArrayTy
-  g.addBuiltinType Int8Id
-  g.addArrayLen 5
-  g.addName "SomeArray"
-  let finalArrayType = finishType(g, a)
-
-  let obj = g.openType ObjectDecl
-  g.nodes.add TypeNode(x: toX(NameVal, g.lit.strings.getOrIncl("MyType")))
-
-  g.addField "p", finalArrayType, 0
-  sealType(g, obj)
-
-  echo g
diff --git a/compiler/nir/nirvm.nim b/compiler/nir/nirvm.nim
deleted file mode 100644
index faa7a1fb7..000000000
--- a/compiler/nir/nirvm.nim
+++ /dev/null
@@ -1,1175 +0,0 @@
-#
-#
-#           The Nim Compiler
-#        (c) Copyright 2023 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-##[ NIR is a little too high level to interpret it efficiently. Thus
-we compute `addresses` for SymIds, labels and offsets for object fields
-in a preprocessing step.
-
-We also split the instruction stream into separate (code, debug) seqs while
-we're at it.
-]##
-
-import std / [syncio, assertions, tables, intsets]
-import ".." / ic / bitabs
-import nirinsts, nirtypes, nirfiles, nirlineinfos
-
-type
-  OpcodeM = enum
-    ImmediateValM,
-    IntValM,
-    StrValM,
-    LoadLocalM, # with local ID
-    LoadGlobalM,
-    LoadProcM,
-    TypedM,   # with type ID
-    PragmaIdM, # with Pragma ID, possible values: see PragmaKey enum
-    NilValM,
-    AllocLocals,
-    SummonParamM,
-    GotoM,
-    CheckedGotoM, # last atom
-
-    ArrayConstrM,
-    ObjConstrM,
-    RetM,
-    YldM,
-
-    SelectM,
-    SelectPairM,  # ((values...), Label)
-    SelectListM,  # (values...)
-    SelectValueM, # (value)
-    SelectRangeM, # (valueA..valueB)
-
-    AddrOfM,
-    ArrayAtM, # (elemSize, addr(a), i)
-    DerefArrayAtM,
-    FieldAtM, # addr(obj.field)
-    DerefFieldAtM,
-
-    LoadM, # a[]
-    AsgnM,  # a = b
-    StoreM, # a[] = b
-    SetExcM,
-    TestExcM,
-
-    CheckedRangeM,
-    CheckedIndexM,
-
-    CallM,
-    CheckedAddM, # with overflow checking etc.
-    CheckedSubM,
-    CheckedMulM,
-    CheckedDivM,
-    CheckedModM,
-    AddM,
-    SubM,
-    MulM,
-    DivM,
-    ModM,
-    BitShlM,
-    BitShrM,
-    BitAndM,
-    BitOrM,
-    BitXorM,
-    BitNotM,
-    BoolNotM,
-    EqM,
-    LeM,
-    LtM,
-    CastM,
-    NumberConvM,
-    CheckedObjConvM,
-    ObjConvM,
-    TestOfM,
-    ProcDeclM,
-    PragmaPairM
-
-const
-  LastAtomicValue = CheckedGotoM
-
-  OpcodeBits = 8'u32
-  OpcodeMask = (1'u32 shl OpcodeBits) - 1'u32
-
-type
-  Instr = distinct uint32
-
-template kind(n: Instr): OpcodeM = OpcodeM(n.uint32 and OpcodeMask)
-template operand(n: Instr): uint32 = (n.uint32 shr OpcodeBits)
-
-template toIns(k: OpcodeM; operand: uint32): Instr =
-  Instr(uint32(k) or (operand shl OpcodeBits))
-
-template toIns(k: OpcodeM; operand: LitId): Instr =
-  Instr(uint32(k) or (operand.uint32 shl OpcodeBits))
-
-type
-  NimStrPayloadVM = object
-    cap: int
-    data: UncheckedArray[char]
-  NimStringVM = object
-    len: int
-    p: ptr NimStrPayloadVM
-
-const
-  GlobalsSize = 1024*24
-
-type
-  PatchPos = distinct int
-  CodePos = distinct int
-
-  Bytecode* = object
-    code: seq[Instr]
-    debug: seq[PackedLineInfo]
-    m: ref NirModule
-    procs: Table[SymId, CodePos]
-    globals: Table[SymId, (uint32, int)]
-    strings: Table[LitId, NimStringVM]
-    globalData: pointer
-    globalsAddr: uint32
-    typeImpls: Table[string, TypeId]
-    offsets: Table[TypeId, seq[(int, TypeId)]]
-    sizes: Table[TypeId, (int, int)] # (size, alignment)
-    oldTypeLen: int
-    procUsagesToPatch: Table[SymId, seq[CodePos]]
-    interactive*: bool
-
-  Universe* = object ## all units: For interpretation we need that
-    units: seq[Bytecode]
-    unitNames: Table[string, int]
-    current: int
-
-proc initBytecode*(m: ref NirModule): Bytecode = Bytecode(m: m, globalData: alloc0(GlobalsSize))
-
-proc debug(bc: Bytecode; t: TypeId) =
-  var buf = ""
-  toString buf, bc.m.types, t
-  echo buf
-
-proc debug(bc: Bytecode; info: PackedLineInfo) =
-  let (litId, line, col) = bc.m.man.unpack(info)
-  echo bc.m.lit.strings[litId], ":", line, ":", col
-
-proc debug(bc: Bytecode; t: Tree; n: NodePos) =
-  var buf = ""
-  toString(t, n, bc.m.lit.strings, bc.m.lit.numbers, bc.m.symnames, buf)
-  echo buf
-
-template `[]`(t: seq[Instr]; n: CodePos): Instr = t[n.int]
-
-proc traverseObject(b: var Bytecode; t, offsetKey: TypeId) =
-  var size = -1
-  var align = -1
-  for x in sons(b.m.types, t):
-    case b.m.types[x].kind
-    of FieldDecl:
-      var offset = -1
-      for y in sons(b.m.types, x):
-        if b.m.types[y].kind == OffsetVal:
-          offset = int(b.m.lit.numbers[b.m.types[y].litId])
-          break
-      b.offsets.mgetOrPut(offsetKey, @[]).add (offset, x.firstSon)
-    of SizeVal:
-      size = int(b.m.lit.numbers[b.m.types[x].litId])
-    of AlignVal:
-      align = int(b.m.lit.numbers[b.m.types[x].litId])
-    of ObjectTy:
-      # inheritance
-      let impl = b.typeImpls.getOrDefault(b.m.lit.strings[b.m.types[x].litId])
-      assert impl.int > 0
-      traverseObject b, impl, offsetKey
-    else: discard
-  if t == offsetKey:
-    b.sizes[t] = (size, align)
-
-proc computeSize(b: var Bytecode; t: TypeId): (int, int) =
-  case b.m.types[t].kind
-  of ObjectDecl, UnionDecl:
-    result = b.sizes[t]
-  of ObjectTy, UnionTy:
-    let impl = b.typeImpls[b.m.lit.strings[b.m.types[t].litId]]
-    result = computeSize(b, impl)
-  of IntTy, UIntTy, FloatTy, BoolTy, CharTy:
-    let s = b.m.types[t].integralBits div 8
-    result = (s, s)
-  of APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy, ProcTy:
-    result = (sizeof(pointer), sizeof(pointer))
-  of ArrayTy:
-    let e = elementType(b.m.types, t)
-    let n = arrayLen(b.m.types, t)
-    let inner = computeSize(b, e)
-    result = (inner[0] * n.int, inner[1])
-  else:
-    result = (0, 0)
-
-proc computeElemSize(b: var Bytecode; t: TypeId): int =
-  case b.m.types[t].kind
-  of ArrayTy, APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy, LastArrayTy:
-    result = computeSize(b, elementType(b.m.types, t))[0]
-  else:
-    raiseAssert "not an array type"
-
-proc traverseTypes(b: var Bytecode) =
-  for t in allTypes(b.m.types, b.oldTypeLen):
-    if b.m.types[t].kind in {ObjectDecl, UnionDecl}:
-      assert b.m.types[t.firstSon].kind == NameVal
-      b.typeImpls[b.m.lit.strings[b.m.types[t.firstSon].litId]] = t
-
-  for t in allTypes(b.m.types, b.oldTypeLen):
-    if b.m.types[t].kind in {ObjectDecl, UnionDecl}:
-      assert b.m.types[t.firstSon].kind == NameVal
-      traverseObject b, t, t
-  b.oldTypeLen = b.m.types.len
-
-const
-  InvalidPatchPos* = PatchPos(-1)
-
-proc isValid(p: PatchPos): bool {.inline.} = p.int != -1
-
-proc prepare(bc: var Bytecode; info: PackedLineInfo; kind: OpcodeM): PatchPos =
-  result = PatchPos bc.code.len
-  bc.code.add toIns(kind, 1'u32)
-  bc.debug.add info
-
-proc add(bc: var Bytecode; info: PackedLineInfo; kind: OpcodeM; raw: uint32) =
-  bc.code.add toIns(kind, raw)
-  bc.debug.add info
-
-proc add(bc: var Bytecode; info: PackedLineInfo; kind: OpcodeM; lit: LitId) =
-  add bc, info, kind, uint32(lit)
-
-proc isAtom(bc: Bytecode; pos: int): bool {.inline.} = bc.code[pos].kind <= LastAtomicValue
-proc isAtom(bc: Bytecode; pos: CodePos): bool {.inline.} = bc.code[pos.int].kind <= LastAtomicValue
-
-proc patch(bc: var Bytecode; pos: PatchPos) =
-  let pos = pos.int
-  let k = bc.code[pos].kind
-  assert k > LastAtomicValue
-  let distance = int32(bc.code.len - pos)
-  assert distance > 0
-  bc.code[pos] = toIns(k, cast[uint32](distance))
-
-template build(bc: var Bytecode; info: PackedLineInfo; kind: OpcodeM; body: untyped) =
-  let pos = prepare(bc, info, kind)
-  body
-  patch(bc, pos)
-
-proc len*(bc: Bytecode): int {.inline.} = bc.code.len
-
-template rawSpan(n: Instr): int = int(operand(n))
-
-proc nextChild(bc: Bytecode; pos: var int) {.inline.} =
-  if bc.code[pos].kind > LastAtomicValue:
-    assert bc.code[pos].operand > 0'u32
-    inc pos, bc.code[pos].rawSpan
-  else:
-    inc pos
-
-proc next(bc: Bytecode; pos: var CodePos) {.inline.} = nextChild bc, int(pos)
-
-iterator sons(bc: Bytecode; n: CodePos): CodePos =
-  var pos = n.int
-  assert bc.code[pos].kind > LastAtomicValue
-  let last = pos + bc.code[pos].rawSpan
-  inc pos
-  while pos < last:
-    yield CodePos pos
-    nextChild bc, pos
-
-iterator sonsFrom1(bc: Bytecode; n: CodePos): CodePos =
-  var pos = n.int
-  assert bc.code[pos].kind > LastAtomicValue
-  let last = pos + bc.code[pos].rawSpan
-  inc pos
-  nextChild bc, pos
-  while pos < last:
-    yield CodePos pos
-    nextChild bc, pos
-
-iterator sonsFrom2(bc: Bytecode; n: CodePos): CodePos =
-  var pos = n.int
-  assert bc.code[pos].kind > LastAtomicValue
-  let last = pos + bc.code[pos].rawSpan
-  inc pos
-  nextChild bc, pos
-  nextChild bc, pos
-  while pos < last:
-    yield CodePos pos
-    nextChild bc, pos
-
-template firstSon(n: CodePos): CodePos = CodePos(n.int+1)
-
-template `[]`(t: Bytecode; n: CodePos): Instr = t.code[n.int]
-
-proc span(bc: Bytecode; pos: int): int {.inline.} =
-  if bc.code[pos].kind <= LastAtomicValue: 1 else: int(bc.code[pos].operand)
-
-iterator triples*(bc: Bytecode; n: CodePos): (uint32, int, CodePos) =
-  var pos = n.int
-  assert bc.code[pos].kind > LastAtomicValue
-  let last = pos + bc.code[pos].rawSpan
-  inc pos
-  while pos < last:
-    let offset = bc.code[pos].operand
-    nextChild bc, pos
-    let size = bc.code[pos].operand.int
-    nextChild bc, pos
-    let val = CodePos pos
-    yield (offset, size, val)
-    nextChild bc, pos
-
-proc toString*(t: Bytecode; pos: CodePos;
-               r: var string; nesting = 0) =
-  if r.len > 0 and r[r.len-1] notin {' ', '\n', '(', '[', '{'}:
-    r.add ' '
-
-  case t[pos].kind
-  of ImmediateValM:
-    r.add $t[pos].operand
-  of IntValM:
-    r.add "IntVal "
-    r.add $t.m.lit.numbers[LitId t[pos].operand]
-  of StrValM:
-    escapeToNimLit(t.m.lit.strings[LitId t[pos].operand], r)
-  of LoadLocalM, LoadGlobalM, LoadProcM, AllocLocals, SummonParamM:
-    r.add $t[pos].kind
-    r.add ' '
-    r.add $t[pos].operand
-  of PragmaIdM:
-    r.add $cast[PragmaKey](t[pos].operand)
-  of TypedM:
-    r.add "T<"
-    r.add $t[pos].operand
-    r.add ">"
-  of NilValM:
-    r.add "NilVal"
-  of GotoM, CheckedGotoM:
-    r.add $t[pos].kind
-    r.add " L"
-    r.add $t[pos].operand
-  else:
-    r.add $t[pos].kind
-    r.add "{\n"
-    for i in 0..<(nesting+1)*2: r.add ' '
-    for p in sons(t, pos):
-      toString t, p, r, nesting+1
-    r.add "\n"
-    for i in 0..<nesting*2: r.add ' '
-    r.add "}"
-
-proc debug(b: Bytecode; pos: CodePos) =
-  var buf = ""
-  toString(b, pos, buf)
-  echo buf
-
-type
-  Preprocessing = object
-    u: ref Universe
-    known: Table[LabelId, CodePos]
-    toPatch: Table[LabelId, seq[CodePos]]
-    locals: Table[SymId, (uint32, int)] # address, size
-    thisModule: uint32
-    localsAddr: uint32
-    markedWithLabel: IntSet
-
-proc align(address, alignment: uint32): uint32 =
-  result = (address + (alignment - 1'u32)) and not (alignment - 1'u32)
-
-proc genGoto(c: var Preprocessing; bc: var Bytecode; info: PackedLineInfo; lab: LabelId; opc: OpcodeM) =
-  let dest = c.known.getOrDefault(lab, CodePos(-1))
-  if dest.int >= 0:
-    bc.add info, opc, uint32 dest
-  else:
-    let here = CodePos(bc.code.len)
-    c.toPatch.mgetOrPut(lab, @[]).add here
-    bc.add info, opc, 1u32 # will be patched once we traversed the label
-
-type
-  AddrMode = enum
-    InDotExpr, WantAddr
-
-template maybeDeref(doDeref: bool; size: int; body: untyped) =
-  var pos = PatchPos(-1)
-  if doDeref:
-    pos = prepare(bc, info, LoadM)
-    bc.add info, ImmediateValM, uint32 size
-  body
-  if doDeref:
-    patch(bc, pos)
-
-proc toReadonlyString(s: string): NimStringVM =
-  if s.len == 0:
-    result = NimStringVM(len: 0, p: nil)
-  else:
-    result = NimStringVM(len: s.len, p: cast[ptr NimStrPayloadVM](alloc(s.len+1+sizeof(int))))
-    copyMem(addr result.p.data[0], addr s[0], s.len+1)
-    result.p.cap = s.len or (1 shl (8 * 8 - 2)) # see also NIM_STRLIT_FLAG
-
-const
-  ForwardedProc = 10_000_000'u32
-
-proc preprocess(c: var Preprocessing; bc: var Bytecode; t: Tree; n: NodePos; flags: set[AddrMode]) =
-  let info = t[n].info
-
-  template recurse(opc) =
-    build bc, info, opc:
-      for ch in sons(t, n): preprocess(c, bc, t, ch, {WantAddr})
-
-  case t[n].kind
-  of Nop, ForeignDecl, ForeignProcDecl:
-    discard "don't use Nop"
-  of ImmediateVal:
-    bc.add info, ImmediateValM, t[n].rawOperand
-  of IntVal:
-    bc.add info, IntValM, t[n].rawOperand
-  of StrVal:
-    let litId = LitId t[n].rawOperand
-    if not bc.strings.hasKey(litId):
-      bc.strings[litId] = toReadonlyString(bc.m.lit.strings[litId])
-    bc.add info, StrValM, t[n].rawOperand
-  of SymDef:
-    discard "happens for proc decls. Don't copy the node as we don't need it"
-  of SymUse:
-    let s = t[n].symId
-    if c.locals.hasKey(s):
-      let (address, size) = c.locals[s]
-      maybeDeref(WantAddr notin flags, size):
-        bc.add info, LoadLocalM, address
-    elif bc.procs.hasKey(s):
-      bc.add info, LoadProcM, uint32 bc.procs[s]
-    elif bc.globals.hasKey(s):
-      let (address, size) = bc.globals[s]
-      maybeDeref(WantAddr notin flags, size):
-        bc.add info, LoadGlobalM, address
-    else:
-      let here = CodePos(bc.code.len)
-      bc.add info, LoadProcM, ForwardedProc + uint32(s)
-      bc.procUsagesToPatch.mgetOrPut(s, @[]).add here
-      #raiseAssert "don't understand SymUse ID " & $int(s)
-
-  of ModuleSymUse:
-    when false:
-      let (x, y) = sons2(t, n)
-      let unit = c.u.unitNames.getOrDefault(bc.m.lit.strings[t[x].litId], -1)
-      let s = t[y].symId
-      if c.u.units[unit].procs.hasKey(s):
-        bc.add info, LoadProcM, uint32 c.u.units[unit].procs[s]
-      elif bc.globals.hasKey(s):
-        maybeDeref(WantAddr notin flags):
-          build bc, info, LoadGlobalM:
-            bc.add info, ImmediateValM, uint32 unit
-            bc.add info, LoadLocalM, uint32 s
-      else:
-        raiseAssert "don't understand ModuleSymUse ID"
-
-    raiseAssert "don't understand ModuleSymUse ID"
-  of Typed:
-    bc.add info, TypedM, t[n].rawOperand
-  of PragmaId:
-    bc.add info, PragmaIdM, t[n].rawOperand
-  of NilVal:
-    bc.add info, NilValM, t[n].rawOperand
-  of LoopLabel, Label:
-    let lab = t[n].label
-    let here = CodePos(bc.code.len)
-    c.known[lab] = here
-    var p: seq[CodePos] = @[]
-    if c.toPatch.take(lab, p):
-      for x in p: (bc.code[x]) = toIns(bc.code[x].kind, uint32 here)
-    c.markedWithLabel.incl here.int # for toString()
-  of Goto, GotoLoop:
-    c.genGoto(bc, info, t[n].label, GotoM)
-  of CheckedGoto:
-    c.genGoto(bc, info, t[n].label, CheckedGotoM)
-  of ArrayConstr:
-    let typ = t[n.firstSon].typeId
-    let s = computeElemSize(bc, typ)
-    build bc, info, ArrayConstrM:
-      bc.add info, ImmediateValM, uint32 s
-      for ch in sonsFrom1(t, n):
-        preprocess(c, bc, t, ch, {WantAddr})
-  of ObjConstr:
-    #debug bc, t, n
-    var i = 0
-    let typ = t[n.firstSon].typeId
-    build bc, info, ObjConstrM:
-      for ch in sons(t, n):
-        if i > 0:
-          if (i mod 2) == 1:
-            let (offset, typ) = bc.offsets[typ][t[ch].immediateVal]
-            let size = computeSize(bc, typ)[0]
-            bc.add info, ImmediateValM, uint32(offset)
-            bc.add info, ImmediateValM, uint32(size)
-          else:
-            preprocess(c, bc, t, ch, {WantAddr})
-        inc i
-  of Ret:
-    recurse RetM
-  of Yld:
-    recurse YldM
-  of Select:
-    recurse SelectM
-  of SelectPair:
-    recurse SelectPairM
-  of SelectList:
-    recurse SelectListM
-  of SelectValue:
-    recurse SelectValueM
-  of SelectRange:
-    recurse SelectRangeM
-  of SummonGlobal, SummonThreadLocal, SummonConst:
-    let (typ, sym) = sons2(t, n)
-
-    let s = t[sym].symId
-    let tid = t[typ].typeId
-    let (size, alignment) = computeSize(bc, tid)
-
-    let global = align(bc.globalsAddr, uint32 alignment)
-    bc.globals[s] = (global, size)
-    bc.globalsAddr += uint32 size
-    assert bc.globalsAddr < GlobalsSize
-
-  of Summon:
-    let (typ, sym) = sons2(t, n)
-
-    let s = t[sym].symId
-    let tid = t[typ].typeId
-    let (size, alignment) = computeSize(bc, tid)
-
-    let local = align(c.localsAddr, uint32 alignment)
-    c.locals[s] = (local, size)
-    c.localsAddr += uint32 size
-    # allocation is combined into the frame allocation so there is no
-    # instruction to emit
-  of SummonParam, SummonResult:
-    let (typ, sym) = sons2(t, n)
-
-    let s = t[sym].symId
-    let tid = t[typ].typeId
-    let (size, alignment) = computeSize(bc, tid)
-
-    let local = align(c.localsAddr, uint32 alignment)
-    c.locals[s] = (local, size)
-    c.localsAddr += uint32 size
-    bc.add info, SummonParamM, local
-    bc.add info, ImmediateValM, uint32 size
-  of Kill:
-    discard "we don't care about Kill instructions"
-  of AddrOf:
-    let (_, arg) = sons2(t, n)
-    preprocess(c, bc, t, arg, {WantAddr})
-    # the address of x is what the VM works with all the time so there is
-    # nothing to compute.
-  of ArrayAt:
-    let (arrayType, a, i) = sons3(t, n)
-    let tid = t[arrayType].typeId
-    let size = uint32 computeElemSize(bc, tid)
-    build bc, info, ArrayAtM:
-      bc.add info, ImmediateValM, size
-      preprocess(c, bc, t, a, {WantAddr})
-      preprocess(c, bc, t, i, {WantAddr})
-  of DerefArrayAt:
-    let (arrayType, a, i) = sons3(t, n)
-    let tid = t[arrayType].typeId
-    let size = uint32 computeElemSize(bc, tid)
-    build bc, info, DerefArrayAtM:
-      bc.add info, ImmediateValM, size
-      preprocess(c, bc, t, a, {WantAddr})
-      preprocess(c, bc, t, i, {WantAddr})
-  of FieldAt:
-    let (typ, a, b) = sons3(t, n)
-    let offset = bc.offsets[t[typ].typeId][t[b].immediateVal][0]
-    build bc, info, FieldAtM:
-      preprocess(c, bc, t, a, flags+{WantAddr})
-      bc.add info, ImmediateValM, uint32(offset)
-  of DerefFieldAt:
-    let (typ, a, b) = sons3(t, n)
-    let offset = bc.offsets[t[typ].typeId][t[b].immediateVal][0]
-    build bc, info, DerefFieldAtM:
-      preprocess(c, bc, t, a, flags+{WantAddr})
-      bc.add info, ImmediateValM, uint32(offset)
-  of Load:
-    let (elemType, a) = sons2(t, n)
-    let tid = t[elemType].typeId
-    build bc, info, LoadM:
-      bc.add info, ImmediateValM, uint32 computeSize(bc, tid)[0]
-      preprocess(c, bc, t, a, {})
-
-  of Store:
-    raiseAssert "Assumption was that Store is unused!"
-  of Asgn:
-    let (elemType, dest, src) = sons3(t, n)
-    let tid = t[elemType].typeId
-    if t[src].kind in {Call, IndirectCall}:
-      # No support for return values, these are mapped to `var T` parameters!
-      build bc, info, CallM:
-        preprocess(c, bc, t, src.skipTyped, {WantAddr})
-        preprocess(c, bc, t, dest, {WantAddr})
-        for ch in sonsFromN(t, src, 2): preprocess(c, bc, t, ch, {WantAddr})
-    elif t[src].kind in {CheckedCall, CheckedIndirectCall}:
-      let (_, gotoInstr, fn) = sons3(t, src)
-      build bc, info, CallM:
-        preprocess(c, bc, t, fn, {WantAddr})
-        preprocess(c, bc, t, dest, {WantAddr})
-        for ch in sonsFromN(t, src, 3): preprocess(c, bc, t, ch, {WantAddr})
-      preprocess c, bc, t, gotoInstr, {}
-    elif t[dest].kind == Load:
-      let (typ, a) = sons2(t, dest)
-      let s = computeSize(bc, tid)[0]
-      build bc, info, StoreM:
-        bc.add info, ImmediateValM, uint32 s
-        preprocess(c, bc, t, a, {WantAddr})
-        preprocess(c, bc, t, src, {})
-    else:
-      let s = computeSize(bc, tid)[0]
-      build bc, info, AsgnM:
-        bc.add info, ImmediateValM, uint32 s
-        preprocess(c, bc, t, dest, {WantAddr})
-        preprocess(c, bc, t, src, {})
-  of SetExc:
-    recurse SetExcM
-  of TestExc:
-    recurse TestExcM
-  of CheckedRange:
-    recurse CheckedRangeM
-  of CheckedIndex:
-    recurse CheckedIndexM
-  of Call, IndirectCall:
-    # avoid the Typed thing at position 0:
-    build bc, info, CallM:
-      for ch in sonsFrom1(t, n): preprocess(c, bc, t, ch, {WantAddr})
-  of CheckedCall, CheckedIndirectCall:
-    # avoid the Typed thing at position 0:
-    let (_, gotoInstr, fn) = sons3(t, n)
-    build bc, info, CallM:
-      preprocess(c, bc, t, fn, {WantAddr})
-      for ch in sonsFromN(t, n, 3): preprocess(c, bc, t, ch, {WantAddr})
-    preprocess c, bc, t, gotoInstr, {WantAddr}
-  of CheckedAdd:
-    recurse CheckedAddM
-  of CheckedSub:
-    recurse CheckedSubM
-  of CheckedMul:
-    recurse CheckedMulM
-  of CheckedDiv:
-    recurse CheckedDivM
-  of CheckedMod:
-    recurse CheckedModM
-  of Add:
-    recurse AddM
-  of Sub:
-    recurse SubM
-  of Mul:
-    recurse MulM
-  of Div:
-    recurse DivM
-  of Mod:
-    recurse ModM
-  of BitShl:
-    recurse BitShlM
-  of BitShr:
-    recurse BitShrM
-  of BitAnd:
-    recurse BitAndM
-  of BitOr:
-    recurse BitOrM
-  of BitXor:
-    recurse BitXorM
-  of BitNot:
-    recurse BitNotM
-  of BoolNot:
-    recurse BoolNotM
-  of Eq:
-    recurse EqM
-  of Le:
-    recurse LeM
-  of Lt:
-    recurse LtM
-  of Cast:
-    recurse CastM
-  of NumberConv:
-    recurse NumberConvM
-  of CheckedObjConv:
-    recurse CheckedObjConvM
-  of ObjConv:
-    recurse ObjConvM
-  of TestOf:
-    recurse TestOfM
-  of Emit:
-    raiseAssert "cannot interpret: Emit"
-  of ProcDecl:
-    var c2 = Preprocessing(u: c.u, thisModule: c.thisModule)
-    let sym = t[n.firstSon].symId
-    let here = CodePos(bc.len)
-    var p: seq[CodePos] = @[]
-    if bc.procUsagesToPatch.take(sym, p):
-      for x in p: (bc.code[x]) = toIns(bc.code[x].kind, uint32 here)
-    bc.procs[sym] = here
-    build bc, info, ProcDeclM:
-      let toPatch = bc.code.len
-      bc.add info, AllocLocals, 0'u32
-      for ch in sons(t, n): preprocess(c2, bc, t, ch, {})
-      bc.code[toPatch] = toIns(AllocLocals, c2.localsAddr)
-    when false:
-      if here.int == 39850:
-        debug bc, t, n
-        debug bc, here
-
-  of PragmaPair:
-    recurse PragmaPairM
-
-const PayloadSize = 128
-
-type
-  StackFrame = ref object
-    locals: pointer   # usually points into `payload` if size is small enough, otherwise it's `alloc`'ed.
-    payload: array[PayloadSize, byte]
-    caller: StackFrame
-    returnAddr: CodePos
-    jumpTo: CodePos # exception handling
-    u: ref Universe
-
-proc newStackFrame(size: int; caller: StackFrame; returnAddr: CodePos): StackFrame =
-  result = StackFrame(caller: caller, returnAddr: returnAddr, u: caller.u)
-  if size <= PayloadSize:
-    result.locals = addr(result.payload)
-  else:
-    result.locals = alloc0(size)
-
-proc popStackFrame(s: StackFrame): StackFrame =
-  if s.locals != addr(s.payload):
-    dealloc s.locals
-  result = s.caller
-
-template `+!`(p: pointer; diff: uint): pointer = cast[pointer](cast[uint](p) + diff)
-
-proc isAtom(tree: seq[Instr]; pos: CodePos): bool {.inline.} = tree[pos.int].kind <= LastAtomicValue
-
-proc span(bc: seq[Instr]; pos: int): int {.inline.} =
-  if bc[pos].kind <= LastAtomicValue: 1 else: int(bc[pos].operand)
-
-proc sons2(tree: seq[Instr]; n: CodePos): (CodePos, CodePos) =
-  assert(not isAtom(tree, n))
-  let a = n.int+1
-  let b = a + span(tree, a)
-  result = (CodePos a, CodePos b)
-
-proc sons3(tree: seq[Instr]; n: CodePos): (CodePos, CodePos, CodePos) =
-  assert(not isAtom(tree, n))
-  let a = n.int+1
-  let b = a + span(tree, a)
-  let c = b + span(tree, b)
-  result = (CodePos a, CodePos b, CodePos c)
-
-proc sons4(tree: seq[Instr]; n: CodePos): (CodePos, CodePos, CodePos, CodePos) =
-  assert(not isAtom(tree, n))
-  let a = n.int+1
-  let b = a + span(tree, a)
-  let c = b + span(tree, b)
-  let d = c + span(tree, c)
-  result = (CodePos a, CodePos b, CodePos c, CodePos d)
-
-proc typeId*(ins: Instr): TypeId {.inline.} =
-  assert ins.kind == TypedM
-  result = TypeId(ins.operand)
-
-proc immediateVal*(ins: Instr): int {.inline.} =
-  assert ins.kind == ImmediateValM
-  result = cast[int](ins.operand)
-
-proc litId*(ins: Instr): LitId {.inline.} =
-  assert ins.kind in {StrValM, IntValM}
-  result = LitId(ins.operand)
-
-proc eval(c: Bytecode; pc: CodePos; s: StackFrame; result: pointer; size: int)
-
-proc evalAddr(c: Bytecode; pc: CodePos; s: StackFrame): pointer =
-  case c.code[pc].kind
-  of LoadLocalM:
-    result = s.locals +! c.code[pc].operand
-  of FieldAtM:
-    let (x, offset) = sons2(c.code, pc)
-    result = evalAddr(c, x, s)
-    result = result +! c.code[offset].operand
-  of DerefFieldAtM:
-    let (x, offset) = sons2(c.code, pc)
-    let p = evalAddr(c, x, s)
-    result = cast[ptr pointer](p)[] +! c.code[offset].operand
-  of ArrayAtM:
-    let (e, a, i) = sons3(c.code, pc)
-    let elemSize = c.code[e].operand
-    result = evalAddr(c, a, s)
-    var idx: int = 0
-    eval(c, i, s, addr idx, sizeof(int))
-    result = result +! (uint32(idx) * elemSize)
-  of DerefArrayAtM:
-    let (e, a, i) = sons3(c.code, pc)
-    let elemSize = c.code[e].operand
-    var p = evalAddr(c, a, s)
-    var idx: int = 0
-    eval(c, i, s, addr idx, sizeof(int))
-    result = cast[ptr pointer](p)[] +! (uint32(idx) * elemSize)
-  of LoadGlobalM:
-    result = c.globalData +! c.code[pc].operand
-  else:
-    raiseAssert("unimplemented addressing mode")
-
-proc `div`(x, y: float32): float32 {.inline.} = x / y
-proc `div`(x, y: float64): float64 {.inline.} = x / y
-
-from std / math import `mod`
-
-template binop(opr) {.dirty.} =
-  template impl(typ) {.dirty.} =
-    var x = default(typ)
-    var y = default(typ)
-    eval c, a, s, addr x, sizeof(typ)
-    eval c, b, s, addr y, sizeof(typ)
-    cast[ptr typ](result)[] = opr(x, y)
-
-  let (t, a, b) = sons3(c.code, pc)
-  let tid = TypeId c.code[t].operand
-  case tid
-  of Bool8Id, Char8Id, UInt8Id: impl uint8
-  of Int8Id: impl int8
-  of Int16Id: impl int16
-  of Int32Id: impl int32
-  of Int64Id: impl int64
-  of UInt16Id: impl uint16
-  of UInt32Id: impl uint32
-  of UInt64Id: impl uint64
-  of Float32Id: impl float32
-  of Float64Id: impl float64
-  else: discard
-
-template checkedBinop(opr) {.dirty.} =
-  template impl(typ) {.dirty.} =
-    var x = default(typ)
-    var y = default(typ)
-    eval c, a, s, addr x, sizeof(typ)
-    eval c, b, s, addr y, sizeof(typ)
-    try:
-      cast[ptr typ](result)[] = opr(x, y)
-    except OverflowDefect, DivByZeroDefect:
-      s.jumpTo = CodePos c.code[j].operand
-
-  let (t, j, a, b) = sons4(c.code, pc)
-  let tid = TypeId c.code[t].operand
-  case tid
-  of Bool8Id, Char8Id, UInt8Id: impl uint8
-  of Int8Id: impl int8
-  of Int16Id: impl int16
-  of Int32Id: impl int32
-  of Int64Id: impl int64
-  of UInt16Id: impl uint16
-  of UInt32Id: impl uint32
-  of UInt64Id: impl uint64
-  of Float32Id: impl float32
-  of Float64Id: impl float64
-  else: discard
-
-template bitop(opr) {.dirty.} =
-  template impl(typ) {.dirty.} =
-    var x = default(typ)
-    var y = default(typ)
-    eval c, a, s, addr x, sizeof(typ)
-    eval c, b, s, addr y, sizeof(typ)
-    cast[ptr typ](result)[] = opr(x, y)
-
-  let (t, a, b) = sons3(c.code, pc)
-  let tid = c.code[t].typeId
-  case tid
-  of Bool8Id, Char8Id, UInt8Id: impl uint8
-  of Int8Id: impl int8
-  of Int16Id: impl int16
-  of Int32Id: impl int32
-  of Int64Id: impl int64
-  of UInt16Id: impl uint16
-  of UInt32Id: impl uint32
-  of UInt64Id: impl uint64
-  else: discard
-
-template cmpop(opr) {.dirty.} =
-  template impl(typ) {.dirty.} =
-    var x = default(typ)
-    var y = default(typ)
-    eval c, a, s, addr x, sizeof(typ)
-    eval c, b, s, addr y, sizeof(typ)
-    cast[ptr bool](result)[] = opr(x, y)
-
-  let (t, a, b) = sons3(c.code, pc)
-  let tid = c.code[t].typeId
-  case tid
-  of Bool8Id, Char8Id, UInt8Id: impl uint8
-  of Int8Id: impl int8
-  of Int16Id: impl int16
-  of Int32Id: impl int32
-  of Int64Id: impl int64
-  of UInt16Id: impl uint16
-  of UInt32Id: impl uint32
-  of UInt64Id: impl uint64
-  of Float32Id: impl float32
-  of Float64Id: impl float64
-  else: discard
-
-proc evalSelect(c: Bytecode; pc: CodePos; s: StackFrame): CodePos =
-  template impl(typ) {.dirty.} =
-    var selector = default(typ)
-    eval c, sel, s, addr selector, sizeof(typ)
-    for pair in sonsFrom2(c, pc):
-      assert c.code[pair].kind == SelectPairM
-      let (values, action) = sons2(c.code, pair)
-      if c.code[values].kind == SelectValueM:
-        var a = default(typ)
-        eval c, values.firstSon, s, addr a, sizeof(typ)
-        if selector == a:
-          return CodePos c.code[action].operand
-      else:
-        assert c.code[values].kind == SelectListM, $c.code[values].kind
-        for v in sons(c, values):
-          case c.code[v].kind
-          of SelectValueM:
-            var a = default(typ)
-            eval c, v.firstSon, s, addr a, sizeof(typ)
-            if selector == a:
-              return CodePos c.code[action].operand
-          of SelectRangeM:
-            let (va, vb) = sons2(c.code, v)
-            var a = default(typ)
-            eval c, va, s, addr a, sizeof(typ)
-            var b = default(typ)
-            eval c, vb, s, addr a, sizeof(typ)
-            if a <= selector and selector <= b:
-              return CodePos c.code[action].operand
-          else: raiseAssert "unreachable"
-    result = CodePos(-1)
-
-  let (t, sel) = sons2(c.code, pc)
-  let tid = c.code[t].typeId
-  case tid
-  of Bool8Id, Char8Id, UInt8Id: impl uint8
-  of Int8Id: impl int8
-  of Int16Id: impl int16
-  of Int32Id: impl int32
-  of Int64Id: impl int64
-  of UInt16Id: impl uint16
-  of UInt32Id: impl uint32
-  of UInt64Id: impl uint64
-  else: raiseAssert "unreachable"
-
-proc eval(c: Bytecode; pc: CodePos; s: StackFrame; result: pointer; size: int) =
-  case c.code[pc].kind
-  of LoadLocalM:
-    let src = s.locals +! c.code[pc].operand
-    copyMem result, src, size
-  of FieldAtM, DerefFieldAtM, ArrayAtM, DerefArrayAtM, LoadGlobalM:
-    let src = evalAddr(c, pc, s)
-    copyMem result, src, size
-  of LoadProcM:
-    let procAddr = c.code[pc].operand
-    cast[ptr pointer](result)[] = cast[pointer](procAddr)
-  of LoadM:
-    let (_, arg) = sons2(c.code, pc)
-    let src = evalAddr(c, arg, s)
-    copyMem result, src, size
-  of CheckedAddM: checkedBinop `+`
-  of CheckedSubM: checkedBinop `-`
-  of CheckedMulM: checkedBinop `*`
-  of CheckedDivM: checkedBinop `div`
-  of CheckedModM: checkedBinop `mod`
-  of AddM: binop `+`
-  of SubM: binop `-`
-  of MulM: binop `*`
-  of DivM: binop `div`
-  of ModM: binop `mod`
-  of BitShlM: bitop `shl`
-  of BitShrM: bitop `shr`
-  of BitAndM: bitop `and`
-  of BitOrM: bitop `or`
-  of BitXorM: bitop `xor`
-  of EqM: cmpop `==`
-  of LeM: cmpop `<=`
-  of LtM: cmpop `<`
-
-  of StrValM:
-    # binary compatible and no deep copy required:
-    copyMem(cast[ptr string](result), addr(c.strings[c[pc].litId]), sizeof(string))
-  of ObjConstrM:
-    for offset, size, val in triples(c, pc):
-      eval c, val, s, result+!offset, size
-  of ArrayConstrM:
-    let elemSize = c.code[pc.firstSon].operand
-    var r = result
-    for ch in sonsFrom1(c, pc):
-      eval c, ch, s, r, elemSize.int
-      r = r+!elemSize # can even do strength reduction here!
-  of NumberConvM:
-    let (t, x) = sons2(c.code, pc)
-    let word = if c[x].kind == NilValM: 0'i64 else: c.m.lit.numbers[c[x].litId]
-
-    template impl(typ: typedesc) {.dirty.} =
-      cast[ptr typ](result)[] = cast[typ](word)
-
-    let tid = c.code[t].typeId
-    case tid
-    of Bool8Id, Char8Id, UInt8Id: impl uint8
-    of Int8Id: impl int8
-    of Int16Id: impl int16
-    of Int32Id: impl int32
-    of Int64Id: impl int64
-    of UInt16Id: impl uint16
-    of UInt32Id: impl uint32
-    of UInt64Id: impl uint64
-    of Float32Id: impl float32
-    of Float64Id: impl float64
-    else:
-      case c.m.types[tid].kind
-      of ProcTy, UPtrTy, APtrTy, AArrayPtrTy, UArrayPtrTy:
-        # the VM always uses 64 bit pointers:
-        impl uint64
-      else:
-        raiseAssert "cannot happen: " & $c.m.types[tid].kind
-  else:
-    #debug c, c.debug[pc.int]
-    raiseAssert "cannot happen: " & $c.code[pc].kind
-
-proc evalProc(c: Bytecode; pc: CodePos; s: StackFrame): CodePos =
-  assert c.code[pc].kind == LoadProcM
-  let procSym = c[pc].operand
-  when false:
-    if procSym >= ForwardedProc:
-      for k, v in c.procUsagesToPatch:
-        if uint32(k) == procSym - ForwardedProc:
-          echo k.int, " ", v.len, " <-- this one"
-        else:
-          echo k.int, " ", v.len
-
-  assert procSym < ForwardedProc
-  result = CodePos(procSym)
-
-proc echoImpl(c: Bytecode; pc: CodePos; frame: StackFrame) =
-  var s = default(NimStringVM)
-  for a in sonsFrom1(c, pc):
-    assert c[a].kind == ArrayConstrM
-    let elemSize = c.code[a.firstSon].operand.int
-    for ch in sonsFrom1(c, a):
-      eval c, ch, frame, addr s, elemSize
-      if s.len > 0:
-        discard stdout.writeBuffer(addr(s.p.data[0]), s.len)
-  stdout.write "\n"
-  stdout.flushFile()
-
-type
-  EvalBuiltinState = enum
-    DidNothing, DidEval, DidError
-
-proc evalBuiltin(c: Bytecode; pc: CodePos; s: StackFrame; prc: CodePos; state: var EvalBuiltinState): CodePos =
-  var prc = prc
-  while true:
-    case c[prc].kind
-    of PragmaPairM:
-      let (x, y) = sons2(c.code, prc)
-      let key = cast[PragmaKey](c[x].operand)
-      case key
-      of CoreName:
-        let lit = c[y].litId
-        case c.m.lit.strings[lit]
-        of "echoBinSafe": echoImpl(c, pc, s)
-        else:
-          raiseAssert "cannot eval: " & c.m.lit.strings[lit]
-        state = DidEval
-      of HeaderImport, DllImport:
-        let lit = c[y].litId
-        raiseAssert "cannot eval: " & c.m.lit.strings[lit]
-      else: discard
-    of PragmaIdM, AllocLocals: discard
-    else: break
-    next c, prc
-  result = prc
-
-proc exec(c: Bytecode; pc: CodePos; u: ref Universe) =
-  var pc = pc
-  var frame = StackFrame(u: u)
-  while pc.int < c.code.len:
-    when false: # c.interactive:
-      echo "running: ", pc.int
-      debug c, pc
-
-    case c.code[pc].kind
-    of GotoM:
-      pc = CodePos(c.code[pc].operand)
-    of AsgnM:
-      let (sz, a, b) = sons3(c.code, pc)
-      let dest = evalAddr(c, a, frame)
-      eval(c, b, frame, dest, c.code[sz].operand.int)
-      next c, pc
-    of StoreM:
-      let (sz, a, b) = sons3(c.code, pc)
-      let destPtr = evalAddr(c, a, frame)
-      let dest = cast[ptr pointer](destPtr)[]
-      eval(c, b, frame, dest, c.code[sz].operand.int)
-      next c, pc
-    of CallM:
-      # No support for return values, these are mapped to `var T` parameters!
-      var prc = evalProc(c, pc.firstSon, frame)
-      assert c.code[prc.firstSon].kind == AllocLocals
-      let frameSize = int c.code[prc.firstSon].operand
-      # skip stupid stuff:
-      var evalState = DidNothing
-      prc = evalBuiltin(c, pc, frame, prc.firstSon, evalState)
-      if evalState != DidNothing:
-        next c, pc
-        if pc.int < c.code.len and c.code[pc].kind == CheckedGotoM:
-          if evalState == DidEval:
-            next c, pc
-          else:
-            pc = CodePos(c.code[pc].operand)
-      else:
-        # setup storage for the proc already:
-        let callInstr = pc
-        next c, pc
-        let s2 = newStackFrame(frameSize, frame, pc)
-        for a in sonsFrom1(c, callInstr):
-          assert c[prc].kind == SummonParamM
-          let paramAddr = c[prc].operand
-          next c, prc
-          assert c[prc].kind == ImmediateValM
-          let paramSize = c[prc].operand.int
-          next c, prc
-          eval(c, a, s2, s2.locals +! paramAddr, paramSize)
-        frame = s2
-        pc = prc
-    of RetM:
-      pc = frame.returnAddr
-      if c.code[pc].kind == CheckedGotoM:
-        pc = frame.jumpTo
-      frame = popStackFrame(frame)
-    of SelectM:
-      let pc2 = evalSelect(c, pc, frame)
-      if pc2.int >= 0:
-        pc = pc2
-      else:
-        next c, pc
-    of ProcDeclM:
-      next c, pc
-    else:
-      #debug c, c.debug[pc.int]
-      raiseAssert "unreachable: " & $c.code[pc].kind
-
-proc execCode*(bc: var Bytecode; t: Tree; n: NodePos) =
-  traverseTypes bc
-  var c = Preprocessing(u: nil, thisModule: 1'u32)
-  let start = CodePos(bc.code.len)
-  var pc = n
-  while pc.int < t.len:
-    #if bc.interactive:
-    #  echo "RUnning: "
-    #  debug bc, t, pc
-    preprocess c, bc, t, pc, {}
-    next t, pc
-  exec bc, start, nil
diff --git a/compiler/nir/stringcases.nim b/compiler/nir/stringcases.nim
deleted file mode 100644
index afdf8fda4..000000000
--- a/compiler/nir/stringcases.nim
+++ /dev/null
@@ -1,200 +0,0 @@
-#
-#
-#           The Nim Compiler
-#        (c) Copyright 2023 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## included from ast2ir.nim
-
-#[
-
-case s
-of "abc", "abbd":
-  echo 1
-of "hah":
-  echo 2
-of "gah":
-  echo 3
-
-# we produce code like this:
-
-if s[0] <= 'a':
-  if s == "abc: goto L1
-  elif s == "abbd": goto L1
-else:
-  if s[2] <= 'h':
-    if s == "hah": goto L2
-    elif s == "gah": goto L3
-goto afterCase
-
-L1:
-  echo 1
-  goto afterCase
-L2:
-  echo 2
-  goto afterCase
-L3:
-  echo 3
-  goto afterCase
-
-afterCase: ...
-
-]#
-
-# We split the set of strings into 2 sets of roughly the same size.
-# The condition used for splitting is a (position, char) tuple.
-# Every string of length > position for which s[position] <= char is in one
-# set else it is in the other set.
-
-from std/sequtils import addUnique
-
-type
-  Key = (LitId, LabelId)
-
-proc splitValue(strings: BiTable[string]; a: openArray[Key]; position: int): (char, float) =
-  var cand: seq[char] = @[]
-  for t in items a:
-    let s = strings[t[0]]
-    if s.len > position: cand.addUnique s[position]
-
-  result = ('\0', -1.0)
-  for disc in items cand:
-    var hits = 0
-    for t in items a:
-      let s = strings[t[0]]
-      if s.len > position and s[position] <= disc:
-        inc hits
-    # the split is the better, the more `hits` is close to `a.len / 2`:
-    let grade = 100000.0 - abs(hits.float - a.len.float / 2.0)
-    if grade > result[1]:
-      result = (disc, grade)
-
-proc tryAllPositions(strings: BiTable[string]; a: openArray[Key]): (char, int) =
-  var m = 0
-  for t in items a:
-    m = max(m, strings[t[0]].len)
-
-  result = ('\0', -1)
-  var best = -1.0
-  for i in 0 ..< m:
-    let current = splitValue(strings, a, i)
-    if current[1] > best:
-      best = current[1]
-      result = (current[0], i)
-
-type
-  SearchKind = enum
-    LinearSearch, SplitSearch
-  SearchResult* = object
-    case kind: SearchKind
-    of LinearSearch:
-      a: seq[Key]
-    of SplitSearch:
-      span: int
-      best: (char, int)
-
-proc emitLinearSearch(strings: BiTable[string]; a: openArray[Key]; dest: var seq[SearchResult]) =
-  var d = SearchResult(kind: LinearSearch, a: @[])
-  for x in a: d.a.add x
-  dest.add d
-
-proc split(strings: BiTable[string]; a: openArray[Key]; dest: var seq[SearchResult]) =
-  if a.len <= 4:
-    emitLinearSearch strings, a, dest
-  else:
-    let best = tryAllPositions(strings, a)
-    var groupA: seq[Key] = @[]
-    var groupB: seq[Key] = @[]
-    for t in items a:
-      let s = strings[t[0]]
-      if s.len > best[1] and s[best[1]] <= best[0]:
-        groupA.add t
-      else:
-        groupB.add t
-    if groupA.len == 0 or groupB.len == 0:
-      emitLinearSearch strings, a, dest
-    else:
-      let toPatch = dest.len
-      dest.add SearchResult(kind: SplitSearch, span: 1, best: best)
-      split strings, groupA, dest
-      split strings, groupB, dest
-      let dist = dest.len - toPatch
-      assert dist > 0
-      dest[toPatch].span = dist
-
-proc toProblemDescription(c: var ProcCon; n: PNode): (seq[Key], LabelId) =
-  result = (@[], newLabels(c.labelGen, n.len))
-  assert n.kind == nkCaseStmt
-  for i in 1..<n.len:
-    let it = n[i]
-    let thisBranch = LabelId(result[1].int + i - 1)
-    if it.kind == nkOfBranch:
-      for j in 0..<it.len-1:
-        assert it[j].kind in {nkStrLit..nkTripleStrLit}
-        result[0].add (c.lit.strings.getOrIncl(it[j].strVal), thisBranch)
-
-proc decodeSolution(c: var ProcCon; dest: var Tree; s: seq[SearchResult]; i: int;
-                    selector: Value; info: PackedLineInfo) =
-  case s[i].kind
-  of SplitSearch:
-    let thenA = i+1
-    let elseA = thenA + (if s[thenA].kind == LinearSearch: 1 else: s[thenA].span)
-    let best = s[i].best
-
-    let tmp = getTemp(c, Bool8Id, info)
-    buildTyped dest, info, Asgn, Bool8Id:
-      dest.copyTree tmp
-      buildTyped dest, info, Call, Bool8Id:
-        c.addUseCodegenProc dest, "nimStrAtLe", info
-        dest.copyTree selector
-        dest.addIntVal c.lit.numbers, info, c.m.nativeIntId, best[1]
-        dest.addIntVal c.lit.numbers, info, Char8Id, best[0].int
-
-    template then() =
-      c.decodeSolution dest, s, thenA, selector, info
-    template otherwise() =
-      c.decodeSolution dest, s, elseA, selector, info
-    buildIfThenElse tmp, then, otherwise
-    freeTemp c, tmp
-
-  of LinearSearch:
-    let tmp = getTemp(c, Bool8Id, info)
-    for x in s[i].a:
-      buildTyped dest, info, Asgn, Bool8Id:
-        dest.copyTree tmp
-        buildTyped dest, info, Call, Bool8Id:
-          c.addUseCodegenProc dest, "eqStrings", info
-          dest.copyTree selector
-          dest.addStrLit info, x[0]
-      buildIf tmp:
-        c.code.gotoLabel info, Goto, x[1]
-    freeTemp c, tmp
-
-proc genStringCase(c: var ProcCon; n: PNode; d: var Value) =
-  let (problem, firstBranch) = toProblemDescription(c, n)
-  var solution: seq[SearchResult] = @[]
-  split c.lit.strings, problem, solution
-
-  # XXX Todo move complex case selector into a temporary.
-  let selector = c.genx(n[0])
-
-  let info = toLineInfo(c, n.info)
-  decodeSolution c, c.code, solution, 0, selector, info
-
-  let lend = newLabel(c.labelGen)
-  c.code.addLabel info, Goto, lend
-  for i in 1..<n.len:
-    let it = n[i]
-    let thisBranch = LabelId(firstBranch.int + i - 1)
-    c.code.addLabel info, Label, thisBranch
-    if it.kind == nkOfBranch:
-      gen(c, it.lastSon, d)
-      c.code.addLabel info, Goto, lend
-    else:
-      gen(c, it.lastSon, d)
-
-  c.code.addLabel info, Label, lend
-  freeTemp c, selector
diff --git a/compiler/nir/types2ir.nim b/compiler/nir/types2ir.nim
deleted file mode 100644
index 8d9583486..000000000
--- a/compiler/nir/types2ir.nim
+++ /dev/null
@@ -1,525 +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, types, options, sighashes, modulegraphs]
-import nirtypes
-
-type
-  TypesCon* = object
-    processed: Table[ItemId, TypeId]
-    processedByName: Table[string, TypeId]
-    recursionCheck: HashSet[ItemId]
-    conf: ConfigRef
-    stringType: TypeId
-
-proc initTypesCon*(conf: ConfigRef): TypesCon =
-  TypesCon(conf: conf, stringType: TypeId(-1))
-
-proc mangle(c: var TypesCon; t: PType): string =
-  result = $sighashes.hashType(t, c.conf)
-
-template cached(c: var TypesCon; t: PType; body: untyped) =
-  result = c.processed.getOrDefault(t.itemId)
-  if result.int == 0:
-    body
-    c.processed[t.itemId] = result
-
-template cachedByName(c: var TypesCon; t: PType; body: untyped) =
-  let key = mangle(c, t)
-  result = c.processedByName.getOrDefault(key)
-  if result.int == 0:
-    body
-    c.processedByName[key] = result
-
-proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId
-
-proc collectFieldTypes(c: var TypesCon; g: var TypeGraph; n: PNode; dest: var Table[ItemId, TypeId]) =
-  case n.kind
-  of nkRecList:
-    for i in 0..<n.len:
-      collectFieldTypes(c, g, n[i], dest)
-  of nkRecCase:
-    assert(n[0].kind == nkSym)
-    collectFieldTypes(c, g, n[0], dest)
-    for i in 1..<n.len:
-      case n[i].kind
-      of nkOfBranch, nkElse:
-        collectFieldTypes c, g, lastSon(n[i]), dest
-      else: discard
-  of nkSym:
-    dest[n.sym.itemId] = typeToIr(c, g, n.sym.typ)
-  else:
-    assert false, "unknown node kind: " & $n.kind
-
-proc objectToIr(c: var TypesCon; g: var TypeGraph; n: PNode; fieldTypes: Table[ItemId, TypeId]; unionId: var int) =
-  case n.kind
-  of nkRecList:
-    for i in 0..<n.len:
-      objectToIr(c, g, n[i], fieldTypes, unionId)
-  of nkRecCase:
-    assert(n[0].kind == nkSym)
-    objectToIr(c, g, n[0], fieldTypes, unionId)
-    let u = openType(g, UnionDecl)
-    g.addName "u_" & $unionId
-    inc unionId
-    for i in 1..<n.len:
-      case n[i].kind
-      of nkOfBranch, nkElse:
-        let subObj = openType(g, ObjectDecl)
-        g.addName "uo_" & $unionId & "_" & $i
-        objectToIr c, g, lastSon(n[i]), fieldTypes, unionId
-        sealType(g, subObj)
-      else: discard
-    sealType(g, u)
-  of nkSym:
-    g.addField n.sym.name.s & "_" & $n.sym.position, fieldTypes[n.sym.itemId], n.sym.offset
-  else:
-    assert false, "unknown node kind: " & $n.kind
-
-proc objectToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
-  if t.baseClass != nil:
-    # ensure we emitted the base type:
-    discard typeToIr(c, g, t.baseClass)
-
-  var unionId = 0
-  var fieldTypes = initTable[ItemId, TypeId]()
-  collectFieldTypes c, g, t.n, fieldTypes
-  let obj = openType(g, ObjectDecl)
-  g.addName mangle(c, t)
-  g.addSize c.conf.getSize(t)
-  g.addAlign c.conf.getAlign(t)
-
-  if t.baseClass != nil:
-    g.addNominalType(ObjectTy, mangle(c, t.baseClass))
-  else:
-    g.addBuiltinType VoidId # object does not inherit
-    if not lacksMTypeField(t):
-      let f2 = g.openType FieldDecl
-      let voidPtr = openType(g, APtrTy)
-      g.addBuiltinType(VoidId)
-      sealType(g, voidPtr)
-      g.addOffset 0 # type field is always at offset 0
-      g.addName "m_type"
-      sealType(g, f2) # FieldDecl
-
-  objectToIr c, g, t.n, fieldTypes, unionId
-  result = finishType(g, obj)
-
-proc objectHeaderToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
-  result = g.nominalType(ObjectTy, mangle(c, t))
-
-proc tupleToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
-  var fieldTypes = newSeq[TypeId](t.len)
-  for i in 0..<t.len:
-    fieldTypes[i] = typeToIr(c, g, t[i])
-  let obj = openType(g, ObjectDecl)
-  g.addName mangle(c, t)
-  g.addSize c.conf.getSize(t)
-  g.addAlign c.conf.getAlign(t)
-
-  var accum = OffsetAccum(maxAlign: 1)
-  for i in 0..<t.len:
-    let child = t[i]
-    g.addField "f_" & $i, fieldTypes[i], accum.offset
-
-    computeSizeAlign(c.conf, child)
-    accum.align(child.align)
-    accum.inc(int32(child.size))
-  result = finishType(g, obj)
-
-proc procToIr(c: var TypesCon; g: var TypeGraph; t: PType; addEnv = false): TypeId =
-  var fieldTypes = newSeq[TypeId](0)
-  for i in 0..<t.len:
-    if t[i] == nil or not isCompileTimeOnly(t[i]):
-      fieldTypes.add typeToIr(c, g, t[i])
-  let obj = openType(g, ProcTy)
-
-  case t.callConv
-  of ccNimCall, ccFastCall, ccClosure: g.addAnnotation "__fastcall"
-  of ccStdCall: g.addAnnotation "__stdcall"
-  of ccCDecl: g.addAnnotation "__cdecl"
-  of ccSafeCall: g.addAnnotation "__safecall"
-  of ccSysCall: g.addAnnotation "__syscall"
-  of ccInline: g.addAnnotation "__inline"
-  of ccNoInline: g.addAnnotation "__noinline"
-  of ccThisCall: g.addAnnotation "__thiscall"
-  of ccNoConvention, ccMember: g.addAnnotation ""
-
-  for i in 0..<fieldTypes.len:
-    g.addType fieldTypes[i]
-
-  if addEnv:
-    let a = openType(g, APtrTy)
-    g.addBuiltinType(VoidId)
-    sealType(g, a)
-
-  if tfVarargs in t.flags:
-    g.addVarargs()
-  result = finishType(g, obj)
-
-proc nativeInt(c: TypesCon): TypeId =
-  case c.conf.target.intSize
-  of 2: result = Int16Id
-  of 4: result = Int32Id
-  else: result = Int64Id
-
-proc openArrayPayloadType*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
-  let e = elementType(t)
-  let elementType = typeToIr(c, g, e)
-  let arr = g.openType AArrayPtrTy
-  g.addType elementType
-  result = finishType(g, arr) # LastArrayTy
-
-proc openArrayToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
-  # object (a: ArrayPtr[T], len: int)
-  let e = elementType(t)
-  let mangledBase = mangle(c, e)
-  let typeName = "NimOpenArray" & mangledBase
-
-  let elementType = typeToIr(c, g, e)
-  #assert elementType.int >= 0, typeToString(t)
-
-  let p = openType(g, ObjectDecl)
-  g.addName typeName
-  g.addSize c.conf.target.ptrSize*2
-  g.addAlign c.conf.target.ptrSize
-
-  let f = g.openType FieldDecl
-  let arr = g.openType AArrayPtrTy
-  g.addType elementType
-  sealType(g, arr) # LastArrayTy
-  g.addOffset 0
-  g.addName "data"
-  sealType(g, f) # FieldDecl
-
-  g.addField "len", c.nativeInt, c.conf.target.ptrSize
-
-  result = finishType(g, p) # ObjectDecl
-
-proc strPayloadType(c: var TypesCon; g: var TypeGraph): (string, TypeId) =
-  result = ("NimStrPayload", TypeId(-1))
-  let p = openType(g, ObjectDecl)
-  g.addName result[0]
-  g.addSize c.conf.target.ptrSize*2
-  g.addAlign c.conf.target.ptrSize
-
-  g.addField "cap", c.nativeInt, 0
-
-  let f = g.openType FieldDecl
-  let arr = g.openType LastArrayTy
-  g.addBuiltinType Char8Id
-  result[1] = finishType(g, arr) # LastArrayTy
-  g.addOffset c.conf.target.ptrSize # comes after the len field
-  g.addName "data"
-  sealType(g, f) # FieldDecl
-
-  sealType(g, p)
-
-proc strPayloadPtrType*(c: var TypesCon; g: var TypeGraph): (TypeId, TypeId) =
-  let (mangled, arrayType) = strPayloadType(c, g)
-  let ffp = g.openType APtrTy
-  g.addNominalType ObjectTy, mangled
-  result = (finishType(g, ffp), arrayType) # APtrTy
-
-proc stringToIr(c: var TypesCon; g: var TypeGraph): TypeId =
-  #[
-
-    NimStrPayload = object
-      cap: int
-      data: UncheckedArray[char]
-
-    NimStringV2 = object
-      len: int
-      p: ptr NimStrPayload
-
-  ]#
-  let payload = strPayloadType(c, g)
-
-  let str = openType(g, ObjectDecl)
-  g.addName "NimStringV2"
-  g.addSize c.conf.target.ptrSize*2
-  g.addAlign c.conf.target.ptrSize
-
-  g.addField "len", c.nativeInt, 0
-
-  let fp = g.openType FieldDecl
-  let ffp = g.openType APtrTy
-  g.addNominalType ObjectTy, "NimStrPayload"
-  sealType(g, ffp) # APtrTy
-  g.addOffset c.conf.target.ptrSize # comes after 'len' field
-  g.addName "p"
-  sealType(g, fp) # FieldDecl
-
-  result = finishType(g, str) # ObjectDecl
-
-proc seqPayloadType(c: var TypesCon; g: var TypeGraph; t: PType): (string, TypeId) =
-  #[
-    NimSeqPayload[T] = object
-      cap: int
-      data: UncheckedArray[T]
-  ]#
-  let e = elementType(t)
-  result = (mangle(c, e), TypeId(-1))
-  let payloadName = "NimSeqPayload" & result[0]
-
-  let elementType = typeToIr(c, g, e)
-
-  let p = openType(g, ObjectDecl)
-  g.addName payloadName
-  g.addSize c.conf.target.intSize
-  g.addAlign c.conf.target.intSize
-
-  g.addField "cap", c.nativeInt, 0
-
-  let f = g.openType FieldDecl
-  let arr = g.openType LastArrayTy
-  g.addType elementType
-  # DO NOT USE `finishType` here as it is an inner type. This is subtle and we
-  # probably need an even better API here.
-  sealType(g, arr)
-  result[1] = TypeId(arr)
-
-  g.addOffset c.conf.target.ptrSize
-  g.addName "data"
-  sealType(g, f) # FieldDecl
-
-  sealType(g, p)
-
-proc seqPayloadPtrType*(c: var TypesCon; g: var TypeGraph; t: PType): (TypeId, TypeId) =
-  let (mangledBase, arrayType) = seqPayloadType(c, g, t)
-  let ffp = g.openType APtrTy
-  g.addNominalType ObjectTy, "NimSeqPayload" & mangledBase
-  result = (finishType(g, ffp), arrayType) # APtrTy
-
-proc seqToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
-  #[
-    NimSeqV2*[T] = object
-      len: int
-      p: ptr NimSeqPayload[T]
-  ]#
-  let (mangledBase, _) = seqPayloadType(c, g, t)
-
-  let sq = openType(g, ObjectDecl)
-  g.addName "NimSeqV2" & mangledBase
-  g.addSize c.conf.getSize(t)
-  g.addAlign c.conf.getAlign(t)
-
-  g.addField "len", c.nativeInt, 0
-
-  let fp = g.openType FieldDecl
-  let ffp = g.openType APtrTy
-  g.addNominalType ObjectTy, "NimSeqPayload" & mangledBase
-  sealType(g, ffp) # APtrTy
-  g.addOffset c.conf.target.ptrSize
-  g.addName "p"
-  sealType(g, fp) # FieldDecl
-
-  result = finishType(g, sq) # ObjectDecl
-
-
-proc closureToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
-  # struct {fn(args, void* env), env}
-  # typedef struct {$n" &
-  #        "N_NIMCALL_PTR($2, ClP_0) $3;$n" &
-  #        "void* ClE_0;$n} $1;$n"
-  let mangledBase = mangle(c, t)
-  let typeName = "NimClosure" & mangledBase
-
-  let procType = procToIr(c, g, t, addEnv=true)
-
-  let p = openType(g, ObjectDecl)
-  g.addName typeName
-  g.addSize c.conf.getSize(t)
-  g.addAlign c.conf.getAlign(t)
-
-  let f = g.openType FieldDecl
-  g.addType procType
-  g.addOffset 0
-  g.addName "ClP_0"
-  sealType(g, f) # FieldDecl
-
-  let f2 = g.openType FieldDecl
-  let voidPtr = openType(g, APtrTy)
-  g.addBuiltinType(VoidId)
-  sealType(g, voidPtr)
-
-  g.addOffset c.conf.target.ptrSize
-  g.addName "ClE_0"
-  sealType(g, f2) # FieldDecl
-
-  result = finishType(g, p) # ObjectDecl
-
-proc bitsetBasetype*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
-  let s = int(getSize(c.conf, t))
-  case s
-  of 1: result = UInt8Id
-  of 2: result = UInt16Id
-  of 4: result = UInt32Id
-  of 8: result = UInt64Id
-  else: result = UInt8Id
-
-proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
-  if t == nil: return VoidId
-  case t.kind
-  of tyInt:
-    case int(getSize(c.conf, t))
-    of 2: result = Int16Id
-    of 4: result = Int32Id
-    else: result = Int64Id
-  of tyInt8: result = Int8Id
-  of tyInt16: result = Int16Id
-  of tyInt32: result = Int32Id
-  of tyInt64: result = Int64Id
-  of tyFloat:
-    case int(getSize(c.conf, t))
-    of 4: result = Float32Id
-    else: result = Float64Id
-  of tyFloat32: result = Float32Id
-  of tyFloat64: result = Float64Id
-  of tyFloat128: result = getFloat128Type(g)
-  of tyUInt:
-    case int(getSize(c.conf, t))
-    of 2: result = UInt16Id
-    of 4: result = UInt32Id
-    else: result = UInt64Id
-  of tyUInt8: result = UInt8Id
-  of tyUInt16: result = UInt16Id
-  of tyUInt32: result = UInt32Id
-  of tyUInt64: result = UInt64Id
-  of tyBool: result = Bool8Id
-  of tyChar: result = Char8Id
-  of tyVoid: result = VoidId
-  of tySink, tyGenericInst, tyDistinct, tyAlias, tyOwned, tyRange:
-    result = typeToIr(c, g, t.skipModifier)
-  of tyEnum:
-    if firstOrd(c.conf, t) < 0:
-      result = Int32Id
-    else:
-      case int(getSize(c.conf, t))
-      of 1: result = UInt8Id
-      of 2: result = UInt16Id
-      of 4: result = Int32Id
-      of 8: result = Int64Id
-      else: result = Int32Id
-  of tyOrdinal, tyGenericBody, tyGenericParam, tyInferred, tyStatic:
-    if t.len > 0:
-      result = typeToIr(c, g, t.skipModifier)
-    else:
-      result = TypeId(-1)
-  of tyFromExpr:
-    if t.n != nil and t.n.typ != nil:
-      result = typeToIr(c, g, t.n.typ)
-    else:
-      result = TypeId(-1)
-  of tyArray:
-    cached(c, t):
-      var n = toInt64(lengthOrd(c.conf, t))
-      if n <= 0: n = 1   # make an array of at least one element
-      let elemType = typeToIr(c, g, t.elementType)
-      let a = openType(g, ArrayTy)
-      g.addType(elemType)
-      g.addArrayLen n
-      g.addName mangle(c, t)
-      result = finishType(g, a)
-  of tyPtr, tyRef:
-    cached(c, t):
-      let e = t.elementType
-      if e.kind == tyUncheckedArray:
-        let elemType = typeToIr(c, g, e.elementType)
-        let a = openType(g, AArrayPtrTy)
-        g.addType(elemType)
-        result = finishType(g, a)
-      else:
-        let elemType = typeToIr(c, g, t.elementType)
-        let a = openType(g, APtrTy)
-        g.addType(elemType)
-        result = finishType(g, a)
-  of tyVar, tyLent:
-    cached(c, t):
-      let e = t.elementType
-      if e.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}:
-        # skip the modifier, `var openArray` is a (ptr, len) pair too:
-        result = typeToIr(c, g, e)
-      else:
-        let elemType = typeToIr(c, g, e)
-        let a = openType(g, APtrTy)
-        g.addType(elemType)
-        result = finishType(g, a)
-  of tySet:
-    let s = int(getSize(c.conf, t))
-    case s
-    of 1: result = UInt8Id
-    of 2: result = UInt16Id
-    of 4: result = UInt32Id
-    of 8: result = UInt64Id
-    else:
-      # array[U8, s]
-      cached(c, t):
-        let a = openType(g, ArrayTy)
-        g.addType(UInt8Id)
-        g.addArrayLen s
-        g.addName mangle(c, t)
-        result = finishType(g, a)
-  of tyPointer, tyNil:
-    # tyNil can happen for code like: `const CRAP = nil` which we have in posix.nim
-    let a = openType(g, APtrTy)
-    g.addBuiltinType(VoidId)
-    result = finishType(g, a)
-  of tyObject:
-    # Objects are special as they can be recursive in Nim. This is easily solvable.
-    # We check if we are already "processing" t. If so, we produce `ObjectTy`
-    # instead of `ObjectDecl`.
-    cached(c, t):
-      if not c.recursionCheck.containsOrIncl(t.itemId):
-        result = objectToIr(c, g, t)
-      else:
-        result = objectHeaderToIr(c, g, t)
-  of tyTuple:
-    cachedByName(c, t):
-      result = tupleToIr(c, g, t)
-  of tyProc:
-    cached(c, t):
-      if t.callConv == ccClosure:
-        result = closureToIr(c, g, t)
-      else:
-        result = procToIr(c, g, t)
-  of tyVarargs, tyOpenArray:
-    cached(c, t):
-      result = openArrayToIr(c, g, t)
-  of tyString:
-    if c.stringType.int < 0:
-      result = stringToIr(c, g)
-      c.stringType = result
-    else:
-      result = c.stringType
-  of tySequence:
-    cachedByName(c, t):
-      result = seqToIr(c, g, t)
-  of tyCstring:
-    cached(c, t):
-      let a = openType(g, AArrayPtrTy)
-      g.addBuiltinType Char8Id
-      result = finishType(g, a)
-  of tyUncheckedArray:
-    # We already handled the `ptr UncheckedArray` in a special way.
-    cached(c, t):
-      let elemType = typeToIr(c, g, t.elementType)
-      let a = openType(g, LastArrayTy)
-      g.addType(elemType)
-      result = finishType(g, a)
-  of tyUntyped, tyTyped:
-    # this avoids a special case for system.echo which is not a generic but
-    # uses `varargs[typed]`:
-    result = VoidId
-  of tyNone, tyEmpty, tyTypeDesc,
-     tyGenericInvocation, tyProxy, tyBuiltInTypeClass,
-     tyUserTypeClass, tyUserTypeClassInst, tyCompositeTypeClass,
-     tyAnd, tyOr, tyNot, tyAnything, tyConcept, tyIterable, tyForward:
-    result = TypeId(-1)
diff --git a/compiler/options.nim b/compiler/options.nim
index bdea506d2..975e21441 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -139,7 +139,6 @@ type
     backendCpp = "cpp"
     backendJs = "js"
     backendObjc = "objc"
-    backendNir = "nir"
     # backendNimscript = "nimscript" # this could actually work
     # backendLlvm = "llvm" # probably not well supported; was cmdCompileToLLVM
 
@@ -147,7 +146,6 @@ type
     cmdNone # not yet processed command
     cmdUnknown # command unmapped
     cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToJS,
-    cmdCompileToNir,
     cmdCrun # compile and run in nimache
     cmdTcc # run the project via TCC backend
     cmdCheck # semantic checking for whole project
@@ -176,7 +174,7 @@ type
 
 const
   cmdBackends* = {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
-                  cmdCompileToJS, cmdCrun, cmdCompileToNir}
+                  cmdCompileToJS, cmdCrun}
   cmdDocLike* = {cmdDoc0, cmdDoc, cmdDoc2tex, cmdJsondoc0, cmdJsondoc,
                  cmdCtags, cmdBuildindex}
 
diff --git a/compiler/pipelines.nim b/compiler/pipelines.nim
index a44edbb7f..55e7fe892 100644
--- a/compiler/pipelines.nim
+++ b/compiler/pipelines.nim
@@ -13,7 +13,6 @@ when not defined(leanCompiler):
 import std/[syncio, objectdollar, assertions, tables, strutils, strtabs]
 import renderer
 import ic/replayer
-import nir/nir
 
 proc setPipeLinePass*(graph: ModuleGraph; pass: PipelinePass) =
   graph.pipelinePass = pass
@@ -45,10 +44,6 @@ proc processPipeline(graph: ModuleGraph; semNode: PNode; bModule: PPassContext):
       result = nil
   of EvalPass, InterpreterPass:
     result = interpreterCode(bModule, semNode)
-  of NirReplPass:
-    result = runCode(bModule, semNode)
-  of NirPass:
-    result = nirBackend(bModule, semNode)
   of NonePass:
     raiseAssert "use setPipeLinePass to set a proper PipelinePass"
 
@@ -111,8 +106,6 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
     case graph.pipelinePass
     of CgenPass:
       setupCgen(graph, module, idgen)
-    of NirPass:
-      openNirBackend(graph, module, idgen)
     of JSgenPass:
       when not defined(leanCompiler):
         setupJSgen(graph, module, idgen)
@@ -120,8 +113,6 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
         nil
     of EvalPass, InterpreterPass:
       setupEvalGen(graph, module, idgen)
-    of NirReplPass:
-      setupNirReplGen(graph, module, idgen)
     of GenDependPass:
       setupDependPass(graph, module, idgen)
     of Docgen2Pass:
@@ -209,10 +200,6 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
       discard finalJSCodeGen(graph, bModule, finalNode)
   of EvalPass, InterpreterPass:
     discard interpreterCode(bModule, finalNode)
-  of NirReplPass:
-    discard runCode(bModule, finalNode)
-  of NirPass:
-    closeNirBackend(bModule, finalNode)
   of SemPass, GenDependPass:
     discard
   of Docgen2Pass, Docgen2TexPass: