Skip to content

Commit 79ba7b3

Browse files
committed
Enable ScalarReplacementOfAggregates
1 parent f0411ff commit 79ba7b3

13 files changed

+313
-342
lines changed

Diff for: compiler/rustc_mir_transform/src/sroa.rs

+45-5
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,29 @@ use rustc_middle::mir::visit::*;
66
use rustc_middle::mir::*;
77
use rustc_middle::ty::{self, Ty, TyCtxt};
88
use rustc_mir_dataflow::value_analysis::{excluded_locals, iter_fields};
9-
use rustc_target::abi::FieldIdx;
9+
use rustc_target::abi::{FieldIdx, ReprFlags, FIRST_VARIANT};
1010

1111
pub struct ScalarReplacementOfAggregates;
1212

1313
impl<'tcx> MirPass<'tcx> for ScalarReplacementOfAggregates {
1414
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
15-
sess.mir_opt_level() >= 3
15+
sess.mir_opt_level() >= 2
1616
}
1717

1818
#[instrument(level = "debug", skip(self, tcx, body))]
1919
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
2020
debug!(def_id = ?body.source.def_id());
21+
22+
// Avoid query cycles (generators require optimized MIR for layout).
23+
if tcx.type_of(body.source.def_id()).subst_identity().is_generator() {
24+
return;
25+
}
26+
2127
let mut excluded = excluded_locals(body);
2228
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
2329
loop {
2430
debug!(?excluded);
25-
let escaping = escaping_locals(&excluded, body);
31+
let escaping = escaping_locals(tcx, param_env, &excluded, body);
2632
debug!(?escaping);
2733
let replacements = compute_flattening(tcx, param_env, body, escaping);
2834
debug!(?replacements);
@@ -48,11 +54,45 @@ impl<'tcx> MirPass<'tcx> for ScalarReplacementOfAggregates {
4854
/// - the locals is a union or an enum;
4955
/// - the local's address is taken, and thus the relative addresses of the fields are observable to
5056
/// client code.
51-
fn escaping_locals(excluded: &BitSet<Local>, body: &Body<'_>) -> BitSet<Local> {
57+
fn escaping_locals<'tcx>(
58+
tcx: TyCtxt<'tcx>,
59+
param_env: ty::ParamEnv<'tcx>,
60+
excluded: &BitSet<Local>,
61+
body: &Body<'tcx>,
62+
) -> BitSet<Local> {
63+
let is_excluded_ty = |ty: Ty<'tcx>| {
64+
if ty.is_union() || ty.is_enum() {
65+
return true;
66+
}
67+
if let ty::Adt(def, _substs) = ty.kind() {
68+
if def.repr().flags.contains(ReprFlags::IS_SIMD) {
69+
// Exclude #[repr(simd)] types so that they are not de-optimized into an array
70+
return true;
71+
}
72+
// We already excluded unions and enums, so this ADT must have one variant
73+
let variant = def.variant(FIRST_VARIANT);
74+
if variant.fields.len() > 1 {
75+
// If this has more than one field, it cannot be a wrapper that only provides a
76+
// niche, so we do not want to automatically exclude it.
77+
return false;
78+
}
79+
let Ok(layout) = tcx.layout_of(param_env.and(ty)) else {
80+
// We can't get the layout
81+
return true;
82+
};
83+
if layout.layout.largest_niche().is_some() {
84+
// This type has a niche
85+
return true;
86+
}
87+
}
88+
// Default for non-ADTs
89+
false
90+
};
91+
5292
let mut set = BitSet::new_empty(body.local_decls.len());
5393
set.insert_range(RETURN_PLACE..=Local::from_usize(body.arg_count));
5494
for (local, decl) in body.local_decls().iter_enumerated() {
55-
if decl.ty.is_union() || decl.ty.is_enum() || excluded.contains(local) {
95+
if excluded.contains(local) || is_excluded_ty(decl.ty) {
5696
set.insert(local);
5797
}
5898
}

Diff for: tests/codegen/issues/issue-105386-ub-in-debuginfo.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// compile-flags: --crate-type=lib -O -Cdebuginfo=2 -Cno-prepopulate-passes
1+
// compile-flags: --crate-type=lib -O -Cdebuginfo=2 -Cno-prepopulate-passes -Zmir-enable-passes=-ScalarReplacementOfAggregates
2+
// MIR SROA will decompose the closure
23
// min-llvm-version: 15.0 # this test uses opaque pointer notation
34
#![feature(stmt_expr_attributes)]
45

@@ -15,8 +16,8 @@ pub fn outer_function(x: S, y: S) -> usize {
1516
// Check that we do not attempt to load from the spilled arg before it is assigned to
1617
// when generating debuginfo.
1718
// CHECK-LABEL: @outer_function
18-
// CHECK: [[spill:%.*]] = alloca %"[closure@{{.*.rs}}:9:23: 9:25]"
19-
// CHECK-NOT: [[ptr_tmp:%.*]] = getelementptr inbounds %"[closure@{{.*.rs}}:9:23: 9:25]", ptr [[spill]]
19+
// CHECK: [[spill:%.*]] = alloca %"[closure@{{.*.rs}}:10:23: 10:25]"
20+
// CHECK-NOT: [[ptr_tmp:%.*]] = getelementptr inbounds %"[closure@{{.*.rs}}:10:23: 10:25]", ptr [[spill]]
2021
// CHECK-NOT: [[load:%.*]] = load ptr, ptr
2122
// CHECK: call void @llvm.lifetime.start{{.*}}({{.*}}, ptr [[spill]])
2223
// CHECK: [[inner:%.*]] = getelementptr inbounds %"{{.*}}", ptr [[spill]]

Diff for: tests/incremental/hashes/match_expressions.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,9 @@ pub fn change_mutability_of_binding_in_pattern(x: u32) -> u32 {
225225
}
226226
}
227227

228+
// Ignore optimized_mir in cfail2, the only change to optimized MIR is a span.
228229
#[cfg(not(any(cfail1,cfail4)))]
229-
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
230+
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")]
230231
#[rustc_clean(cfg="cfail3")]
231232
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")]
232233
#[rustc_clean(cfg="cfail6")]

Diff for: tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.diff

+44-52
Original file line numberDiff line numberDiff line change
@@ -11,35 +11,33 @@
1111
+ debug self => _3; // in scope 1 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
1212
+ debug rhs => _4; // in scope 1 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
1313
+ let mut _5: u16; // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL
14-
+ let mut _6: (u32,); // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL
15-
+ let mut _7: u32; // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL
1614
+ scope 2 {
1715
+ scope 3 (inlined core::num::<impl u16>::unchecked_shl::conv) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL
18-
+ debug x => _7; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL
19-
+ let mut _8: std::option::Option<u16>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL
20-
+ let mut _9: std::result::Result<u16, std::num::TryFromIntError>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL
16+
+ debug x => _4; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL
17+
+ let mut _6: std::option::Option<u16>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL
18+
+ let mut _7: std::result::Result<u16, std::num::TryFromIntError>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL
2119
+ scope 4 {
2220
+ scope 5 (inlined <u32 as TryInto<u16>>::try_into) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL
23-
+ debug self => _7; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
21+
+ debug self => _4; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
2422
+ scope 6 (inlined convert::num::<impl TryFrom<u32> for u16>::try_from) { // at $SRC_DIR/core/src/convert/mod.rs:LL:COL
25-
+ debug u => _7; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
26-
+ let mut _10: bool; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
27-
+ let mut _11: u32; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
28-
+ let mut _12: u16; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
23+
+ debug u => _4; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
24+
+ let mut _8: bool; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
25+
+ let mut _9: u32; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
26+
+ let mut _10: u16; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
2927
+ }
3028
+ }
3129
+ scope 7 (inlined Result::<u16, TryFromIntError>::ok) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL
32-
+ debug self => _9; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
33-
+ let mut _13: isize; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
34-
+ let _14: u16; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
30+
+ debug self => _7; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
31+
+ let mut _11: isize; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
32+
+ let _12: u16; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
3533
+ scope 8 {
36-
+ debug x => _14; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
34+
+ debug x => _12; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
3735
+ }
3836
+ }
3937
+ scope 9 (inlined #[track_caller] Option::<u16>::unwrap_unchecked) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL
40-
+ debug self => _8; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
41-
+ let mut _15: &std::option::Option<u16>; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
42-
+ let mut _16: isize; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
38+
+ debug self => _6; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
39+
+ let mut _13: &std::option::Option<u16>; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
40+
+ let mut _14: isize; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
4341
+ scope 10 {
4442
+ debug val => _5; // in scope 10 at $SRC_DIR/core/src/option.rs:LL:COL
4543
+ }
@@ -52,7 +50,7 @@
5250
+ }
5351
+ }
5452
+ scope 12 (inlined Option::<u16>::is_some) { // at $SRC_DIR/core/src/option.rs:LL:COL
55-
+ debug self => _15; // in scope 12 at $SRC_DIR/core/src/option.rs:LL:COL
53+
+ debug self => _13; // in scope 12 at $SRC_DIR/core/src/option.rs:LL:COL
5654
+ }
5755
+ }
5856
+ }
@@ -70,18 +68,14 @@
7068
- // + span: $DIR/unchecked_shifts.rs:11:7: 11:20
7169
- // + literal: Const { ty: unsafe fn(u16, u32) -> u16 {core::num::<impl u16>::unchecked_shl}, val: Value(<ZST>) }
7270
+ StorageLive(_5); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
73-
+ StorageLive(_6); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
74-
+ _6 = (_4,); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
75-
+ StorageLive(_7); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
76-
+ _7 = move (_6.0: u32); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
77-
+ StorageLive(_8); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
78-
+ StorageLive(_9); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
79-
+ StorageLive(_10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
80-
+ StorageLive(_11); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
81-
+ _11 = const 65535_u32; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
82-
+ _10 = Gt(_7, move _11); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
83-
+ StorageDead(_11); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
84-
+ switchInt(move _10) -> [0: bb3, otherwise: bb2]; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
71+
+ StorageLive(_6); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
72+
+ StorageLive(_7); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
73+
+ StorageLive(_8); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
74+
+ StorageLive(_9); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
75+
+ _9 = const 65535_u32; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
76+
+ _8 = Gt(_4, move _9); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
77+
+ StorageDead(_9); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
78+
+ switchInt(move _8) -> [0: bb3, otherwise: bb2]; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
8579
}
8680

8781
bb1: {
@@ -92,30 +86,30 @@
9286
+ }
9387
+
9488
+ bb2: {
95-
+ _9 = Result::<u16, TryFromIntError>::Err(const TryFromIntError(())); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
89+
+ _7 = Result::<u16, TryFromIntError>::Err(const TryFromIntError(())); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
9690
+ // mir::Constant
9791
+ // + span: no-location
9892
+ // + literal: Const { ty: TryFromIntError, val: Value(<ZST>) }
9993
+ goto -> bb4; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
10094
+ }
10195
+
10296
+ bb3: {
103-
+ StorageLive(_12); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
104-
+ _12 = _7 as u16 (IntToInt); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
105-
+ _9 = Result::<u16, TryFromIntError>::Ok(move _12); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
106-
+ StorageDead(_12); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
97+
+ StorageLive(_10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
98+
+ _10 = _4 as u16 (IntToInt); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
99+
+ _7 = Result::<u16, TryFromIntError>::Ok(move _10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
100+
+ StorageDead(_10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
107101
+ goto -> bb4; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
108102
+ }
109103
+
110104
+ bb4: {
111-
+ StorageDead(_10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
112-
+ StorageLive(_14); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
113-
+ _13 = discriminant(_9); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
114-
+ switchInt(move _13) -> [0: bb7, 1: bb5, otherwise: bb6]; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
105+
+ StorageDead(_8); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
106+
+ StorageLive(_12); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
107+
+ _11 = discriminant(_7); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
108+
+ switchInt(move _11) -> [0: bb7, 1: bb5, otherwise: bb6]; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
115109
+ }
116110
+
117111
+ bb5: {
118-
+ _8 = Option::<u16>::None; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
112+
+ _6 = Option::<u16>::None; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
119113
+ goto -> bb8; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
120114
+ }
121115
+
@@ -124,25 +118,23 @@
124118
+ }
125119
+
126120
+ bb7: {
127-
+ _14 = move ((_9 as Ok).0: u16); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
128-
+ _8 = Option::<u16>::Some(move _14); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
121+
+ _12 = move ((_7 as Ok).0: u16); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
122+
+ _6 = Option::<u16>::Some(move _12); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
129123
+ goto -> bb8; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
130124
+ }
131125
+
132126
+ bb8: {
133-
+ StorageDead(_14); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
134-
+ StorageDead(_9); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
135-
+ StorageLive(_15); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
136-
+ _16 = discriminant(_8); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
137-
+ switchInt(move _16) -> [1: bb9, otherwise: bb6]; // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
127+
+ StorageDead(_12); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
128+
+ StorageDead(_7); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
129+
+ StorageLive(_13); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
130+
+ _14 = discriminant(_6); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
131+
+ switchInt(move _14) -> [1: bb9, otherwise: bb6]; // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
138132
+ }
139133
+
140134
+ bb9: {
141-
+ _5 = move ((_8 as Some).0: u16); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
142-
+ StorageDead(_15); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
143-
+ StorageDead(_8); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
144-
+ StorageDead(_7); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
145-
+ StorageDead(_6); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
135+
+ _5 = move ((_6 as Some).0: u16); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
136+
+ StorageDead(_13); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
137+
+ StorageDead(_6); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
146138
+ _0 = unchecked_shl::<u16>(_3, move _5) -> [return: bb1, unwind unreachable]; // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
147139
+ // mir::Constant
148140
+ // + span: $SRC_DIR/core/src/num/uint_macros.rs:LL:COL

0 commit comments

Comments
 (0)