Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

DUMPIR & Recipe / NamedPhases

Addresses apply to ptxas v13.0.88 (CUDA 13.0). VA base 0x400000 (non-PIE).

The DUMPIR knob and the recipe/NamedPhases knob are the two primary mechanisms for inspecting ptxas's internal IR at points in the optimization pipeline. DUMPIR is an OCG string knob that triggers an IR dump after a named phase completes. The recipe knob (OCG knob index 298) diverts the optimizer driver onto the recipe path, where a small DSL builds a custom phase schedule. Both knobs accept phase names resolved through a case-insensitive binary search over the sorted phase-name table by sub_C641D0 (305 bytes). The name table holds 159 entries (IDs 0–158), copied from off_22BD0C0; on lookup failure the search returns the NOP sentinel, ID 158.

DUMPIR knobOCG string knob (ROT13: QhzcVE), registered in ctor_005 at 0x412B80
Recipe / NamedPhases knobOCG knob index 298 (config+0x53D0 presence, +0x53D8 value)
Phase name lookupsub_C641D0 (305 bytes, case-insensitive binary search)
Table sortsub_C63FA0 (on-demand iterative quicksort via sub_C639A0)
Name table159 entries at off_22BD0C0 (1272 bytes); all IDs 0–158 named
Recipe tokenizersub_798B60 (1,776 bytes)
Recipe schedule buildersub_9F4040
Report passesPhases 9, 96, 102, 126, 129, 130
Sentinel return158 (NOP phase, returned on lookup failure)

DUMPIR Knob

The DUMPIR knob is a string-valued OCG knob that takes one or more phase names. When set, the compiler dumps the Ori IR state after the named phase executes. This is the primary IR inspection mechanism for NVIDIA developers debugging the optimization pipeline.

Usage

ptxas -knob DUMPIR=AllocateRegisters input.ptx -o output.cubin

The knob value is a phase name string. The name is resolved through the phase name lookup function (sub_C641D0) using case-insensitive comparison, so allocateregisters, ALLOCATEREGISTERS, and AllocateRegisters all match.

The DUMPIR knob exists in two instantiations:

  • OCG instance (ROT13: QhzcVE at 0x21BDBAD): registered in ctor_005 at 0x412B80. This is the primary instance for the optimization pipeline.
  • DAG instance (ROT13: QhzcVE at 0x21DCC95): registered in ctor_007 at 0x421920. This controls IR dumps in the Mercury SASS/DAG pipeline.

Diagnostic Reference

The DUMPIR knob is referenced in register allocation error diagnostics. When a register allocation verification failure occurs, sub_A55D80 and sub_A76030 emit:

Please use -knob DUMPIR=AllocateRegisters for debugging

This tells the developer to re-run with the DUMPIR knob set to AllocateRegisters to inspect the IR state entering register allocation, which helps diagnose mismatches between pre- and post-allocation reaching definitions.

DUMPIR is part of a family of 17 dump-related OCG knobs across two constructor registrations. The OCG pipeline registers 11 dump knobs in ctor_005 (0x412A40--0x412D60); the Mercury/DAG pipeline registers 6 in ctor_007 (0x421880--0x421A10). All knob names and their definition-table offsets are ROT13-encoded in the binary (e.g. 0k14q0 decodes to 0x14D0).

OCG Pipeline Dump Knobs (ctor_005)

Knob NameROT13Reg AddressDef OffsetPurpose
DumpCallGraphQhzcPnyyTencu0x412A400x1490Dump the inter-procedural call graph
DumpCFGQhzcPST0x412A900x14A0Dump the control flow graph
DumpFlowQhzcSybj0x412AE00x14B0Dump data flow information (reaching defs, live sets)
DumpInstPhaseQhzcVafgCunfr0x412B300x14C0Dump per-instruction phase annotations
DumpIRQhzcVE0x412B800x14D0Dump the Ori IR after a named phase
DumpIRInfoAsIntegerQhzcVEVasbNfVagrtre0x412BD00x14E0Dump IR with integer-format operand info
DumpKnobsQhzcXabof0x412C200x14F0Dump all knob values to stderr
DumpPerfMetricsForBlockQhzcCresZrgevpfSbeOybpx0x412C700x1500Dump per-basic-block performance metrics
DumpPerfStatsQhzcCresFgngf0x412CC00x1510Dump performance statistics
DumpSASSQhzcFNFF0x412D100x1520Dump generated SASS assembly
DumpSBInstInfoQhzcFOVafgVasb0x412D600x1530Dump scoreboard per-instruction info

The "Def Offset" column is the byte offset into the 16-byte-stride knob definition table. Dividing by 16 gives the definition-table index: DumpCallGraph is index 329, DumpSBInstInfo is index 339. These indices are distinct from the 72-byte runtime knob slot indices used by GetKnobIntValue.

Adjacent knobs in ctor_005 (for boundary context):

  • 0x4129F0: DoYieldInsertionWAR_SW2491854 (offset 0x1480) — immediately before DumpCallGraph
  • 0x412DB0: EmitLDCU (offset 0x1540) — immediately after DumpSBInstInfo

Mercury/DAG Pipeline Dump Knobs (ctor_007)

Knob NameROT13Reg AddressPurpose
DumpAnnotQhzcNaabg0x421880Dump instruction annotations
DumpCFGQhzcPST0x4218D0Dump DAG pipeline CFG
DumpIRQhzcVE0x421920Dump DAG pipeline IR
DumpMercOpCountsQhzcZrepBcPbhagf0x421970Dump Mercury opcode distribution
DumpReconstitutedBinaryQhzcErpbafgvghgrqOvanel0x4219C0Dump reconstituted binary output
DumpRPOQhzcECB0x421A10Dump reverse post-order traversal

Three knob names appear in both pipelines: DumpCFG, DumpIR, and (implicitly) their string addresses differ (0x21BDBF0 vs 0x21DCCA0 for DumpCFG). Setting one does not affect the other.

Recipe / NamedPhases Knob (OCG 298)

The recipe knob (OCG index 298) diverts the optimizer driver sub_7FB6C0 onto the recipe path (sub_9F63D0sub_9F4040), where a small DSL builds a custom phase schedule that replaces the default 157-entry order. Unlike DUMPIR, which passively observes, this knob actively controls which phases run and in what order. It is an internal engineering interface (gated by a knob, not a documented user-facing ptxas flag); default compiles never reach it. The recipe schedule is fed to the same dispatch loop sub_C64F70 as the default path, with a computed length — and this is the only path that can schedule IDs 157 (DebuggerBreak) and 158 (NOP).

Knob Location

NamedPhases is at OCG knob index 298. The runtime byte offset is 298 * 72 = 21456 from the knob state base. This is confirmed by the decompiled code in sub_798B60:

// sub_798B60 (NamedPhases parser)
v11 = *(ctx + 72);                    // knob state base pointer
v12 = *(byte*)(v11 + 21456);          // type tag at knob index 298
if (!v12) return 0;                   // knob not set => no filtering
if (v12 == 5)                         // type 5 = string
    v14 = *(ptr*)(v11 + 21464);       // string value at +8 from type tag

Parser — sub_798B60

The recipe tokenizer (sub_798B60, 1,776 bytes) reads the knob value string and parses it into parallel arrays of up to 256 entries. The schedule builder sub_9F4040 (reached from the optimizer driver via sub_9F63D0) consumes those arrays and applies the recipe DSL to the default 157-identity schedule. The "NamedPhases" string appears in both: at 0x798E90 in the tokenizer and at 0x9F42B0 in the schedule builder — they are two stages of the same recipe path, not a separate Mercury mechanism.

The tokenizer operates as follows:

  1. Reads knob value at offset 21456 from the knob state
  2. If the knob is unset (type byte == 0), returns immediately (no filtering)
  3. If the knob is a string (type byte == 5), extracts the string pointer
  4. Copies the string into a pool-allocated buffer
  5. Tokenizes using strtok_r with comma (,) as delimiter
  6. For each token, calls sub_798280 (ParsePhaseNameFragment) to split the phase name from optional parameters
  7. Stores results in parallel arrays: names[], values[], full_strings[] (max 256 entries)

Phase Name Fragment Parser — sub_798280

Each comma-separated token in the NamedPhases string is parsed by sub_798280 into two components:

  • Phase name: characters up to the first , separator, uppercased during parsing
  • Parameter suffix: characters after , up to the next + delimiter or end-of-string

The + character acts as an entry separator (analogous to how the DisablePhases string uses + to delimit multiple phase names). This allows:

-knob NamedPhases=PhaseA,param1+PhaseB,param2+PhaseC

The Recipe DSL — sub_9F4040

The schedule builder sub_9F4040 starts from the default 157-identity schedule (sub_C60D20()) and applies a small DSL parsed from the tokenized recipe string. Explicit phase IDs are clamped to [0, 159] and unknown phase names map to 158/NOP via sub_C641D0. These tokens operate on the main OCG phase schedule — they are not Mercury-specific:

TokenDecompiled LineMatch MethodEffect
NamedPhases381string comparereplace the schedule with the explicit name list (each name → ID via sub_C641D0)
p%d467sprintf "p%d"select phases by numeric index; value from the parallel value array, clamped to [0,159]
shuffle843strlen + byte compare (8 chars)seeded pairwise rotation pass over the schedule slots (reps-controlled)
repsstring comparenumber of shuffle iterations (≤ 256)
swap1950strlen + byte compare (6 chars)swap a pair of schedule slots (base offset 1)
swap21007strlen + byte compare (6 chars)swap a pair of schedule slots (base offset 2)
swap31061strlen + byte compare (6 chars)swap a pair of schedule slots (base offset 3)
swap41119strlen + byte compare (6 chars)swap a pair of schedule slots (base offset 4)
swap51162strlen + byte compare (6 chars)swap a pair of schedule slots (base offset 5)
swap61202strcmp()swap a pair of schedule slots (base offset 6)
dce1/dce2/dce31556 / 1282 / 1319counter triggerinject OriPerformLiveDead (DCE) at the counter position
cpy1/cpy2/cpy31648 / 1395 / 1442counter triggerinject OriCopyProp at the counter position

shuffle and swap1swap6 are recipe keywords, not phase names: they do not exist in the phase name table at off_22BD0C0. Their matching is done inline with strlen-guarded character comparison (not strcmp — except swap6, the last in a fallthrough chain). The dceN/cpyN tokens inject real registered phases: OriPerformLiveDead (the DCE family, IDs 18/38/70/99) and OriCopyProp (ID 22), both resolved through sub_C641D0. OCG knob 297 is pulsed once per applied recipe element as a diagnostic "recipe-applied" counter. For the full DSL see the Optimization Pipeline page.

Phase Name Lookup — sub_C641D0

The binary search function sub_C641D0 (305 bytes) resolves a phase name string to a phase index. It is the core name resolution used by both DUMPIR and NamedPhases.

Algorithm

int PhaseManager::lookup_phase(const char* query) {
    ensure_sorted();                          // sub_C63FA0

    // Binary search over sorted {name_ptr, index} pairs
    // Each entry is 16 bytes: [8-byte name pointer, 4-byte phase index, 4-byte padding]
    int lo = 0, hi = sorted_count;
    while (hi > 0) {
        int mid = hi / 2;
        // Case-insensitive string comparison via tolower()
        int cmp = strcasecmp(table[lo + mid].name, query);
        if (cmp < 0) {
            hi -= mid + 1;
            lo += mid + 1;
        } else if (cmp == 0) {
            return table[lo + mid].index;     // found
        } else {
            hi = mid;
        }
    }

    // Verify final position (handles edge case)
    if (lo < end && strcasecmp(table[lo].name, query) == 0)
        return table[lo].index;

    return 158;                               // sentinel: NOP phase
}

The comparison uses tolower() on each character individually, making the search fully case-insensitive. On lookup failure, the function returns 158 (the sentinel NOP phase), not an error code. This means misspelled phase names silently resolve to a no-op rather than producing an error.

Sorted Table Construction — sub_C63FA0

The sorted name table is lazily constructed. sub_C63FA0 checks whether the current sorted count matches the expected count (stored at PhaseManager+104). If they differ, it:

  1. Grows the sorted table array if needed (1.5x growth policy)
  2. Copies name pointers from the raw phase name table (off_22BD0C0)
  3. Each entry is 16 bytes: {char* name, int phase_index}, where phase_index is the array position
  4. Sorts using iterative quicksort (sub_C639A0) with median-of-three pivot selection

The sort is performed once and cached. Subsequent lookups reuse the sorted table without re-sorting.

Report Passes

Six phases in the pipeline are dedicated diagnostic/dump passes. They are no-ops by default and activate only when specific debug options are enabled:

PhaseNameTriggerOutput
9ReportInitialRepresentationDUMPIR knob, --keepOri IR after initial lowering (pre-optimization)
96ReportBeforeSchedulingDUMPIR knob, --keepOri IR entering scheduling/RA stage
102ReportAfterRegisterAllocationDUMPIR knob, --keepOri IR after register allocation
126ReportFinalMemoryUsage--stat=phase-wiseMemory pool consumption summary
129DumpNVuCodeText--keep, DUMPIRSASS text disassembly (cuobjdump-style)
130DumpNVuCodeHex--keep, DUMPIRRaw SASS hex dump

Additionally, ReportBeforeRegisterAllocation (at 0x22BD068) is a phase name in the table but is handled as an arch-specific phase (index >= 139), providing an IR dump point immediately before register allocation in backends that override it.

Report Pass Activation

Report passes check their activation condition in the isNoOp() virtual method. When the DUMPIR knob is set to a phase name, the report pass compares the current phase name against the DUMPIR value. If they match, isNoOp() returns false and the pass executes its dump logic.

The dispatch loop in sub_C64F70 constructs diagnostic context strings around each phase execution:

// Before execution (line 117 of sub_C64F70):
*(_QWORD *)buffer = 0x2065726F666542LL;    // "Before " as 8-byte LE literal
memcpy(buffer + 7, phase_name, len + 1);   // append phase name after "Before "

// After execution (line 196 of sub_C64F70):
strcpy(buffer, "After ");                  // 6-byte prefix
memcpy(buffer + 6, phase_name, len + 1);   // append phase name after "After "

The literal 0x2065726F666542 decomposes as bytes 42 65 66 6F 72 65 20 = ASCII "Before " (7 bytes including trailing space, plus a null in the 8th byte that gets overwritten by memcpy). The "After " path uses strcpy instead of a literal store because it is only 6 bytes and the code path is post-execution (not latency-critical).

These strings appear in diagnostic output when --stat=phase-wise is enabled:

Before GeneralOptimize  ::  [Total 1234 KB]  [Freeable 567 KB]  [Freeable Leaked 12 KB] (2%)
After GeneralOptimize   ::  [Total 1456 KB]  [Freeable 789 KB]  [Freeable Leaked 23 KB] (3%)

The string addresses in the binary are:

  • "Before " at 0x22BC3D3
  • "After " at 0x22BC3DB
  • " :: " at 0x22BC3E2 (separator between phase name and stats)
  • "[Total " at 0x22BC3E9
  • "[Freeable " at 0x22BC3F6
  • "[Freeable Leaked " at 0x22BC401
  • "All Phases Summary" at 0x22BC416 (final summary label)

Phase-Wise Statistics — --stat=phase-wise

The --stat CLI option (processed in sub_432A00 at 0x432E5A) accepts a comma-separated list of report modes:

ptxas --stat=phase-wise input.ptx -o output.cubin
ModeShortDescription
timetPrint compilation time
memorymPrint peak memory usage
phase-wisepPrint per-phase time and memory delta
detaileddPrint all of the above

When phase-wise is enabled (string comparison at 0x4460F8 in sub_445EB0), the dispatch loop's timing flag (PhaseManager+72) is set, and sub_C64310 runs after every phase to print memory deltas.

IR Output Format

The DUMPIR dump emits a per-function statistics header (using # comment prefix) followed by the Ori IR listing. The statistics header is emitted by sub_A3A7E0 and contains hardware performance estimates computed from the current IR state.

Per-Function Statistics Header

# 142 instructions, 24 R-regs
# [inst=142] [texInst=0] [tepid=0] [rregs=24]
# [FP16 inst=0] [FP16 VectInst=0] [Percentage Vectorized=0.00]
# [est latency = 87] [LSpillB=0] [LRefillB=0], [SSpillB=0], [SRefillB=0], [LowLmemSpillSize=0] [FrameLmemSpillSize=0]
# [LNonSpillB=0] [LNonRefillB=0], [NonSpillSize=0]
# [Occupancy = 0.750000], [est numDivergentBranches=2] [attributeMemUsage=0], [programSize=1024]
# [est fp=12] [est half=0], [est trancedental=0], [est ipa=0], [est shared=0], [est controlFlow=8], [est loadStore=24]
# [est tex=0] [est pairs=4]
# [issue thru=0.888889] [fp thru=0.111111] [half thru=0.000000], [trancedental thru=0.000000], [ipa thru=0.000000]
# [shared thru=0.000000] [controlFlow thru=0.062500] [texLoadStore thru=0.187500], [reg thru=0.000000], [warp thru=0.000000]
# [partially unrolled loops=0] [non-unrolled loops=1]
# [CB-Bound Tex=0] [UR-Bound Tex=0] [Bindless Tex=0] [Partially Bound Tex=0]
# [UDP inst=0] [numVecToURConverts inst=0]
# [maxNumLiveValuesAtSuspend=0]
# [instHint=142] [instPairs=4]
# [worstcaseLat=87.000000]
# [avgcaseLat=52.500000]
# [SharedMem Alloc thru=0.000000]
# [Precise inst=0]

The format strings are at two locations in rodata:

Address RangeContextNotes
0x21EBF76--0x21EC3B0Pre-register-allocation statsCommas between some [SSpillB=%d], [SRefillB=%d] fields
0x21FA008--0x21FA0A0Post-register-allocation statsNo commas: [SSpillB=%d] [SRefillB=%d]

The [Occupancy] line's typo "trancedental" (missing 's') is present in the binary itself and matches NVIDIA's original source.

Statistics Field Glossary

FieldMeaning
instTotal instruction count
texInstTexture/surface instruction count
tepidTexture instruction count (alternate metric)
rregsR-register (GPR) count
LSpillB / LRefillBLocal-memory spill/refill byte counts
SSpillB / SRefillBShared-memory spill/refill byte counts
LowLmemSpillSizeLow local-memory spill total
FrameLmemSpillSizeFrame-level local-memory spill total
LNonSpillB / LNonRefillBLocal-memory non-spill traffic bytes
OccupancyEstimated warp occupancy (0.0–1.0)
numDivergentBranchesEstimated divergent branch count
attributeMemUsageAttribute memory usage (shader inputs)
programSizeTotal program size in bytes
issue thruIssue throughput (instructions per cycle)
fp thru / half thruFP32 / FP16 throughput
trancedental thruTranscendental (SFU) throughput
ipa thruInterpolation throughput
shared thruShared memory throughput
texLoadStore thruTexture + load/store throughput
reg thruRegister throughput
warp thruWarp-level throughput
CB-Bound TexConstant-bank-bound texture references
UR-Bound TexUniform-register-bound texture references
Bindless TexBindless texture references
UDP instUniform datapath instruction count
numVecToURConvertsVector-to-uniform-register conversion count
maxNumLiveValuesAtSuspendPeak live values at suspension point
instHint / instPairsInstruction hint count / instruction pair count
worstcaseLat / avgcaseLatWorst-case / average-case latency estimates
SharedMem Alloc thruShared memory allocation throughput
Precise instPrecise (non-relaxed) instruction count

Mercury Pipeline Dump Points

The Mercury/DAG pipeline emits its own "After" labels at fixed points in the encode-decode-expand flow. These labels are used by both the DumpIR (DAG) knob and the DumpAnnot knob:

LabelString AddressPipeline Stage
After Decode0x202D5CEAfter initial SASS decode
After Expansion0x202D5DBAfter instruction expansion
After WAR post-expansion0x202D604After WAR insertion (post-expansion)
After Opex0x202D60FAfter operand expansion
After WAR post-opexing0x202DCD0After WAR insertion (post-opex)
After MercWARs0x202DCDFAfter Mercury WAR pass
After MercOpex0x21E5C33After Mercury operand expansion
After MercConverter0x22B7B38After Mercury format conversion
After MercExpand0x22BC3DBAfter Mercury instruction expansion
After EncodeAndDecode0x23D1A60After encode-decode round-trip

Memory Statistics Format

The sub_C64310 (ReportPhaseStats) function formats memory sizes using three thresholds:

Size RangeFormatExample
< 1024 bytes%d (raw integer)512
< 10 MB%.3lf KB (kilobytes, 3 decimals)1234.567 KB
>= 10 MB%.3lf MB (megabytes, 3 decimals)12.345 MB

The memory format reuses the suffix from "PeakMemoryUsage = %.3lf KB" (at 0x1CE7BB6) by referencing the string at offset +24 to extract just " KB". The pool-consumption variant uses "[Pool Consumption = " at 0x22BC3B3.

Phase Name Table

The static phase name table at off_22BD0C0 contains 159 entries (IDs 0–158), copied wholesale into the PhaseManager by sub_C62720 (1272 = 159*8 bytes). After sorting by sub_C63FA0, the binary search in sub_C641D0 provides O(log n) lookup — approximately 8 comparisons for ~159 entries.

The 159 entries cover every phase ID:

  • IDs 0–138 — the base pipeline phases with fixed names
  • IDs 139–156 — the late-pipeline phases (Mercury encoding, scoreboards, register map, diagnostics), all named, e.g. ProcessO0WaitsAndSBs (139) … DumpNVuCodeHex (156)
  • IDs 157–158DebuggerBreak and NOP, named and registered but excluded from the default 157-entry schedule

The AllocateRegisters string (0x21F0229) also appears as a phase name referenced by the register allocation subsystem (sub_A55D80, sub_A76030) and is present in the name table at 0x22BD490.

Interaction with --keep

The --keep flag triggers output file retention and activates certain report passes. When --keep is set:

  1. Phase 129 (DumpNVuCodeText) writes a human-readable SASS disassembly to a .sass file
  2. Phase 130 (DumpNVuCodeHex) writes raw SASS binary as hex
  3. Report phases 9, 96, and 102 may produce .ori intermediate representation dumps

The --keep flag is processed in the CLI option handler (sub_43CC70 at 0x43D850) which generates the .sass file extension.

Function Map

AddressSizeFunctionConfidence
sub_798280900ParsePhaseNameFragment — splits NAME,PARAM from a recipe tokenMEDIUM
sub_798B601,776recipe tokenizer — tokenizes the OCG-knob-298 recipe stringCERTAIN
sub_9F4040~7,400recipe schedule builder — applies the recipe DSL to the default OCG scheduleHIGH
sub_9F63D0342recipe path entry — builds PhaseManager, calls sub_9F4040, dispatches via sub_C64F70HIGH
sub_A3A7E0~2,000CodeObject::EmitStats — per-function statistics header printerHIGH
sub_C639A0~800QuicksortNameTable — iterative quicksort for phase name tableMEDIUM
sub_C63FA0~600EnsureSortedNameTable — lazy sorted table constructionMEDIUM
sub_C641D0305PhaseManager::LookupPhase — case-insensitive binary searchCERTAIN
sub_C643103,168PhaseManager::ReportPhaseStats — per-phase timing/memory reporterHIGH
sub_C64F701,455PhaseManager::Dispatch — main phase execution loopCERTAIN
sub_A55D80~2,000RegAlloc::VerifyReachingDefs — references DUMPIR in error messageHIGH
sub_A76030~1,000RegAlloc::VerifyMismatch — references DUMPIR in error messageHIGH

Reimplementation Notes

  1. DUMPIR is a string knob, not a boolean. The value is a phase name that triggers a dump after that specific phase. To dump at multiple points, run separate compilations with different DUMPIR values. There is no comma-separated multi-phase dump syntax for DUMPIR itself.

  2. NamedPhases uses comma+plus syntax. Commas separate name-from-parameter within a single entry; + separates multiple entries. The phase name portion is uppercased during parsing. Parameters are preserved as-is.

  3. Lookup failure is silent. An unrecognized phase name in DUMPIR or NamedPhases resolves to phase index 158 (NOP sentinel), not an error. The compiler does not warn about misspelled phase names.

  4. The sorted table is 16 bytes per entry: {char* name, int32 index, int32 padding}. The sort is stable only within the quicksort's three-way partitioning — duplicate names (which do not occur in practice) would have undefined ordering.

  5. Two DumpIR knob instances exist (OCG and DAG). They are independent — setting one does not affect the other. The OCG instance controls the 159-phase optimization pipeline; the DAG instance controls the Mercury SASS pipeline. Three knob names (DumpCFG, DumpIR, DumpAnnot/DumpRPO) have separate OCG and DAG instances with distinct ROT13 string addresses.

  6. Memory statistics format uses three thresholds: bytes (< 1 KB), kilobytes with 3 decimals (< 10 MB), megabytes with 3 decimals (>= 10 MB). The reporter is sub_C64310.

  7. NamedPhases in Mercury (sub_9F4040) supports 7 pure pseudo-phases (shuffle, swap1--swap6) that do not exist in the main phase table. These use inline strlen-guarded byte comparison, not strcmp (except swap6). Two additional names (OriPerformLiveDead, OriCopyProp) ARE in the main table but are conditionally injected into Mercury's phase sequence based on register-pressure/correctness state flags.

  8. The "Before" string is a raw 8-byte LE literal store, not a strcpy. The dispatch loop writes 0x2065726F666542 directly to the buffer, which is "Before " in ASCII. The "After " banner is emitted by a similar inline literal store (a 4-byte 0x65746641 "Afte" plus a 2-byte 0x2072 "r " plus a null), not a runtime strcpy. Both are gated by isNoOp() returning false; neither affects whether the phase's execute() runs.

  9. Statistics header has two variants. The pre-register-allocation format strings (at 0x21EC050) use commas between some spill fields: [SSpillB=%d], [SRefillB=%d]. The post-register-allocation variant (at 0x21FA008) drops those commas: [SSpillB=%d] [SRefillB=%d]. A reimplementation should match whichever variant is appropriate for the dump point.

  10. The "trancedental" typo is canonical. Both the format string and the stats output use "trancedental" (missing 's'). A reimplementation should preserve this spelling for compatibility with tools that parse the output.

Cross-References