summary refs log tree commit diff stats
path: root/compiler/ic/cbackend.nim
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2021-01-23 08:06:15 +0100
committerGitHub <noreply@github.com>2021-01-23 08:06:15 +0100
commit8241e55023ee32c9ec0b5443723bbe91f4fe875f (patch)
treed14be71f134b1789db54028704748c4dbed46bfa /compiler/ic/cbackend.nim
parenteae3bdf8fe554cdd334b8a53de63fd9bf10a7832 (diff)
downloadNim-8241e55023ee32c9ec0b5443723bbe91f4fe875f.tar.gz
IC: next steps (#16729)
* IC: dead code elimination pass
* preparations for a different codegen strategy
* added documentation to the newly written code
* IC: backend code
* IC: backend adjustments
* optimized the compiler a bit
* IC: yet another massive refactoring
* fixes regressions
* cleanups
Diffstat (limited to 'compiler/ic/cbackend.nim')
-rw-r--r--compiler/ic/cbackend.nim102
1 files changed, 102 insertions, 0 deletions
diff --git a/compiler/ic/cbackend.nim b/compiler/ic/cbackend.nim
new file mode 100644
index 000000000..fbc2d401e
--- /dev/null
+++ b/compiler/ic/cbackend.nim
@@ -0,0 +1,102 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2021 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## New entry point into our C/C++ code generator. Ideally
+## somebody would rewrite the old backend (which is 8000 lines of crufty Nim code)
+## to work on packed trees directly and produce the C code as an AST which can
+## then be rendered to text in a very simple manner. Unfortunately nobody wrote
+## this code. So instead we wrap the existing cgen.nim and its friends so that
+## we call directly into the existing code generation logic but avoiding the
+## naive, outdated `passes` design. Thus you will see some
+## `useAliveDataFromDce in flags` checks in the old code -- the old code is
+## also doing cross-module dependency tracking and DCE that we don't need
+## anymore. DCE is now done as prepass over the entire packed module graph.
+
+import std / [intsets, algorithm]
+import ".." / [ast, options, lineinfos, modulegraphs, cgendata, cgen,
+  pathutils, extccomp, msgs]
+
+import packed_ast, to_packed_ast, bitabs, dce, rodfiles
+
+proc unpackTree(g: ModuleGraph; thisModule: int;
+                tree: PackedTree; n: NodePos): PNode =
+  var decoder = initPackedDecoder(g.config, g.cache)
+  result = loadNodes(decoder, g.packed, thisModule, tree, n)
+
+proc generateCodeForModule(g: ModuleGraph; m: var LoadedModule; alive: var AliveSyms) =
+  if g.backend == nil:
+    g.backend = cgendata.newModuleList(g)
+
+  var bmod = cgen.newModule(BModuleList(g.backend), m.module, g.config)
+  bmod.idgen = idgenFromLoadedModule(m)
+  bmod.flags.incl useAliveDataFromDce
+  bmod.alive = move alive[m.module.position]
+
+  for p in allNodes(m.fromDisk.topLevel):
+    let n = unpackTree(g, m.module.position, m.fromDisk.topLevel, p)
+    cgen.genTopLevelStmt(bmod, n)
+
+  finalCodegenActions(g, bmod, newNodeI(nkStmtList, m.module.info))
+
+proc addFileToLink(config: ConfigRef; m: PSym) =
+  let filename = AbsoluteFile toFullPath(config, m.position.FileIndex)
+  let ext =
+      if config.backend == backendCpp: ".nim.cpp"
+      elif config.backend == backendObjc: ".nim.m"
+      else: ".nim.c"
+  let cfile = changeFileExt(completeCfilePath(config, withPackageName(config, filename)), ext)
+  var cf = Cfile(nimname: m.name.s, cname: cfile,
+                 obj: completeCfilePath(config, toObjFile(config, cfile)),
+                 flags: {CfileFlag.Cached})
+  addFileToCompile(config, cf)
+
+proc aliveSymsChanged(config: ConfigRef; position: int; alive: AliveSyms): bool =
+  let asymFile = toRodFile(config, AbsoluteFile toFullPath(config, position.FileIndex), ".alivesyms")
+  var s = newSeqOfCap[int32](alive[position].len)
+  for a in items(alive[position]): s.add int32(a)
+  sort(s)
+  var f2 = rodfiles.open(asymFile.string)
+  f2.loadHeader()
+  f2.loadSection aliveSymsSection
+  var oldData: seq[int32]
+  f2.loadSeq(oldData)
+  f2.close
+  if f2.err == ok and oldData == s:
+    result = false
+  else:
+    result = true
+    var f = rodfiles.create(asymFile.string)
+    f.storeHeader()
+    f.storeSection aliveSymsSection
+    f.storeSeq(s)
+    close f
+
+proc generateCode*(g: ModuleGraph) =
+  ## The single entry point, generate C(++) code for the entire
+  ## Nim program aka `ModuleGraph`.
+  var alive = computeAliveSyms(g.packed, g.config)
+
+  for i in 0..high(g.packed):
+    # case statement here to enforce exhaustive checks.
+    case g.packed[i].status
+    of undefined:
+      discard "nothing to do"
+    of loading:
+      assert false
+    of storing, outdated:
+      generateCodeForModule(g, g.packed[i], alive)
+    of loaded:
+      # Even though this module didn't change, DCE might trigger a change.
+      # Consider this case: Module A uses symbol S from B and B does not use
+      # S itself. A is then edited not to use S either. Thus we have to
+      # recompile B in order to remove S from the final result.
+      if aliveSymsChanged(g.config, g.packed[i].module.position, alive):
+        generateCodeForModule(g, g.packed[i], alive)
+      else:
+        addFileToLink(g.config, g.packed[i].module)