Add IR serialization: compile from a Nautilus IR file, skipping tracing - #393
Draft
PhilippGrulich wants to merge 4 commits into
Draft
Add IR serialization: compile from a Nautilus IR file, skipping tracing#393PhilippGrulich wants to merge 4 commits into
PhilippGrulich wants to merge 4 commits into
Conversation
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
Contributor
There was a problem hiding this comment.
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.
…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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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) andserializeIRemit 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.cppis deleted;toStringandserializeIRshare a single writer (IRSerializationUtil) with a single rendering:$1in text would be ambiguous (this was caught as an actual asmjit miscompile during testing). The writer numbers values block by block, arguments before operations;computePrintedValueIdsexposes the same numbering for consumers that correlate operations with the text.call @"_Z3addii" "add(int, int)"(...).toStringnever throws — a non-null pointer constant (a raw, process-specific address) renders as the*placeholder.serializeIRvalidates the graph first and fails with a descriptive error instead of writing a file the parser would reject later.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:
IRSourceMapgains a per-functionOperation* → printed-idtable andMLIRLoweringProviderroutes every NameLoc, shadow-alloca key, and dump-line lookup through a newdollarIdhelper. 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_BOOLoverrides, and GPU plugin — which is the bulk of the diff.Parser (
IRParser)IRGraph, wires the CFG through the same helpers as the trace-to-IR conversion, rebuilds predecessor lists, and runsIRVerifierbefore returning — malformed input fails at load time with line/column diagnostics.IRSymbolResolvercallback, then viadlsymon the recorded mangled symbol.; ...source-location comment trailers; legacyfunc_*dumps are rejected with an error pointing at the current writers.Compiler & public API
JITCompiler/TieredJITCompilergaincompileToSerializedIR(trace → IR text) andcompileIRModule(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 viaCompiledModule::getFunction<Signature>(name).Tests
ir-pass-tests/IRSerializationTest.cpp: parse→serialize fixed-point round trips covering every operation form,toString == serializeIRidentity, 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.Notes
ENABLE_COMPILER+ENABLE_TRACING; other configurations throw a descriptive error.docs/ir-serialization.md.🤖 Generated with Claude Code
https://claude.ai/code/session_01RRYVYANDgKxKATtrCQk9px