IC: compilerprocs mechanism

This commit is contained in:
araq
2025-12-06 14:29:08 +01:00
parent e154a2b7be
commit 25122dac30
4 changed files with 68 additions and 9 deletions

View File

@@ -1420,10 +1420,32 @@ 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
# Get or create the SymId for this symbol name
let symId = pool.syms.getOrIncl(symName)
# Now resolve it - this will create the PSym stub
result = resolveHookSym(c, symId)
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

View File

@@ -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

View File

@@ -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)

View File

@@ -39,8 +39,9 @@ proc loadModuleDependencies(g: ModuleGraph; mainFileIdx: FileIndex): seq[PSym] =
if visited.containsOrIncl(int(fileIdx)):
continue
# Load module from NIF
let module = moduleFromNifFile(g, fileIdx, cachedModules)
# 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:
continue
@@ -71,8 +72,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):
@@ -92,11 +95,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)
# This ensures all modules are added to modulesClosed
let mainModule = g.getModule(mainFileIdx)
for module in modules:
if module != mainModule:
@@ -106,6 +110,13 @@ proc generateCode*(g: ModuleGraph; mainFileIdx: FileIndex) =
if mainModule != nil:
generateCodeForModule(g, mainModule)
# 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)
# Write C files
if g.backend != nil:
cgenWriteModules(g.backend, g.config)