Skip to content

Commit 6d069a0

Browse files
committed
Auto merge of #117359 - tmiasko:call-def, r=cjgillot
Fix def-use check for call terminators Fixes #117331.
2 parents 003fa88 + 6873465 commit 6d069a0

File tree

4 files changed

+93
-30
lines changed

4 files changed

+93
-30
lines changed

compiler/rustc_codegen_ssa/src/mir/analyze.rs

+13-6
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
3636

3737
// Arguments get assigned to by means of the function being called
3838
for arg in mir.args_iter() {
39-
analyzer.assign(arg, DefLocation::Argument);
39+
analyzer.define(arg, DefLocation::Argument);
4040
}
4141

4242
// If there exists a local definition that dominates all uses of that local,
@@ -74,7 +74,7 @@ struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
7474
}
7575

7676
impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
77-
fn assign(&mut self, local: mir::Local, location: DefLocation) {
77+
fn define(&mut self, local: mir::Local, location: DefLocation) {
7878
let kind = &mut self.locals[local];
7979
match *kind {
8080
LocalKind::ZST => {}
@@ -162,7 +162,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
162162
debug!("visit_assign(place={:?}, rvalue={:?})", place, rvalue);
163163

164164
if let Some(local) = place.as_local() {
165-
self.assign(local, DefLocation::Body(location));
165+
self.define(local, DefLocation::Assignment(location));
166166
if self.locals[local] != LocalKind::Memory {
167167
let decl_span = self.fx.mir.local_decls[local].source_info.span;
168168
if !self.fx.rvalue_creates_operand(rvalue, decl_span) {
@@ -183,9 +183,14 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
183183

184184
fn visit_local(&mut self, local: mir::Local, context: PlaceContext, location: Location) {
185185
match context {
186-
PlaceContext::MutatingUse(MutatingUseContext::Call)
187-
| PlaceContext::MutatingUse(MutatingUseContext::Yield) => {
188-
self.assign(local, DefLocation::Body(location));
186+
PlaceContext::MutatingUse(MutatingUseContext::Call) => {
187+
let call = location.block;
188+
let TerminatorKind::Call { target, .. } =
189+
self.fx.mir.basic_blocks[call].terminator().kind
190+
else {
191+
bug!()
192+
};
193+
self.define(local, DefLocation::CallReturn { call, target });
189194
}
190195

191196
PlaceContext::NonUse(_)
@@ -237,6 +242,8 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
237242
}
238243
}
239244
}
245+
246+
PlaceContext::MutatingUse(MutatingUseContext::Yield) => bug!(),
240247
}
241248
}
242249
}

compiler/rustc_middle/src/mir/mod.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -1611,14 +1611,29 @@ impl Location {
16111611
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
16121612
pub enum DefLocation {
16131613
Argument,
1614-
Body(Location),
1614+
Assignment(Location),
1615+
CallReturn { call: BasicBlock, target: Option<BasicBlock> },
16151616
}
16161617

16171618
impl DefLocation {
16181619
pub fn dominates(self, location: Location, dominators: &Dominators<BasicBlock>) -> bool {
16191620
match self {
16201621
DefLocation::Argument => true,
1621-
DefLocation::Body(def) => def.successor_within_block().dominates(location, dominators),
1622+
DefLocation::Assignment(def) => {
1623+
def.successor_within_block().dominates(location, dominators)
1624+
}
1625+
DefLocation::CallReturn { target: None, .. } => false,
1626+
DefLocation::CallReturn { call, target: Some(target) } => {
1627+
// The definition occurs on the call -> target edge. The definition dominates a use
1628+
// if and only if the edge is on all paths from the entry to the use.
1629+
//
1630+
// Note that a call terminator has only one edge that can reach the target, so when
1631+
// the call strongly dominates the target, all paths from the entry to the target
1632+
// go through the call -> target edge.
1633+
call != target
1634+
&& dominators.dominates(call, target)
1635+
&& dominators.dominates(target, location.block)
1636+
}
16221637
}
16231638
}
16241639
}

compiler/rustc_mir_transform/src/ssa.rs

+33-22
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ impl SsaLocals {
4040
let dominators = body.basic_blocks.dominators();
4141

4242
let direct_uses = IndexVec::from_elem(0, &body.local_decls);
43-
let mut visitor = SsaVisitor { assignments, assignment_order, dominators, direct_uses };
43+
let mut visitor =
44+
SsaVisitor { body, assignments, assignment_order, dominators, direct_uses };
4445

4546
for local in body.args_iter() {
4647
visitor.assignments[local] = Set1::One(DefLocation::Argument);
@@ -110,7 +111,7 @@ impl SsaLocals {
110111
body: &'a Body<'tcx>,
111112
) -> impl Iterator<Item = (Local, &'a Rvalue<'tcx>, Location)> + 'a {
112113
self.assignment_order.iter().filter_map(|&local| {
113-
if let Set1::One(DefLocation::Body(loc)) = self.assignments[local] {
114+
if let Set1::One(DefLocation::Assignment(loc)) = self.assignments[local] {
114115
let stmt = body.stmt_at(loc).left()?;
115116
// `loc` must point to a direct assignment to `local`.
116117
let Some((target, rvalue)) = stmt.kind.as_assign() else { bug!() };
@@ -134,21 +135,21 @@ impl SsaLocals {
134135
AssignedValue::Arg,
135136
Location { block: START_BLOCK, statement_index: 0 },
136137
),
137-
Set1::One(DefLocation::Body(loc)) => {
138+
Set1::One(DefLocation::Assignment(loc)) => {
138139
let bb = &mut basic_blocks[loc.block];
139-
let value = if loc.statement_index < bb.statements.len() {
140-
// `loc` must point to a direct assignment to `local`.
141-
let stmt = &mut bb.statements[loc.statement_index];
142-
let StatementKind::Assign(box (target, ref mut rvalue)) = stmt.kind else {
143-
bug!()
144-
};
145-
assert_eq!(target.as_local(), Some(local));
146-
AssignedValue::Rvalue(rvalue)
147-
} else {
148-
let term = bb.terminator_mut();
149-
AssignedValue::Terminator(&mut term.kind)
140+
// `loc` must point to a direct assignment to `local`.
141+
let stmt = &mut bb.statements[loc.statement_index];
142+
let StatementKind::Assign(box (target, ref mut rvalue)) = stmt.kind else {
143+
bug!()
150144
};
151-
f(local, value, loc)
145+
assert_eq!(target.as_local(), Some(local));
146+
f(local, AssignedValue::Rvalue(rvalue), loc)
147+
}
148+
Set1::One(DefLocation::CallReturn { call, .. }) => {
149+
let bb = &mut basic_blocks[call];
150+
let loc = Location { block: call, statement_index: bb.statements.len() };
151+
let term = bb.terminator_mut();
152+
f(local, AssignedValue::Terminator(&mut term.kind), loc)
152153
}
153154
_ => {}
154155
}
@@ -201,14 +202,15 @@ impl SsaLocals {
201202
}
202203
}
203204

204-
struct SsaVisitor<'a> {
205+
struct SsaVisitor<'tcx, 'a> {
206+
body: &'a Body<'tcx>,
205207
dominators: &'a Dominators<BasicBlock>,
206208
assignments: IndexVec<Local, Set1<DefLocation>>,
207209
assignment_order: Vec<Local>,
208210
direct_uses: IndexVec<Local, u32>,
209211
}
210212

211-
impl SsaVisitor<'_> {
213+
impl SsaVisitor<'_, '_> {
212214
fn check_dominates(&mut self, local: Local, loc: Location) {
213215
let set = &mut self.assignments[local];
214216
let assign_dominates = match *set {
@@ -224,7 +226,7 @@ impl SsaVisitor<'_> {
224226
}
225227
}
226228

227-
impl<'tcx> Visitor<'tcx> for SsaVisitor<'_> {
229+
impl<'tcx> Visitor<'tcx> for SsaVisitor<'tcx, '_> {
228230
fn visit_local(&mut self, local: Local, ctxt: PlaceContext, loc: Location) {
229231
match ctxt {
230232
PlaceContext::MutatingUse(MutatingUseContext::Projection)
@@ -250,9 +252,18 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor<'_> {
250252

251253
fn visit_place(&mut self, place: &Place<'tcx>, ctxt: PlaceContext, loc: Location) {
252254
let location = match ctxt {
253-
PlaceContext::MutatingUse(
254-
MutatingUseContext::Store | MutatingUseContext::Call | MutatingUseContext::Yield,
255-
) => Some(DefLocation::Body(loc)),
255+
PlaceContext::MutatingUse(MutatingUseContext::Store) => {
256+
Some(DefLocation::Assignment(loc))
257+
}
258+
PlaceContext::MutatingUse(MutatingUseContext::Call) => {
259+
let call = loc.block;
260+
let TerminatorKind::Call { target, .. } =
261+
self.body.basic_blocks[call].terminator().kind
262+
else {
263+
bug!()
264+
};
265+
Some(DefLocation::CallReturn { call, target })
266+
}
256267
_ => None,
257268
};
258269
if let Some(location) = location
@@ -359,7 +370,7 @@ impl StorageLiveLocals {
359370
for (statement_index, statement) in bbdata.statements.iter().enumerate() {
360371
if let StatementKind::StorageLive(local) = statement.kind {
361372
storage_live[local]
362-
.insert(DefLocation::Body(Location { block, statement_index }));
373+
.insert(DefLocation::Assignment(Location { block, statement_index }));
363374
}
364375
}
365376
}

tests/ui/mir/ssa_call_ret.rs

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Regression test for issue #117331, where variable `a` was misidentified as
2+
// being in SSA form (the definition occurs on the return edge only).
3+
//
4+
// edition:2021
5+
// compile-flags: --crate-type=lib
6+
// build-pass
7+
// needs-unwind
8+
#![feature(custom_mir, core_intrinsics)]
9+
use core::intrinsics::mir::*;
10+
11+
#[custom_mir(dialect = "runtime", phase = "optimized")]
12+
pub fn f() -> u32 {
13+
mir!(
14+
let a: u32;
15+
{
16+
Call(a = g(), bb1, UnwindCleanup(bb2))
17+
}
18+
bb1 = {
19+
RET = a;
20+
Return()
21+
}
22+
bb2 (cleanup) = {
23+
RET = a;
24+
UnwindResume()
25+
}
26+
)
27+
}
28+
29+
#[inline(never)]
30+
pub fn g() -> u32 { 0 }

0 commit comments

Comments
 (0)