summary refs log tree commit diff stats
path: root/compiler/ic
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/ic')
-rw-r--r--compiler/ic/cbackend.nim10
-rw-r--r--compiler/ic/dce.nim53
-rw-r--r--compiler/ic/packed_ast.nim1
-rw-r--r--compiler/ic/replayer.nim16
-rw-r--r--compiler/ic/to_packed_ast.nim52
5 files changed, 106 insertions, 26 deletions
diff --git a/compiler/ic/cbackend.nim b/compiler/ic/cbackend.nim
index fbc2d401e..7670b34a6 100644
--- a/compiler/ic/cbackend.nim
+++ b/compiler/ic/cbackend.nim
@@ -51,10 +51,12 @@ proc addFileToLink(config: ConfigRef; m: PSym) =
       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)
+  let objFile = completeCfilePath(config, toObjFile(config, cfile))
+  if fileExists(objFile):
+    var cf = Cfile(nimname: m.name.s, cname: cfile,
+                   obj: objFile,
+                   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")
diff --git a/compiler/ic/dce.nim b/compiler/ic/dce.nim
index a6a4ab3b6..eb36e0302 100644
--- a/compiler/ic/dce.nim
+++ b/compiler/ic/dce.nim
@@ -9,18 +9,20 @@
 
 ## Dead code elimination (=DCE) for IC.
 
-import std / intsets
-import ".." / [ast, options, lineinfos]
+import std / [intsets, tables]
+import ".." / [ast, options, lineinfos, types]
 
 import packed_ast, to_packed_ast, bitabs
 
 type
   AliveSyms* = seq[IntSet]
   AliveContext* = object ## Purpose is to fill the 'alive' field.
-    stack: seq[(int, NodePos)] ## A stack for marking symbols as alive.
+    stack: seq[(int, TOptions, NodePos)] ## A stack for marking symbols as alive.
     decoder: PackedDecoder ## We need a PackedDecoder for module ID address translations.
     thisModule: int  ## The module we're currently analysing for DCE.
     alive: AliveSyms ## The final result of our computation.
+    options: TOptions
+    compilerProcs: Table[string, (int, int32)]
 
 proc isExportedToC(c: var AliveContext; g: PackedModuleGraph; symId: int32): bool =
   ## "Exported to C" procs are special (these are marked with '.exportc') because these
@@ -36,6 +38,8 @@ proc isExportedToC(c: var AliveContext; g: PackedModuleGraph; symId: int32): boo
       result = true
       # XXX: This used to be a condition to:
       #  (sfExportc in prc.flags and lfExportLib in prc.loc.flags) or
+    if sfCompilerProc in flags:
+      c.compilerProcs[g[c.thisModule].fromDisk.sh.strings[symPtr.name]] = (c.thisModule, symId)
 
 template isNotGeneric(n: NodePos): bool = ithSon(tree, n, genericParamsPos).kind == nkEmpty
 
@@ -45,7 +49,40 @@ proc followLater(c: var AliveContext; g: PackedModuleGraph; module: int; item: i
   if not c.alive[module].containsOrIncl(item):
     let body = g[module].fromDisk.sh.syms[item].ast
     if body != emptyNodeId:
-      c.stack.add((module, NodePos(body)))
+      let opt = g[module].fromDisk.sh.syms[item].options
+      c.stack.add((module, opt, NodePos(body)))
+
+proc requestCompilerProc(c: var AliveContext; g: PackedModuleGraph; name: string) =
+  let (module, item) = c.compilerProcs[name]
+  followLater(c, g, module, item)
+
+proc loadTypeKind(t: PackedItemId; c: AliveContext; g: PackedModuleGraph; toSkip: set[TTypeKind]): TTypeKind =
+  template kind(t: ItemId): TTypeKind = g[t.module].fromDisk.sh.types[t.item].kind
+
+  var t2 = translateId(t, g, c.thisModule, c.decoder.config)
+  result = t2.kind
+  while result in toSkip:
+    t2 = translateId(g[t2.module].fromDisk.sh.types[t2.item].types[^1], g, t2.module, c.decoder.config)
+    result = t2.kind
+
+proc rangeCheckAnalysis(c: var AliveContext; g: PackedModuleGraph; tree: PackedTree; n: NodePos) =
+  ## Replicates the logic of `ccgexprs.genRangeChck`.
+  ## XXX Refactor so that the duplicated logic is avoided. However, for now it's not clear
+  ## the approach has enough merit.
+  var dest = loadTypeKind(n.typ, c, g, abstractVar)
+  if optRangeCheck notin c.options or dest in {tyUInt..tyUInt64}:
+    discard "no need to generate a check because it was disabled"
+  else:
+    let n0t = loadTypeKind(n.firstSon.typ, c, g, {})
+    if n0t in {tyUInt, tyUInt64}:
+      c.requestCompilerProc(g, "raiseRangeErrorNoArgs")
+    else:
+      let raiser =
+        case loadTypeKind(n.typ, c, g, abstractVarRange)
+        of tyUInt..tyUInt64, tyChar: "raiseRangeErrorU"
+        of tyFloat..tyFloat128: "raiseRangeErrorF"
+        else: "raiseRangeErrorI"
+      c.requestCompilerProc(g, raiser)
 
 proc aliveCode(c: var AliveContext; g: PackedModuleGraph; tree: PackedTree; n: NodePos) =
   ## Marks the symbols we encounter when we traverse the AST at `tree[n]` as alive, unless
@@ -71,6 +108,8 @@ proc aliveCode(c: var AliveContext; g: PackedModuleGraph; tree: PackedTree; n: N
     discard
   of nkVarSection, nkLetSection, nkConstSection:
     discard
+  of nkChckRangeF, nkChckRange64, nkChckRange:
+    rangeCheckAnalysis(c, g, tree, n)
   of nkProcDef, nkConverterDef, nkMethodDef, nkLambda, nkDo, nkFuncDef:
     if n.firstSon.kind == nkSym and isNotGeneric(n):
       if isExportedToC(c, g, n.firstSon.operand):
@@ -85,14 +124,16 @@ proc followNow(c: var AliveContext; g: PackedModuleGraph) =
   ## Mark all entries in the stack. Marking can add more entries
   ## to the stack but eventually we have looked at every alive symbol.
   while c.stack.len > 0:
-    let (modId, ast) = c.stack.pop()
+    let (modId, opt, ast) = c.stack.pop()
     c.thisModule = modId
+    c.options = opt
     aliveCode(c, g, g[modId].fromDisk.bodies, ast)
 
 proc computeAliveSyms*(g: PackedModuleGraph; conf: ConfigRef): AliveSyms =
   ## Entry point for our DCE algorithm.
   var c = AliveContext(stack: @[], decoder: PackedDecoder(config: conf),
-                       thisModule: -1, alive: newSeq[IntSet](g.len))
+                       thisModule: -1, alive: newSeq[IntSet](g.len),
+                       options: conf.options)
   for i in countdown(high(g), 0):
     if g[i].status != undefined:
       c.thisModule = i
diff --git a/compiler/ic/packed_ast.nim b/compiler/ic/packed_ast.nim
index 95cac4700..86636f902 100644
--- a/compiler/ic/packed_ast.nim
+++ b/compiler/ic/packed_ast.nim
@@ -62,6 +62,7 @@ type
     position*: int
     offset*: int
     externalName*: LitId # instead of TLoc
+    locFlags*: TLocFlags
     annex*: PackedLib
     when hasFFI:
       cname*: LitId
diff --git a/compiler/ic/replayer.nim b/compiler/ic/replayer.nim
index 579fa8f1b..b0ea557e4 100644
--- a/compiler/ic/replayer.nim
+++ b/compiler/ic/replayer.nim
@@ -127,3 +127,19 @@ proc replayGenericCacheInformation*(g: ModuleGraph; module: int) =
     let sym = loadSymFromId(g.config, g.cache, g.packed, module,
                             PackedItemId(module: LitId(0), item: it))
     methodDef(g, g.idgen, sym)
+
+  for it in mitems(g.packed[module].fromDisk.compilerProcs):
+    let symId = FullId(module: module, packed: PackedItemId(module: LitId(0), item: it[1]))
+    g.lazyCompilerprocs[g.packed[module].fromDisk.sh.strings[it[0]]] = symId
+
+  for it in mitems(g.packed[module].fromDisk.converters):
+    let symId = FullId(module: module, packed: PackedItemId(module: LitId(0), item: it))
+    g.ifaces[module].converters.add LazySym(id: symId, sym: nil)
+
+  for it in mitems(g.packed[module].fromDisk.trmacros):
+    let symId = FullId(module: module, packed: PackedItemId(module: LitId(0), item: it))
+    g.ifaces[module].patterns.add LazySym(id: symId, sym: nil)
+
+  for it in mitems(g.packed[module].fromDisk.pureEnums):
+    let symId = FullId(module: module, packed: PackedItemId(module: LitId(0), item: it))
+    g.ifaces[module].pureEnums.add LazySym(id: symId, sym: nil)
diff --git a/compiler/ic/to_packed_ast.nim b/compiler/ic/to_packed_ast.nim
index 8b6e63f9e..4a0deede4 100644
--- a/compiler/ic/to_packed_ast.nim
+++ b/compiler/ic/to_packed_ast.nim
@@ -32,8 +32,8 @@ type
     #producedGenerics*: Table[GenericKey, SymId]
     exports*: seq[(LitId, int32)]
     reexports*: seq[(LitId, PackedItemId)]
-    compilerProcs*, trmacros*, converters*, pureEnums*: seq[(LitId, int32)]
-    methods*: seq[int32]
+    compilerProcs*: seq[(LitId, int32)]
+    converters*, methods*, trmacros*, pureEnums*: seq[int32]
     macroUsages*: seq[(PackedItemId, PackedLineInfo)]
 
     typeInstCache*: seq[(PackedItemId, PackedItemId)]
@@ -154,17 +154,14 @@ proc addExported*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
   m.exports.add((nameId, s.itemId.item))
 
 proc addConverter*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
-  let nameId = getOrIncl(m.sh.strings, s.name.s)
-  m.converters.add((nameId, s.itemId.item))
+  m.converters.add(s.itemId.item)
 
 proc addTrmacro*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
-  let nameId = getOrIncl(m.sh.strings, s.name.s)
-  m.trmacros.add((nameId, s.itemId.item))
+  m.trmacros.add(s.itemId.item)
 
 proc addPureEnum*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
-  let nameId = getOrIncl(m.sh.strings, s.name.s)
   assert s.kind == skType
-  m.pureEnums.add((nameId, s.itemId.item))
+  m.pureEnums.add(s.itemId.item)
 
 proc addMethod*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
   m.methods.add s.itemId.item
@@ -349,6 +346,7 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId
       p.alignment = s.alignment
 
     p.externalName = toLitId(if s.loc.r.isNil: "" else: $s.loc.r, m)
+    p.locFlags = s.loc.flags
     c.addMissing s.typ
     p.typ = s.typ.storeType(c, m)
     c.addMissing s.owner
@@ -453,7 +451,7 @@ proc toPackedNodeTopLevel*(n: PNode, encoder: var PackedEncoder; m: var PackedMo
   flush encoder, m
 
 proc loadError(err: RodFileError; filename: AbsoluteFile) =
-  echo "Error: ", $err, "\nloading file: ", filename.string
+  echo "Error: ", $err, " loading file: ", filename.string
 
 proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef): RodFileError =
   m.sh = Shared()
@@ -751,6 +749,7 @@ proc symBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
   let externalName = g[si].fromDisk.sh.strings[s.externalName]
   if externalName != "":
     result.loc.r = rope externalName
+  result.loc.flags = s.locFlags
 
 proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s: PackedItemId): PSym =
   if s == nilItemId:
@@ -819,6 +818,17 @@ proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; t
       result = g[si].types[t.item]
     assert result.itemId.item > 0
 
+proc newPackage(config: ConfigRef; cache: IdentCache; fileIdx: FileIndex): PSym =
+  let filename = AbsoluteFile toFullPath(config, fileIdx)
+  let name = getIdent(cache, splitFile(filename).name)
+  let info = newLineInfo(fileIdx, 1, 1)
+  let
+    pck = getPackageName(config, filename.string)
+    pck2 = if pck.len > 0: pck else: "unknown"
+    pack = getIdent(cache, pck2)
+  result = newSym(skPackage, getIdent(cache, pck2),
+    ItemId(module: PackageModuleId, item: int32(fileIdx)), nil, info)
+
 proc setupLookupTables(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
                        fileIdx: FileIndex; m: var LoadedModule) =
   m.iface = initTable[PIdent, seq[PackedItemId]]()
@@ -836,6 +846,7 @@ proc setupLookupTables(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCa
                   name: getIdent(cache, splitFile(filename).name),
                   info: newLineInfo(fileIdx, 1, 1),
                   position: int(fileIdx))
+  m.module.owner = newPackage(conf, cache, fileIdx)
 
 proc loadToReplayNodes(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
                        fileIdx: FileIndex; m: var LoadedModule) =
@@ -851,7 +862,7 @@ proc loadToReplayNodes(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCa
       m.module.ast.add loadNodes(decoder, g, int(fileIdx), m.fromDisk.toReplay, p)
 
 proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
-                    fileIdx: FileIndex): bool =
+                    fileIdx: FileIndex; cachedModules: var seq[FileIndex]): bool =
   # Does the file belong to the fileIdx need to be recompiled?
   let m = int(fileIdx)
   if m >= g.len:
@@ -870,11 +881,12 @@ proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache
         let fid = toFileIndex(dep, g[m].fromDisk, conf)
         # Warning: we need to traverse the full graph, so
         # do **not use break here**!
-        if needsRecompile(g, conf, cache, fid):
+        if needsRecompile(g, conf, cache, fid, cachedModules):
           result = true
 
       if not result:
         setupLookupTables(g, conf, cache, fileIdx, g[m])
+        cachedModules.add fileIdx
       g[m].status = if result: outdated else: loaded
     else:
       loadError(err, rod)
@@ -887,14 +899,16 @@ proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache
     result = true
 
 proc moduleFromRodFile*(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
-                        fileIdx: FileIndex): PSym =
+                        fileIdx: FileIndex; cachedModules: var seq[FileIndex]): PSym =
   ## Returns 'nil' if the module needs to be recompiled.
-  if needsRecompile(g, conf, cache, fileIdx):
+  if needsRecompile(g, conf, cache, fileIdx, cachedModules):
     result = nil
   else:
     result = g[int fileIdx].module
     assert result != nil
-    loadToReplayNodes(g, conf, cache, fileIdx, g[int fileIdx])
+    assert result.position == int(fileIdx)
+    for m in cachedModules:
+      loadToReplayNodes(g, conf, cache, m, g[int m])
 
 template setupDecoder() {.dirty.} =
   var decoder = PackedDecoder(
@@ -919,7 +933,10 @@ proc loadProcBody*(config: ConfigRef, cache: IdentCache;
 
 proc loadTypeFromId*(config: ConfigRef, cache: IdentCache;
                      g: var PackedModuleGraph; module: int; id: PackedItemId): PType =
-  result = g[module].types[id.item]
+  if id.item < g[module].types.len:
+    result = g[module].types[id.item]
+  else:
+    result = nil
   if result == nil:
     var decoder = PackedDecoder(
       lastModule: int32(-1),
@@ -931,7 +948,10 @@ proc loadTypeFromId*(config: ConfigRef, cache: IdentCache;
 
 proc loadSymFromId*(config: ConfigRef, cache: IdentCache;
                     g: var PackedModuleGraph; module: int; id: PackedItemId): PSym =
-  result = g[module].syms[id.item]
+  if id.item < g[module].syms.len:
+    result = g[module].syms[id.item]
+  else:
+    result = nil
   if result == nil:
     var decoder = PackedDecoder(
       lastModule: int32(-1),