Skip to content

Commit e767c56

Browse files
authored
Cranelift: fix an inliner bug where the last-inlined block was not inserted in the layout (#11513)
Fixes #11493
1 parent 3b6234a commit e767c56

2 files changed

Lines changed: 65 additions & 1 deletion

File tree

cranelift/codegen/src/inline.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ fn inline_one(
364364
// Prepare for translating the actual instructions by inserting the inlined
365365
// blocks into the caller's layout in the same order that they appear in the
366366
// callee.
367-
let last_inlined_block = inline_block_layout(func, call_block, callee, &entity_map);
367+
let mut last_inlined_block = inline_block_layout(func, call_block, callee, &entity_map);
368368

369369
// Translate each instruction from the callee into the caller,
370370
// appending them to their associated block in the caller.
@@ -492,6 +492,18 @@ fn inline_one(
492492
// empty blocks from the caller's layout.
493493
for block in entity_map.iter_inlined_blocks(func) {
494494
if func.layout.is_block_inserted(block) && func.layout.first_inst(block).is_none() {
495+
log::trace!("removing unreachable inlined block from layout: {block}");
496+
497+
// If the block being removed is our last-inlined block, then back
498+
// it up to the previous block in the layout, which will be the new
499+
// last-inlined block after this one's removal.
500+
if block == last_inlined_block {
501+
last_inlined_block = func.layout.prev_block(last_inlined_block).expect(
502+
"there will always at least be the block that contained the call we are \
503+
inlining",
504+
);
505+
}
506+
495507
func.layout.remove_block(block);
496508
}
497509
}
@@ -517,6 +529,10 @@ fn inline_one(
517529
fixup_inlined_call_exception_tables(allocs, func, call_exception_table);
518530
}
519531

532+
debug_assert!(
533+
func.layout.is_block_inserted(last_inlined_block),
534+
"last_inlined_block={last_inlined_block} should be inserted in the layout"
535+
);
520536
last_inlined_block
521537
}
522538

@@ -972,18 +988,24 @@ fn inline_block_layout(
972988
callee: &ir::Function,
973989
entity_map: &EntityMap,
974990
) -> ir::Block {
991+
debug_assert!(func.layout.is_block_inserted(call_block));
992+
975993
// Iterate over callee blocks in layout order, inserting their associated
976994
// inlined block into the caller's layout.
977995
let mut prev_inlined_block = call_block;
978996
let mut next_callee_block = callee.layout.entry_block();
979997
while let Some(callee_block) = next_callee_block {
998+
debug_assert!(func.layout.is_block_inserted(prev_inlined_block));
999+
9801000
let inlined_block = entity_map.inlined_block(callee_block);
9811001
func.layout
9821002
.insert_block_after(inlined_block, prev_inlined_block);
9831003

9841004
prev_inlined_block = inlined_block;
9851005
next_callee_block = callee.layout.next_block(callee_block);
9861006
}
1007+
1008+
debug_assert!(func.layout.is_block_inserted(prev_inlined_block));
9871009
prev_inlined_block
9881010
}
9891011

cranelift/filetests/filetests/inline/unreachable-block.clif

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,45 @@ block0():
4444
; v1 -> v2
4545
; return v1
4646
; }
47+
48+
;; A similar test as above, but with multiple and indirectly unreachable blocks.
49+
function %f3() -> i32 {
50+
block0:
51+
jump block1
52+
block1:
53+
v0 = iconst.i32 42
54+
return v0
55+
block2:
56+
jump block3
57+
block3:
58+
trap user42
59+
}
60+
61+
; (no functions inlined into %f3)
62+
63+
function %f4() -> i32 {
64+
fn0 = %f3() -> i32
65+
block0:
66+
v0 = call fn0()
67+
return v0
68+
}
69+
70+
; function %f4() -> i32 fast {
71+
; sig0 = () -> i32 fast
72+
; fn0 = %f3 sig0
73+
;
74+
; block0:
75+
; jump block1
76+
;
77+
; block1:
78+
; jump block2
79+
;
80+
; block2:
81+
; v2 = iconst.i32 42
82+
; jump block5(v2) ; v2 = 42
83+
;
84+
; block5(v1: i32):
85+
; v0 -> v1
86+
; return v0
87+
; }
88+

0 commit comments

Comments
 (0)