Skip to content

Commit 6313134

Browse files
authored
Merge pull request #16499 from argotorg/mark-on-enqueue-for-bring-up-target-slot-stack-traversal
Stack shuffler: use mark-on-enqueue for bringUpTargetSlot
2 parents 61baed5 + d153bfe commit 6313134

File tree

3 files changed

+88
-3
lines changed

3 files changed

+88
-3
lines changed

Changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Compiler Features:
77
* General: Restrict the existing experimental features (`generic-solidity`, `lsp`, `ethdebug`, `eof`, `evm`, `ast-import`, `evmasm-import`, `ir-ast`, `ssa-cfg`) to experimental mode.
88
* Metadata: Store the state of the experimental mode in JSON and CBOR metadata. In CBOR this broadens the meaning of the existing `experimental` field, which used to indicate only the presence of certain experimental pragmas in the source.
99
* Standard JSON Interface: Introduce `settings.experimental` setting required for enabling the experimental mode.
10+
* Yul EVM Code Transform: Improve stack shuffler performance by fixing a BFS deduplication issue.
1011

1112
Bugfixes:
1213

libyul/backends/evm/StackHelpers.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,13 +186,13 @@ class Shuffler
186186
static bool bringUpTargetSlot(ShuffleOperations& _ops, size_t _targetOffset)
187187
{
188188
std::list<size_t> toVisit{_targetOffset};
189-
std::set<size_t> visited;
189+
// mark on enqueue
190+
std::set<size_t> visited{_targetOffset};
190191

191192
while (!toVisit.empty())
192193
{
193194
auto offset = *toVisit.begin();
194195
toVisit.erase(toVisit.begin());
195-
visited.emplace(offset);
196196
if (_ops.targetMultiplicity(offset) > 0)
197197
{
198198
_ops.pushOrDupTarget(offset);
@@ -204,11 +204,12 @@ class Shuffler
204204
!_ops.isCompatible(nextOffset, nextOffset) &&
205205
_ops.isCompatible(nextOffset, offset)
206206
)
207-
if (!visited.count(nextOffset))
207+
if (visited.insert(nextOffset).second) // insert returns false if already present
208208
toVisit.emplace_back(nextOffset);
209209
}
210210
return false;
211211
}
212+
212213
/// Performs a single stack operation, transforming the source layout closer to the target layout.
213214
template<typename... Args>
214215
static bool shuffleStep(Args&&... args)
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// This is a regression test in context of https://github.com/argotorg/solidity/pull/16499:
2+
// A BFS deduplication performance bug in `bringUpTargetSlot` where the same offset could be enqueued multiple times
3+
// before being visited, by marking offsets as seen on enqueue rather than on dequeue.
4+
{
5+
mstore(memoryguard(0x10000), 1)
6+
sstore(mload(calldataload(0)), 1)
7+
{
8+
function foo_n_0(x_4, x_5)
9+
{
10+
if x_5 {
11+
x_4 := 0x2000000000001
12+
}
13+
x_4 := call(
14+
call(
15+
blockhash(0x200000000001),
16+
0x20000000001,
17+
0x2000000001,
18+
mod("h", 32768),
19+
mod(0x200000001, 32768),
20+
mod(0x20000001, 32768),
21+
mod(0x2000001, 32768)
22+
),
23+
0x200001,
24+
0x20001,
25+
mod(0x2001, 32768),
26+
mod(calldatasize(), 32768),
27+
mod(calldatasize(), 32768),
28+
mod(
29+
call(
30+
call(
31+
x_4,
32+
0x201,
33+
number(),
34+
mod(0x21, 32768),
35+
mod(0x3, 32768),
36+
mod(0x3f, 32768),
37+
mod(address(), 32768)
38+
),
39+
0x3ff,
40+
0x3fff,
41+
mod(0x3ffff, 32768),
42+
mod(9042383626829830, 32768),
43+
mod(0x3fffff, 32768),
44+
mod(0x3ffffff, 32768)
45+
),
46+
32768
47+
)
48+
)
49+
}
50+
foo_n_0(0x200000000000000001, 0x20000000000000001)
51+
foo_n_0(sload(224),calldataload(288))
52+
foo_n_0(0x3ffffffffffff, 0x3fffffffffffff)
53+
foo_n_0(0x3fffffffffffffff, 0x3ffffffffffffffff)
54+
foo_n_0(0x3ffffffffffffffffff, 0x3fffffffffffffffffff)
55+
}
56+
}
57+
// ====
58+
// EVMVersion: >homestead
59+
// ----
60+
// step: fullSuite
61+
//
62+
// {
63+
// {
64+
// mstore(memoryguard(0x010000), 1)
65+
// sstore(mload(calldataload(0)), 1)
66+
// let x := 0x200000000000000001
67+
// x := 0x2000000000001
68+
// let _1 := and(call(call(x, 0x201, number(), 0x21, 0x3, 0x3f, and(address(), 32767)), 0x3ff, 0x3fff, 32767, 6, 32767, 32767), 32767)
69+
// pop(call(call(blockhash(0x200000000001), 0x20000000001, 0x2000000001, and("h", 32767), 1, 1, 1), 0x200001, 0x20001, 0x2001, and(calldatasize(), 32767), and(calldatasize(), 32767), _1))
70+
// let x_1 := sload(224)
71+
// if calldataload(288) { x_1 := x }
72+
// pop(call(call(blockhash(0x200000000001), 0x20000000001, 0x2000000001, and("h", 32767), 1, 1, 1), 0x200001, 0x20001, 0x2001, and(calldatasize(), 32767), and(calldatasize(), 32767), and(call(call(x_1, 0x201, number(), 0x21, 0x3, 0x3f, and(address(), 32767)), 0x3ff, 0x3fff, 32767, 6, 32767, 32767), 32767)))
73+
// let x_2 := 0x3ffffffffffff
74+
// x_2 := x
75+
// pop(call(call(blockhash(0x200000000001), 0x20000000001, 0x2000000001, and("h", 32767), 1, 1, 1), 0x200001, 0x20001, 0x2001, and(calldatasize(), 32767), and(calldatasize(), 32767), and(call(call(x, 0x201, number(), 0x21, 0x3, 0x3f, and(address(), 32767)), 0x3ff, 0x3fff, 32767, 6, 32767, 32767), 32767)))
76+
// let x_3 := 0x3fffffffffffffff
77+
// x_3 := x
78+
// pop(call(call(blockhash(0x200000000001), 0x20000000001, 0x2000000001, and("h", 32767), 1, 1, 1), 0x200001, 0x20001, 0x2001, and(calldatasize(), 32767), and(calldatasize(), 32767), and(call(call(x, 0x201, number(), 0x21, 0x3, 0x3f, and(address(), 32767)), 0x3ff, 0x3fff, 32767, 6, 32767, 32767), 32767)))
79+
// let x_4 := 0x3ffffffffffffffffff
80+
// x_4 := x
81+
// pop(call(call(blockhash(0x200000000001), 0x20000000001, 0x2000000001, and("h", 32767), 1, 1, 1), 0x200001, 0x20001, 0x2001, and(calldatasize(), 32767), and(calldatasize(), 32767), and(call(call(x, 0x201, number(), 0x21, 0x3, 0x3f, and(address(), 32767)), 0x3ff, 0x3fff, 32767, 6, 32767, 32767), 32767)))
82+
// }
83+
// }

0 commit comments

Comments
 (0)