Skip to content

Commit a04ce83

Browse files
committed
What if we skip the projection loop in analyze altogether?
1 parent 95332e1 commit a04ce83

File tree

7 files changed

+31
-118
lines changed

7 files changed

+31
-118
lines changed

compiler/rustc_codegen_ssa/src/mir/analyze.rs

Lines changed: 1 addition & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
//! An analysis to determine which locals require allocas and
22
//! which do not.
33
4-
use rustc_abi as abi;
54
use rustc_data_structures::graph::dominators::Dominators;
65
use rustc_index::bit_set::DenseBitSet;
76
use rustc_index::{IndexSlice, IndexVec};
87
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
98
use rustc_middle::mir::{self, DefLocation, Location, TerminatorKind, traversal};
10-
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
9+
use rustc_middle::ty::layout::LayoutOf;
1110
use rustc_middle::{bug, span_bug};
1211
use tracing::debug;
1312

@@ -135,74 +134,6 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> LocalAnalyzer<'a, 'b, 'tcx, Bx>
135134
self.visit_local(place_ref.local, mut_projection, location);
136135
return;
137136
}
138-
139-
// Scan through to ensure the only projections are those which
140-
// `FunctionCx::maybe_codegen_consume_direct` can handle.
141-
let base_ty = self.fx.monomorphized_place_ty(mir::PlaceRef::from(place_ref.local));
142-
let mut layout = self.fx.cx.layout_of(base_ty);
143-
for elem in place_ref.projection {
144-
if layout.is_zst() {
145-
// Any further projections must still be ZSTs, so we're good.
146-
break;
147-
}
148-
149-
#[track_caller]
150-
fn compatible_projection(src: TyAndLayout<'_>, tgt: TyAndLayout<'_>) -> bool {
151-
fn compatible_initness(a: abi::Scalar, b: abi::Scalar) -> bool {
152-
!a.is_uninit_valid() || b.is_uninit_valid()
153-
}
154-
155-
use abi::BackendRepr::*;
156-
match (src.backend_repr, tgt.backend_repr) {
157-
_ if tgt.is_zst() => true,
158-
(Scalar(a), Scalar(b))
159-
| (SimdVector { element: a, .. }, SimdVector { element: b, .. }) => {
160-
compatible_initness(a, b)
161-
}
162-
(ScalarPair(a0, a1), Scalar(b)) => {
163-
compatible_initness(a0, b) && compatible_initness(a1, b)
164-
}
165-
(ScalarPair(a0, a1), ScalarPair(b0, b1)) => {
166-
compatible_initness(a0, b0) && compatible_initness(a1, b1)
167-
}
168-
_ => bug!("Mismatched layouts in analysis\nsrc: {src:?}\ntgt: {tgt:?}"),
169-
}
170-
}
171-
172-
match *elem {
173-
mir::PlaceElem::Field(fidx, ..) => {
174-
let field_layout = layout.field(self.fx.cx, fidx.as_usize());
175-
if compatible_projection(layout, field_layout) {
176-
layout = field_layout;
177-
continue;
178-
}
179-
}
180-
mir::PlaceElem::Downcast(_, vidx) => {
181-
let variant_layout = layout.for_variant(self.fx.cx, vidx);
182-
if compatible_projection(layout, variant_layout) {
183-
layout = variant_layout;
184-
continue;
185-
}
186-
}
187-
188-
mir::PlaceElem::Index(..)
189-
| mir::PlaceElem::ConstantIndex { .. }
190-
| mir::PlaceElem::Subslice { .. }
191-
| mir::PlaceElem::OpaqueCast(..)
192-
| mir::PlaceElem::UnwrapUnsafeBinder(..)
193-
| mir::PlaceElem::Subtype(..) => {}
194-
195-
mir::PlaceElem::Deref => bug!("Deref after first position"),
196-
}
197-
198-
// If the above didn't `continue`, we can't handle the projection.
199-
self.locals[place_ref.local] = LocalKind::Memory;
200-
return;
201-
}
202-
debug_assert!(
203-
!self.fx.cx.is_backend_ref(layout),
204-
"Post-projection {place_ref:?} layout should be non-Ref, but it's {layout:?}",
205-
);
206137
}
207138

208139
// Even with supported projections, we still need to have `visit_local`

compiler/rustc_codegen_ssa/src/mir/operand.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
371371
self.val
372372
} else if field.size == layout.size {
373373
debug_assert_eq!(offset.bytes(), 0);
374-
if downcast_variant.is_some() {
374+
if downcast_variant.is_some() || self.layout.ty.is_union() {
375375
fx.codegen_transmute_operand(bx, *self, field)
376376
} else {
377377
self.val

tests/codegen/enum/enum-extract.rs

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,20 @@ use std::mem::MaybeUninit;
1616
use std::num::NonZero;
1717
use std::ptr::NonNull;
1818

19-
// This doesn't actually end up in an SSA value because `extract_field`
20-
// doesn't know how to do the equivalent of `!noundef` without a load.
2119
#[no_mangle]
2220
fn use_option_u32(x: Option<u32>) -> u32 {
2321
// CHECK-LABEL: @use_option_u32
24-
// OPT-SAME: (i32 noundef range(i32 0, 2) %0, i32 %1)
22+
// OPT-SAME: (i32 noundef range(i32 0, 2) %x.0, i32 %x.1)
2523

2624
// CHECK-NOT: alloca
27-
// CHECK: %x = alloca [8 x i8]
28-
// CHECK-NOT: alloca
29-
// CHECK: %[[X0:.+]] = load i32, ptr %x
30-
// CHECK: %[[DISCR:.+]] = zext i32 %[[X0]] to i64
25+
// CHECK: %[[DISCR:.+]] = zext i32 %x.0 to i64
3126
// CHECK: %[[IS_SOME:.+]] = trunc nuw i64 %[[DISCR]] to i1
3227
// OPT: %[[LIKELY:.+]] = call i1 @llvm.expect.i1(i1 %[[IS_SOME]], i1 true)
3328
// OPT: br i1 %[[LIKELY]], label %[[BLOCK:.+]],
3429
// DBG: br i1 %[[IS_SOME]], label %[[BLOCK:.+]],
3530

3631
// CHECK: [[BLOCK]]:
37-
// CHECK: %[[X1P:.+]] = getelementptr inbounds i8, ptr %x, i64 4
38-
// CHECK: %[[X1:.+]] = load i32, ptr %[[X1P]]
39-
// OPT-SAME: !noundef
40-
// CHECK: ret i32 %[[X1]]
32+
// CHECK: ret i32 %x.1
4133

4234
if let Some(val) = x { val } else { unreachable!() }
4335
}

tests/codegen/intrinsics/cold_path3.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ pub fn test(x: Option<u32>) {
4444
_ => path_a(),
4545
}
4646

47-
// CHECK-LABEL: @test({{.+}} %0, {{.+}} %1)
48-
// CHECK: switch i32 %1, label %bb1 [
47+
// CHECK-LABEL: @test({{.+}} %x.0, {{.+}} %x.1)
48+
// CHECK: switch i32 %x.1, label %bb1 [
4949
// CHECK: i32 0, label %bb6
5050
// CHECK: i32 1, label %bb5
5151
// CHECK: i32 2, label %bb4
@@ -75,8 +75,8 @@ pub fn test2(x: Option<u32>) {
7575
}
7676
}
7777

78-
// CHECK-LABEL: @test2({{.+}} %0, {{.+}} %1)
79-
// CHECK: switch i32 %1, label %bb1 [
78+
// CHECK-LABEL: @test2({{.+}} %x.0, {{.+}} %x.1)
79+
// CHECK: switch i32 %x.1, label %bb1 [
8080
// CHECK: i32 10, label %bb5
8181
// CHECK: i32 11, label %bb4
8282
// CHECK: i32 13, label %bb3

tests/codegen/range-loop.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ pub fn call_for_zero_to_n(n: u32, f: fn(u32)) {
1414
// CHECK: start:
1515
// CHECK-NOT: alloca
1616
// CHECK: %[[IND:.+]] = alloca [4 x i8]
17-
// CHECK-NEXT: %[[ALWAYS_SOME_OPTION:.+]] = alloca
1817
// CHECK-NOT: alloca
1918
// CHECK: store i32 0, ptr %[[IND]],
2019
// CHECK: br label %[[HEAD:.+]]
@@ -31,10 +30,7 @@ pub fn call_for_zero_to_n(n: u32, f: fn(u32)) {
3130
// CHECK: %[[T2:.+]] = load i32, ptr %[[IND]],
3231
// CHECK: %[[T3:.+]] = add nuw i32 %[[T2]], 1
3332
// CHECK: store i32 %[[T3]], ptr %[[IND]],
34-
35-
// CHECK: store i32 %[[T2]]
36-
// CHECK: %[[T4:.+]] = load i32
37-
// CHECK: call void %f(i32{{.+}}%[[T4]])
33+
// CHECK: call void %f(i32{{.+}}%[[T2]])
3834

3935
for i in 0..n {
4036
f(i);

tests/codegen/try_question_mark_nop.rs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,18 @@
1212
use std::ops::ControlFlow::{self, Break, Continue};
1313
use std::ptr::NonNull;
1414

15-
// CHECK-LABEL: @option_nop_match_32({{.+}} %0, {{.+}} %1)
15+
// CHECK-LABEL: @option_nop_match_32({{.+}} %x.0, {{.+}} %x.1)
1616
#[no_mangle]
1717
pub fn option_nop_match_32(x: Option<u32>) -> Option<u32> {
1818
// CHECK: start:
19-
// CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i32 %0 to i1
19+
// CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i32 %x.0 to i1
2020

21-
// NINETEEN-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i32 %0, i32 0
21+
// NINETEEN-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i32 %x.0, i32 0
2222
// NINETEEN-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } poison, i32 [[SELECT]], 0
23-
// NINETEEN-NEXT: [[REG3:%.*]] = insertvalue { i32, i32 } [[REG2]], i32 %1, 1
23+
// NINETEEN-NEXT: [[REG3:%.*]] = insertvalue { i32, i32 } [[REG2]], i32 %x.1, 1
2424

25-
// TWENTY-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i32 %1, i32 undef
26-
// TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } poison, i32 %0, 0
25+
// TWENTY-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i32 %x.1, i32 undef
26+
// TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } poison, i32 %x.0, 0
2727
// TWENTY-NEXT: [[REG3:%.*]] = insertvalue { i32, i32 } [[REG2]], i32 [[SELECT]], 1
2828

2929
// CHECK-NEXT: ret { i32, i32 } [[REG3]]
@@ -33,12 +33,12 @@ pub fn option_nop_match_32(x: Option<u32>) -> Option<u32> {
3333
}
3434
}
3535

36-
// CHECK-LABEL: @option_nop_traits_32({{.+}} %0, {{.+}} %1)
36+
// CHECK-LABEL: @option_nop_traits_32({{.+}} %x.0, {{.+}} %x.1)
3737
#[no_mangle]
3838
pub fn option_nop_traits_32(x: Option<u32>) -> Option<u32> {
3939
// CHECK: start:
40-
// TWENTY-NEXT: %[[IS_SOME:.+]] = trunc nuw i32 %0 to i1
41-
// TWENTY-NEXT: select i1 %[[IS_SOME]], i32 %1, i32 undef
40+
// TWENTY-NEXT: %[[IS_SOME:.+]] = trunc nuw i32 %x.0 to i1
41+
// TWENTY-NEXT: select i1 %[[IS_SOME]], i32 %x.1, i32 undef
4242
// CHECK-NEXT: insertvalue { i32, i32 }
4343
// CHECK-NEXT: insertvalue { i32, i32 }
4444
// CHECK-NEXT: ret { i32, i32 }
@@ -91,18 +91,18 @@ pub fn control_flow_nop_traits_32(x: ControlFlow<i32, u32>) -> ControlFlow<i32,
9191
try { x? }
9292
}
9393

94-
// CHECK-LABEL: @option_nop_match_64({{.+}} %0, {{.+}} %1)
94+
// CHECK-LABEL: @option_nop_match_64({{.+}} %x.0, {{.+}} %x.1)
9595
#[no_mangle]
9696
pub fn option_nop_match_64(x: Option<u64>) -> Option<u64> {
9797
// CHECK: start:
98-
// CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i64 %0 to i1
98+
// CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i64 %x.0 to i1
9999

100-
// NINETEEN-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i64 %0, i64 0
100+
// NINETEEN-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i64 %x.0, i64 0
101101
// NINETEEN-NEXT: [[REG2:%.*]] = insertvalue { i64, i64 } poison, i64 [[SELECT]], 0
102-
// NINETEEN-NEXT: [[REG3:%.*]] = insertvalue { i64, i64 } [[REG2]], i64 %1, 1
102+
// NINETEEN-NEXT: [[REG3:%.*]] = insertvalue { i64, i64 } [[REG2]], i64 %x.1, 1
103103

104-
// TWENTY-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i64 %1, i64 undef
105-
// TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i64, i64 } poison, i64 %0, 0
104+
// TWENTY-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i64 %x.1, i64 undef
105+
// TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i64, i64 } poison, i64 %x.0, 0
106106
// TWENTY-NEXT: [[REG3:%.*]] = insertvalue { i64, i64 } [[REG2]], i64 [[SELECT]], 1
107107

108108
// CHECK-NEXT: ret { i64, i64 } [[REG3]]
@@ -112,12 +112,12 @@ pub fn option_nop_match_64(x: Option<u64>) -> Option<u64> {
112112
}
113113
}
114114

115-
// CHECK-LABEL: @option_nop_traits_64({{.+}} %0, {{.+}} %1)
115+
// CHECK-LABEL: @option_nop_traits_64({{.+}} %x.0, {{.+}} %x.1)
116116
#[no_mangle]
117117
pub fn option_nop_traits_64(x: Option<u64>) -> Option<u64> {
118118
// CHECK: start:
119-
// TWENTY-NEXT: %[[TRUNC:[0-9]+]] = trunc nuw i64 %0 to i1
120-
// TWENTY-NEXT: %[[SEL:\.[0-9]+]] = select i1 %[[TRUNC]], i64 %1, i64 undef
119+
// TWENTY-NEXT: %[[TRUNC:.+]] = trunc nuw i64 %x.0 to i1
120+
// TWENTY-NEXT: %[[SEL:.+]] = select i1 %[[TRUNC]], i64 %x.1, i64 undef
121121
// CHECK-NEXT: insertvalue { i64, i64 }
122122
// CHECK-NEXT: insertvalue { i64, i64 }
123123
// CHECK-NEXT: ret { i64, i64 }

tests/codegen/union-abi.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -137,20 +137,14 @@ pub fn test_CUnionU128(_: CUnionU128) {
137137
pub union UnionBool {
138138
b: bool,
139139
}
140-
// CHECK: define {{(dso_local )?}}noundef zeroext i1 @test_UnionBool(i8 %0)
140+
// CHECK: define {{(dso_local )?}}noundef zeroext i1 @test_UnionBool(i8 %b)
141141
#[no_mangle]
142142
pub fn test_UnionBool(b: UnionBool) -> bool {
143143
// Note the lack of `noundef` on the parameter, because (at least for now)
144-
// all unions are allowed to be fully-uninitialized. We thus write it to
145-
// memory and read it via `!noundef` when asserting validity.
144+
// all unions are allowed to be fully-uninitialized.
146145

147146
// CHECK-NOT: alloca
148-
// CHECK: %b = alloca [1 x i8], align 1
149-
// CHECK-NOT: alloca
150-
// CHECK: store i8 %0, ptr %b, align 1
151-
// CHECK: %[[WIDE:.+]] = load i8, ptr %b, align 1
152-
// CHECK-SAME: !noundef
153-
// CHECK: %[[BOOL:.+]] = trunc nuw i8 %[[WIDE]] to i1
147+
// CHECK: %[[BOOL:.+]] = trunc nuw i8 %b to i1
154148
// CHECK: ret i1 %[[BOOL]]
155149

156150
unsafe { b.b }

0 commit comments

Comments
 (0)