mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-06 13:07:48 +00:00
IC: progress (#25339)
This commit is contained in:
@@ -211,7 +211,7 @@ proc toNifSymName(w: var Writer; sym: PSym): string =
|
||||
result = sym.name.s
|
||||
result.add '.'
|
||||
result.addInt sym.disamb
|
||||
if sym.itemId notin w.locals and sym.kindImpl notin skLocalSymKinds:
|
||||
if sym.kindImpl notin skLocalSymKinds and sym.itemId notin w.locals:
|
||||
# Global symbol: ident.disamb.moduleSuffix
|
||||
let module = sym.itemId.module
|
||||
result.add '.'
|
||||
@@ -406,13 +406,13 @@ proc writeSymDef(w: var Writer; dest: var TokenBuf; sym: PSym) =
|
||||
dest.addParRi
|
||||
|
||||
# Collect for later unloading after entire module is written
|
||||
if sym.kindImpl notin {skModule, skPackage}:
|
||||
if sym.kindImpl notin {skPackage}:
|
||||
# do not unload modules
|
||||
w.writtenSyms.add sym
|
||||
|
||||
proc shouldWriteSymDef(w: Writer; sym: PSym): bool {.inline.} =
|
||||
# Don't write module/package symbols - they don't have NIF files
|
||||
if sym.kindImpl in {skModule, skPackage}:
|
||||
if sym.kindImpl in {skPackage}:
|
||||
return false
|
||||
# Already written - don't write again
|
||||
if sym.state == Sealed:
|
||||
@@ -430,7 +430,7 @@ proc shouldWriteSymDef(w: Writer; sym: PSym): bool {.inline.} =
|
||||
proc writeSym(w: var Writer; dest: var TokenBuf; sym: PSym) =
|
||||
if sym == nil:
|
||||
dest.addDotToken()
|
||||
elif sym.kindImpl in {skModule, skPackage}:
|
||||
elif sym.kindImpl in {skPackage}:
|
||||
# Write module/package symbols as dots - they're resolved differently
|
||||
# (by position/FileIndex, not by NIF lookup)
|
||||
dest.addDotToken()
|
||||
@@ -1084,6 +1084,8 @@ proc loadSymFromCursor(c: var DecodeContext; s: PSym; n: var Cursor; thisModule:
|
||||
if s.kindImpl == skModule:
|
||||
expect n, DotToken
|
||||
inc n
|
||||
var isKnownFile = false
|
||||
s.positionImpl = int c.infos.config.registerNifSuffix(thisModule, isKnownFile)
|
||||
else:
|
||||
loadField s.positionImpl
|
||||
|
||||
@@ -1097,11 +1099,10 @@ proc loadSymFromCursor(c: var DecodeContext; s: PSym; n: var Cursor; thisModule:
|
||||
# Load the AST for routine symbols (procs, funcs, etc.)
|
||||
if s.kindImpl in routineKinds:
|
||||
s.astImpl = loadNode(c, n, thisModule, localSyms)
|
||||
elif n.kind == DotToken:
|
||||
inc n
|
||||
else:
|
||||
if n.kind == DotToken:
|
||||
inc n
|
||||
else:
|
||||
raiseAssert "expected '.' for non-routine symbol AST but got " & $n.kind
|
||||
raiseAssert "expected '.' for non-routine symbol AST but got " & $n.kind
|
||||
loadLoc c, n, s.locImpl
|
||||
s.constraintImpl = loadNode(c, n, thisModule, localSyms)
|
||||
s.instantiatedFromImpl = loadSymStub(c, n, thisModule, localSyms)
|
||||
@@ -1420,10 +1421,37 @@ proc resolveHookSym*(c: var DecodeContext; symId: nifstreams.SymId): PSym =
|
||||
disamb: sn.count.int32, state: Partial)
|
||||
c.syms[id] = (result, offs)
|
||||
|
||||
proc tryResolveCompilerProc*(c: var DecodeContext; name: string; moduleFileIdx: FileIndex): PSym =
|
||||
## Tries to resolve a compiler proc from a module by checking the NIF index.
|
||||
## Returns nil if the symbol doesn't exist.
|
||||
let suffix = moduleSuffix(c.infos.config, moduleFileIdx)
|
||||
let symName = name & ".0." & suffix
|
||||
|
||||
# Check if module index is loaded, if not load it
|
||||
let module = moduleId(c, suffix)
|
||||
|
||||
# Check if symbol exists in the index (check both public and private)
|
||||
var offs = c.mods[module].index.public.getOrDefault(symName)
|
||||
if offs.offset == 0:
|
||||
offs = c.mods[module].index.private.getOrDefault(symName)
|
||||
if offs.offset == 0:
|
||||
return nil
|
||||
|
||||
# Create a stub symbol
|
||||
let val = addr c.mods[module].symCounter
|
||||
inc val[]
|
||||
let id = ItemId(module: int32(module), item: val[])
|
||||
result = c.syms.getOrDefault(id)[0]
|
||||
if result == nil:
|
||||
result = PSym(itemId: id, kindImpl: skProc, name: c.cache.getIdent(name),
|
||||
disamb: 0, state: Partial)
|
||||
c.syms[id] = (result, offs)
|
||||
|
||||
proc loadNifModule*(c: var DecodeContext; f: FileIndex; interf, interfHidden: var TStrTable;
|
||||
hooks: var Table[nifstreams.SymId, HooksPerType];
|
||||
converters: var seq[(string, string)];
|
||||
classes: var seq[ClassIndexEntry]): PNode =
|
||||
classes: var seq[ClassIndexEntry];
|
||||
loadFullAst: bool = false): PNode =
|
||||
let suffix = moduleSuffix(c.infos.config, f)
|
||||
|
||||
# Ensure module index is loaded - moduleId returns the FileIndex for this suffix
|
||||
@@ -1440,29 +1468,62 @@ proc loadNifModule*(c: var DecodeContext; f: FileIndex; interf, interfHidden: va
|
||||
# Return classes/methods from the index
|
||||
classes = move c.mods[module].index.classes
|
||||
|
||||
# Check for replay actions at the start of the NIF file
|
||||
# Load the module AST (or just replay actions if loadFullAst is false)
|
||||
result = newNode(nkStmtList)
|
||||
let s = addr c.mods[module].stream
|
||||
s.r.jumpTo 0 # Start from beginning
|
||||
discard processDirectives(s.r)
|
||||
var localSyms = initTable[string, PSym]()
|
||||
# Read root stmts node
|
||||
var t = next(s[])
|
||||
if t.kind == ParLe and pool.tags[t.tagId] == toNifTag(nkStmtList):
|
||||
t = next(s[]) # skip flags
|
||||
t = next(s[]) # skip type
|
||||
# Check if first node is a (replay ...) container
|
||||
if t.kind == ParLe and pool.tags[t.tagId] == "replay":
|
||||
t = next(s[]) # move past (replay
|
||||
# Parse all replay actions inside the container
|
||||
while t.kind != ParRi and t.kind != EofToken:
|
||||
if t.kind == ParLe:
|
||||
# Process all top-level statements
|
||||
while t.kind != ParRi and t.kind != EofToken:
|
||||
if t.kind == ParLe:
|
||||
let tag = pool.tags[t.tagId]
|
||||
if tag == "replay":
|
||||
# Always load replay actions (macro cache operations)
|
||||
t = next(s[]) # move past (replay
|
||||
while t.kind != ParRi and t.kind != EofToken:
|
||||
if t.kind == ParLe:
|
||||
var buf = createTokenBuf(50)
|
||||
nifcursors.parse(s[], buf, t.info)
|
||||
var cursor = cursorAt(buf, 0)
|
||||
let replayNode = loadNode(c, cursor, suffix, localSyms)
|
||||
if replayNode != nil:
|
||||
result.sons.add replayNode
|
||||
t = next(s[])
|
||||
elif loadFullAst:
|
||||
# Parse the full statement
|
||||
var buf = createTokenBuf(50)
|
||||
nifcursors.parse(s[], buf, t.info)
|
||||
buf.add t # Add the ParLe token we already read
|
||||
var nested = 1
|
||||
while nested > 0:
|
||||
t = next(s[])
|
||||
buf.add t
|
||||
if t.kind == ParLe:
|
||||
inc nested
|
||||
elif t.kind == ParRi:
|
||||
dec nested
|
||||
elif t.kind == EofToken:
|
||||
break
|
||||
var cursor = cursorAt(buf, 0)
|
||||
let replayNode = loadNode(c, cursor, suffix, localSyms)
|
||||
if replayNode != nil:
|
||||
result.sons.add replayNode
|
||||
let stmtNode = loadNode(c, cursor, suffix, localSyms)
|
||||
if stmtNode != nil:
|
||||
result.sons.add stmtNode
|
||||
else:
|
||||
# Skip over the statement by counting parentheses
|
||||
var nested = 1
|
||||
while nested > 0:
|
||||
t = next(s[])
|
||||
if t.kind == ParLe:
|
||||
inc nested
|
||||
elif t.kind == ParRi:
|
||||
dec nested
|
||||
elif t.kind == EofToken:
|
||||
break
|
||||
else:
|
||||
t = next(s[])
|
||||
|
||||
when isMainModule:
|
||||
|
||||
@@ -16,13 +16,10 @@
|
||||
## implementation.
|
||||
|
||||
template detectVersion(field, corename) =
|
||||
if m.g.field == 0:
|
||||
let core = getCompilerProc(m.g.graph, corename)
|
||||
if core == nil or core.kind != skConst:
|
||||
m.g.field = 1
|
||||
else:
|
||||
m.g.field = toInt(ast.getInt(core.astdef))
|
||||
result = m.g.field
|
||||
if m.g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc, gcHooks}:
|
||||
result = 2
|
||||
else:
|
||||
result = 1
|
||||
|
||||
proc detectStrVersion(m: BModule): int =
|
||||
detectVersion(strVersion, "nimStrVersion")
|
||||
|
||||
@@ -721,7 +721,7 @@ proc genRecordFieldsAux(m: BModule; n: PNode,
|
||||
# have to recurse via 'getTypeDescAux'. And not doing so prevents problems
|
||||
# with heavily templatized C++ code:
|
||||
if not isImportedCppType(rectype):
|
||||
let fieldType = field.loc.lode.typ.skipTypes(abstractInst)
|
||||
let fieldType = field.loc.t.skipTypes(abstractInst)
|
||||
var typ: Rope = ""
|
||||
var isFlexArray = false
|
||||
var initializer = ""
|
||||
|
||||
@@ -447,6 +447,7 @@ proc mainCommand*(graph: ModuleGraph) =
|
||||
of cmdNifC:
|
||||
# Generate C code from NIF files
|
||||
wantMainModule(conf)
|
||||
setOutFile(conf)
|
||||
commandNifC(graph)
|
||||
of cmdDeps:
|
||||
# Generate .build.nif for nifmake
|
||||
|
||||
@@ -435,7 +435,30 @@ proc copyTypeProps*(g: ModuleGraph; module: int; dest, src: PType) =
|
||||
|
||||
proc loadCompilerProc*(g: ModuleGraph; name: string): PSym =
|
||||
result = nil
|
||||
if g.config.symbolFiles == disabledSf: return nil
|
||||
if g.config.symbolFiles == disabledSf:
|
||||
# For NIF-based compilation, search in loaded NIF modules
|
||||
when not defined(nimKochBootstrap):
|
||||
# Only try to resolve from NIF if we're actually using NIF files (cmdNifC)
|
||||
if g.config.cmd == cmdNifC:
|
||||
# First try system module (most compilerprocs are there)
|
||||
let systemFileIdx = g.config.m.systemFileIdx
|
||||
if systemFileIdx != InvalidFileIdx:
|
||||
result = tryResolveCompilerProc(ast.program, name, systemFileIdx)
|
||||
if result != nil:
|
||||
strTableAdd(g.compilerprocs, result)
|
||||
return result
|
||||
|
||||
# Try threadpool module (some compilerprocs like FlowVar are there)
|
||||
# Find threadpool module by searching loaded modules
|
||||
for moduleIdx in 0..<g.ifaces.len:
|
||||
let module = g.ifaces[moduleIdx].module
|
||||
if module != nil and module.name.s == "threadpool":
|
||||
let threadpoolFileIdx = module.position.FileIndex
|
||||
result = tryResolveCompilerProc(ast.program, name, threadpoolFileIdx)
|
||||
if result != nil:
|
||||
strTableAdd(g.compilerprocs, result)
|
||||
return result
|
||||
return nil
|
||||
|
||||
# slow, linear search, but the results are cached:
|
||||
for module in 0..<len(g.packed):
|
||||
@@ -755,9 +778,11 @@ proc moduleFromRodFile*(g: ModuleGraph; fileIdx: FileIndex;
|
||||
|
||||
when not defined(nimKochBootstrap):
|
||||
proc moduleFromNifFile*(g: ModuleGraph; fileIdx: FileIndex;
|
||||
cachedModules: var seq[FileIndex]): PSym =
|
||||
cachedModules: var seq[FileIndex];
|
||||
loadFullAst: bool = false): PSym =
|
||||
## Returns 'nil' if the module needs to be recompiled.
|
||||
## Loads module from NIF file when optCompress is enabled.
|
||||
## When loadFullAst is true, loads the complete module AST for code generation.
|
||||
|
||||
if not fileExists(toNifFilename(g.config, fileIdx)):
|
||||
return nil
|
||||
@@ -779,7 +804,7 @@ when not defined(nimKochBootstrap):
|
||||
var converters: seq[(string, string)] = @[]
|
||||
var classes: seq[ClassIndexEntry] = @[]
|
||||
result.astImpl = loadNifModule(ast.program, fileIdx, g.ifaces[fileIdx.int].interf,
|
||||
g.ifaces[fileIdx.int].interfHidden, hooks, converters, classes)
|
||||
g.ifaces[fileIdx.int].interfHidden, hooks, converters, classes, loadFullAst)
|
||||
# Register hooks from NIF index with the module graph
|
||||
for typSymId, hooksPerType in hooks:
|
||||
let typeItemId = parseTypeSymIdToItemId(ast.program, typSymId)
|
||||
|
||||
@@ -30,29 +30,23 @@ proc loadModuleDependencies(g: ModuleGraph; mainFileIdx: FileIndex): seq[PSym] =
|
||||
## Returns all modules that need code generation, in dependency order.
|
||||
var visited = initIntSet()
|
||||
var stack: seq[FileIndex] = @[mainFileIdx]
|
||||
var modules: seq[PSym] = @[]
|
||||
result = @[]
|
||||
var cachedModules: seq[FileIndex] = @[]
|
||||
|
||||
while stack.len > 0:
|
||||
let fileIdx = stack.pop()
|
||||
|
||||
if visited.containsOrIncl(int(fileIdx)):
|
||||
continue
|
||||
|
||||
# Load module from NIF
|
||||
let module = moduleFromNifFile(g, fileIdx, cachedModules)
|
||||
if module == nil:
|
||||
continue
|
||||
|
||||
modules.add module
|
||||
|
||||
# Add dependencies to stack (they come from cachedModules)
|
||||
for dep in cachedModules:
|
||||
if not visited.contains(int(dep)):
|
||||
stack.add dep
|
||||
cachedModules.setLen(0)
|
||||
|
||||
result = modules
|
||||
if not visited.containsOrIncl(int(fileIdx)):
|
||||
# Only load full AST for main module; others are loaded lazily by codegen
|
||||
let isMainModule = fileIdx == mainFileIdx
|
||||
let module = moduleFromNifFile(g, fileIdx, cachedModules, loadFullAst=isMainModule)
|
||||
if module != nil:
|
||||
result.add module
|
||||
# Add dependencies to stack (they come from cachedModules)
|
||||
for dep in cachedModules:
|
||||
if not visited.contains(int(dep)):
|
||||
stack.add dep
|
||||
cachedModules.setLen(0)
|
||||
|
||||
proc setupNifBackendModule(g: ModuleGraph; module: PSym): BModule =
|
||||
## Set up a BModule for code generation from a NIF module.
|
||||
@@ -71,8 +65,10 @@ proc generateCodeForModule(g: ModuleGraph; module: PSym) =
|
||||
if module.ast != nil:
|
||||
cgen.genTopLevelStmt(bmod, module.ast)
|
||||
|
||||
# Finalize the module
|
||||
finalCodegenActions(g, bmod, newNodeI(nkStmtList, module.info))
|
||||
# Finalize the module (this adds it to modulesClosed)
|
||||
# Create an empty stmt list as the init body - genInitCode in writeModule will set it up properly
|
||||
let initStmt = newNodeI(nkStmtList, module.info)
|
||||
finalCodegenActions(g, bmod, initStmt)
|
||||
|
||||
# Generate dispatcher methods
|
||||
for disp in getDispatchers(g):
|
||||
@@ -84,6 +80,14 @@ proc generateCode*(g: ModuleGraph; mainFileIdx: FileIndex) =
|
||||
|
||||
# Reset backend state
|
||||
resetForBackend(g)
|
||||
let mainModule = g.getModule(mainFileIdx)
|
||||
|
||||
# Also ensure system module is set up and generated if it exists
|
||||
if g.systemModule != nil and g.systemModule != mainModule:
|
||||
let systemBmod = BModuleList(g.backend).modules[g.systemModule.position]
|
||||
if systemBmod == nil:
|
||||
discard setupNifBackendModule(g, g.systemModule)
|
||||
generateCodeForModule(g, g.systemModule)
|
||||
|
||||
# Load all modules in dependency order using stack traversal
|
||||
let modules = loadModuleDependencies(g, mainFileIdx)
|
||||
@@ -92,12 +96,12 @@ proc generateCode*(g: ModuleGraph; mainFileIdx: FileIndex) =
|
||||
"Cannot load NIF file for main module: " & toFullPath(g.config, mainFileIdx))
|
||||
return
|
||||
|
||||
# Set up backend modules
|
||||
# Set up backend modules for all modules that need code generation
|
||||
for module in modules:
|
||||
discard setupNifBackendModule(g, module)
|
||||
|
||||
# Generate code for all modules except main (main goes last)
|
||||
let mainModule = g.getModule(mainFileIdx)
|
||||
# This ensures all modules are added to modulesClosed
|
||||
for module in modules:
|
||||
if module != mainModule:
|
||||
generateCodeForModule(g, module)
|
||||
|
||||
@@ -118,8 +118,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
|
||||
if conf.selectedGC == gcUnselected:
|
||||
if conf.backend in {backendC, backendCpp, backendObjc} or
|
||||
(conf.cmd in cmdDocLike and conf.backend != backendJs) or
|
||||
conf.cmd == cmdGendepend or
|
||||
conf.cmd == cmdM:
|
||||
conf.cmd in {cmdGendepend, cmdNifC, cmdDeps, cmdM}:
|
||||
initOrcDefines(conf)
|
||||
|
||||
mainCommand(graph)
|
||||
|
||||
@@ -85,9 +85,3 @@ func countSetBitsImpl*(x: SomeInteger): int {.inline.} =
|
||||
else:
|
||||
when sizeof(x) <= 4: result = countBitsImpl(x.uint32)
|
||||
else: result = countBitsImpl(x.uint64)
|
||||
|
||||
proc countBits32*(n: uint32): int {.compilerproc, inline.} =
|
||||
result = countSetBitsImpl(n)
|
||||
|
||||
proc countBits64*(n: uint64): int {.compilerproc, inline.} =
|
||||
result = countSetBitsImpl(n)
|
||||
|
||||
@@ -10,6 +10,13 @@
|
||||
# set handling
|
||||
|
||||
|
||||
# IC: compilerprocs now must be defined in system.nim or threadpool.nim!
|
||||
proc countBits32*(n: uint32): int {.compilerproc, inline.} =
|
||||
result = countSetBitsImpl(n)
|
||||
|
||||
proc countBits64*(n: uint64): int {.compilerproc, inline.} =
|
||||
result = countSetBitsImpl(n)
|
||||
|
||||
proc cardSetImpl(s: ptr UncheckedArray[uint8], len: int): int {.inline.} =
|
||||
var i = 0
|
||||
result = 0
|
||||
|
||||
Reference in New Issue
Block a user