IC: final tweaks (#25958)

This commit is contained in:
Andreas Rumpf
2026-07-04 10:13:39 +02:00
committed by GitHub
parent 8f78c8de60
commit 0bfb59f6d4
4 changed files with 62 additions and 9 deletions

View File

@@ -1249,15 +1249,21 @@ proc commandIc*(conf: ConfigRef) =
let nifmake = findNifmake()
# Build the per-module rules concurrently: nifmake fans out all commands at
# each DAG depth via execProcesses (defaults to all cores). Cold builds are
# otherwise serial (one child at a time) and leave the machine idle. Opt out
# with `-d:icNoParallel` (e.g. for readable, non-interleaved child output
# when debugging a build), or cap the concurrency with `-d:icJobs:N` — an
# uncapped fan-out across many cores can exhaust RAM on a large project
# (each `nim m`/`cg` child holds its own module graph), which nifmake's own
# `-j:N` exists to bound.
# otherwise serial (one child at a time) and leave the machine idle. An
# uncapped fan-out across many cores can exhaust RAM on a large project (each
# `nim m`/`cg` child holds its own module graph), which nifmake's own `-j:N`
# exists to bound. Concurrency is chosen (highest precedence first):
# * `-d:icNoParallel` -> serial (readable, non-interleaved child output)
# * `-d:icJobs:N` -> cap at N (legacy IC-tuning define)
# * `--parallelBuild:N` -> cap at N (the standard Nim build-parallelism
# flag; a no-op for `nim c` under IC, so we give
# it meaning here — lets Nimbus devs pick their
# own value without a `-d:` define)
# * otherwise -> uncapped (all cores)
let parallel =
if isDefined(conf, "icNoParallel"): ""
elif isDefined(conf, "icJobs"): " --parallel:" & conf.symbols["icJobs"]
elif conf.numberOfProcessors > 0: " --parallel:" & $conf.numberOfProcessors
else: " --parallel"
# Phase 1 — frontend (nifler + `nim m`), run to a discovery fixpoint.

View File

@@ -219,8 +219,18 @@ proc collectBifStrLits*(path: string): seq[string] =
## string literal it holds, in order — the binary analogue of the old nifstreams
## scan that collected `StrLit`s. Keeps nifcore types out of `deps.nim`, which
## only needs the recorded string list.
##
## Uses `loadFromFile` (a full read into owned memory) rather than the mmap-backed
## `bif.load`, then CLOSES the handle. `bif.load` intentionally leaves the mapping
## resident for the process lifetime; for the `nim ic` driver that reads these
## sidecars while `nim m` children rewrite them, a lingering read mapping is a
## Windows sharing violation: the child's `open(path, fmWrite)` fails with
## `IOError: cannot open`. These sidecars are tiny, so the zero-copy mmap buys
## nothing here anyway.
result = @[]
var m = bif.load(path)
var f = open(path, fmRead)
var m = bif.loadFromFile(f)
close(f)
var c = m.buf.beginRead()
while c.hasMore:
if c.kind == StrLit: result.add strVal(c)

View File

@@ -47,6 +47,11 @@ type
CoConsiderOwned
CoDistinct
CoHashTypeInsideNode
CoPrecise # produce a FRONTEND-faithful, unique key (for the
# stable NIF *name*, not hook dedup): keep distinctions
# sem makes that the backend identity collapses — e.g.
# an `int literal(x)` type carries its value so it does
# not merge with `int`. See `getTypeKey`/`typeKeyHook`.
TypeLoader* = proc (t: PType) {.nimcall.}
SymLoader* = proc (s: PSym) {.nimcall.}
@@ -139,6 +144,20 @@ proc maybeImported(c: var Context; s: PSym; conf: ConfigRef) {.inline.} =
if s != nil and {sfImportc, sfExportc} * s.flagsImpl != {}:
c.symKey(s, conf)
proc emitPreciseFlags(c: var Context; t: PType; flags: set[ConsiderFlag]) {.inline.} =
## Under CoPrecise the NIF *name* must be as fine as `types.sameType`, which
## compares `eqTypeFlags * flags` (see `sameFlags`). Without this a
## `proc() {.gcsafe.}` keyed identically to `proc()`, and a `ref X not nil`
## identically to `ref X` — the loader would then merge two frontend-distinct
## types onto one NIF name. Emitted only for the naming path (CoPrecise); the
## `setAttachedOp` hook key (no CoPrecise) is unaffected, so its byte layout is
## unchanged.
if CoPrecise in flags:
let ef = eqTypeFlags * t.flagsImpl
if ef != {}:
withTree c.m, "´tflags":
for f in ef: c.m.addIntLit ord(f)
proc backendTypeName(t: PType; conf: ConfigRef): string =
## Stable cross-module identity of a backend-minted (lower-stage) type: its
## serialized `@bk` NIF name (mirrors ast2nif.nifTypeName). A closure-env
@@ -229,6 +248,10 @@ proc typeKey(c: var Context; t: PType; flags: set[ConsiderFlag]; conf: ConfigRef
of tyInt:
withTree c.m, "i":
c.m.addIntLit -1
# An `int literal(x)` type (nImpl holds the value) must stay distinct from
# plain `int` for the NIF name, else overload resolution breaks on reload.
if CoPrecise in flags and t.nImpl != nil:
c.m.addIntLit t.nImpl.intVal
maybeImported(c, t.symImpl, conf)
of tyInt8:
withTree c.m, "i":
@@ -266,6 +289,14 @@ proc typeKey(c: var Context; t: PType; flags: set[ConsiderFlag]; conf: ConfigRef
withTree c.m, "u":
c.m.addIntLit 64
maybeImported(c, t.symImpl, conf)
of tyFloat:
withTree c.m, "f":
c.m.addIntLit -1
# A `float literal(x)` type (nImpl = nkFloatLit) must stay distinct from
# plain `float`, just like the `int literal(x)` case above.
if CoPrecise in flags and t.nImpl != nil and t.nImpl.kind in {nkFloatLit..nkFloat64Lit}:
c.m.addFloatLit t.nImpl.floatVal
maybeImported(c, t.symImpl, conf)
of tyObject, tyEnum:
if t.typeInstImpl != nil:
# prevent against infinite recursions here, see bug #8883:
@@ -381,6 +412,9 @@ proc typeKey(c: var Context; t: PType; flags: set[ConsiderFlag]; conf: ConfigRef
c.m.addIdent toNifTag(t.callConvImpl)
if tfVarargs in t.flagsImpl: c.m.addIdent "´varargs"
# `.gcsafe`/`.noSideEffect` (in eqTypeFlags) distinguish proc types under
# sameType, so they must distinguish the NIF name too.
emitPreciseFlags(c, t, flags)
of tyArray:
withTree c.m, toNifTag(t.kind):
if t.sonsImpl.len == 0:
@@ -395,6 +429,9 @@ proc typeKey(c: var Context; t: PType; flags: set[ConsiderFlag]; conf: ConfigRef
c.typeKey t.sonsImpl[i], flags, conf
if tfNotNil in t.flagsImpl and CoType notin flags:
c.m.addIdent "´notnil"
# tfNotNil/tfVarIsPtr/tfIsOutParam (eqTypeFlags) part of sameType identity
# for ref/ptr/var/lent/sink; the hook path (no CoPrecise) keeps its layout.
emitPreciseFlags(c, t, flags)
proc typeKey*(t: PType; conf: ConfigRef; tl: TypeLoader; sl: SymLoader): string =
var c: Context = Context(m: createMangler(30, -1), tl: tl, sl: sl,

View File

@@ -16,11 +16,11 @@ const
ChecksumsStableCommit = "5c132cd332cce5d64a0da9ac3e4c9664313dccb4" # 0.2.2
SatStableCommit = "9d52513b3c68bfb929dbd687d4fb2836cfee6936"
NimonyStableCommit = "557b865192e25e8e76ce4ccc81c6ea71676e92e7" # unversioned \
NimonyStableCommit = "6f9ac6655dc6724ae4e5ccb93b8123c18d54391a" # unversioned \
# Note that Nimony uses Nim as a git submodule but we don't want to install
# Nimony's dependency to Nim as we are Nim. So a `git clone` without --recursive
# is **required** here.
# Commit from 2026-07-01 -- contains a critical feature addition from nifmake for us
# Commit from 2026-07-03 -- .bif files are memory mapped too
# examples of possible values for fusion: #head, #ea82b54, 1.2.3
FusionStableHash = "#562467452b32cb7a97410ea177f083e6d8405734"