IC: module suffix is now the trailing token of mangled C names

Reorder mangleProcNameExt and makeUnique so the module suffix comes LAST:
name_u<disamb>__<suffix> (was name__<suffix>_u<disamb>). The suffix is now a
strippable trailing token, so content-addressed cross-module merging (the
per-module backend's instance/hook dedup) can recover a mint-site-independent
name by chopping everything from the final "__" -- no reference rewriting.

Also drops the main-module special case in mangleProcNameExt: it omitted the
suffix because the main module's symbols key on its NIF-suffix file index. But
the backend already aliases that suffix to the main's source index
(nifbackend.loadModuleDependencies), so graph.ifaces[s.itemId.module] is
populated for the main module too -- the guard was redundant. Main-module
procs now mangle uniformly (e.g. mainProc_u0__<mainname>).

icFormatVersion 3 -> 4: cached .c.nif artifacts hold the old name scheme and
must be wiped.

Validated: koch boot (non-IC self-host) reaches fixed point; koch ic thallo
tconverter timp tmiscs tparseutils all green; a 3-module diamond IC build
runs correctly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Araq
2026-06-13 22:09:16 +02:00
parent 4434e2d6bd
commit b4c71af517
3 changed files with 14 additions and 13 deletions

View File

@@ -112,12 +112,13 @@ proc encodeName*(name: string): string =
proc makeUnique(m: BModule; s: PSym, name: string = ""): string =
result = if name == "": s.name.s else: name
result.add "__"
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
# keep backend-minted ids out of the `_u` namespace; their item counter
# restarts at 0 and would collide with loaded symbols' ids
result.add(if s.itemId.isBackendMinted: "_c" else: "_u")
result.add $s.itemId.item
# module suffix LAST (a strippable trailing token; see `mangleProcNameExt`)
result.add "__"
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
proc encodeSym*(m: BModule; s: PSym; makeUnique: bool = false; extra: string = ""): string =
#Module::Type

View File

@@ -53,14 +53,9 @@ proc mangleParamExt*(s: PSym): string =
result.addInt s.position
proc mangleProcNameExt*(graph: ModuleGraph, s: PSym): string =
result = "__"
# Under incremental compilation the main module is registered at its source
# file index, but its symbols are keyed by the NIF-suffix file index, which has
# no `ifaces` slot. Only the main module has this gap (dependencies are
# registered at their suffix index), so omitting the unique name for it stays
# collision-free: the mangled base name plus `disamb` already disambiguate.
if s.itemId.module >= 0 and s.itemId.module < graph.ifaces.len:
result.add graph.ifaces[s.itemId.module].uniqueName
# The disambiguator comes first and the module suffix LAST, so the suffix is
# a strippable trailing token: content-addressed cross-module merging chops
# everything from the final `__` to recover a mint-site-independent name.
if s.itemId.isBackendMinted:
# A symbol minted during IC codegen (`idGeneratorForBackend`): its idgen
# starts with an EMPTY per-name disamb table, so its `disamb` restarts at 0
@@ -70,10 +65,10 @@ proc mangleProcNameExt*(graph: ModuleGraph, s: PSym): string =
# lifts, emits and compiles them in one run), so the per-module-unique
# item id is a safe and deterministic discriminator; the `_c` marker keeps
# the namespace disjoint from `_u<disamb>`.
result.add "_c"
result = "_c"
result.addInt s.itemId.item
else:
result.add "_u"
result = "_u"
# Use `disamb` rather than `itemId.item`: under incremental compilation a
# symbol loaded from a NIF file gets a fresh, load-order-dependent `itemId.item`
# (from the per-module symbol counter), which is neither stable across the
@@ -82,3 +77,5 @@ proc mangleProcNameExt*(graph: ModuleGraph, s: PSym): string =
# and, together with the already-prepended mangled name, yields a unique and
# stable C identifier.
result.addInt s.disamb
result.add "__"
result.add graph.ifaces[s.itemId.module].uniqueName

View File

@@ -29,7 +29,7 @@ const
nimEnableCovariance* = defined(nimEnableCovariance)
icFormatVersion* = "3"
icFormatVersion* = "4"
## Version of the IC cache format (the sem-NIF module layout written by
## ast2nif.nim plus the iface/impl/edges side files). Bump it whenever
## that layout changes: `commandIc` wipes a nimcache whose `ic.version`
@@ -42,6 +42,9 @@ const
## wiped rather than warm-rebuilt.
## v3: added the `.s.deps` sidecar (real post-sem imports) and switched the
## macro-generated-import discovery from `icmissing.txt` to it.
## v4: backend C-name scheme change — the module suffix is now the trailing
## token (`name_u<disamb>__<suffix>`, was `name__<suffix>_u<disamb>`), so
## cached `.c.nif` artifacts hold incompatible names and must be wiped.
type # please make sure we have under 32 options
# (improves code efficiency a lot!)