Skip to content

Add IR serialization: compile from a Nautilus IR file, skipping tracing - #393

Draft
PhilippGrulich wants to merge 4 commits into
mainfrom
claude/nautilus-ir-input-skip-trace-ffc94y
Draft

Add IR serialization: compile from a Nautilus IR file, skipping tracing#393
PhilippGrulich wants to merge 4 commits into
mainfrom
claude/nautilus-ir-input-skip-trace-ffc94y

Conversation

@PhilippGrulich

@PhilippGrulich PhilippGrulich commented Jul 10, 2026

Copy link
Copy Markdown
Member

Summary

This PR lets the Nautilus compiler take a previously generated IR file as input and compile it directly, skipping the tracing frontend entirely — and there is now exactly one IR text format: IRGraph::toString (the IR dumps) and serializeIR emit byte-identical output, so every dump is a loadable module.

Use cases: faster startup (trace once, reload later), build-time/offline tracing, and debugging backends against hand-inspectable, re-loadable IR.

Design

One format

The old fmt-formatter printer in IRGraph.cpp is deleted; toString and serializeIR share a single writer (IRSerializationUtil) with a single rendering:

  • Function-wide unique value ids. The in-memory IR distinguishes values by pointer identity and legitimately reuses numeric ids across blocks, and passes like block-argument pruning create cross-block references — so a bare $1 in text would be ambiguous (this was caught as an actual asmjit miscompile during testing). The writer numbers values block by block, arguments before operations; computePrintedValueIds exposes the same numbering for consumers that correlate operations with the text.
  • Real external symbols. Proxy calls and address-of print as call @"_Z3addii" "add(int, int)"(...).
  • Strictness is the only difference. toString never throws — a non-null pointer constant (a raw, process-specific address) renders as the * placeholder. serializeIR validates the graph first and fails with a descriptive error instead of writing a file the parser would reject later.
  • Previously-lost information is now printed: select/call_indirect/addressof (previously a bare $N :type), != comparisons (previously an empty operator), branch probabilities (prob(...)), alloca specs and function attributes.

MLIR debug info

Printed ids no longer equal stored operation identifiers, so the debug-info chain translates: IRSourceMap gains a per-function Operation* → printed-id table and MLIRLoweringProvider routes every NameLoc, shadow-alloca key, and dump-line lookup through a new dollarId helper. GDB variable names keep matching the dump text.

Golden fixtures

Mangled symbols depend on the build (raw addresses for non-exported functions, lambda names), so the tracing tests normalize external references to @"<symbol>" "<name>" placeholders before comparison (testing::normalizeExternalFunctionReferences, shared with the GPU plugin's tracing test). All IR fixtures are regenerated in the unified format — core, ENABLE_SHORT_CIRCUIT_BOOL overrides, and GPU plugin — which is the bulk of the diff.

Parser (IRParser)

  • Reconstructs the graph in an arena-backed IRGraph, wires the CFG through the same helpers as the trace-to-IR conversion, rebuilds predecessor lists, and runs IRVerifier before returning — malformed input fails at load time with line/column diagnostics.
  • External functions are re-resolved in the loading process: first via an optional IRSymbolResolver callback, then via dlsym on the recorded mangled symbol.
  • Skips ; ... source-location comment trailers; legacy func_* dumps are rejected with an error pointing at the current writers.

Compiler & public API

  • JITCompiler/TieredJITCompiler gain compileToSerializedIR (trace → IR text) and compileIRModule (pre-built graph → module state, with the usual tier-0 compile + background tier-1 promotion; interpreter tier-0 falls back to synchronous tier-1 since a loaded module has no callables to interpret).
  • NautilusEngine::loadModuleFromIR(text, resolver) / loadModuleFromIRFile(path, resolver) compile the IR directly; functions are retrieved by name via CompiledModule::getFunction<Signature>(name).
// Producer (traces once)
auto module = engine.createModule();
module.registerFunction("digitSum", digitSum);
std::ofstream("digitSum.nautilus") << module.serializeIR();

// Consumer (no tracing)
auto loaded = engine.loadModuleFromIRFile("digitSum.nautilus");
auto digitSum = loaded.getFunction<int32_t(int32_t)>("digitSum");

Tests

  • ir-pass-tests/IRSerializationTest.cpp: parse→serialize fixed-point round trips covering every operation form, toString == serializeIR identity, cross-block references, legacy-format handling, and error reporting (undefined/ambiguous values, unknown blocks, type mismatches, unresolvable symbols, lossy legacy input, verification failures).
  • execution-tests/IRSerializationExecutionTest.cpp: serialize→load→execute equivalence against the traced path across all available backends (loops/nested control flow, floats/casts, pointer loads, runtime calls with a symbol resolver, file-based loading), plus error paths.
  • Golden fixtures regenerated and green in all three local configs (default, short-circuit-bool, GPU plugin tracing).
  • Full local suite: 363/363 tests pass (clang-18, MLIR backend off in this environment; the MLIR debug-info changes are validated by the CI matrix).

Notes

  • Loaded IR is the already-optimized IR (passes run before serialization), so the IR pass pipeline is not re-run on load.
  • Loading requires ENABLE_COMPILER + ENABLE_TRACING; other configurations throw a descriptive error.
  • Fixes a pre-existing unused-variable compile error in the GPU plugin when both GPU backends are disabled.
  • New doc: docs/ir-serialization.md.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RRYVYANDgKxKATtrCQk9px

Introduce a portable text format for Nautilus IR and the machinery to
compile a module directly from it, bypassing the tracing frontend:

- IRSerializationUtil: complete, parseable writer for IRGraph. Uses the
  IRGraph::toString grammar but emits everything the pretty printer
  drops (proxy-call symbols/names, call and function attributes, alloca
  specs, branch probabilities, select/indirect-call/address-of). Values
  are renumbered with function-wide unique ids so cross-block
  references created by IR passes stay unambiguous in text. Non-null
  pointer constants are rejected as process-specific.
- IRParser: reconstructs an IRGraph from the text, resolves external
  functions via an optional resolver callback with dlsym fallback,
  rebuilds predecessor lists, and verifies the graph (IRVerifier)
  before handing it to a backend.
- JITCompiler/TieredJITCompiler: new compileToSerializedIR (trace to
  portable IR text) and compileIRModule (compile a pre-built graph into
  a module state with the usual tier-0 + background tier-1 promotion).
- Public API: NautilusModule::serializeIR() produces the IR text;
  NautilusEngine::loadModuleFromIR/loadModuleFromIRFile compile it
  directly, exposing the module's functions by name.
- FunctionOperation: expose the attribute map for serialization.
- Tests: parser/serializer round-trip and error-case unit tests, and
  engine-level execution equivalence tests across all backends (loops,
  floats, pointers, runtime calls with symbol resolution, file loading).
- Docs: docs/ir-serialization.md describing the workflow and format.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RRYVYANDgKxKATtrCQk9px

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tracing Benchmark

Details
Benchmark suite Current: 9c56f47 Previous: 57e8585 Ratio
ir_add 613.507 ns (± 39.1254) 800.179 ns (± 63.0847) 0.77
ir_ifThenElse 1.25987 us (± 83.9558) 1.64244 us (± 124.198) 0.77
ir_deeplyNestedIfElse 3.00265 us (± 200.963) 3.42801 us (± 258.335) 0.88
ir_loop 1.3526 us (± 125.643) 1.77591 us (± 261.701) 0.76
ir_ifInsideLoop 2.52343 us (± 265.883) 2.99854 us (± 320.344) 0.84
ir_loopDirectCall 1.52919 us (± 85.1957) 1.97267 us (± 295.523) 0.78
ir_pointerLoop 1.74195 us (± 145.717) 2.09606 us (± 222.109) 0.83
ir_staticLoop 1.19547 us (± 73.4998) 1.51781 us (± 248.926) 0.79
ir_fibonacci 1.6022 us (± 155.776) 1.85757 us (± 186.618) 0.86
ir_gcd 1.25833 us (± 141.315) 1.59126 us (± 280.899) 0.79
ir_nestedIf10 6.24665 us (± 359.946) 7.93997 us (± 768.651) 0.79
ir_nestedIf100 81.8895 us (± 4.19891) 89.4148 us (± 3.75679) 0.92
ir_chainedIf10 9.73277 us (± 735.087) 12.1461 us (± 1.10628) 0.80
ir_chainedIf100 138.541 us (± 10.371) 171.592 us (± 13.1834) 0.81
comp_mlir_add 6.88638 ms (± 850.854) 5.99332 ms (± 491.66) 1.15
comp_mlir_ifThenElse 6.91877 ms (± 313.695) 6.38908 ms (± 601.103) 1.08
comp_mlir_deeplyNestedIfElse 5.89688 ms (± 221.238) 5.3951 ms (± 527.83) 1.09
comp_mlir_loop 7.90266 ms (± 280.763) 7.55451 ms (± 572.693) 1.05
comp_mlir_ifInsideLoop 26.4331 ms (± 1.84104) 30.2577 ms (± 714.376) 0.87
comp_mlir_loopDirectCall 11.5296 ms (± 357.94) 13.409 ms (± 670.246) 0.86
comp_mlir_pointerLoop 24.8088 ms (± 691.433) 29.4484 ms (± 790.147) 0.84
comp_mlir_staticLoop 5.65745 ms (± 208.541) 5.34851 ms (± 608.009) 1.06
comp_mlir_fibonacci 10.8041 ms (± 807.846) 11.4544 ms (± 795.116) 0.94
comp_mlir_gcd 9.37371 ms (± 282.407) 9.9064 ms (± 544.163) 0.95
comp_mlir_nestedIf10 10.6184 ms (± 499.176) 11.503 ms (± 786.242) 0.92
comp_mlir_nestedIf100 22.6558 ms (± 675.127) 26.2399 ms (± 671.578) 0.86
comp_mlir_chainedIf10 10.8112 ms (± 371.53) 10.3095 ms (± 620.769) 1.05
comp_mlir_chainedIf100 54.7492 ms (± 2.47255) 22.0591 ms (± 551.846) 2.48
comp_cpp_add 34.1389 ms (± 35.3458) 26.7938 ms (± 957.905) 1.27
comp_cpp_ifThenElse 27.6295 ms (± 20.7382) 27.2635 ms (± 997.476) 1.01
comp_cpp_deeplyNestedIfElse 40.3568 ms (± 58.5254) 27.6892 ms (± 449.216) 1.46
comp_cpp_loop 35.7719 ms (± 36.8189) 26.7853 ms (± 227.078) 1.34
comp_cpp_ifInsideLoop 42.6682 ms (± 54.7784) 27.1871 ms (± 540.233) 1.57
comp_cpp_loopDirectCall 29.2579 ms (± 29.1156) 27.2963 ms (± 227.416) 1.07
comp_cpp_pointerLoop 31.6043 ms (± 30.3958) 27.1928 ms (± 481.373) 1.16
comp_cpp_staticLoop 33.6419 ms (± 30.5547) 26.7106 ms (± 226.511) 1.26
comp_cpp_fibonacci 35.4269 ms (± 43.4228) 27.1174 ms (± 226.305) 1.31
comp_cpp_gcd 38.5156 ms (± 39.5544) 27.0979 ms (± 254.901) 1.42
comp_cpp_nestedIf10 43.7048 ms (± 39.7482) 29.5322 ms (± 178.994) 1.48
comp_cpp_nestedIf100 53.9666 ms (± 21.4193) 55.1474 ms (± 1.2752) 0.98
comp_cpp_chainedIf10 39.3691 ms (± 47.2116) 30.0046 ms (± 531.779) 1.31
comp_cpp_chainedIf100 72.3865 ms (± 54.8129) 59.2427 ms (± 384.59) 1.22
comp_bc_add 10.8221 us (± 2.11574) 15.5138 us (± 2.67823) 0.70
comp_bc_ifThenElse 13.9536 us (± 3.46238) 20.626 us (± 3.64135) 0.68
comp_bc_deeplyNestedIfElse 18.577 us (± 3.66285) 25.6626 us (± 4.57103) 0.72
comp_bc_loop 12.6805 us (± 2.54333) 20.5306 us (± 4.62572) 0.62
comp_bc_ifInsideLoop 16.2555 us (± 3.5899) 24.6636 us (± 4.17769) 0.66
comp_bc_loopDirectCall 12.1903 us (± 2.57022) 21.6884 us (± 3.63588) 0.56
comp_bc_pointerLoop 14.4625 us (± 3.09855) 23.1699 us (± 3.82171) 0.62
comp_bc_staticLoop 13.1214 us (± 1.61593) 18.9414 us (± 3.85837) 0.69
comp_bc_fibonacci 13.117 us (± 1.7978) 21.6434 us (± 5.3148) 0.61
comp_bc_gcd 12.7679 us (± 2.25434) 20.5197 us (± 6.34281) 0.62
comp_bc_nestedIf10 37.1389 us (± 5.09297) 48.3411 us (± 7.22903) 0.77
comp_bc_nestedIf100 266.352 us (± 12.7889) 284.134 us (± 22.1062) 0.94
comp_bc_chainedIf10 46.9793 us (± 6.39062) 63.6357 us (± 8.32889) 0.74
comp_bc_chainedIf100 450.983 us (± 21.8149) 468.737 us (± 15.0929) 0.96
comp_tbc_add 1.72036 us (± 138.628) 1.84687 us (± 108.73) 0.93
comp_tbc_ifThenElse 4.01344 us (± 298.159) 4.13604 us (± 308.723) 0.97
comp_tbc_deeplyNestedIfElse 9.47815 us (± 1.52729) 9.57435 us (± 1.47032) 0.99
comp_tbc_loop 4.17236 us (± 494.364) 4.29019 us (± 631.173) 0.97
comp_tbc_ifInsideLoop 6.86158 us (± 1.14405) 7.32805 us (± 840.167) 0.94
comp_tbc_loopDirectCall 4.26952 us (± 264.612) 4.44475 us (± 429.528) 0.96
comp_tbc_pointerLoop 5.10827 us (± 358.238) 5.37766 us (± 473.795) 0.95
comp_tbc_staticLoop 4.73549 us (± 325.341) 4.61368 us (± 388.737) 1.03
comp_tbc_fibonacci 4.21683 us (± 255.605) 4.67836 us (± 509.087) 0.90
comp_tbc_gcd 3.26582 us (± 158.398) 3.85544 us (± 372.962) 0.85
comp_tbc_nestedIf10 27.7358 us (± 1.58594) 26.9243 us (± 4.25127) 1.03
comp_tbc_nestedIf100 283.548 us (± 28.6909) 273.569 us (± 10.3499) 1.04
comp_tbc_chainedIf10 35.4895 us (± 2.5628) 33.1793 us (± 3.55761) 1.07
comp_tbc_chainedIf100 400.009 us (± 22.9733) 399.195 us (± 12.933) 1.00
comp_asmjit_add 14.5861 us (± 5.672) 23.707 us (± 5.55472) 0.62
comp_asmjit_ifThenElse 16.8506 us (± 3.03468) 33.0951 us (± 5.47173) 0.51
comp_asmjit_deeplyNestedIfElse 29.4835 us (± 8.46561) 50.7312 us (± 10.1235) 0.58
comp_asmjit_loop 18.7874 us (± 3.40226) 32.7064 us (± 4.90803) 0.57
comp_asmjit_ifInsideLoop 26.8256 us (± 8.27614) 47.8386 us (± 8.93617) 0.56
comp_asmjit_loopDirectCall 18.5418 us (± 2.84604) 43.2145 us (± 10.9832) 0.43
comp_asmjit_pointerLoop 21.2385 us (± 3.76997) 45.4758 us (± 8.99895) 0.47
comp_asmjit_staticLoop 19.0305 us (± 3.35251) 29.6573 us (± 4.66609) 0.64
comp_asmjit_fibonacci 19.8722 us (± 3.57072) 34.7377 us (± 6.71867) 0.57
comp_asmjit_gcd 17.2506 us (± 2.45217) 34.5033 us (± 7.38019) 0.50
comp_asmjit_nestedIf10 51.9736 us (± 7.78962) 75.6875 us (± 9.3828) 0.69
comp_asmjit_nestedIf100 432.833 us (± 22.5859) 542.237 us (± 143.719) 0.80
comp_asmjit_chainedIf10 69.1129 us (± 11.3787) 98.3665 us (± 18.608) 0.70
comp_asmjit_chainedIf100 575.906 us (± 25.5167) 639.703 us (± 20.2426) 0.90
exec_mlir_add 11.6185 ns (± 1.30986) 11.0557 ns (± 1.40956) 1.05
exec_mlir_fibonacci 21.5892 us (± 3.1101) 15.8369 us (± 3.98961) 1.36
exec_mlir_sum 481.037 us (± 36.027) 605.374 us (± 56.6621) 0.79
exec_cpp_add 3.55445 ns (± 0.179947) 5.03774 ns (± 1.25159) 0.71
exec_cpp_fibonacci 29.891 us (± 4.98955) 49.4957 us (± 7.13745) 0.60
exec_cpp_sum 7.07306 ms (± 378.924) 11.4328 ms (± 75.9807) 0.62
exec_bc_add 37.671 ns (± 2.4072) 51.608 ns (± 19.841) 0.73
exec_bc_fibonacci 280.82 us (± 14.9366) 432.957 us (± 13.3195) 0.65
exec_bc_sum 63.6546 ms (± 1.57932) 95.3998 ms (± 324.196) 0.67
exec_tbc_add 21.0788 ns (± 1.27901) 28.0294 ns (± 4.45194) 0.75
exec_tbc_fibonacci 125.114 us (± 5.43001) 143.142 us (± 8.17062) 0.87
exec_tbc_sum 30.7855 ms (± 1.22527) 36.6451 ms (± 242.439) 0.84
exec_asmjit_add 3.18865 ns (± 0.36257) 3.61065 ns (± 0.567519) 0.88
exec_asmjit_fibonacci 15.5561 us (± 1.68066) 14.7109 us (± 3.50444) 1.06
exec_asmjit_sum 2.7695 ms (± 135.613) 2.8107 ms (± 35.4744) 0.99
exec_bc_add_passesOff 39.6883 ns (± 2.18957) 49.769 ns (± 12.9652) 0.80
exec_bc_add_passesOn 39.3002 ns (± 5.54387) 54.2062 ns (± 26.768) 0.73
exec_bc_fibonacci_passesOff 282.829 us (± 12.1125) 430.978 us (± 9.9409) 0.66
exec_bc_fibonacci_passesOn 262.57 us (± 15.7327) 389.75 us (± 11.2048) 0.67
exec_bc_sum_passesOff 65.0755 ms (± 1.37094) 95.4443 ms (± 306.724) 0.68
exec_bc_sum_passesOn 58.7449 ms (± 2.32443) 80.0464 ms (± 1.55427) 0.73
exec_tbc_add_passesOff 23.5225 ns (± 5.01315) 27.6872 ns (± 3.52582) 0.85
exec_tbc_add_passesOn 22.5163 ns (± 1.21815) 27.8079 ns (± 4.07699) 0.81
exec_tbc_fibonacci_passesOff 122.39 us (± 6.1114) 142.754 us (± 6.42009) 0.86
exec_tbc_fibonacci_passesOn 128.044 us (± 4.90862) 147.259 us (± 12.6545) 0.87
exec_tbc_sum_passesOff 31.0826 ms (± 773.96) 37.0381 ms (± 1.12525) 0.84
exec_tbc_sum_passesOn 30.2303 ms (± 840.631) 34.4965 ms (± 1.03922) 0.88
exec_asmjit_add_passesOff 3.14718 ns (± 0.166785) 3.53454 ns (± 0.424915) 0.89
exec_asmjit_add_passesOn 3.18315 ns (± 0.234604) 3.55599 ns (± 0.505255) 0.90
exec_asmjit_fibonacci_passesOff 15.829 us (± 1.61867) 14.4851 us (± 1.84471) 1.09
exec_asmjit_fibonacci_passesOn 16.1929 us (± 1.67778) 14.4741 us (± 1.60525) 1.12
exec_asmjit_sum_passesOff 2.79953 ms (± 134.743) 2.84525 ms (± 129.165) 0.98
exec_asmjit_sum_passesOn 2.80635 ms (± 112.503) 2.80794 ms (± 44.4851) 1.00
exec_bc_add_noRegAlloc 40.3469 ns (± 4.60663) 48.6562 ns (± 9.94503) 0.83
exec_bc_add_regAlloc 39.2808 ns (± 5.17086) 49.7544 ns (± 11.6185) 0.79
exec_bc_fibonacci_noRegAlloc 283.802 us (± 12.2087) 434.605 us (± 14.9837) 0.65
exec_bc_fibonacci_regAlloc 263.732 us (± 10.0968) 435.496 us (± 21.3106) 0.61
exec_bc_sum_noRegAlloc 64.4477 ms (± 1.68618) 95.539 ms (± 346.951) 0.67
exec_bc_sum_regAlloc 64.5748 ms (± 914.184) 95.656 ms (± 1.75854) 0.68
exec_bc_add_call 37.1052 ns (± 3.33333) 50.4321 ns (± 14.0989) 0.74
exec_bc_add_switch 40.2959 ns (± 2.74059) 46.3651 ns (± 14.2695) 0.87
exec_bc_add_threaded 34.9756 ns (± 1.91369) 43.9361 ns (± 12.2427) 0.80
exec_bc_fibonacci_call 263.05 us (± 10.5793) 435.852 us (± 23.3171) 0.60
exec_bc_fibonacci_switch 306.83 us (± 11.2205) 341.778 us (± 24.7643) 0.90
exec_bc_fibonacci_threaded 423.837 us (± 21.2657) 436.671 us (± 10.6617) 0.97
exec_bc_sum_call 64.9881 ms (± 1.50807) 95.3087 ms (± 1.02482) 0.68
exec_bc_sum_switch 66.8696 ms (± 2.07838) 78.9231 ms (± 4.83781) 0.85
exec_bc_sum_threaded 83.9402 ms (± 2.48194) 86.8674 ms (± 3.57788) 0.97
exec_bc_add_threaded_noReuse 35.6736 ns (± 1.97541) 44.4622 ns (± 14.8683) 0.80
exec_bc_add_threaded_reuse 28.6031 ns (± 2.36375) 37.7233 ns (± 10.1076) 0.76
exec_bc_fibonacci_threaded_noReuse 436.404 us (± 13.6429) 437.594 us (± 12.4193) 1.00
exec_bc_fibonacci_threaded_reuse 439.035 us (± 8.2789) 437.654 us (± 12.2593) 1.00
exec_bc_sum_threaded_noReuse 85.1166 ms (± 4.17312) 86.5764 ms (± 857.355) 0.98
exec_bc_sum_threaded_reuse 84.5522 ms (± 1.57212) 86.5631 ms (± 728.279) 0.98
exec_bc_add_threaded_noSuperinstr 35.8478 ns (± 2.32136) 43.339 ns (± 14.3218) 0.83
exec_bc_add_threaded_superinstr 35.7317 ns (± 2.87373) 43.2167 ns (± 13.1311) 0.83
e2e_tiered_bc_to_mlir 4102.42 us (± 158107) 3456.46 us (± 220256) 1.19
e2e_single_mlir 6.67581 ms (± 207.005) 5.68644 ms (± 175.385) 1.17
exec_bc_addOne 33.2333 ns (± 3.28419) 41.2382 ns (± 4.14299) 0.81
exec_mlir_addOne 399.581 ns (± 9.59986) 309.518 ns (± 32.9033) 1.29
exec_cpp_addOne 3.64508 ns (± 0.364484) 4.05183 ns (± 0.681424) 0.90
exec_interpreted_addOne 37.7503 ns (± 2.62267) 38.4172 ns (± 2.24249) 0.98
trace_add 2.60525 us (± 294.835) 2.64262 us (± 436.794) 0.99
completing_trace_add 2.85873 us (± 686.303) 2.43034 us (± 249.32) 1.18
trace_ifThenElse 9.78296 us (± 1.98863) 9.1715 us (± 1.38032) 1.07
completing_trace_ifThenElse 5.07309 us (± 797.227) 4.91708 us (± 616.378) 1.03
trace_deeplyNestedIfElse 28.5352 us (± 6.39807) 27.2739 us (± 3.21557) 1.05
completing_trace_deeplyNestedIfElse 13.7941 us (± 2.3387) 13.387 us (± 1.84215) 1.03
trace_loop 9.43904 us (± 1.34864) 9.12212 us (± 1.62307) 1.03
completing_trace_loop 5.38101 us (± 875.056) 5.06542 us (± 721.07) 1.06
trace_ifInsideLoop 19.0678 us (± 4.15288) 17.5774 us (± 2.78682) 1.08
completing_trace_ifInsideLoop 9.36121 us (± 1.57865) 8.65444 us (± 1.2119) 1.08
trace_loopDirectCall 9.10656 us (± 1.6312) 9.21272 us (± 1.64539) 0.99
completing_trace_loopDirectCall 5.29519 us (± 903.972) 4.87127 us (± 539.877) 1.09
trace_pointerLoop 15.604 us (± 3.41206) 14.9751 us (± 3.21305) 1.04
completing_trace_pointerLoop 11.2586 us (± 1.76136) 10.2085 us (± 1.61247) 1.10
trace_staticLoop 7.24393 us (± 832.976) 7.79006 us (± 979.652) 0.93
completing_trace_staticLoop 8.42349 us (± 1.48648) 8.20436 us (± 1.10015) 1.03
trace_fibonacci 10.9799 us (± 2.34729) 10.6515 us (± 1.80422) 1.03
completing_trace_fibonacci 6.79897 us (± 1.11518) 6.26744 us (± 876.44) 1.08
trace_gcd 9.19359 us (± 2.83242) 8.21963 us (± 1.18849) 1.12
completing_trace_gcd 4.34902 us (± 510.192) 4.26185 us (± 610.605) 1.02
trace_nestedIf10 45.7014 us (± 7.37638) 46.7829 us (± 8.45157) 0.98
completing_trace_nestedIf10 45.3313 us (± 8.59649) 46.4003 us (± 6.51132) 0.98
trace_nestedIf100 1.70397 ms (± 79.228) 1.95501 ms (± 57.3054) 0.87
completing_trace_nestedIf100 1.78508 ms (± 44.3839) 2.00154 ms (± 47.6321) 0.89
trace_chainedIf10 104.908 us (± 12.5567) 105.365 us (± 8.65087) 1.00
completing_trace_chainedIf10 52.002 us (± 8.62038) 51.675 us (± 7.74622) 1.01
trace_chainedIf100 4.53843 ms (± 161.798) 5.03528 ms (± 56.0521) 0.90
completing_trace_chainedIf100 2.09806 ms (± 52.4673) 2.37795 ms (± 50.9887) 0.88
ssa_add 147.155 ns (± 10.7306) 183.83 ns (± 16.6683) 0.80
ssa_ifThenElse 432.172 ns (± 35.2631) 467.842 ns (± 68.7583) 0.92
ssa_deeplyNestedIfElse 1.17918 us (± 92.3522) 1.13372 us (± 117.974) 1.04
ssa_loop 431.509 ns (± 30.531) 468.901 ns (± 28.3934) 0.92
ssa_ifInsideLoop 953.952 ns (± 119.319) 870.088 ns (± 59.6988) 1.10
ssa_loopDirectCall 419.372 ns (± 21.6548) 470.812 ns (± 32.719) 0.89
ssa_pointerLoop 544.666 ns (± 34.2328) 578.805 ns (± 32.2757) 0.94
ssa_staticLoop 359.136 ns (± 19.1616) 412.877 ns (± 33.2236) 0.87
ssa_fibonacci 468.923 ns (± 35.2206) 492.827 ns (± 37.4911) 0.95
ssa_gcd 434.742 ns (± 28.3797) 443.925 ns (± 35.7483) 0.98
tiered_twotier_addOne 4.07384 ms (± 181.472) 3.38869 ms (± 147.902) 1.20
tiered_singletier_addOne 3.94557 ms (± 140.312) 3.33063 ms (± 172.924) 1.18
single_compile_mlir_addOne 3.9989 ms (± 122.413) 3.3162 ms (± 140.71) 1.21
single_compile_cpp_addOne 32.8324 ms (± 37.0476) 26.257 ms (± 594.395) 1.25
single_compile_bc_addOne 56.5291 us (± 19.2404) 75.7619 us (± 15.6831) 0.75
tiered_twotier_sumLoop 5.67205 ms (± 247.714) 5.54054 ms (± 173.866) 1.02
tiered_singletier_sumLoop 5.63089 ms (± 178.048) 5.38694 ms (± 136.019) 1.05
single_compile_mlir_sumLoop 5.73247 ms (± 171.654) 5.39259 ms (± 134.34) 1.06
single_compile_cpp_sumLoop 29.314 ms (± 29.3941) 26.8957 ms (± 858.901) 1.09
single_compile_bc_sumLoop 107.449 us (± 21.4911) 135.832 us (± 20.1429) 0.79

This comment was automatically generated by workflow using github-action-benchmark.

claude added 3 commits July 10, 2026 11:48
…ouble

Fixes the macos-15 clang CI build: std::from_chars for floating-point
types is not implemented in libc++, so prob(...) values are now parsed
via strtod on a bounded copy, and parseNumber<T> is statically
constrained to integral types.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RRYVYANDgKxKATtrCQk9px
IRGraph::toString and the IR serializer now share a single writer and a
single grammar with two renderings:

- Portable (serializeIR): renumbered function-wide-unique value ids,
  full external symbols, strict errors on process-specific state.
- Display (toString): stored identifiers so dumps line up with
  in-memory state (verifier messages, backend register frames, MLIR
  debug info), deterministic func_* placeholders for external
  functions, '*' placeholders for pointer constants, and the opt-in
  '; ...' source-location trailers.

The old fmt-formatter printer in IRGraph.cpp is deleted. Compared to
it, display dumps gain information that was previously lost: select /
indirect-call / address-of operations print properly (previously a
bare '$N :type'), '!=' comparisons are no longer printed with an
empty operator, branch probabilities appear as 'prob(...)', and
function headers carry alloca specs and attributes.

GraphViz node labels use the new printOperation helper. The parser
skips '; ...' comment trailers and rejects display dumps with hidden
call symbols ('func_*') with an error that points at serializeIR.

All golden IR files (test/data ir/, after_constant_folding/,
after_empty_block_elim/, including the ENABLE_SHORT_CIRCUIT_BOOL
overrides, and the GPU plugin's ir/ fixtures) are regenerated in the
new format. Fixes an unused-variable error in the GPU plugin when both
GPU backends are disabled.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RRYVYANDgKxKATtrCQk9px
The IR dump and the serialized IR are now byte-identical: every dump is
a loadable module. The writer has a single rendering — function-wide
unique value ids, external functions printed as '@"symbol" "name"' —
and the only difference between toString and serializeIR is strictness:
serializeIR validates the graph up front (rejecting process-specific
state such as non-null pointer constants, which toString renders as the
'*' placeholder), so a successfully serialized file is always loadable.

Consequences carried through:

- MLIR debug info: the printed ids no longer equal the stored operation
  identifiers, so IRSourceMap gains a per-function Operation* ->
  printed-id table (computePrintedValueIds, the writer's numbering) and
  MLIRLoweringProvider translates through it (new dollarId helper) for
  NameLocs, shadow allocas, and dump-line lookups. GDB variable names
  keep matching the dump text.
- Golden fixtures: external-function references carry build-dependent
  symbols (raw addresses for non-exported functions), so the tracing
  tests normalize them to '@"<symbol>" "<name>"' placeholders before
  comparison (testing::normalizeExternalFunctionReferences, shared with
  the GPU plugin's tracing test). All IR fixtures regenerated in the
  unified format (core, short-circuit-bool overrides, GPU plugin).
- The parser rejects legacy 'func_*' dumps with an error pointing at
  the current writers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RRYVYANDgKxKATtrCQk9px
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants