Skip to content

Commit df8b765

Browse files
committed
Auto merge of #146355 - cjgillot:gvn-union, r=jackh726
GVN: Support unions. Supporting union values is not very hard, and allows to const-prop them. r? `@ghost` for perf
2 parents 5b9007b + 6fba73e commit df8b765

8 files changed

+85
-22
lines changed

compiler/rustc_mir_transform/src/gvn.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,8 @@ enum Value<'tcx> {
202202
/// An aggregate value, either tuple/closure/struct/enum.
203203
/// This does not contain unions, as we cannot reason with the value.
204204
Aggregate(VariantIdx, Vec<VnIndex>),
205+
/// A union aggregate value.
206+
Union(FieldIdx, VnIndex),
205207
/// A raw pointer aggregate built from a thin pointer and metadata.
206208
RawPtr {
207209
/// Thin pointer component. This is field 0 in MIR.
@@ -563,6 +565,21 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
563565
return None;
564566
}
565567
}
568+
Union(active_field, field) => {
569+
let field = self.evaluated[field].as_ref()?;
570+
if matches!(ty.backend_repr, BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..))
571+
{
572+
let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?;
573+
let field_dest = self.ecx.project_field(&dest, active_field).discard_err()?;
574+
self.ecx.copy_op(field, &field_dest).discard_err()?;
575+
self.ecx
576+
.alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id())
577+
.discard_err()?;
578+
dest.into()
579+
} else {
580+
return None;
581+
}
582+
}
566583
RawPtr { pointer, metadata } => {
567584
let pointer = self.evaluated[pointer].as_ref()?;
568585
let metadata = self.evaluated[metadata].as_ref()?;
@@ -735,6 +752,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
735752
ProjectionElem::Field(f, _) => {
736753
if let Value::Aggregate(_, fields) = self.get(value) {
737754
return Some((projection_ty, fields[f.as_usize()]));
755+
} else if let Value::Union(active, field) = *self.get(value)
756+
&& active == f
757+
{
758+
return Some((projection_ty, field));
738759
} else if let Value::Projection(outer_value, ProjectionElem::Downcast(_, read_variant)) = self.get(value)
739760
&& let Value::Aggregate(written_variant, fields) = self.get(*outer_value)
740761
// This pass is not aware of control-flow, so we do not know whether the
@@ -1106,7 +1127,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
11061127
| AggregateKind::Coroutine(..) => FIRST_VARIANT,
11071128
AggregateKind::Adt(_, variant_index, _, _, None) => variant_index,
11081129
// Do not track unions.
1109-
AggregateKind::Adt(_, _, _, _, Some(_)) => return None,
1130+
AggregateKind::Adt(_, _, _, _, Some(active_field)) => {
1131+
let field = *fields.first()?;
1132+
return Some(self.insert(ty, Value::Union(active_field, field)));
1133+
}
11101134
AggregateKind::RawPtr(..) => {
11111135
assert_eq!(field_ops.len(), 2);
11121136
let [mut pointer, metadata] = fields.try_into().unwrap();

tests/mir-opt/const_prop/invalid_constant.main.GVN.diff

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,27 @@
2828
bb0: {
2929
StorageLive(_1);
3030
StorageLive(_2);
31-
_2 = InvalidChar { int: const 1114113_u32 };
32-
_1 = copy (_2.1: char);
31+
- _2 = InvalidChar { int: const 1114113_u32 };
32+
- _1 = copy (_2.1: char);
33+
+ _2 = const InvalidChar {{ int: 1114113_u32, chr: {transmute(0x00110001): char} }};
34+
+ _1 = const {transmute(0x00110001): char};
3335
StorageDead(_2);
3436
StorageLive(_3);
3537
StorageLive(_4);
3638
StorageLive(_5);
37-
_5 = InvalidTag { int: const 4_u32 };
38-
_4 = copy (_5.1: E);
39-
_3 = [move _4];
39+
- _5 = InvalidTag { int: const 4_u32 };
40+
- _4 = copy (_5.1: E);
41+
- _3 = [move _4];
42+
+ _5 = const InvalidTag {{ int: 4_u32, e: Scalar(0x00000004): E }};
43+
+ _4 = const Scalar(0x00000004): E;
44+
+ _3 = [const Scalar(0x00000004): E];
4045
StorageDead(_4);
4146
StorageDead(_5);
4247
nop;
4348
nop;
4449
StorageLive(_8);
45-
_8 = NoVariants { int: const 0_u32 };
50+
- _8 = NoVariants { int: const 0_u32 };
51+
+ _8 = const NoVariants {{ int: 0_u32, empty: ZeroSized: Empty }};
4652
nop;
4753
nop;
4854
nop;
@@ -55,5 +61,17 @@
5561
StorageDead(_1);
5662
return;
5763
}
64+
+ }
65+
+
66+
+ ALLOC0 (size: 4, align: 4) {
67+
+ 00 00 00 00 │ ....
68+
+ }
69+
+
70+
+ ALLOC1 (size: 4, align: 4) {
71+
+ 04 00 00 00 │ ....
72+
+ }
73+
+
74+
+ ALLOC2 (size: 4, align: 4) {
75+
+ 01 00 11 00 │ ....
5876
}
5977

tests/mir-opt/const_prop/transmute.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ pub unsafe fn invalid_bool() -> bool {
4343
// EMIT_MIR transmute.undef_union_as_integer.GVN.diff
4444
pub unsafe fn undef_union_as_integer() -> u32 {
4545
// CHECK-LABEL: fn undef_union_as_integer(
46-
// CHECK: _1 = Union32 {
47-
// CHECK: _0 = move _1 as u32 (Transmute);
46+
// CHECK: _1 = const Union32
47+
// CHECK: _0 = const {{.*}}: u32;
4848
union Union32 {
4949
value: u32,
5050
unit: (),

tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.32bit.diff

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,16 @@
1212
- _2 = ();
1313
- _1 = Union32 { value: move _2 };
1414
+ _2 = const ();
15-
+ _1 = Union32 { value: const () };
15+
+ _1 = const Union32 {{ value: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: u32, unit: () }};
1616
StorageDead(_2);
17-
_0 = move _1 as u32 (Transmute);
17+
- _0 = move _1 as u32 (Transmute);
18+
+ _0 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: u32;
1819
StorageDead(_1);
1920
return;
2021
}
22+
+ }
23+
+
24+
+ ALLOC0 (size: 4, align: 4) {
25+
+ __ __ __ __ │ ░░░░
2126
}
2227

tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.64bit.diff

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,16 @@
1212
- _2 = ();
1313
- _1 = Union32 { value: move _2 };
1414
+ _2 = const ();
15-
+ _1 = Union32 { value: const () };
15+
+ _1 = const Union32 {{ value: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: u32, unit: () }};
1616
StorageDead(_2);
17-
_0 = move _1 as u32 (Transmute);
17+
- _0 = move _1 as u32 (Transmute);
18+
+ _0 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: u32;
1819
StorageDead(_1);
1920
return;
2021
}
22+
+ }
23+
+
24+
+ ALLOC0 (size: 4, align: 4) {
25+
+ __ __ __ __ │ ░░░░
2126
}
2227

tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,26 @@
66
let _1: main::Un;
77
let mut _2: u32;
88
scope 1 {
9-
debug un => _1;
9+
debug un => const Un {{ us: 1_u32 }};
1010
scope 3 (inlined std::mem::drop::<u32>) {
11-
debug _x => _2;
11+
debug _x => const 1_u32;
1212
}
1313
}
1414
scope 2 (inlined val) {
1515
}
1616

1717
bb0: {
1818
StorageLive(_1);
19-
_1 = Un { us: const 1_u32 };
19+
nop;
2020
StorageLive(_2);
21-
_2 = copy (_1.0: u32);
21+
nop;
2222
StorageDead(_2);
2323
StorageDead(_1);
2424
return;
2525
}
2626
}
2727

28+
ALLOC0 (size: 4, align: 4) {
29+
01 00 00 00 │ ....
30+
}
31+

tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,26 @@
66
let _1: main::Un;
77
let mut _2: u32;
88
scope 1 {
9-
debug un => _1;
9+
debug un => const Un {{ us: 1_u32 }};
1010
scope 3 (inlined std::mem::drop::<u32>) {
11-
debug _x => _2;
11+
debug _x => const 1_u32;
1212
}
1313
}
1414
scope 2 (inlined val) {
1515
}
1616

1717
bb0: {
1818
StorageLive(_1);
19-
_1 = Un { us: const 1_u32 };
19+
nop;
2020
StorageLive(_2);
21-
_2 = copy (_1.0: u32);
21+
nop;
2222
StorageDead(_2);
2323
StorageDead(_1);
2424
return;
2525
}
2626
}
2727

28+
ALLOC0 (size: 4, align: 4) {
29+
01 00 00 00 │ ....
30+
}
31+

tests/mir-opt/dest-prop/union.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ fn val() -> u32 {
88
// EMIT_MIR union.main.DestinationPropagation.diff
99
fn main() {
1010
// CHECK-LABEL: fn main(
11-
// CHECK: {{_.*}} = Un { us: const 1_u32 };
11+
// CHECK: debug un => const Un
12+
// CHECK: debug _x => const 1_u32;
13+
// CHECK: bb0: {
14+
// CHECK-NEXT: return;
1215
union Un {
1316
us: u32,
1417
}

0 commit comments

Comments
 (0)