summary refs log tree commit diff stats
path: root/compiler/nir/cir.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/nir/cir.nim')
-rw-r--r--compiler/nir/cir.nim983
1 files changed, 0 insertions, 983 deletions
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