Add move semantics to val<T> for class types - #277
Open
PhilippGrulich wants to merge 3 commits into
Open
Conversation
Previously val<ValueType> for class types had only a copy constructor, which forced an alloca + memcpy/copy_construct on every rvalue. NRVO failures (e.g. multi-return functions) and explicit std::move(x) silently fell back to deep copies. Add a real move constructor and move assignment that transfer the underlying alloca/heap pointer and a moved_ flag that suppresses the source's traced destruct() call and heap free, so the resource is released exactly once. Constrain the variadic-args constructor to exclude same-type so the dedicated copy/move ctors always win in overload resolution. Tests cover move construction (trivial and non-trivial), move assignment, self-move, ctor/dtor balance via a CountedDtor struct, and return-by-value with both NRVO-friendly and conditional-return paths. Static asserts verify nothrow move semantics.
Contributor
There was a problem hiding this comment.
Tracing Benchmark
Details
| Benchmark suite | Current: c348f19 | Previous: 10a6635 | Ratio |
|---|---|---|---|
exec_bc_addOne |
36.6807 ns (± 1.64919) |
37.3468 ns (± 8.00576) |
0.98 |
exec_mlir_addOne |
303.155 ns (± 9.34104) |
258.029 ns (± 4.30464) |
1.17 |
exec_cpp_addOne |
3.90529 ns (± 0.846163) |
3.6505 ns (± 0.452295) |
1.07 |
exec_interpreted_addOne |
38.3997 ns (± 1.64403) |
38.3209 ns (± 4.07534) |
1.00 |
comp_mlir_add |
6.65752 ms (± 209.106) |
5.52896 ms (± 150.264) |
1.20 |
comp_mlir_ifThenElse |
7.52157 ms (± 223.739) |
6.15129 ms (± 143.859) |
1.22 |
comp_mlir_deeplyNestedIfElse |
6.26438 ms (± 257.847) |
5.04123 ms (± 67.5269) |
1.24 |
comp_mlir_loop |
9.18899 ms (± 257.1) |
7.23834 ms (± 348.192) |
1.27 |
comp_mlir_ifInsideLoop |
31.397 ms (± 450.092) |
28.78 ms (± 822.48) |
1.09 |
comp_mlir_loopDirectCall |
14.2982 ms (± 239.606) |
12.4205 ms (± 456.737) |
1.15 |
comp_mlir_pointerLoop |
30.254 ms (± 124.516) |
28.18 ms (± 795.83) |
1.07 |
comp_mlir_staticLoop |
6.16367 ms (± 215.743) |
4.98862 ms (± 45.2884) |
1.24 |
comp_mlir_fibonacci |
12.6686 ms (± 176.531) |
10.5174 ms (± 254.747) |
1.20 |
comp_mlir_gcd |
11.2626 ms (± 182.85) |
9.43739 ms (± 66.7206) |
1.19 |
comp_mlir_nestedIf10 |
12.4785 ms (± 159.94) |
10.9118 ms (± 562.598) |
1.14 |
comp_mlir_nestedIf100 |
27.4398 ms (± 2.2828) |
25.5045 ms (± 614.911) |
1.08 |
comp_mlir_chainedIf10 |
11.9877 ms (± 157.301) |
9.77351 ms (± 299.372) |
1.23 |
comp_mlir_chainedIf100 |
22.9228 ms (± 244.475) |
20.2026 ms (± 289.302) |
1.13 |
comp_cpp_add |
29.4674 ms (± 320.551) |
25.3523 ms (± 536.121) |
1.16 |
comp_cpp_ifThenElse |
29.9561 ms (± 215.914) |
25.6938 ms (± 472.16) |
1.17 |
comp_cpp_deeplyNestedIfElse |
31.2041 ms (± 206.136) |
26.2772 ms (± 280.811) |
1.19 |
comp_cpp_loop |
30.1161 ms (± 177.083) |
25.3249 ms (± 302.8) |
1.19 |
comp_cpp_ifInsideLoop |
32.4895 ms (± 4.77889) |
26.0316 ms (± 253.783) |
1.25 |
comp_cpp_loopDirectCall |
30.6467 ms (± 189.113) |
25.5171 ms (± 227.43) |
1.20 |
comp_cpp_pointerLoop |
30.8244 ms (± 195.128) |
25.7051 ms (± 267.651) |
1.20 |
comp_cpp_staticLoop |
30.079 ms (± 301.997) |
25.1416 ms (± 369.29) |
1.20 |
comp_cpp_fibonacci |
30.8963 ms (± 1.00737) |
25.9456 ms (± 429.397) |
1.19 |
comp_cpp_gcd |
30.1578 ms (± 337.799) |
25.3955 ms (± 444.048) |
1.19 |
comp_cpp_nestedIf10 |
33.2888 ms (± 258.969) |
28.4827 ms (± 851.989) |
1.17 |
comp_cpp_nestedIf100 |
67.4103 ms (± 2.8987) |
62.4417 ms (± 958.238) |
1.08 |
comp_cpp_chainedIf10 |
35.8127 ms (± 650.659) |
31.448 ms (± 927.552) |
1.14 |
comp_cpp_chainedIf100 |
97.735 ms (± 599.963) |
92.2053 ms (± 608.636) |
1.06 |
comp_bc_add |
14.5523 us (± 2.46773) |
14.582 us (± 1.75527) |
1.00 |
comp_bc_ifThenElse |
16.9757 us (± 3.87851) |
18.6811 us (± 3.58857) |
0.91 |
comp_bc_deeplyNestedIfElse |
20.1906 us (± 4.4203) |
22.7163 us (± 4.31134) |
0.89 |
comp_bc_loop |
17.0116 us (± 3.82698) |
18.9731 us (± 4.056) |
0.90 |
comp_bc_ifInsideLoop |
19.1749 us (± 4.07394) |
21.2198 us (± 3.74251) |
0.90 |
comp_bc_loopDirectCall |
16.9648 us (± 3.71354) |
18.9753 us (± 3.3135) |
0.89 |
comp_bc_pointerLoop |
17.962 us (± 3.75302) |
20.1783 us (± 3.72759) |
0.89 |
comp_bc_staticLoop |
16.6423 us (± 3.46135) |
17.3933 us (± 3.71277) |
0.96 |
comp_bc_fibonacci |
17.1275 us (± 4.45912) |
18.4986 us (± 2.35865) |
0.93 |
comp_bc_gcd |
16.2905 us (± 2.58377) |
17.9795 us (± 2.53701) |
0.91 |
comp_bc_nestedIf10 |
31.312 us (± 4.64734) |
34.8719 us (± 4.27966) |
0.90 |
comp_bc_nestedIf100 |
197.904 us (± 10.3863) |
191.397 us (± 12.8541) |
1.03 |
comp_bc_chainedIf10 |
44.5023 us (± 9.42467) |
49.1121 us (± 5.49462) |
0.91 |
comp_bc_chainedIf100 |
326.771 us (± 14.1643) |
297.447 us (± 12.8065) |
1.10 |
comp_asmjit_add |
17.922 us (± 5.02276) |
20.7886 us (± 3.14001) |
0.86 |
comp_asmjit_ifThenElse |
27.4451 us (± 5.95218) |
32.8265 us (± 5.22408) |
0.84 |
comp_asmjit_deeplyNestedIfElse |
49.1078 us (± 10.3235) |
56.0766 us (± 9.15709) |
0.88 |
comp_asmjit_loop |
29.4295 us (± 5.70893) |
35.0292 us (± 5.17887) |
0.84 |
comp_asmjit_ifInsideLoop |
49.246 us (± 11.1204) |
57.2267 us (± 11.6151) |
0.86 |
comp_asmjit_loopDirectCall |
32.5169 us (± 5.7859) |
44.056 us (± 5.42689) |
0.74 |
comp_asmjit_pointerLoop |
35.6107 us (± 6.00339) |
48.1419 us (± 8.30256) |
0.74 |
comp_asmjit_staticLoop |
24.3038 us (± 4.96982) |
28.3138 us (± 5.3941) |
0.86 |
comp_asmjit_fibonacci |
31.6513 us (± 6.02046) |
43.0434 us (± 8.60098) |
0.74 |
comp_asmjit_gcd |
29.3456 us (± 5.84492) |
35.0731 us (± 6.56689) |
0.84 |
comp_asmjit_nestedIf10 |
98.2901 us (± 13.628) |
104.565 us (± 14.2612) |
0.94 |
comp_asmjit_nestedIf100 |
1075.95 us (± 18228.4) |
1068.05 us (± 146903) |
1.01 |
comp_asmjit_chainedIf10 |
150.59 us (± 16.3488) |
154.231 us (± 15.4403) |
0.98 |
comp_asmjit_chainedIf100 |
2.28894 ms (± 25.8592) |
2.13529 ms (± 28.6135) |
1.07 |
trace_add |
2.27962 us (± 243.82) |
2.49638 us (± 295.356) |
0.91 |
completing_trace_add |
2.27011 us (± 201.665) |
2.4736 us (± 334.61) |
0.92 |
trace_ifThenElse |
8.38265 us (± 1.48178) |
9.30328 us (± 1.67908) |
0.90 |
completing_trace_ifThenElse |
4.5841 us (± 560.73) |
4.70958 us (± 574.319) |
0.97 |
trace_deeplyNestedIfElse |
25.431 us (± 6.11794) |
26.0099 us (± 3.07346) |
0.98 |
completing_trace_deeplyNestedIfElse |
12.9767 us (± 2.27464) |
13.1091 us (± 1.70257) |
0.99 |
trace_loop |
8.34233 us (± 1.41618) |
8.71348 us (± 1.22788) |
0.96 |
completing_trace_loop |
4.72452 us (± 568.718) |
4.77327 us (± 516.624) |
0.99 |
trace_ifInsideLoop |
16.3045 us (± 3.41567) |
17.3334 us (± 2.90873) |
0.94 |
completing_trace_ifInsideLoop |
8.50969 us (± 1.33914) |
8.82408 us (± 1.28846) |
0.96 |
trace_loopDirectCall |
8.51579 us (± 1.54073) |
8.96005 us (± 1.49533) |
0.95 |
completing_trace_loopDirectCall |
4.72729 us (± 665.15) |
5.1524 us (± 762.558) |
0.92 |
trace_pointerLoop |
13.8343 us (± 2.79313) |
14.2471 us (± 2.16149) |
0.97 |
completing_trace_pointerLoop |
10.264 us (± 1.61819) |
10.4746 us (± 1.84546) |
0.98 |
trace_staticLoop |
7.51429 us (± 934.839) |
7.6142 us (± 1.0114) |
0.99 |
completing_trace_staticLoop |
7.43998 us (± 774.405) |
7.46691 us (± 872.687) |
1.00 |
trace_fibonacci |
9.91118 us (± 1.93685) |
10.1531 us (± 1.57566) |
0.98 |
completing_trace_fibonacci |
6.05382 us (± 949.561) |
6.17947 us (± 858.737) |
0.98 |
trace_gcd |
7.57195 us (± 1.21147) |
8.05058 us (± 1.02295) |
0.94 |
completing_trace_gcd |
3.89298 us (± 495.86) |
4.06246 us (± 448.501) |
0.96 |
trace_nestedIf10 |
40.4034 us (± 8.0849) |
37.7878 us (± 6.23274) |
1.07 |
completing_trace_nestedIf10 |
40.0172 us (± 7.861) |
38.9354 us (± 7.34432) |
1.03 |
trace_nestedIf100 |
1.50363 ms (± 32.1424) |
1.34644 ms (± 53.7282) |
1.12 |
completing_trace_nestedIf100 |
1.51145 ms (± 32.682) |
1.35177 ms (± 56.6128) |
1.12 |
trace_chainedIf10 |
97.9942 us (± 12.6066) |
99.7738 us (± 12.6143) |
0.98 |
completing_trace_chainedIf10 |
51.448 us (± 9.34201) |
49.9159 us (± 9.0803) |
1.03 |
trace_chainedIf100 |
4.48531 ms (± 92.4317) |
4.48434 ms (± 79.2886) |
1.00 |
completing_trace_chainedIf100 |
2.33602 ms (± 37.0324) |
2.26925 ms (± 73.0211) |
1.03 |
e2e_tiered_bc_to_mlir |
45.7762 us (± 17.9026) |
56.5271 us (± 14.5799) |
0.81 |
e2e_single_mlir |
7.04356 ms (± 158.116) |
5.53847 ms (± 193.361) |
1.27 |
tiered_compile_addOne |
46.0516 us (± 16.6342) |
55.7034 us (± 13.3607) |
0.83 |
single_compile_mlir_addOne |
3.79795 ms (± 147.733) |
3.28567 ms (± 103.998) |
1.16 |
single_compile_cpp_addOne |
29.5067 ms (± 161.167) |
25.0471 ms (± 510.067) |
1.18 |
single_compile_bc_addOne |
46.6153 us (± 16.9782) |
56.0618 us (± 12.9099) |
0.83 |
tiered_compile_sumLoop |
64.773 us (± 20.5285) |
77.4694 us (± 16.0654) |
0.84 |
single_compile_mlir_sumLoop |
6.13673 ms (± 177.091) |
5.30892 ms (± 116.288) |
1.16 |
single_compile_cpp_sumLoop |
30.3831 ms (± 181.712) |
25.7075 ms (± 518.009) |
1.18 |
single_compile_bc_sumLoop |
64.3333 us (± 18.0549) |
77.1814 us (± 14.9321) |
0.83 |
ir_add |
713.108 ns (± 40.4354) |
772.195 ns (± 71.3318) |
0.92 |
ir_ifThenElse |
1.49787 us (± 83.6574) |
1.61196 us (± 182.266) |
0.93 |
ir_deeplyNestedIfElse |
3.28766 us (± 226.822) |
3.38468 us (± 292.836) |
0.97 |
ir_loop |
1.55598 us (± 75.371) |
1.65684 us (± 243.329) |
0.94 |
ir_ifInsideLoop |
2.75981 us (± 164.086) |
2.89326 us (± 320.554) |
0.95 |
ir_loopDirectCall |
1.73049 us (± 119.649) |
1.81889 us (± 168.556) |
0.95 |
ir_pointerLoop |
1.92079 us (± 157.685) |
2.05088 us (± 272.65) |
0.94 |
ir_staticLoop |
1.41845 us (± 83.3022) |
1.51351 us (± 200.357) |
0.94 |
ir_fibonacci |
1.6754 us (± 91.438) |
1.77363 us (± 155.603) |
0.94 |
ir_gcd |
1.41406 us (± 86.433) |
1.56065 us (± 170.558) |
0.91 |
ir_nestedIf10 |
7.75785 us (± 497.784) |
8.02456 us (± 1.15304) |
0.97 |
ir_nestedIf100 |
90.9018 us (± 4.31277) |
87.6189 us (± 6.58879) |
1.04 |
ir_chainedIf10 |
11.7154 us (± 741.042) |
11.6437 us (± 1.02792) |
1.01 |
ir_chainedIf100 |
167.591 us (± 5.85271) |
164.697 us (± 8.40094) |
1.02 |
ssa_add |
183.944 ns (± 10.6176) |
204.202 ns (± 28.1667) |
0.90 |
ssa_ifThenElse |
434.501 ns (± 22.6209) |
484.779 ns (± 51.85) |
0.90 |
ssa_deeplyNestedIfElse |
1.11647 us (± 71.2799) |
1.20907 us (± 105.009) |
0.92 |
ssa_loop |
457.492 ns (± 24.4312) |
533.363 ns (± 80.3068) |
0.86 |
ssa_ifInsideLoop |
864.099 ns (± 65.8921) |
959.38 ns (± 91.9966) |
0.90 |
ssa_loopDirectCall |
463.803 ns (± 26.2942) |
538.332 ns (± 83.9372) |
0.86 |
ssa_pointerLoop |
552.117 ns (± 26.5441) |
612.761 ns (± 60.7414) |
0.90 |
ssa_staticLoop |
431.105 ns (± 21.6339) |
475.509 ns (± 52.7257) |
0.91 |
ssa_fibonacci |
479.247 ns (± 29.221) |
530.832 ns (± 47.7214) |
0.90 |
ssa_gcd |
420.656 ns (± 30.483) |
468.824 ns (± 43.3429) |
0.90 |
exec_mlir_add |
12.4989 ns (± 1.13498) |
10.7701 ns (± 1.25718) |
1.16 |
exec_mlir_fibonacci |
17.5517 us (± 1.80779) |
13.3631 us (± 1.67729) |
1.31 |
exec_mlir_sum |
597.559 us (± 63.953) |
513.173 us (± 15.8951) |
1.16 |
exec_cpp_add |
4.59301 ns (± 0.616091) |
4.84074 ns (± 0.975486) |
0.95 |
exec_cpp_fibonacci |
109.307 us (± 8.79131) |
97.148 us (± 14.5938) |
1.13 |
exec_cpp_sum |
23.7475 ms (± 1.10339) |
35.9689 ms (± 194.582) |
0.66 |
exec_bc_add |
43.303 ns (± 2.69646) |
43.5894 ns (± 5.2732) |
0.99 |
exec_bc_fibonacci |
623.521 us (± 11.7385) |
753.817 us (± 16.9593) |
0.83 |
exec_bc_sum |
142.236 ms (± 4.78023) |
163.437 ms (± 1.52509) |
0.87 |
exec_asmjit_add |
3.53821 ns (± 0.239277) |
3.59554 ns (± 0.522867) |
0.98 |
exec_asmjit_fibonacci |
22.4047 us (± 1.92995) |
20.7515 us (± 1.80854) |
1.08 |
exec_asmjit_sum |
5.29664 ms (± 33.1865) |
4.84254 ms (± 26.3078) |
1.09 |
exec_bc_add_noRegAlloc |
43.3671 ns (± 2.63002) |
44.3788 ns (± 6.39372) |
0.98 |
exec_bc_add_regAlloc |
43.3469 ns (± 4.72047) |
43.9551 ns (± 5.99039) |
0.99 |
exec_bc_fibonacci_noRegAlloc |
629.585 us (± 11.007) |
751.654 us (± 14.3443) |
0.84 |
exec_bc_fibonacci_regAlloc |
620.122 us (± 6.96616) |
751.761 us (± 11.6866) |
0.82 |
exec_bc_sum_noRegAlloc |
148.526 ms (± 24.1712) |
163.167 ms (± 446.848) |
0.91 |
exec_bc_sum_regAlloc |
141.558 ms (± 2.52588) |
163.266 ms (± 1.17473) |
0.87 |
This comment was automatically generated by workflow using github-action-benchmark.
The move ctor previously initialized value_ptr via val<T*>'s copy constructor, which in tracing mode emits an extra traceCopy/ASSIGN SSA op for what is logically just a pointer alias. Construct value_ptr directly from the source's (raw pointer, TypedValueRef) so no IR op is emitted for the move itself; only the source's refcount entry remains in place via TypedValueRefHolder, which is purely host-side bookkeeping. The new traces moveConstructTrivial and returnByValue lock in the optimal IR (one ALLOCA, no traceCopy) so any future regression that re-introduces the copy in the move path will fail the snapshot test.
…r val Verifies the alloca count for a fully-unrolled static loop where each iteration constructs a fresh val<Test> and copy-assigns it into a val<Test> declared outside the loop. With three unrolled iterations the IR has four allocas (one for outer plus one per iteration for inner) and three memcpy calls for the copy-assignments; outer keeps its single slot because copy-assignment writes through the existing pointer rather than reallocating.
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.
Previously val for class types had only a copy constructor,
which forced an alloca + memcpy/copy_construct on every rvalue. NRVO
failures (e.g. multi-return functions) and explicit std::move(x) silently
fell back to deep copies.
Add a real move constructor and move assignment that transfer the
underlying alloca/heap pointer and a moved_ flag that suppresses the
source's traced destruct() call and heap free, so the resource is
released exactly once. Constrain the variadic-args constructor to
exclude same-type so the dedicated copy/move ctors always win in
overload resolution.
Tests cover move construction (trivial and non-trivial), move
assignment, self-move, ctor/dtor balance via a CountedDtor struct,
and return-by-value with both NRVO-friendly and conditional-return
paths. Static asserts verify nothrow move semantics.