Skip to content

Commit fad6bb8

Browse files
committed
Auto merge of #118075 - tmiasko:validate-critical-call-edges, r=cjgillot
Validate there are no critical call edges in optimized MIR
2 parents e2e978f + 329d015 commit fad6bb8

File tree

4 files changed

+56
-2
lines changed

4 files changed

+56
-2
lines changed

compiler/rustc_const_eval/src/transform/validate.rs

+22
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.

compiler/rustc_mir_transform/src/coroutine.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
//! Otherwise it drops all the values in scope at the last suspension point.
5252
5353
use crate::abort_unwinding_calls;
54+
use crate::add_call_guards;
5455
use crate::deref_separator::deref_finder;
5556
use crate::errors;
5657
use crate::pass_manager as pm;
@@ -1176,7 +1177,7 @@ fn create_coroutine_drop_shim<'tcx>(
11761177
pm::run_passes_no_validate(
11771178
tcx,
11781179
&mut body,
1179-
&[&abort_unwinding_calls::AbortUnwindingCalls],
1180+
&[&abort_unwinding_calls::AbortUnwindingCalls, &add_call_guards::CriticalCallEdges],
11801181
None,
11811182
);
11821183

compiler/rustc_mir_transform/src/shim.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
111111
&deref_separator::Derefer,
112112
&remove_noop_landing_pads::RemoveNoopLandingPads,
113113
&simplify::SimplifyCfg::MakeShim,
114-
&add_call_guards::CriticalCallEdges,
115114
&abort_unwinding_calls::AbortUnwindingCalls,
115+
&add_call_guards::CriticalCallEdges,
116116
],
117117
Some(MirPhase::Runtime(RuntimePhase::Optimized)),
118118
);
+31
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)