added a 'koch ic' command for easier adhoc testing of IC (#17508)

* added a 'koch ic' command for easier adhoc testing of IC
* IC: progress
* IC: enable generics test
* make tests green
This commit is contained in:
Andreas Rumpf 2021-03-26 08:52:26 +01:00 • committed by GitHub
commit e3e9742143
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 96 additions and 14 deletions

View file

@ -1357,9 +1357,6 @@ proc genTypeInfoV2Impl(m: BModule, t, origType: PType, name: Rope; info: TLineIn
if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions: if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions:
discard genTypeInfoV1(m, t, info) discard genTypeInfoV1(m, t, info)
proc moduleOpenForCodegen(m: BModule; module: int32): bool {.inline.} =
result = module < m.g.modules.len and m.g.modules[module] != nil
proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope = proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope =
let origType = t let origType = t
# distinct types can have their own destructors # distinct types can have their own destructors
@ -1384,7 +1381,7 @@ proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope =
m.typeInfoMarkerV2[sig] = result m.typeInfoMarkerV2[sig] = result
let owner = t.skipTypes(typedescPtrs).itemId.module let owner = t.skipTypes(typedescPtrs).itemId.module
if owner != m.module.position and moduleOpenForCodegen(m, owner): if owner != m.module.position and moduleOpenForCodegen(m.g.graph, FileIndex owner):
# make sure the type info is created in the owner module # make sure the type info is created in the owner module
discard genTypeInfoV2(m.g.modules[owner], origType, info) discard genTypeInfoV2(m.g.modules[owner], origType, info)
# reference the type info as extern here # reference the type info as extern here
@ -1463,7 +1460,7 @@ proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope =
return prefixTI.rope & result & ")".rope return prefixTI.rope & result & ")".rope
var owner = t.skipTypes(typedescPtrs).itemId.module var owner = t.skipTypes(typedescPtrs).itemId.module
if owner != m.module.position and moduleOpenForCodegen(m, owner): if owner != m.module.position and moduleOpenForCodegen(m.g.graph, FileIndex owner):
# make sure the type info is created in the owner module # make sure the type info is created in the owner module
discard genTypeInfoV1(m.g.modules[owner], origType, info) discard genTypeInfoV1(m.g.modules[owner], origType, info)
# reference the type info as extern here # reference the type info as extern here

View file

@ -22,6 +22,7 @@ when not defined(leanCompiler):
import strutils except `%` # collides with ropes.`%` import strutils except `%` # collides with ropes.`%`
from ic / ic import ModuleBackendFlag
from modulegraphs import ModuleGraph, PPassContext from modulegraphs import ModuleGraph, PPassContext
from lineinfos import from lineinfos import
warnGcMem, errXMustBeCompileTime, hintDependency, errGenerated, errCannotOpenFile warnGcMem, errXMustBeCompileTime, hintDependency, errGenerated, errCannotOpenFile
@ -1501,6 +1502,33 @@ proc genMainProc(m: BModule) =
if m.config.cppCustomNamespace.len > 0: if m.config.cppCustomNamespace.len > 0:
m.s[cfsProcs].add openNamespaceNim(m.config.cppCustomNamespace) m.s[cfsProcs].add openNamespaceNim(m.config.cppCustomNamespace)
proc registerInitProcs*(g: BModuleList; m: PSym; flags: set[ModuleBackendFlag]) =
## Called from the IC backend.
if HasDatInitProc in flags:
let datInit = getSomeNameForModule(m) & "DatInit000"
g.mainModProcs.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [datInit])
g.mainDatInit.addf("\t$1();$N", [datInit])
if HasModuleInitProc in flags:
let init = getSomeNameForModule(m) & "Init000"
g.mainModProcs.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [init])
let initCall = "\t$1();$N" % [init]
if sfMainModule in m.flags:
g.mainModInit.add(initCall)
elif sfSystemModule in m.flags:
g.mainDatInit.add(initCall) # systemInit must called right after systemDatInit if any
else:
g.otherModsInit.add(initCall)
proc whichInitProcs*(m: BModule): set[ModuleBackendFlag] =
# called from IC.
result = {}
if m.hcrOn or m.preInitProc.s(cpsInit).len > 0 or m.preInitProc.s(cpsStmts).len > 0:
result.incl HasModuleInitProc
for i in cfsTypeInit1..cfsDynLibInit:
if m.s[i].len != 0:
result.incl HasDatInitProc
break
proc registerModuleToMain(g: BModuleList; m: BModule) = proc registerModuleToMain(g: BModuleList; m: BModule) =
let let
init = m.getInitName init = m.getInitName
@ -1595,6 +1623,7 @@ proc genDatInitCode(m: BModule) =
if moduleDatInitRequired: if moduleDatInitRequired:
m.s[cfsDatInitProc].add(prc) m.s[cfsDatInitProc].add(prc)
#rememberFlag(m.g.graph, m.module, HasDatInitProc)
# Very similar to the contents of symInDynamicLib - basically only the # Very similar to the contents of symInDynamicLib - basically only the
# things needed for the hot code reloading runtime procs to be loaded # things needed for the hot code reloading runtime procs to be loaded
@ -1725,6 +1754,7 @@ proc genInitCode(m: BModule) =
if moduleInitRequired or sfMainModule in m.module.flags: if moduleInitRequired or sfMainModule in m.module.flags:
m.s[cfsInitProc].add(prc) m.s[cfsInitProc].add(prc)
#rememberFlag(m.g.graph, m.module, HasModuleInitProc)
genDatInitCode(m) genDatInitCode(m)

View file

@ -44,9 +44,11 @@ proc generateCodeForModule(g: ModuleGraph; m: var LoadedModule; alive: var Alive
cgen.genTopLevelStmt(bmod, n) cgen.genTopLevelStmt(bmod, n)
finalCodegenActions(g, bmod, newNodeI(nkStmtList, m.module.info)) finalCodegenActions(g, bmod, newNodeI(nkStmtList, m.module.info))
m.fromDisk.backendFlags = cgen.whichInitProcs(bmod)
proc replayTypeInfo(g: ModuleGraph; m: var LoadedModule; origin: FileIndex) = proc replayTypeInfo(g: ModuleGraph; m: var LoadedModule; origin: FileIndex) =
for x in mitems(m.fromDisk.emittedTypeInfo): for x in mitems(m.fromDisk.emittedTypeInfo):
#echo "found type ", x, " for file ", int(origin)
g.emittedTypeInfo[x] = origin g.emittedTypeInfo[x] = origin
proc addFileToLink(config: ConfigRef; m: PSym) = proc addFileToLink(config: ConfigRef; m: PSym) =
@ -112,12 +114,16 @@ proc generateCode*(g: ModuleGraph) =
resetForBackend(g) resetForBackend(g)
var alive = computeAliveSyms(g.packed, g.config) var alive = computeAliveSyms(g.packed, g.config)
when false:
for i in 0..high(g.packed):
echo i, " is of status ", g.packed[i].status, " ", toFullPath(g.config, FileIndex(i))
for i in 0..high(g.packed): for i in 0..high(g.packed):
# case statement here to enforce exhaustive checks. # case statement here to enforce exhaustive checks.
case g.packed[i].status case g.packed[i].status
of undefined: of undefined:
discard "nothing to do" discard "nothing to do"
of loading: of loading, stored:
assert false assert false
of storing, outdated: of storing, outdated:
generateCodeForModule(g, g.packed[i], alive) generateCodeForModule(g, g.packed[i], alive)
@ -133,3 +139,7 @@ proc generateCode*(g: ModuleGraph) =
else: else:
addFileToLink(g.config, g.packed[i].module) addFileToLink(g.config, g.packed[i].module)
replayTypeInfo(g, g.packed[i], FileIndex(i)) replayTypeInfo(g, g.packed[i], FileIndex(i))
if g.backend == nil:
g.backend = cgendata.newModuleList(g)
registerInitProcs(BModuleList(g.backend), g.packed[i].module, g.packed[i].fromDisk.backendFlags)

View file

@ -22,6 +22,10 @@ type
options: TOptions options: TOptions
globalOptions: TGlobalOptions globalOptions: TGlobalOptions
ModuleBackendFlag* = enum
HasDatInitProc
HasModuleInitProc
PackedModule* = object ## the parts of a PackedEncoder that are part of the .rod file PackedModule* = object ## the parts of a PackedEncoder that are part of the .rod file
definedSymbols: string definedSymbols: string
includes: seq[(LitId, string)] # first entry is the module filename itself includes: seq[(LitId, string)] # first entry is the module filename itself
@ -43,6 +47,7 @@ type
enumToStringProcs*: seq[(PackedItemId, PackedItemId)] enumToStringProcs*: seq[(PackedItemId, PackedItemId)]
emittedTypeInfo*: seq[string] emittedTypeInfo*: seq[string]
backendFlags*: set[ModuleBackendFlag]
sh*: Shared sh*: Shared
cfg: PackedConfig cfg: PackedConfig
@ -556,6 +561,9 @@ proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef
loadSeqSection enumToStringProcsSection, m.enumToStringProcs loadSeqSection enumToStringProcsSection, m.enumToStringProcs
loadSeqSection typeInfoSection, m.emittedTypeInfo loadSeqSection typeInfoSection, m.emittedTypeInfo
f.loadSection backendFlagsSection
f.loadPrim m.backendFlags
close(f) close(f)
result = f.err result = f.err
@ -619,6 +627,9 @@ proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var Pac
storeSeqSection enumToStringProcsSection, m.enumToStringProcs storeSeqSection enumToStringProcsSection, m.enumToStringProcs
storeSeqSection typeInfoSection, m.emittedTypeInfo storeSeqSection typeInfoSection, m.emittedTypeInfo
f.storeSection backendFlagsSection
f.storePrim m.backendFlags
close(f) close(f)
encoder.disable() encoder.disable()
if f.err != ok: if f.err != ok:
@ -646,7 +657,8 @@ type
storing, # state is strictly for stress-testing purposes storing, # state is strictly for stress-testing purposes
loading, loading,
loaded, loaded,
outdated outdated,
stored # store is complete, no further additions possible
LoadedModule* = object LoadedModule* = object
status*: ModuleStatus status*: ModuleStatus
@ -673,7 +685,7 @@ proc toFileIndexCached*(c: var PackedDecoder; g: PackedModuleGraph; thisModule:
proc translateLineInfo(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; proc translateLineInfo(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
x: PackedLineInfo): TLineInfo = x: PackedLineInfo): TLineInfo =
assert g[thisModule].status in {loaded, storing} assert g[thisModule].status in {loaded, storing, stored}
result = TLineInfo(line: x.line, col: x.col, result = TLineInfo(line: x.line, col: x.col,
fileIndex: toFileIndexCached(c, g, thisModule, x.file)) fileIndex: toFileIndexCached(c, g, thisModule, x.file))
@ -806,7 +818,7 @@ proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s:
result = nil result = nil
else: else:
let si = moduleIndex(c, g, thisModule, s) let si = moduleIndex(c, g, thisModule, s)
assert g[si].status in {loaded, storing} assert g[si].status in {loaded, storing, stored}
if not g[si].symsInit: if not g[si].symsInit:
g[si].symsInit = true g[si].symsInit = true
setLen g[si].syms, g[si].fromDisk.sh.syms.len setLen g[si].syms, g[si].fromDisk.sh.syms.len
@ -852,7 +864,7 @@ proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; t
result = nil result = nil
else: else:
let si = moduleIndex(c, g, thisModule, t) let si = moduleIndex(c, g, thisModule, t)
assert g[si].status in {loaded, storing} assert g[si].status in {loaded, storing, stored}
assert t.item > 0 assert t.item > 0
if not g[si].typesInit: if not g[si].typesInit:
@ -950,7 +962,7 @@ proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache
of loading, loaded: of loading, loaded:
# For loading: Assume no recompile is required. # For loading: Assume no recompile is required.
result = false result = false
of outdated, storing: of outdated, storing, stored:
result = true result = true
proc moduleFromRodFile*(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache; proc moduleFromRodFile*(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;

View file

@ -37,6 +37,7 @@ type
methodsPerTypeSection methodsPerTypeSection
enumToStringProcsSection enumToStringProcsSection
typeInfoSection # required by the backend typeInfoSection # required by the backend
backendFlagsSection
aliveSymsSection # beware, this is stored in a `.alivesyms` file. aliveSymsSection # beware, this is stored in a `.alivesyms` file.
RodFileError* = enum RodFileError* = enum

View file

@ -455,11 +455,25 @@ proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym =
elif fileIdx.int32 < g.ifaces.len: elif fileIdx.int32 < g.ifaces.len:
result = g.ifaces[fileIdx.int32].module result = g.ifaces[fileIdx.int32].module
proc moduleOpenForCodegen*(g: ModuleGraph; m: FileIndex): bool {.inline.} =
if g.config.symbolFiles == disabledSf:
result = true
else:
result = g.packed[m.int32].status notin {undefined, stored, loaded}
proc rememberEmittedTypeInfo*(g: ModuleGraph; m: FileIndex; ti: string) = proc rememberEmittedTypeInfo*(g: ModuleGraph; m: FileIndex; ti: string) =
#assert(not isCachedModule(g, m.int32)) #assert(not isCachedModule(g, m.int32))
if g.config.symbolFiles != disabledSf: if g.config.symbolFiles != disabledSf:
#assert g.encoders[m.int32].isActive #assert g.encoders[m.int32].isActive
assert g.packed[m.int32].status != stored
g.packed[m.int32].fromDisk.emittedTypeInfo.add ti g.packed[m.int32].fromDisk.emittedTypeInfo.add ti
#echo "added typeinfo ", m.int32, " ", ti, " suspicious ", not g.encoders[m.int32].isActive
proc rememberFlag*(g: ModuleGraph; m: PSym; flag: ModuleBackendFlag) =
if g.config.symbolFiles != disabledSf:
#assert g.encoders[m.int32].isActive
assert g.packed[m.position].status != stored
g.packed[m.position].fromDisk.backendFlags.incl flag
proc closeRodFile*(g: ModuleGraph; m: PSym) = proc closeRodFile*(g: ModuleGraph; m: PSym) =
if g.config.symbolFiles in {readOnlySf, v2Sf}: if g.config.symbolFiles in {readOnlySf, v2Sf}:
@ -469,6 +483,8 @@ proc closeRodFile*(g: ModuleGraph; m: PSym) =
let mint = m.position let mint = m.position
saveRodFile(toRodFile(g.config, AbsoluteFile toFullPath(g.config, FileIndex(mint))), saveRodFile(toRodFile(g.config, AbsoluteFile toFullPath(g.config, FileIndex(mint))),
g.encoders[mint], g.packed[mint].fromDisk) g.encoders[mint], g.packed[mint].fromDisk)
g.packed[mint].status = stored
elif g.config.symbolFiles == stressTest: elif g.config.symbolFiles == stressTest:
# debug code, but maybe a good idea for production? Could reduce the compiler's # debug code, but maybe a good idea for production? Could reduce the compiler's
# memory consumption considerably at the cost of more loads from disk. # memory consumption considerably at the cost of more loads from disk.

View file

@ -458,8 +458,8 @@ proc temp(args: string) =
inc i inc i
let d = getAppDir() let d = getAppDir()
var output = d / "compiler" / "nim".exe let output = d / "compiler" / "nim".exe
var finalDest = d / "bin" / "nim_temp".exe let finalDest = d / "bin" / "nim_temp".exe
# 125 is the magic number to tell git bisect to skip the current commit. # 125 is the magic number to tell git bisect to skip the current commit.
var (bootArgs, programArgs) = splitArgs(args) var (bootArgs, programArgs) = splitArgs(args)
if "doc" notin programArgs and if "doc" notin programArgs and
@ -483,6 +483,22 @@ proc xtemp(cmd: string) =
finally: finally:
copyExe(d / "bin" / "nim_backup".exe, d / "bin" / "nim".exe) copyExe(d / "bin" / "nim_backup".exe, d / "bin" / "nim".exe)
proc icTest(args: string) =
temp("")
let inp = os.parseCmdLine(args)[0]
let content = readFile(inp)
let nimExe = getAppDir() / "bin" / "nim_temp".exe
var i = 0
for fragment in content.split("#!EDIT!#"):
let file = inp.replace(".nim", "_temp.nim")
writeFile(file, fragment)
var cmd = nimExe & " cpp --ic:on --listcmd "
if i == 0:
cmd.add "-f "
cmd.add quoteShell(file)
exec(cmd)
inc i
proc buildDrNim(args: string) = proc buildDrNim(args: string) =
if not dirExists("dist/nimz3"): if not dirExists("dist/nimz3"):
exec("git clone https://github.com/zevv/nimz3.git dist/nimz3") exec("git clone https://github.com/zevv/nimz3.git dist/nimz3")
@ -705,6 +721,7 @@ when isMainModule:
of "fusion": of "fusion":
let suffix = if latest: HeadHash else: FusionStableHash let suffix = if latest: HeadHash else: FusionStableHash
exec("nimble install -y fusion@$#" % suffix) exec("nimble install -y fusion@$#" % suffix)
of "ic": icTest(op.cmdLineRest)
else: showHelp() else: showHelp()
break break
of cmdEnd: break of cmdEnd: break

View file

@ -1,6 +1,5 @@
discard """ discard """
output: "bar" output: "bar"
disabled: "true"
""" """
import tables import tables