IC: add -d:icSymCount, and use it to settle the full-compiler comparison

Counts every `newSym` mint, by kind, and reports on exit. A gensym's number is
its item id, so ONE extra symbol anywhere shifts every later name in the
generated C — which makes a mint count far more sensitive than diffing output,
and localises a difference by symbol kind instead of by whichever file happened
to show it.

It was written to answer a question I had reported wrongly. Comparing the
cursor-driven and `PNode`-driven builds over the whole compiler showed 3 of 215
`.c` files differing, and I attributed 2 of them to the compiler being
nondeterministic. That control was invalid: I had compared two runs across an
edit to `ccgexprs.nim`, so what I read as nondeterminism was line numbers moving
inside assertion strings. The compiler is DETERMINISTIC — same binary, same
source, twice, 0 of 215 differ.

What the count establishes: the two builds mint exactly the same symbols,
515_551 of them, with no per-kind difference at all. So nothing in the cursor
path creates or skips a symbol, and the earlier gensym-numbered differences —
which had zero non-gensym lines — were ordering, not extra work.

On the current tree the comparison is clean: cursor-driven and `PNode`-driven
produce BYTE-IDENTICAL `.c` for all 215 files of `compiler/nim.nim`. I have not
isolated why the same comparison showed 3 differences one commit earlier; the
commit between was behaviour-neutral by inspection, so I am recording the
observation rather than a claim about its cause.

Verified: both build configurations compile; the diagnostic is behind a define
and costs nothing otherwise.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XEF7FJvUkGKvG9LSGuEaNR
This commit is contained in:
Araq
2026-08-30 16:16:08 +02:00
parent 31a7b6bc85
commit 603953376d

View File

@@ -781,10 +781,28 @@ when false:
echo k
echo v
when defined(icSymCount):
import std / [syncio, exitprocs, tables as symCountTables]
var symMints*: symCountTables.CountTable[string]
var symMintTotal*: int
var symCountHooked = false
proc newSym*(symKind: TSymKind, name: PIdent, idgen: IdGenerator; owner: PSym,
info: TLineInfo; options: TOptions = {}): PSym =
# generates a symbol and initializes the hash field too
assert not name.isNil
when defined(icSymCount):
# Counting symbol MINTS, not their names in the output: a gensym's number is
# its item id, so one extra symbol anywhere shifts every later name. A count
# is therefore far more sensitive than diffing generated C, and it localises
# the extra mint by kind instead of by whatever file happened to show it.
inc symMintTotal
symMints.inc $symKind
if not symCountHooked:
symCountHooked = true
addExitProc proc () =
stderr.writeLine "SYMMINT total=" & $symMintTotal
for k, v in symMints: stderr.writeLine "SYMMINT " & k & "=" & $v
let id = nextSymId idgen
result = PSym(name: name, kindImpl: symKind, flagsImpl: {}, infoImpl: info, itemId: id,
optionsImpl: options, ownerFieldImpl: owner, offsetImpl: defaultOffset,