Skip to content

Commit aef512f

Browse files
authored
Merge pull request #16140 from ethereum/ssacfg_consteval_if_switch
SSACFG: Explicitly constant condition if and switch
2 parents 6260712 + 140fdbd commit aef512f

File tree

5 files changed

+184
-60
lines changed

5 files changed

+184
-60
lines changed

libyul/backends/evm/SSAControlFlowGraphBuilder.cpp

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -287,20 +287,33 @@ void SSAControlFlowGraphBuilder::operator()(FunctionDefinition const& _functionD
287287

288288
void SSAControlFlowGraphBuilder::operator()(If const& _if)
289289
{
290-
auto condition = std::visit(*this, *_if.condition);
291-
auto ifBranch = m_graph.makeBlock(debugDataOf(_if.body));
292-
auto afterIf = m_graph.makeBlock(debugDataOf(currentBlock()));
293-
conditionalJump(
294-
debugDataOf(_if),
295-
condition,
296-
ifBranch,
297-
afterIf
298-
);
299-
sealBlock(ifBranch);
300-
m_currentBlock = ifBranch;
301-
(*this)(_if.body);
302-
jump(debugDataOf(_if.body), afterIf);
303-
sealBlock(afterIf);
290+
std::optional<bool> constantCondition;
291+
if (auto const* literalCondition = std::get_if<Literal>(_if.condition.get()))
292+
constantCondition = literalCondition->value.value() != 0;
293+
// deal with literal (constant) conditions explicitly
294+
if (constantCondition)
295+
{
296+
if (*constantCondition)
297+
// Always true - skip conditional, just execute if branch
298+
(*this)(_if.body);
299+
}
300+
else
301+
{
302+
auto condition = std::visit(*this, *_if.condition);
303+
auto ifBranch = m_graph.makeBlock(debugDataOf(_if.body));
304+
auto afterIf = m_graph.makeBlock(debugDataOf(currentBlock()));
305+
conditionalJump(
306+
debugDataOf(_if),
307+
condition,
308+
ifBranch,
309+
afterIf
310+
);
311+
sealBlock(ifBranch);
312+
m_currentBlock = ifBranch;
313+
(*this)(_if.body);
314+
jump(debugDataOf(_if.body), afterIf);
315+
sealBlock(afterIf);
316+
}
304317
}
305318

306319
void SSAControlFlowGraphBuilder::operator()(Switch const& _switch)
@@ -342,6 +355,28 @@ void SSAControlFlowGraphBuilder::operator()(Switch const& _switch)
342355
}
343356
else
344357
{
358+
if (auto const* constantExpression = std::get_if<Literal>(_switch.expression.get()))
359+
{
360+
Case const* matchedCase = nullptr;
361+
// select case that matches (or default if available)
362+
for (auto const& switchCase: _switch.cases)
363+
{
364+
if (!switchCase.value)
365+
matchedCase = &switchCase;
366+
if (switchCase.value && switchCase.value->value.value() == constantExpression->value.value())
367+
{
368+
matchedCase = &switchCase;
369+
break;
370+
}
371+
}
372+
if (matchedCase)
373+
{
374+
// inject directly into the current block
375+
(*this)(matchedCase->body);
376+
}
377+
return;
378+
}
379+
345380
std::optional<BuiltinHandle> equalityBuiltinHandle = m_dialect.equalityFunctionHandle();
346381
yulAssert(equalityBuiltinHandle);
347382

test/libyul/yulSSAControlFlowGraph/if.yul

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
let x := calldataload(3)
3-
if 0 {
3+
if mload(42) {
44
x := calldataload(77)
55
}
66
let y := calldataload(x)
@@ -17,26 +17,27 @@
1717
// Block0_0 [label="\
1818
// Block 0; (0, max 2)\nLiveIn: \l\
1919
// LiveOut: v1\l\nv1 := calldataload(3)\l\
20+
// v3 := mload(42)\l\
2021
// "];
2122
// Block0_0 -> Block0_0Exit;
22-
// Block0_0Exit [label="{ If 0 | { <0> Zero | <1> NonZero }}" shape=Mrecord];
23+
// Block0_0Exit [label="{ If v3 | { <0> Zero | <1> NonZero }}" shape=Mrecord];
2324
// Block0_0Exit:0 -> Block0_2 [style="solid"];
2425
// Block0_0Exit:1 -> Block0_1 [style="solid"];
2526
// Block0_1 [label="\
2627
// Block 1; (1, max 2)\nLiveIn: \l\
27-
// LiveOut: v4\l\nv4 := calldataload(77)\l\
28+
// LiveOut: v5\l\nv5 := calldataload(77)\l\
2829
// "];
2930
// Block0_1 -> Block0_1Exit [arrowhead=none];
3031
// Block0_1Exit [label="Jump" shape=oval];
3132
// Block0_1Exit -> Block0_2 [style="solid"];
3233
// Block0_2 [label="\
33-
// Block 2; (2, max 2)\nLiveIn: v5\l\
34-
// LiveOut: \l\nv5 := φ(\l\
34+
// Block 2; (2, max 2)\nLiveIn: v6\l\
35+
// LiveOut: \l\nv6 := φ(\l\
3536
// Block 0 => v1,\l\
36-
// Block 1 => v4\l\
37+
// Block 1 => v5\l\
3738
// )\l\
38-
// v6 := calldataload(v5)\l\
39-
// sstore(0, v6)\l\
39+
// v7 := calldataload(v6)\l\
40+
// sstore(0, v7)\l\
4041
// "];
4142
// Block0_2Exit [label="MainExit"];
4243
// Block0_2 -> Block0_2Exit;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
let x := calldataload(3)
3+
// this should not appear in the output at all
4+
if 0 {
5+
x := calldataload(77)
6+
}
7+
// this should avoid a conditional jump
8+
if 33 {
9+
x := calldataload(42)
10+
}
11+
let y := calldataload(x)
12+
sstore(y, 0)
13+
}
14+
// ----
15+
// digraph SSACFG {
16+
// nodesep=0.7;
17+
// graph[fontname="DejaVu Sans"]
18+
// node[shape=box,fontname="DejaVu Sans"];
19+
//
20+
// Entry0 [label="Entry"];
21+
// Entry0 -> Block0_0;
22+
// Block0_0 [label="\
23+
// Block 0; (0, max 0)\nLiveIn: \l\
24+
// LiveOut: \l\nv1 := calldataload(3)\l\
25+
// v3 := calldataload(42)\l\
26+
// v4 := calldataload(v3)\l\
27+
// sstore(0, v4)\l\
28+
// "];
29+
// Block0_0Exit [label="MainExit"];
30+
// Block0_0 -> Block0_0Exit;
31+
// }

test/libyul/yulSSAControlFlowGraph/nested_for.yul

Lines changed: 40 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
for { let i := 0 } lt(i, 3) { i := add(i, 1) } {
33
for { let j := 0 } lt(j, 3) { j := add(j, 1) } {
44
for { let k := 0 } lt(k, 3) { k := add(k, 1) } {
5-
if 0 {
5+
if mload(0) {
66
for { let l := 0 } lt(l, 3) { l := add(l, 1) } {
77
sstore(l, add(add(i,j),k))
88
}
99
}
10-
if 1 {
10+
if mload(1) {
1111
for { let l := 0 } lt(l, 3) { l := add(l, 1) } {
1212
sstore(l, add(add(i,j),k))
1313
}
@@ -36,7 +36,7 @@
3636
// Block 1; (1, max 24)\nLiveIn: v3\l\
3737
// LiveOut: v3\l\nv3 := φ(\l\
3838
// Block 0 => v1,\l\
39-
// Block 3 => v41\l\
39+
// Block 3 => v43\l\
4040
// )\l\
4141
// v4 := lt(3, v3)\l\
4242
// "];
@@ -60,7 +60,7 @@
6060
// Block 5; (3, max 23)\nLiveIn: v3,v6\l\
6161
// LiveOut: v3,v6\l\nv6 := φ(\l\
6262
// Block 2 => v5,\l\
63-
// Block 7 => v40\l\
63+
// Block 7 => v42\l\
6464
// )\l\
6565
// v7 := lt(3, v6)\l\
6666
// "];
@@ -85,7 +85,7 @@
8585
// Block 9; (5, max 21)\nLiveIn: v3,v6,v9\l\
8686
// LiveOut: v3,v6,v9\l\nv9 := φ(\l\
8787
// Block 6 => v8,\l\
88-
// Block 11 => v36\l\
88+
// Block 11 => v38\l\
8989
// )\l\
9090
// v10 := lt(3, v9)\l\
9191
// "];
@@ -95,16 +95,17 @@
9595
// Block0_9Exit:1 -> Block0_10 [style="solid"];
9696
// Block0_3 [label="\
9797
// Block 3; (23, max 23)\nLiveIn: v3\l\
98-
// LiveOut: v41\l\nv41 := add(1, v3)\l\
98+
// LiveOut: v43\l\nv43 := add(1, v3)\l\
9999
// "];
100100
// Block0_3 -> Block0_3Exit [arrowhead=none];
101101
// Block0_3Exit [label="Jump" shape=oval];
102102
// Block0_3Exit -> Block0_1 [style="dashed"];
103103
// Block0_10 [label="\
104104
// Block 10; (6, max 19)\nLiveIn: v3,v6,v9\l\
105-
// LiveOut: v3,v6,v9\l\n"];
105+
// LiveOut: v3,v6,v9\l\nv11 := mload(0)\l\
106+
// "];
106107
// Block0_10 -> Block0_10Exit;
107-
// Block0_10Exit [label="{ If 0 | { <0> Zero | <1> NonZero }}" shape=Mrecord];
108+
// Block0_10Exit [label="{ If v11 | { <0> Zero | <1> NonZero }}" shape=Mrecord];
108109
// Block0_10Exit:0 -> Block0_14 [style="solid"];
109110
// Block0_10Exit:1 -> Block0_13 [style="solid"];
110111
// Block0_12 [label="\
@@ -115,40 +116,41 @@
115116
// Block0_12Exit -> Block0_7 [style="solid"];
116117
// Block0_13 [label="\
117118
// Block 13; (7, max 19)\nLiveIn: v3,v6,v9\l\
118-
// LiveOut: v3,v6,v9,v11\l\nv11 := 0\l\
119+
// LiveOut: v3,v6,v9,v12\l\nv12 := 0\l\
119120
// "];
120121
// Block0_13 -> Block0_13Exit [arrowhead=none];
121122
// Block0_13Exit [label="Jump" shape=oval];
122123
// Block0_13Exit -> Block0_15 [style="solid"];
123124
// Block0_14 [label="\
124125
// Block 14; (12, max 19)\nLiveIn: v3,v6,v9\l\
125-
// LiveOut: v3,v6,v9\l\n"];
126+
// LiveOut: v3,v6,v9\l\nv24 := mload(1)\l\
127+
// "];
126128
// Block0_14 -> Block0_14Exit;
127-
// Block0_14Exit [label="{ If 1 | { <0> Zero | <1> NonZero }}" shape=Mrecord];
129+
// Block0_14Exit [label="{ If v24 | { <0> Zero | <1> NonZero }}" shape=Mrecord];
128130
// Block0_14Exit:0 -> Block0_20 [style="solid"];
129131
// Block0_14Exit:1 -> Block0_19 [style="solid"];
130132
// Block0_7 [label="\
131133
// Block 7; (21, max 21)\nLiveIn: v3,v6\l\
132-
// LiveOut: v3,v40\l\nv40 := add(1, v6)\l\
134+
// LiveOut: v3,v42\l\nv42 := add(1, v6)\l\
133135
// "];
134136
// Block0_7 -> Block0_7Exit [arrowhead=none];
135137
// Block0_7Exit [label="Jump" shape=oval];
136138
// Block0_7Exit -> Block0_5 [style="dashed"];
137139
// Block0_15 [label="\
138-
// Block 15; (8, max 19)\nLiveIn: v3,v6,v9,v12\l\
139-
// LiveOut: v3,v6,v9,v12\l\nv12 := φ(\l\
140-
// Block 13 => v11,\l\
141-
// Block 17 => v20\l\
140+
// Block 15; (8, max 19)\nLiveIn: v3,v6,v9,v13\l\
141+
// LiveOut: v3,v6,v9,v13\l\nv13 := φ(\l\
142+
// Block 13 => v12,\l\
143+
// Block 17 => v21\l\
142144
// )\l\
143-
// v13 := lt(3, v12)\l\
145+
// v14 := lt(3, v13)\l\
144146
// "];
145147
// Block0_15 -> Block0_15Exit;
146-
// Block0_15Exit [label="{ If v13 | { <0> Zero | <1> NonZero }}" shape=Mrecord];
148+
// Block0_15Exit [label="{ If v14 | { <0> Zero | <1> NonZero }}" shape=Mrecord];
147149
// Block0_15Exit:0 -> Block0_18 [style="solid"];
148150
// Block0_15Exit:1 -> Block0_16 [style="solid"];
149151
// Block0_19 [label="\
150152
// Block 19; (13, max 19)\nLiveIn: v3,v6,v9\l\
151-
// LiveOut: v3,v6,v9,v23\l\nv23 := 0\l\
153+
// LiveOut: v3,v6,v9,v25\l\nv25 := 0\l\
152154
// "];
153155
// Block0_19 -> Block0_19Exit [arrowhead=none];
154156
// Block0_19Exit [label="Jump" shape=oval];
@@ -160,10 +162,10 @@
160162
// Block0_20Exit [label="Jump" shape=oval];
161163
// Block0_20Exit -> Block0_11 [style="solid"];
162164
// Block0_16 [label="\
163-
// Block 16; (9, max 10)\nLiveIn: v3,v6,v9,v12\l\
164-
// LiveOut: v3,v6,v9,v12\l\nv17 := add(v6, v3)\l\
165-
// v18 := add(v9, v17)\l\
166-
// sstore(v18, v12)\l\
165+
// Block 16; (9, max 10)\nLiveIn: v3,v6,v9,v13\l\
166+
// LiveOut: v3,v6,v9,v13\l\nv18 := add(v6, v3)\l\
167+
// v19 := add(v9, v18)\l\
168+
// sstore(v19, v13)\l\
167169
// "];
168170
// Block0_16 -> Block0_16Exit [arrowhead=none];
169171
// Block0_16Exit [label="Jump" shape=oval];
@@ -175,36 +177,36 @@
175177
// Block0_18Exit [label="Jump" shape=oval];
176178
// Block0_18Exit -> Block0_14 [style="solid"];
177179
// Block0_21 [label="\
178-
// Block 21; (14, max 19)\nLiveIn: v3,v6,v9,v24\l\
179-
// LiveOut: v3,v6,v9,v24\l\nv24 := φ(\l\
180-
// Block 19 => v23,\l\
181-
// Block 23 => v31\l\
180+
// Block 21; (14, max 19)\nLiveIn: v3,v6,v9,v26\l\
181+
// LiveOut: v3,v6,v9,v26\l\nv26 := φ(\l\
182+
// Block 19 => v25,\l\
183+
// Block 23 => v33\l\
182184
// )\l\
183-
// v25 := lt(3, v24)\l\
185+
// v27 := lt(3, v26)\l\
184186
// "];
185187
// Block0_21 -> Block0_21Exit;
186-
// Block0_21Exit [label="{ If v25 | { <0> Zero | <1> NonZero }}" shape=Mrecord];
188+
// Block0_21Exit [label="{ If v27 | { <0> Zero | <1> NonZero }}" shape=Mrecord];
187189
// Block0_21Exit:0 -> Block0_24 [style="solid"];
188190
// Block0_21Exit:1 -> Block0_22 [style="solid"];
189191
// Block0_11 [label="\
190192
// Block 11; (19, max 19)\nLiveIn: v3,v6,v9\l\
191-
// LiveOut: v3,v6,v36\l\nv36 := add(1, v9)\l\
193+
// LiveOut: v3,v6,v38\l\nv38 := add(1, v9)\l\
192194
// "];
193195
// Block0_11 -> Block0_11Exit [arrowhead=none];
194196
// Block0_11Exit [label="Jump" shape=oval];
195197
// Block0_11Exit -> Block0_9 [style="dashed"];
196198
// Block0_17 [label="\
197-
// Block 17; (10, max 10)\nLiveIn: v3,v6,v9,v12\l\
198-
// LiveOut: v3,v6,v9,v20\l\nv20 := add(1, v12)\l\
199+
// Block 17; (10, max 10)\nLiveIn: v3,v6,v9,v13\l\
200+
// LiveOut: v3,v6,v9,v21\l\nv21 := add(1, v13)\l\
199201
// "];
200202
// Block0_17 -> Block0_17Exit [arrowhead=none];
201203
// Block0_17Exit [label="Jump" shape=oval];
202204
// Block0_17Exit -> Block0_15 [style="dashed"];
203205
// Block0_22 [label="\
204-
// Block 22; (15, max 16)\nLiveIn: v3,v6,v9,v24\l\
205-
// LiveOut: v3,v6,v9,v24\l\nv29 := add(v6, v3)\l\
206-
// v30 := add(v9, v29)\l\
207-
// sstore(v30, v24)\l\
206+
// Block 22; (15, max 16)\nLiveIn: v3,v6,v9,v26\l\
207+
// LiveOut: v3,v6,v9,v26\l\nv31 := add(v6, v3)\l\
208+
// v32 := add(v9, v31)\l\
209+
// sstore(v32, v26)\l\
208210
// "];
209211
// Block0_22 -> Block0_22Exit [arrowhead=none];
210212
// Block0_22Exit [label="Jump" shape=oval];
@@ -216,8 +218,8 @@
216218
// Block0_24Exit [label="Jump" shape=oval];
217219
// Block0_24Exit -> Block0_20 [style="solid"];
218220
// Block0_23 [label="\
219-
// Block 23; (16, max 16)\nLiveIn: v3,v6,v9,v24\l\
220-
// LiveOut: v3,v6,v9,v31\l\nv31 := add(1, v24)\l\
221+
// Block 23; (16, max 16)\nLiveIn: v3,v6,v9,v26\l\
222+
// LiveOut: v3,v6,v9,v33\l\nv33 := add(1, v26)\l\
221223
// "];
222224
// Block0_23 -> Block0_23Exit [arrowhead=none];
223225
// Block0_23Exit [label="Jump" shape=oval];
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
{
2+
let x := calldataload(3)
3+
4+
// this should yield calldataload(88) directly
5+
switch 1
6+
case 0 {
7+
x := calldataload(77)
8+
}
9+
case 1 {
10+
x := calldataload(88)
11+
}
12+
default {
13+
x := calldataload(99)
14+
}
15+
16+
// this should yield the default case
17+
switch 55
18+
case 0 {
19+
x := calldataload(77)
20+
}
21+
case 1 {
22+
x := calldataload(88)
23+
}
24+
default {
25+
x := calldataload(99)
26+
}
27+
28+
// this should be skipped entirely
29+
switch 66
30+
case 0 {
31+
x := calldataload(77)
32+
}
33+
case 1 {
34+
x := calldataload(88)
35+
}
36+
sstore(x, 0)
37+
}
38+
// ----
39+
// digraph SSACFG {
40+
// nodesep=0.7;
41+
// graph[fontname="DejaVu Sans"]
42+
// node[shape=box,fontname="DejaVu Sans"];
43+
//
44+
// Entry0 [label="Entry"];
45+
// Entry0 -> Block0_0;
46+
// Block0_0 [label="\
47+
// Block 0; (0, max 0)\nLiveIn: \l\
48+
// LiveOut: \l\nv1 := calldataload(3)\l\
49+
// v4 := calldataload(88)\l\
50+
// v7 := calldataload(99)\l\
51+
// sstore(0, v7)\l\
52+
// "];
53+
// Block0_0Exit [label="MainExit"];
54+
// Block0_0 -> Block0_0Exit;
55+
// }

0 commit comments

Comments
 (0)