Skip to content

Commit 523f8f8

Browse files
committed
Compute reachable locals as part of non_ssa_locals
1 parent 0ea5dc5 commit 523f8f8

File tree

6 files changed

+78
-111
lines changed

6 files changed

+78
-111
lines changed

Diff for: compiler/rustc_codegen_ssa/src/mir/analyze.rs

+15-14
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,16 @@ use crate::traits::*;
1616
pub(crate) fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
1717
fx: &FunctionCx<'a, 'tcx, Bx>,
1818
traversal_order: &[mir::BasicBlock],
19-
reachable_locals: &BitSet<mir::Local>,
2019
) -> BitSet<mir::Local> {
2120
let mir = fx.mir;
2221
let dominators = mir.basic_blocks.dominators();
2322
let locals = mir
2423
.local_decls
25-
.iter_enumerated()
26-
.map(|(local, decl)| {
27-
if !reachable_locals.contains(local) {
28-
return LocalKind::Unused;
29-
}
24+
.iter()
25+
.map(|decl| {
3026
let ty = fx.monomorphize(decl.ty);
3127
let layout = fx.cx.spanned_layout_of(ty, decl.source_info.span);
32-
if layout.is_zst() {
33-
LocalKind::ZST
34-
} else if fx.cx.is_backend_immediate(layout) || fx.cx.is_backend_scalar_pair(layout) {
35-
LocalKind::Unused
36-
} else {
37-
LocalKind::Memory
38-
}
28+
if layout.is_zst() { LocalKind::ZST } else { LocalKind::Unused }
3929
})
4030
.collect();
4131

@@ -83,11 +73,22 @@ struct LocalAnalyzer<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> {
8373

8474
impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> LocalAnalyzer<'a, 'b, 'tcx, Bx> {
8575
fn define(&mut self, local: mir::Local, location: DefLocation) {
76+
let fx = self.fx;
8677
let kind = &mut self.locals[local];
78+
let decl = &fx.mir.local_decls[local];
8779
match *kind {
8880
LocalKind::ZST => {}
8981
LocalKind::Memory => {}
90-
LocalKind::Unused => *kind = LocalKind::SSA(location),
82+
LocalKind::Unused => {
83+
let ty = fx.monomorphize(decl.ty);
84+
let layout = fx.cx.spanned_layout_of(ty, decl.source_info.span);
85+
*kind =
86+
if fx.cx.is_backend_immediate(layout) || fx.cx.is_backend_scalar_pair(layout) {
87+
LocalKind::SSA(location)
88+
} else {
89+
LocalKind::Memory
90+
};
91+
}
9192
LocalKind::SSA(_) => *kind = LocalKind::Memory,
9293
}
9394
}

Diff for: compiler/rustc_codegen_ssa/src/mir/mod.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -192,9 +192,6 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
192192
})
193193
.collect();
194194

195-
let (traversal_order, reachable_locals) =
196-
traversal::mono_reachable_reverse_postorder(mir, cx.tcx(), instance);
197-
198195
let mut fx = FunctionCx {
199196
instance,
200197
mir,
@@ -221,7 +218,8 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
221218

222219
fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut start_bx);
223220

224-
let memory_locals = analyze::non_ssa_locals(&fx, &traversal_order, &reachable_locals);
221+
let traversal_order = traversal::mono_reachable_reverse_postorder(mir, cx.tcx(), instance);
222+
let memory_locals = analyze::non_ssa_locals(&fx, &traversal_order);
225223

226224
// Allocate variable and temp allocas
227225
let local_values = {
@@ -286,6 +284,12 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
286284
fx.codegen_block(bb);
287285
unreached_blocks.remove(bb);
288286
}
287+
288+
// FIXME: These empty unreachable blocks are *mostly* a waste. They are occasionally
289+
// targets for a SwitchInt terminator, but the reimplementation of the mono-reachable
290+
// simplification in SwitchInt lowering sometimes misses cases that
291+
// mono_reachable_reverse_postorder manages to figure out.
292+
// The solution is to do something like post-mono GVN. But for now we have this hack.
289293
for bb in unreached_blocks.iter() {
290294
fx.codegen_block_as_unreachable(bb);
291295
}

Diff for: compiler/rustc_middle/src/mir/basic_blocks.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ impl<'tcx> BasicBlocks<'tcx> {
7171
#[inline]
7272
pub fn reverse_postorder(&self) -> &[BasicBlock] {
7373
self.cache.reverse_postorder.get_or_init(|| {
74-
let mut rpo: Vec<_> = Postorder::new(&self.basic_blocks, START_BLOCK).collect();
74+
let mut rpo: Vec<_> = Postorder::new(&self.basic_blocks, START_BLOCK, ()).collect();
7575
rpo.reverse();
7676
rpo
7777
})

Diff for: compiler/rustc_middle/src/mir/traversal.rs

+40-82
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use super::*;
2-
use crate::mir::visit::Visitor;
32

43
/// Preorder traversal of a graph.
54
///
@@ -105,36 +104,46 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> {
105104
/// ```
106105
///
107106
/// A Postorder traversal of this graph is `D B C A` or `D C B A`
108-
pub struct Postorder<'a, 'tcx> {
107+
pub struct Postorder<'a, 'tcx, C> {
109108
basic_blocks: &'a IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
110109
visited: BitSet<BasicBlock>,
111110
visit_stack: Vec<(BasicBlock, Successors<'a>)>,
112111
root_is_start_block: bool,
112+
extra: C,
113113
}
114114

115-
impl<'a, 'tcx> Postorder<'a, 'tcx> {
115+
impl<'a, 'tcx, C> Postorder<'a, 'tcx, C>
116+
where
117+
C: Customization<'tcx>,
118+
{
116119
pub fn new(
117120
basic_blocks: &'a IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
118121
root: BasicBlock,
119-
) -> Postorder<'a, 'tcx> {
122+
extra: C,
123+
) -> Postorder<'a, 'tcx, C> {
120124
let mut po = Postorder {
121125
basic_blocks,
122126
visited: BitSet::new_empty(basic_blocks.len()),
123127
visit_stack: Vec::new(),
124128
root_is_start_block: root == START_BLOCK,
129+
extra,
125130
};
126131

127-
let data = &po.basic_blocks[root];
128-
129-
if let Some(ref term) = data.terminator {
130-
po.visited.insert(root);
131-
po.visit_stack.push((root, term.successors()));
132-
po.traverse_successor();
133-
}
132+
po.visit(root);
133+
po.traverse_successor();
134134

135135
po
136136
}
137137

138+
fn visit(&mut self, bb: BasicBlock) {
139+
if !self.visited.insert(bb) {
140+
return;
141+
}
142+
let data = &self.basic_blocks[bb];
143+
let successors = C::successors(data, self.extra);
144+
self.visit_stack.push((bb, successors));
145+
}
146+
138147
fn traverse_successor(&mut self) {
139148
// This is quite a complex loop due to 1. the borrow checker not liking it much
140149
// and 2. what exactly is going on is not clear
@@ -184,16 +193,15 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> {
184193
// since we've already visited `E`, that child isn't added to the stack. The last
185194
// two iterations yield `B` and finally `A` for a final traversal of [E, D, C, B, A]
186195
while let Some(bb) = self.visit_stack.last_mut().and_then(|(_, iter)| iter.next_back()) {
187-
if self.visited.insert(bb) {
188-
if let Some(term) = &self.basic_blocks[bb].terminator {
189-
self.visit_stack.push((bb, term.successors()));
190-
}
191-
}
196+
self.visit(bb);
192197
}
193198
}
194199
}
195200

196-
impl<'tcx> Iterator for Postorder<'_, 'tcx> {
201+
impl<'tcx, C> Iterator for Postorder<'_, 'tcx, C>
202+
where
203+
C: Customization<'tcx>,
204+
{
197205
type Item = BasicBlock;
198206

199207
fn next(&mut self) -> Option<BasicBlock> {
@@ -233,88 +241,38 @@ pub fn postorder<'a, 'tcx>(
233241
reverse_postorder(body).rev()
234242
}
235243

236-
struct UsedLocals(BitSet<Local>);
237-
238-
impl<'tcx> Visitor<'tcx> for UsedLocals {
239-
fn visit_local(
240-
&mut self,
241-
local: Local,
242-
_ctx: crate::mir::visit::PlaceContext,
243-
_location: Location,
244-
) {
245-
self.0.insert(local);
246-
}
247-
}
248-
249-
struct MonoReachablePostorder<'a, 'tcx> {
250-
basic_blocks: &'a IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
251-
visited: BitSet<BasicBlock>,
252-
visit_stack: Vec<(BasicBlock, Successors<'a>)>,
253-
locals: UsedLocals,
254-
tcx: TyCtxt<'tcx>,
255-
instance: Instance<'tcx>,
244+
/// Lets us plug in some additional logic and data into a Postorder traversal. Or not.
245+
pub trait Customization<'tcx>: Copy {
246+
fn successors<'a>(_: &'a BasicBlockData<'tcx>, _: Self) -> Successors<'a>;
256247
}
257248

258-
impl<'a, 'tcx> MonoReachablePostorder<'a, 'tcx> {
259-
fn new(
260-
body: &'a Body<'tcx>,
261-
tcx: TyCtxt<'tcx>,
262-
instance: Instance<'tcx>,
263-
) -> MonoReachablePostorder<'a, 'tcx> {
264-
let basic_blocks = &body.basic_blocks;
265-
let mut po = MonoReachablePostorder {
266-
basic_blocks,
267-
visited: BitSet::new_empty(basic_blocks.len()),
268-
visit_stack: Vec::new(),
269-
locals: UsedLocals(BitSet::new_empty(body.local_decls.len())),
270-
tcx,
271-
instance,
272-
};
273-
274-
po.visit(START_BLOCK);
275-
po.traverse_successor();
276-
po
277-
}
278-
279-
fn visit(&mut self, bb: BasicBlock) {
280-
if !self.visited.insert(bb) {
281-
return;
282-
}
283-
let data = &self.basic_blocks[bb];
284-
self.locals.visit_basic_block_data(bb, data);
285-
let successors = data.mono_successors(self.tcx, self.instance);
286-
self.visit_stack.push((bb, successors));
287-
}
288-
289-
fn traverse_successor(&mut self) {
290-
while let Some(bb) = self.visit_stack.last_mut().and_then(|(_, iter)| iter.next_back()) {
291-
self.visit(bb);
292-
}
249+
impl<'tcx> Customization<'tcx> for () {
250+
fn successors<'a>(data: &'a BasicBlockData<'tcx>, _: ()) -> Successors<'a> {
251+
data.terminator().successors()
293252
}
294253
}
295254

296-
impl<'tcx> Iterator for MonoReachablePostorder<'_, 'tcx> {
297-
type Item = BasicBlock;
298-
299-
fn next(&mut self) -> Option<BasicBlock> {
300-
let (bb, _) = self.visit_stack.pop()?;
301-
self.traverse_successor();
302-
Some(bb)
255+
impl<'tcx> Customization<'tcx> for (TyCtxt<'tcx>, Instance<'tcx>) {
256+
fn successors<'a>(
257+
data: &'a BasicBlockData<'tcx>,
258+
(tcx, instance): (TyCtxt<'tcx>, Instance<'tcx>),
259+
) -> Successors<'a> {
260+
data.mono_successors(tcx, instance)
303261
}
304262
}
305263

306264
pub fn mono_reachable_reverse_postorder<'a, 'tcx>(
307265
body: &'a Body<'tcx>,
308266
tcx: TyCtxt<'tcx>,
309267
instance: Instance<'tcx>,
310-
) -> (Vec<BasicBlock>, BitSet<Local>) {
311-
let mut iter = MonoReachablePostorder::new(body, tcx, instance);
268+
) -> Vec<BasicBlock> {
269+
let mut iter = Postorder::new(&body.basic_blocks, START_BLOCK, (tcx, instance));
312270
let mut items = Vec::with_capacity(body.basic_blocks.len());
313271
while let Some(block) = iter.next() {
314272
items.push(block);
315273
}
316274
items.reverse();
317-
(items, iter.locals.0)
275+
items
318276
}
319277

320278
/// Returns an iterator over all basic blocks reachable from the `START_BLOCK` in no particular

Diff for: tests/codegen/constant-branch.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,19 @@
77
// CHECK-LABEL: @if_bool
88
#[no_mangle]
99
pub fn if_bool() {
10-
// CHECK: br label %{{.+}}
10+
// CHECK-NOT: br i1
11+
// CHECK-NOT: switch
1112
_ = if true { 0 } else { 1 };
1213

13-
// CHECK: br label %{{.+}}
1414
_ = if false { 0 } else { 1 };
1515
}
1616

1717
// CHECK-LABEL: @if_constant_int_eq
1818
#[no_mangle]
1919
pub fn if_constant_int_eq() {
20+
// CHECK-NOT: br i1
21+
// CHECK-NOT: switch
2022
let val = 0;
21-
// CHECK: br label %{{.+}}
2223
_ = if val == 0 { 0 } else { 1 };
2324

2425
// CHECK: br label %{{.+}}
@@ -28,20 +29,19 @@ pub fn if_constant_int_eq() {
2829
// CHECK-LABEL: @if_constant_match
2930
#[no_mangle]
3031
pub fn if_constant_match() {
31-
// CHECK: br label %{{.+}}
32+
// CHECK-NOT: br i1
33+
// CHECK-NOT: switch
3234
_ = match 1 {
3335
1 => 2,
3436
2 => 3,
3537
_ => 4,
3638
};
3739

38-
// CHECK: br label %{{.+}}
3940
_ = match 1 {
4041
2 => 3,
4142
_ => 4,
4243
};
4344

44-
// CHECK: br label %{{.+}}
4545
_ = match -1 {
4646
-1 => 1,
4747
_ => 0,

Diff for: tests/codegen/no-alloca-inside-if-false.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0
1+
//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0 -Cpanic=abort
2+
// Check that there's an alloca for the reference and the vector, but nothing else.
3+
// We use panic=abort because unwinding panics give hint::black_box a cleanup block, which has
4+
// another alloca.
25

36
#![crate_type = "lib"]
47

58
#[inline(never)]
69
fn test<const SIZE: usize>() {
710
// CHECK-LABEL: no_alloca_inside_if_false::test
811
// CHECK: start:
9-
// CHECK-NEXT: %0 = alloca
10-
// CHECK-NEXT: %vec = alloca
11-
// CHECK-NOT: %arr = alloca
12+
// CHECK-NEXT: alloca [{{12|24}} x i8]
13+
// CHECK-NOT: alloca
1214
if const { SIZE < 4096 } {
1315
let arr = [0u8; SIZE];
1416
std::hint::black_box(&arr);
@@ -18,6 +20,8 @@ fn test<const SIZE: usize>() {
1820
}
1921
}
2022

23+
// CHECK-LABEL: @main
24+
#[no_mangle]
2125
pub fn main() {
2226
test::<8192>();
2327
}

0 commit comments

Comments
 (0)