Skip to content

Commit cef892e

Browse files
committed
Validate there are no critical call edges in optimized MIR
1 parent 0ff8610 commit cef892e

File tree

2 files changed

+53
-0
lines changed

2 files changed

+53
-0
lines changed

compiler/rustc_const_eval/src/transform/validate.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,12 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> {
285285
UnwindAction::Unreachable | UnwindAction::Terminate(UnwindTerminateReason::Abi) => (),
286286
}
287287
}
288+
289+
fn is_critical_call_edge(&self, target: Option<BasicBlock>, unwind: UnwindAction) -> bool {
290+
let Some(target) = target else { return false };
291+
matches!(unwind, UnwindAction::Cleanup(_) | UnwindAction::Terminate(_))
292+
&& self.body.basic_blocks.predecessors()[target].len() > 1
293+
}
288294
}
289295

290296
impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
@@ -425,6 +431,22 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
425431
}
426432
self.check_unwind_edge(location, *unwind);
427433

434+
// The code generation assumes that there are no critical call edges. The assumption
435+
// is used to simplify inserting code that should be executed along the return edge
436+
// from the call. FIXME(tmiasko): Since this is a strictly code generation concern,
437+
// the code generation should be responsible for handling it.
438+
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Optimized)
439+
&& self.is_critical_call_edge(*target, *unwind)
440+
{
441+
self.fail(
442+
location,
443+
format!(
444+
"encountered critical edge in `Call` terminator {:?}",
445+
terminator.kind,
446+
),
447+
);
448+
}
449+
428450
// The call destination place and Operand::Move place used as an argument might be
429451
// passed by a reference to the callee. Consequently they must be non-overlapping
430452
// and cannot be packed. Currently this simply checks for duplicate places.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Optimized MIR shouldn't have critical call edges
2+
//
3+
// build-fail
4+
// edition: 2021
5+
// compile-flags: --crate-type=lib
6+
// failure-status: 101
7+
// dont-check-compiler-stderr
8+
// error-pattern: encountered critical edge in `Call` terminator
9+
#![feature(custom_mir, core_intrinsics)]
10+
use core::intrinsics::mir::*;
11+
12+
#[custom_mir(dialect = "runtime", phase = "optimized")]
13+
#[inline(always)]
14+
pub fn f(a: u32) -> u32 {
15+
mir!(
16+
{
17+
match a {
18+
0 => bb1,
19+
_ => bb2,
20+
}
21+
}
22+
bb1 = {
23+
Call(RET = f(1), bb2, UnwindTerminate(ReasonAbi))
24+
}
25+
26+
bb2 = {
27+
RET = 2;
28+
Return()
29+
}
30+
)
31+
}

0 commit comments

Comments
 (0)