Skip to content

Commit 6fba73e

Browse files
committed
GVN: Support unions.
1 parent b50f345 commit 6fba73e

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
@@ -178,6 +178,8 @@ enum Value<'tcx> {
178178
/// An aggregate value, either tuple/closure/struct/enum.
179179
/// This does not contain unions, as we cannot reason with the value.
180180
Aggregate(VariantIdx, Vec<VnIndex>),
181+
/// A union aggregate value.
182+
Union(FieldIdx, VnIndex),
181183
/// A raw pointer aggregate built from a thin pointer and metadata.
182184
RawPtr {
183185
/// Thin pointer component. This is field 0 in MIR.
@@ -431,6 +433,21 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
431433
return None;
432434
}
433435
}
436+
Union(active_field, field) => {
437+
let field = self.evaluated[field].as_ref()?;
438+
if matches!(ty.backend_repr, BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..))
439+
{
440+
let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?;
441+
let field_dest = self.ecx.project_field(&dest, active_field).discard_err()?;
442+
self.ecx.copy_op(field, &field_dest).discard_err()?;
443+
self.ecx
444+
.alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id())
445+
.discard_err()?;
446+
dest.into()
447+
} else {
448+
return None;
449+
}
450+
}
434451
RawPtr { pointer, metadata } => {
435452
let pointer = self.evaluated[pointer].as_ref()?;
436453
let metadata = self.evaluated[metadata].as_ref()?;
@@ -608,6 +625,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
608625
ProjectionElem::Field(f, _) => {
609626
if let Value::Aggregate(_, fields) = self.get(value) {
610627
return Some((projection_ty, fields[f.as_usize()]));
628+
} else if let Value::Union(active, field) = *self.get(value)
629+
&& active == f
630+
{
631+
return Some((projection_ty, field));
611632
} else if let Value::Projection(outer_value, ProjectionElem::Downcast(_, read_variant)) = self.get(value)
612633
&& let Value::Aggregate(written_variant, fields) = self.get(*outer_value)
613634
// This pass is not aware of control-flow, so we do not know whether the
@@ -980,7 +1001,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
9801001
| AggregateKind::Coroutine(..) => FIRST_VARIANT,
9811002
AggregateKind::Adt(_, variant_index, _, _, None) => variant_index,
9821003
// Do not track unions.
983-
AggregateKind::Adt(_, _, _, _, Some(_)) => return None,
1004+
AggregateKind::Adt(_, _, _, _, Some(active_field)) => {
1005+
let field = *fields.first()?;
1006+
return Some(self.insert(ty, Value::Union(active_field, field)));
1007+
}
9841008
AggregateKind::RawPtr(..) => {
9851009
assert_eq!(field_ops.len(), 2);
9861010
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)