diff options
Diffstat (limited to 'compiler/ic')
-rw-r--r-- | compiler/ic/cbackend.nim | 10 | ||||
-rw-r--r-- | compiler/ic/dce.nim | 53 | ||||
-rw-r--r-- | compiler/ic/packed_ast.nim | 1 | ||||
-rw-r--r-- | compiler/ic/replayer.nim | 16 | ||||
-rw-r--r-- | compiler/ic/to_packed_ast.nim | 52 |
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), |