Skip to content

Commit b32ee44

Browse files
committed
Find the unified merge block that all literal match arms jump to
1 parent d1b11a5 commit b32ee44

File tree

2 files changed

+57
-1
lines changed

2 files changed

+57
-1
lines changed

crates/codegen/src/yul/emitter.rs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use hir::hir_def::{
55
};
66
use mir::{
77
BasicBlockId, CallOrigin, LoopInfo, MirFunction, Terminator, ValueId, ValueOrigin,
8-
ir::{MatchArmPattern, SwitchOrigin, SwitchValue},
8+
ir::{MatchArmPattern, SwitchOrigin, SwitchTarget, SwitchValue},
99
lower_module,
1010
};
1111
use rustc_hash::FxHashMap;
@@ -207,6 +207,10 @@ impl<'db> YulEmitter<'db> {
207207
" default ",
208208
vec![YulDoc::line(format!("{temp} := {default_expr}"))],
209209
));
210+
if let Some(merge_block) = self.match_merge_block(targets, default)? {
211+
let next_docs = self.emit_block_with_ctx(merge_block, loop_ctx, state)?;
212+
docs.extend(next_docs);
213+
}
210214
Ok(docs)
211215
}
212216
SwitchOrigin::None => {
@@ -263,6 +267,45 @@ impl<'db> YulEmitter<'db> {
263267
}
264268
}
265269

270+
/// Finds the unified merge block that all literal match arms jump to, if any.
271+
fn match_merge_block(
272+
&self,
273+
targets: &[SwitchTarget],
274+
default: BasicBlockId,
275+
) -> Result<Option<BasicBlockId>, YulError> {
276+
let mut merge = None;
277+
for block_id in targets
278+
.iter()
279+
.map(|target| target.block)
280+
.chain(std::iter::once(default))
281+
{
282+
let block = self
283+
.mir_func
284+
.body
285+
.blocks
286+
.get(block_id.index())
287+
.ok_or_else(|| YulError::Unsupported("invalid block in match lowering".into()))?;
288+
match block.terminator {
289+
Terminator::Goto { target } => match merge {
290+
Some(existing) if existing != target => {
291+
return Err(YulError::Unsupported(
292+
"match arms must converge to a single merge block".into(),
293+
));
294+
}
295+
None => merge = Some(target),
296+
_ => {}
297+
},
298+
Terminator::Unreachable => {}
299+
_ => {
300+
return Err(YulError::Unsupported(
301+
"match arms must jump to a merge block".into(),
302+
));
303+
}
304+
}
305+
}
306+
Ok(merge)
307+
}
308+
266309
/// Looks up metadata about the loop that starts at `header`, if it exists.
267310
fn loop_info(&self, header: BasicBlockId) -> Option<LoopInfo> {
268311
self.mir_func.body.loop_headers.get(&header).copied()

crates/codegen/tests/fixtures/match_literal.snap

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ input_file: tests/fixtures/match_literal.fe
1313
default {
1414
v0 := 2
1515
}
16+
ret := v0
1617
}
1718
}
1819
{
@@ -28,6 +29,7 @@ input_file: tests/fixtures/match_literal.fe
2829
default {
2930
v0 := 3
3031
}
32+
ret := v0
3133
}
3234
}
3335
{
@@ -43,6 +45,7 @@ input_file: tests/fixtures/match_literal.fe
4345
default {
4446
v0 := 3
4547
}
48+
ret := v0
4649
}
4750
}
4851
{
@@ -58,6 +61,7 @@ input_file: tests/fixtures/match_literal.fe
5861
default {
5962
v0 := 3
6063
}
64+
ret := v0
6165
}
6266
}
6367
{
@@ -73,6 +77,7 @@ input_file: tests/fixtures/match_literal.fe
7377
default {
7478
v0 := 3
7579
}
80+
ret := v0
7681
}
7782
}
7883
{
@@ -88,6 +93,7 @@ input_file: tests/fixtures/match_literal.fe
8893
default {
8994
v0 := 3
9095
}
96+
ret := v0
9197
}
9298
}
9399
{
@@ -103,6 +109,7 @@ input_file: tests/fixtures/match_literal.fe
103109
default {
104110
v0 := 3
105111
}
112+
ret := v0
106113
}
107114
}
108115
{
@@ -118,6 +125,7 @@ input_file: tests/fixtures/match_literal.fe
118125
default {
119126
v0 := 3
120127
}
128+
ret := v0
121129
}
122130
}
123131
{
@@ -133,6 +141,7 @@ input_file: tests/fixtures/match_literal.fe
133141
default {
134142
v0 := 3
135143
}
144+
ret := v0
136145
}
137146
}
138147
{
@@ -148,6 +157,7 @@ input_file: tests/fixtures/match_literal.fe
148157
default {
149158
v0 := 3
150159
}
160+
ret := v0
151161
}
152162
}
153163
{
@@ -163,6 +173,7 @@ input_file: tests/fixtures/match_literal.fe
163173
default {
164174
v0 := 3
165175
}
176+
ret := v0
166177
}
167178
}
168179
{
@@ -178,6 +189,7 @@ input_file: tests/fixtures/match_literal.fe
178189
default {
179190
v0 := 3
180191
}
192+
ret := v0
181193
}
182194
}
183195
{
@@ -193,5 +205,6 @@ input_file: tests/fixtures/match_literal.fe
193205
default {
194206
v0 := 3
195207
}
208+
ret := v0
196209
}
197210
}

0 commit comments

Comments
 (0)