Skip to content

Commit c20a466

Browse files
committed
Fix def-use check for call terminators
1 parent bbcc169 commit c20a466

File tree

3 files changed

+63
-30
lines changed

3 files changed

+63
-30
lines changed

compiler/rustc_codegen_ssa/src/mir/analyze.rs

Lines changed: 13 additions & 6 deletions
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

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1577,14 +1577,29 @@ impl Location {
15771577
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
15781578
pub enum DefLocation {
15791579
Argument,
1580-
Body(Location),
1580+
Assignment(Location),
1581+
CallReturn { call: BasicBlock, target: Option<BasicBlock> },
15811582
}
15821583

15831584
impl DefLocation {
15841585
pub fn dominates(self, location: Location, dominators: &Dominators<BasicBlock>) -> bool {
15851586
match self {
15861587
DefLocation::Argument => true,
1587-
DefLocation::Body(def) => def.successor_within_block().dominates(location, dominators),
1588+
DefLocation::Assignment(def) => {
1589+
def.successor_within_block().dominates(location, dominators)
1590+
}
1591+
DefLocation::CallReturn { target: None, .. } => false,
1592+
DefLocation::CallReturn { call, target: Some(target) } => {
1593+
// The definition occurs on the call -> target edge. The definition dominates a use
1594+
// if and only if the edge is on all paths from the entry to the use.
1595+
//
1596+
// Note that a call terminator has only one edge that can reach the target, so when
1597+
// the call strongly dominates the target, all paths from the entry to the target
1598+
// go through the call -> target edge.
1599+
call != target
1600+
&& dominators.dominates(call, target)
1601+
&& dominators.dominates(target, location.block)
1602+
}
15881603
}
15891604
}
15901605
}

compiler/rustc_mir_transform/src/ssa.rs

Lines changed: 33 additions & 22 deletions
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
}

0 commit comments

Comments
 (0)