Skip to content

Commit 293f8e8

Browse files
committedJan 9, 2025
Refactor the cast-then-cast cases together, and support transmute-then-transmute
·
1.88.01.86.0
1 parent 03650dd commit 293f8e8

12 files changed

+588
-112
lines changed
 

‎compiler/rustc_mir_transform/src/gvn.rs

Lines changed: 113 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,110 +1366,112 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
13661366
return self.new_opaque();
13671367
}
13681368

1369-
let mut was_updated = false;
1370-
1371-
// Transmuting `*const T` <=> `*mut T` is just a pointer cast,
1372-
// which we might be able to merge with other ones later.
1373-
if let Transmute = kind
1374-
&& let ty::RawPtr(from_pointee, _) = from.kind()
1375-
&& let ty::RawPtr(to_pointee, _) = to.kind()
1376-
&& from_pointee == to_pointee
1377-
{
1378-
*kind = PtrToPtr;
1379-
was_updated = true;
1380-
}
1381-
1382-
// If a cast just casts away the metadata again, then we can get it by
1383-
// casting the original thin pointer passed to `from_raw_parts`
1384-
if let PtrToPtr = kind
1385-
&& let Value::Aggregate(AggregateTy::RawPtr { data_pointer_ty, .. }, _, fields) =
1386-
self.get(value)
1387-
&& let ty::RawPtr(to_pointee, _) = to.kind()
1388-
&& to_pointee.is_sized(self.tcx, self.typing_env())
1389-
{
1390-
from = *data_pointer_ty;
1391-
value = fields[0];
1392-
was_updated = true;
1393-
if *data_pointer_ty == to {
1394-
return Some(fields[0]);
1369+
let mut was_ever_updated = false;
1370+
loop {
1371+
let mut was_updated_this_iteration = false;
1372+
1373+
// Transmuting `*const T` <=> `*mut T` is just a pointer cast,
1374+
// which we might be able to merge with other ones later.
1375+
if let Transmute = kind
1376+
&& let ty::RawPtr(from_pointee, _) = from.kind()
1377+
&& let ty::RawPtr(to_pointee, _) = to.kind()
1378+
&& from_pointee == to_pointee
1379+
{
1380+
*kind = PtrToPtr;
1381+
was_updated_this_iteration = true;
13951382
}
1396-
}
13971383

1398-
// PtrToPtr-then-PtrToPtr can skip the intermediate step
1399-
if let PtrToPtr = kind
1400-
&& let Value::Cast { kind: inner_kind, value: inner_value, from: inner_from, to: _ } =
1401-
*self.get(value)
1402-
&& let PtrToPtr = inner_kind
1403-
{
1404-
from = inner_from;
1405-
value = inner_value;
1406-
was_updated = true;
1407-
if inner_from == to {
1408-
return Some(inner_value);
1384+
// If a cast just casts away the metadata again, then we can get it by
1385+
// casting the original thin pointer passed to `from_raw_parts`
1386+
if let PtrToPtr = kind
1387+
&& let Value::Aggregate(AggregateTy::RawPtr { data_pointer_ty, .. }, _, fields) =
1388+
self.get(value)
1389+
&& let ty::RawPtr(to_pointee, _) = to.kind()
1390+
&& to_pointee.is_sized(self.tcx, self.typing_env())
1391+
{
1392+
from = *data_pointer_ty;
1393+
value = fields[0];
1394+
was_updated_this_iteration = true;
1395+
if *data_pointer_ty == to {
1396+
return Some(fields[0]);
1397+
}
14091398
}
1410-
}
14111399

1412-
// Aggregate-then-Transmute can just transmute the original field value,
1413-
// so long as the bytes of a value from only from a single field.
1414-
if let Transmute = kind
1415-
&& let Value::Aggregate(
1416-
AggregateTy::Def(aggregate_did, aggregate_args),
1417-
variant_idx,
1418-
field_values,
1419-
) = self.get(value)
1420-
&& let aggregate_ty =
1421-
self.tcx.type_of(aggregate_did).instantiate(self.tcx, aggregate_args)
1422-
&& let Some((field_idx, field_ty)) =
1423-
self.value_is_all_in_one_field(aggregate_ty, *variant_idx)
1424-
{
1425-
from = field_ty;
1426-
value = field_values[field_idx.as_usize()];
1427-
was_updated = true;
1428-
if field_ty == to {
1429-
return Some(value);
1400+
// Aggregate-then-Transmute can just transmute the original field value,
1401+
// so long as the bytes of a value from only from a single field.
1402+
if let Transmute = kind
1403+
&& let Value::Aggregate(
1404+
AggregateTy::Def(aggregate_did, aggregate_args),
1405+
variant_idx,
1406+
field_values,
1407+
) = self.get(value)
1408+
&& let aggregate_ty =
1409+
self.tcx.type_of(aggregate_did).instantiate(self.tcx, aggregate_args)
1410+
&& let Some((field_idx, field_ty)) =
1411+
self.value_is_all_in_one_field(aggregate_ty, *variant_idx)
1412+
{
1413+
from = field_ty;
1414+
value = field_values[field_idx.as_usize()];
1415+
was_updated_this_iteration = true;
1416+
if field_ty == to {
1417+
return Some(value);
1418+
}
14301419
}
1431-
}
14321420

1433-
// PtrToPtr-then-Transmute can just transmute the original, so long as the
1434-
// PtrToPtr didn't change metadata (and thus the size of the pointer)
1435-
if let Transmute = kind
1436-
&& let Value::Cast {
1437-
kind: PtrToPtr,
1421+
// Various cast-then-cast cases can be simplified.
1422+
if let Value::Cast {
1423+
kind: inner_kind,
14381424
value: inner_value,
14391425
from: inner_from,
14401426
to: inner_to,
14411427
} = *self.get(value)
1442-
&& self.pointers_have_same_metadata(inner_from, inner_to)
1443-
{
1444-
from = inner_from;
1445-
value = inner_value;
1446-
was_updated = true;
1447-
if inner_from == to {
1448-
return Some(inner_value);
1428+
{
1429+
let new_kind = match (inner_kind, *kind) {
1430+
// Even if there's a narrowing cast in here that's fine, because
1431+
// things like `*mut [i32] -> *mut i32 -> *const i32` and
1432+
// `*mut [i32] -> *const [i32] -> *const i32` can skip the middle in MIR.
1433+
(PtrToPtr, PtrToPtr) => Some(PtrToPtr),
1434+
// PtrToPtr-then-Transmute is fine so long as the pointer cast is identity:
1435+
// `*const T -> *mut T -> NonNull<T>` is fine, but we need to check for narrowing
1436+
// to skip things like `*const [i32] -> *const i32 -> NonNull<T>`.
1437+
(PtrToPtr, Transmute)
1438+
if self.pointers_have_same_metadata(inner_from, inner_to) =>
1439+
{
1440+
Some(Transmute)
1441+
}
1442+
// Similarly, for Transmute-then-PtrToPtr. Note that we need to check different
1443+
// variables for their metadata, and thus this can't merge with the previous arm.
1444+
(Transmute, PtrToPtr) if self.pointers_have_same_metadata(from, to) => {
1445+
Some(Transmute)
1446+
}
1447+
// If would be legal to always do this, but we don't want to hide information
1448+
// from the backend that it'd otherwise be able to use for optimizations.
1449+
(Transmute, Transmute)
1450+
if !self.type_may_have_niche_of_interest_to_backend(inner_to) =>
1451+
{
1452+
Some(Transmute)
1453+
}
1454+
_ => None,
1455+
};
1456+
if let Some(new_kind) = new_kind {
1457+
*kind = new_kind;
1458+
from = inner_from;
1459+
value = inner_value;
1460+
was_updated_this_iteration = true;
1461+
if inner_from == to {
1462+
return Some(inner_value);
1463+
}
1464+
}
14491465
}
1450-
}
14511466

1452-
// Transmute-then-PtrToPtr can just transmute the original, so long as the
1453-
// PtrToPtr won't change metadata (and thus the size of the pointer)
1454-
if let PtrToPtr = kind
1455-
&& let Value::Cast {
1456-
kind: Transmute,
1457-
value: inner_value,
1458-
from: inner_from,
1459-
to: _inner_to,
1460-
} = *self.get(value)
1461-
&& self.pointers_have_same_metadata(from, to)
1462-
{
1463-
*kind = Transmute;
1464-
from = inner_from;
1465-
value = inner_value;
1466-
was_updated = true;
1467-
if inner_from == to {
1468-
return Some(inner_value);
1467+
if was_updated_this_iteration {
1468+
was_ever_updated = true;
1469+
} else {
1470+
break;
14691471
}
14701472
}
14711473

1472-
if was_updated && let Some(op) = self.try_as_operand(value, location) {
1474+
if was_ever_updated && let Some(op) = self.try_as_operand(value, location) {
14731475
*operand = op;
14741476
}
14751477

@@ -1492,6 +1494,28 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
14921494
}
14931495
}
14941496

1497+
/// Returns `false` if we know for sure that this type has no interesting niche,
1498+
/// and thus we can skip transmuting through it without worrying.
1499+
///
1500+
/// The backend will emit `assume`s when transmuting between types with niches,
1501+
/// so we want to preserve `i32 -> char -> u32` so that that data is around,
1502+
/// but it's fine to skip whole-range-is-value steps like `A -> u32 -> B`.
1503+
fn type_may_have_niche_of_interest_to_backend(&self, ty: Ty<'tcx>) -> bool {
1504+
let Ok(layout) = self.ecx.layout_of(ty) else {
1505+
// If it's too generic or something, then assume it might be interesting later.
1506+
return true;
1507+
};
1508+
1509+
match layout.backend_repr {
1510+
BackendRepr::Uninhabited => true,
1511+
BackendRepr::Scalar(a) => !a.is_always_valid(&self.ecx),
1512+
BackendRepr::ScalarPair(a, b) => {
1513+
!a.is_always_valid(&self.ecx) || !b.is_always_valid(&self.ecx)
1514+
}
1515+
BackendRepr::Vector { .. } | BackendRepr::Memory { .. } => false,
1516+
}
1517+
}
1518+
14951519
fn value_is_all_in_one_field(
14961520
&self,
14971521
ty: Ty<'tcx>,

‎tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-abort.diff

Lines changed: 129 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,49 @@
1717
let mut _14: u16;
1818
let _15: ();
1919
let mut _16: u16;
20-
let mut _17: std::result::Result<aggregate_struct_then_transmute::Never, u16>;
20+
let mut _17: std::result::Result<Never, u16>;
21+
let mut _19: u16;
22+
let _20: ();
23+
let mut _21: u32;
24+
let mut _22: std::option::Option<u16>;
25+
let mut _24: u16;
26+
let _25: ();
27+
let mut _26: i16;
28+
let mut _27: MyId;
29+
let mut _29: u16;
30+
let mut _30: u16;
31+
let _31: ();
32+
let mut _32: u32;
33+
let mut _33: aggregate_struct_then_transmute::Pair;
34+
let mut _35: u16;
35+
let mut _36: u16;
36+
let _37: ();
37+
let mut _38: u16;
38+
let mut _39: aggregate_struct_then_transmute::Pair;
2139
scope 1 {
2240
debug a => _2;
2341
let _7: TypedId<std::string::String>;
2442
scope 2 {
2543
debug b => _7;
26-
let _13: std::result::Result<aggregate_struct_then_transmute::Never, u16>;
44+
let _13: std::result::Result<Never, u16>;
2745
scope 3 {
2846
debug c => _13;
47+
let _18: std::option::Option<u16>;
48+
scope 4 {
49+
debug d => _18;
50+
let _23: MyId;
51+
scope 5 {
52+
debug e => _23;
53+
let _28: aggregate_struct_then_transmute::Pair;
54+
scope 6 {
55+
debug f => _28;
56+
let _34: aggregate_struct_then_transmute::Pair;
57+
scope 7 {
58+
debug g => _34;
59+
}
60+
}
61+
}
62+
}
2963
}
3064
}
3165
}
@@ -101,12 +135,105 @@
101135
bb3: {
102136
StorageDead(_16);
103137
StorageDead(_15);
138+
- StorageLive(_18);
139+
+ nop;
140+
StorageLive(_19);
141+
_19 = copy _1;
142+
- _18 = Option::<u16>::Some(move _19);
143+
+ _18 = Option::<u16>::Some(copy _1);
144+
StorageDead(_19);
145+
StorageLive(_20);
146+
StorageLive(_21);
147+
StorageLive(_22);
148+
_22 = copy _18;
149+
- _21 = move _22 as u32 (Transmute);
150+
+ _21 = copy _18 as u32 (Transmute);
151+
StorageDead(_22);
152+
_20 = opaque::<u32>(move _21) -> [return: bb4, unwind unreachable];
153+
}
154+
155+
bb4: {
156+
StorageDead(_21);
157+
StorageDead(_20);
158+
StorageLive(_23);
159+
StorageLive(_24);
160+
_24 = copy _1;
161+
- _23 = MyId(move _24);
162+
+ _23 = copy _2;
163+
StorageDead(_24);
164+
StorageLive(_25);
165+
StorageLive(_26);
166+
StorageLive(_27);
167+
- _27 = move _23;
168+
- _26 = move _27 as i16 (Transmute);
169+
+ _27 = copy _2;
170+
+ _26 = copy _1 as i16 (Transmute);
171+
StorageDead(_27);
172+
_25 = opaque::<i16>(move _26) -> [return: bb5, unwind unreachable];
173+
}
174+
175+
bb5: {
176+
StorageDead(_26);
177+
StorageDead(_25);
178+
- StorageLive(_28);
179+
+ nop;
180+
StorageLive(_29);
181+
_29 = copy _1;
182+
StorageLive(_30);
183+
_30 = copy _1;
184+
- _28 = Pair(move _29, move _30);
185+
+ _28 = Pair(copy _1, copy _1);
186+
StorageDead(_30);
187+
StorageDead(_29);
188+
StorageLive(_31);
189+
StorageLive(_32);
190+
StorageLive(_33);
191+
- _33 = move _28;
192+
- _32 = move _33 as u32 (Transmute);
193+
+ _33 = copy _28;
194+
+ _32 = copy _28 as u32 (Transmute);
195+
StorageDead(_33);
196+
_31 = opaque::<u32>(move _32) -> [return: bb6, unwind unreachable];
197+
}
198+
199+
bb6: {
200+
StorageDead(_32);
201+
StorageDead(_31);
202+
StorageLive(_34);
203+
StorageLive(_35);
204+
_35 = copy _1;
205+
StorageLive(_36);
206+
_36 = copy _1;
207+
- _34 = Pair(move _35, move _36);
208+
+ _34 = copy _28;
209+
StorageDead(_36);
210+
StorageDead(_35);
211+
StorageLive(_37);
212+
StorageLive(_38);
213+
StorageLive(_39);
214+
- _39 = move _34;
215+
- _38 = move _39 as u16 (Transmute);
216+
+ _39 = copy _28;
217+
+ _38 = copy _28 as u16 (Transmute);
218+
StorageDead(_39);
219+
_37 = opaque::<u16>(move _38) -> [return: bb7, unwind unreachable];
220+
}
221+
222+
bb7: {
223+
StorageDead(_38);
224+
StorageDead(_37);
104225
_0 = const ();
226+
StorageDead(_34);
227+
- StorageDead(_28);
228+
+ nop;
229+
StorageDead(_23);
230+
- StorageDead(_18);
105231
- StorageDead(_13);
106232
- StorageDead(_7);
107233
- StorageDead(_2);
108234
+ nop;
109235
+ nop;
236+
+ nop;
110237
+ nop;
111238
return;
112239
}

‎tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-unwind.diff

Lines changed: 129 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,49 @@
1717
let mut _14: u16;
1818
let _15: ();
1919
let mut _16: u16;
20-
let mut _17: std::result::Result<aggregate_struct_then_transmute::Never, u16>;
20+
let mut _17: std::result::Result<Never, u16>;
21+
let mut _19: u16;
22+
let _20: ();
23+
let mut _21: u32;
24+
let mut _22: std::option::Option<u16>;
25+
let mut _24: u16;
26+
let _25: ();
27+
let mut _26: i16;
28+
let mut _27: MyId;
29+
let mut _29: u16;
30+
let mut _30: u16;
31+
let _31: ();
32+
let mut _32: u32;
33+
let mut _33: aggregate_struct_then_transmute::Pair;
34+
let mut _35: u16;
35+
let mut _36: u16;
36+
let _37: ();
37+
let mut _38: u16;
38+
let mut _39: aggregate_struct_then_transmute::Pair;
2139
scope 1 {
2240
debug a => _2;
2341
let _7: TypedId<std::string::String>;
2442
scope 2 {
2543
debug b => _7;
26-
let _13: std::result::Result<aggregate_struct_then_transmute::Never, u16>;
44+
let _13: std::result::Result<Never, u16>;
2745
scope 3 {
2846
debug c => _13;
47+
let _18: std::option::Option<u16>;
48+
scope 4 {
49+
debug d => _18;
50+
let _23: MyId;
51+
scope 5 {
52+
debug e => _23;
53+
let _28: aggregate_struct_then_transmute::Pair;
54+
scope 6 {
55+
debug f => _28;
56+
let _34: aggregate_struct_then_transmute::Pair;
57+
scope 7 {
58+
debug g => _34;
59+
}
60+
}
61+
}
62+
}
2963
}
3064
}
3165
}
@@ -101,12 +135,105 @@
101135
bb3: {
102136
StorageDead(_16);
103137
StorageDead(_15);
138+
- StorageLive(_18);
139+
+ nop;
140+
StorageLive(_19);
141+
_19 = copy _1;
142+
- _18 = Option::<u16>::Some(move _19);
143+
+ _18 = Option::<u16>::Some(copy _1);
144+
StorageDead(_19);
145+
StorageLive(_20);
146+
StorageLive(_21);
147+
StorageLive(_22);
148+
_22 = copy _18;
149+
- _21 = move _22 as u32 (Transmute);
150+
+ _21 = copy _18 as u32 (Transmute);
151+
StorageDead(_22);
152+
_20 = opaque::<u32>(move _21) -> [return: bb4, unwind continue];
153+
}
154+
155+
bb4: {
156+
StorageDead(_21);
157+
StorageDead(_20);
158+
StorageLive(_23);
159+
StorageLive(_24);
160+
_24 = copy _1;
161+
- _23 = MyId(move _24);
162+
+ _23 = copy _2;
163+
StorageDead(_24);
164+
StorageLive(_25);
165+
StorageLive(_26);
166+
StorageLive(_27);
167+
- _27 = move _23;
168+
- _26 = move _27 as i16 (Transmute);
169+
+ _27 = copy _2;
170+
+ _26 = copy _1 as i16 (Transmute);
171+
StorageDead(_27);
172+
_25 = opaque::<i16>(move _26) -> [return: bb5, unwind continue];
173+
}
174+
175+
bb5: {
176+
StorageDead(_26);
177+
StorageDead(_25);
178+
- StorageLive(_28);
179+
+ nop;
180+
StorageLive(_29);
181+
_29 = copy _1;
182+
StorageLive(_30);
183+
_30 = copy _1;
184+
- _28 = Pair(move _29, move _30);
185+
+ _28 = Pair(copy _1, copy _1);
186+
StorageDead(_30);
187+
StorageDead(_29);
188+
StorageLive(_31);
189+
StorageLive(_32);
190+
StorageLive(_33);
191+
- _33 = move _28;
192+
- _32 = move _33 as u32 (Transmute);
193+
+ _33 = copy _28;
194+
+ _32 = copy _28 as u32 (Transmute);
195+
StorageDead(_33);
196+
_31 = opaque::<u32>(move _32) -> [return: bb6, unwind continue];
197+
}
198+
199+
bb6: {
200+
StorageDead(_32);
201+
StorageDead(_31);
202+
StorageLive(_34);
203+
StorageLive(_35);
204+
_35 = copy _1;
205+
StorageLive(_36);
206+
_36 = copy _1;
207+
- _34 = Pair(move _35, move _36);
208+
+ _34 = copy _28;
209+
StorageDead(_36);
210+
StorageDead(_35);
211+
StorageLive(_37);
212+
StorageLive(_38);
213+
StorageLive(_39);
214+
- _39 = move _34;
215+
- _38 = move _39 as u16 (Transmute);
216+
+ _39 = copy _28;
217+
+ _38 = copy _28 as u16 (Transmute);
218+
StorageDead(_39);
219+
_37 = opaque::<u16>(move _38) -> [return: bb7, unwind continue];
220+
}
221+
222+
bb7: {
223+
StorageDead(_38);
224+
StorageDead(_37);
104225
_0 = const ();
226+
StorageDead(_34);
227+
- StorageDead(_28);
228+
+ nop;
229+
StorageDead(_23);
230+
- StorageDead(_18);
105231
- StorageDead(_13);
106232
- StorageDead(_7);
107233
- StorageDead(_2);
108234
+ nop;
109235
+ nop;
236+
+ nop;
110237
+ nop;
111238
return;
112239
}

‎tests/mir-opt/gvn.rs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -946,7 +946,42 @@ unsafe fn aggregate_struct_then_transmute(id: u16) {
946946
let c = Err::<Never, u16>(id);
947947
opaque(std::intrinsics::transmute::<_, u16>(c));
948948

949-
enum Never {}
949+
// CHECK: [[TEMP1:_[0-9]+]] = Option::<u16>::Some(copy _1);
950+
// CHECK: [[TEMP2:_[0-9]+]] = copy [[TEMP1]] as u32 (Transmute);
951+
// CHECK: opaque::<u32>(move [[TEMP2]])
952+
let d = Some(id);
953+
opaque(std::intrinsics::transmute::<_, u32>(d));
954+
955+
// Still need the transmute, but the aggregate can be skipped
956+
// CHECK: [[TEMP:_[0-9]+]] = copy _1 as i16 (Transmute);
957+
// CHECK: opaque::<i16>(move [[TEMP]])
958+
let e = MyId(id);
959+
opaque(std::intrinsics::transmute::<_, i16>(e));
960+
961+
// CHECK: [[PAIR:_[0-9]+]] = Pair(copy _1, copy _1);
962+
// CHECK: [[TEMP:_[0-9]+]] = copy [[PAIR]] as u32 (Transmute);
963+
// CHECK: opaque::<u32>(move [[TEMP]])
964+
struct Pair(u16, u16);
965+
let f = Pair(id, id);
966+
opaque(std::intrinsics::transmute::<_, u32>(f));
967+
968+
// CHECK: [[TEMP:_[0-9]+]] = copy [[PAIR]] as u16 (Transmute);
969+
// CHECK: opaque::<u16>(move [[TEMP]])
970+
let g = Pair(id, id);
971+
opaque(std::intrinsics::transmute_unchecked::<_, u16>(g));
972+
}
973+
974+
unsafe fn transmute_then_transmute_again(a: u32, c: char) {
975+
// CHECK: [[TEMP1:_[0-9]+]] = copy _1 as char (Transmute);
976+
// CHECK: [[TEMP2:_[0-9]+]] = copy [[TEMP1]] as i32 (Transmute);
977+
// CHECK: opaque::<i32>(move [[TEMP2]])
978+
let x = std::intrinsics::transmute::<u32, char>(a);
979+
opaque(std::intrinsics::transmute::<char, i32>(x));
980+
981+
// CHECK: [[TEMP:_[0-9]+]] = copy _2 as i32 (Transmute);
982+
// CHECK: opaque::<i32>(move [[TEMP]])
983+
let x = std::intrinsics::transmute::<char, u32>(c);
984+
opaque(std::intrinsics::transmute::<u32, i32>(x));
950985
}
951986

952987
// Transmuting can skip a pointer cast so long as it wasn't a fat-to-thin cast.
@@ -1050,6 +1085,8 @@ struct MyId(u16);
10501085
#[repr(transparent)]
10511086
struct TypedId<T>(u16, PhantomData<T>);
10521087

1088+
enum Never {}
1089+
10531090
// EMIT_MIR gvn.subexpression_elimination.GVN.diff
10541091
// EMIT_MIR gvn.wrap_unwrap.GVN.diff
10551092
// EMIT_MIR gvn.repeated_index.GVN.diff
@@ -1083,6 +1120,7 @@ struct TypedId<T>(u16, PhantomData<T>);
10831120
// EMIT_MIR gvn.generic_cast_metadata.GVN.diff
10841121
// EMIT_MIR gvn.cast_pointer_eq.GVN.diff
10851122
// EMIT_MIR gvn.aggregate_struct_then_transmute.GVN.diff
1123+
// EMIT_MIR gvn.transmute_then_transmute_again.GVN.diff
10861124
// EMIT_MIR gvn.cast_pointer_then_transmute.GVN.diff
10871125
// EMIT_MIR gvn.transmute_then_cast_pointer.GVN.diff
10881126
// EMIT_MIR gvn.remove_casts_must_change_both_sides.GVN.diff
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
- // MIR for `transmute_then_transmute_again` before GVN
2+
+ // MIR for `transmute_then_transmute_again` after GVN
3+
4+
fn transmute_then_transmute_again(_1: u32, _2: char) -> () {
5+
debug a => _1;
6+
debug c => _2;
7+
let mut _0: ();
8+
let _3: char;
9+
let mut _4: u32;
10+
let _5: ();
11+
let mut _6: i32;
12+
let mut _7: char;
13+
let mut _9: char;
14+
let _10: ();
15+
let mut _11: i32;
16+
let mut _12: u32;
17+
scope 1 {
18+
debug x => _3;
19+
let _8: u32;
20+
scope 2 {
21+
debug x => _8;
22+
}
23+
}
24+
25+
bb0: {
26+
- StorageLive(_3);
27+
+ nop;
28+
StorageLive(_4);
29+
_4 = copy _1;
30+
- _3 = move _4 as char (Transmute);
31+
+ _3 = copy _1 as char (Transmute);
32+
StorageDead(_4);
33+
StorageLive(_5);
34+
StorageLive(_6);
35+
StorageLive(_7);
36+
_7 = copy _3;
37+
- _6 = move _7 as i32 (Transmute);
38+
+ _6 = copy _3 as i32 (Transmute);
39+
StorageDead(_7);
40+
_5 = opaque::<i32>(move _6) -> [return: bb1, unwind unreachable];
41+
}
42+
43+
bb1: {
44+
StorageDead(_6);
45+
StorageDead(_5);
46+
- StorageLive(_8);
47+
+ nop;
48+
StorageLive(_9);
49+
_9 = copy _2;
50+
- _8 = move _9 as u32 (Transmute);
51+
+ _8 = copy _2 as u32 (Transmute);
52+
StorageDead(_9);
53+
StorageLive(_10);
54+
StorageLive(_11);
55+
StorageLive(_12);
56+
_12 = copy _8;
57+
- _11 = move _12 as i32 (Transmute);
58+
+ _11 = copy _2 as i32 (Transmute);
59+
StorageDead(_12);
60+
_10 = opaque::<i32>(move _11) -> [return: bb2, unwind unreachable];
61+
}
62+
63+
bb2: {
64+
StorageDead(_11);
65+
StorageDead(_10);
66+
_0 = const ();
67+
- StorageDead(_8);
68+
- StorageDead(_3);
69+
+ nop;
70+
+ nop;
71+
return;
72+
}
73+
}
74+
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
- // MIR for `transmute_then_transmute_again` before GVN
2+
+ // MIR for `transmute_then_transmute_again` after GVN
3+
4+
fn transmute_then_transmute_again(_1: u32, _2: char) -> () {
5+
debug a => _1;
6+
debug c => _2;
7+
let mut _0: ();
8+
let _3: char;
9+
let mut _4: u32;
10+
let _5: ();
11+
let mut _6: i32;
12+
let mut _7: char;
13+
let mut _9: char;
14+
let _10: ();
15+
let mut _11: i32;
16+
let mut _12: u32;
17+
scope 1 {
18+
debug x => _3;
19+
let _8: u32;
20+
scope 2 {
21+
debug x => _8;
22+
}
23+
}
24+
25+
bb0: {
26+
- StorageLive(_3);
27+
+ nop;
28+
StorageLive(_4);
29+
_4 = copy _1;
30+
- _3 = move _4 as char (Transmute);
31+
+ _3 = copy _1 as char (Transmute);
32+
StorageDead(_4);
33+
StorageLive(_5);
34+
StorageLive(_6);
35+
StorageLive(_7);
36+
_7 = copy _3;
37+
- _6 = move _7 as i32 (Transmute);
38+
+ _6 = copy _3 as i32 (Transmute);
39+
StorageDead(_7);
40+
_5 = opaque::<i32>(move _6) -> [return: bb1, unwind continue];
41+
}
42+
43+
bb1: {
44+
StorageDead(_6);
45+
StorageDead(_5);
46+
- StorageLive(_8);
47+
+ nop;
48+
StorageLive(_9);
49+
_9 = copy _2;
50+
- _8 = move _9 as u32 (Transmute);
51+
+ _8 = copy _2 as u32 (Transmute);
52+
StorageDead(_9);
53+
StorageLive(_10);
54+
StorageLive(_11);
55+
StorageLive(_12);
56+
_12 = copy _8;
57+
- _11 = move _12 as i32 (Transmute);
58+
+ _11 = copy _2 as i32 (Transmute);
59+
StorageDead(_12);
60+
_10 = opaque::<i32>(move _11) -> [return: bb2, unwind continue];
61+
}
62+
63+
bb2: {
64+
StorageDead(_11);
65+
StorageDead(_10);
66+
_0 = const ();
67+
- StorageDead(_8);
68+
- StorageDead(_3);
69+
+ nop;
70+
+ nop;
71+
return;
72+
}
73+
}
74+

‎tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,13 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
9090
StorageLive(_11);
9191
StorageLive(_3);
9292
StorageLive(_6);
93-
StorageLive(_5);
93+
StorageLive(_4);
9494
_3 = PtrMetadata(copy _1);
9595
_4 = &raw const (*_1);
96+
StorageLive(_5);
9697
_5 = copy _4 as *const T (PtrToPtr);
97-
_6 = NonNull::<T> { pointer: copy _5 };
98+
_6 = NonNull::<T> { pointer: move _5 };
99+
StorageDead(_5);
98100
StorageLive(_9);
99101
switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
100102
}
@@ -121,7 +123,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
121123
_11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> };
122124
StorageDead(_10);
123125
StorageDead(_9);
124-
StorageDead(_5);
126+
StorageDead(_4);
125127
StorageDead(_6);
126128
StorageDead(_3);
127129
_12 = Enumerate::<std::slice::Iter<'_, T>> { iter: copy _11, count: const 0_usize };

‎tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,13 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
6565
StorageLive(_11);
6666
StorageLive(_3);
6767
StorageLive(_6);
68-
StorageLive(_5);
68+
StorageLive(_4);
6969
_3 = PtrMetadata(copy _1);
7070
_4 = &raw const (*_1);
71+
StorageLive(_5);
7172
_5 = copy _4 as *const T (PtrToPtr);
72-
_6 = NonNull::<T> { pointer: copy _5 };
73+
_6 = NonNull::<T> { pointer: move _5 };
74+
StorageDead(_5);
7375
StorageLive(_9);
7476
switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
7577
}
@@ -96,7 +98,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
9698
_11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> };
9799
StorageDead(_10);
98100
StorageDead(_9);
99-
StorageDead(_5);
101+
StorageDead(_4);
100102
StorageDead(_6);
101103
StorageDead(_3);
102104
_12 = Enumerate::<std::slice::Iter<'_, T>> { iter: copy _11, count: const 0_usize };

‎tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,13 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
5757
bb0: {
5858
StorageLive(_3);
5959
StorageLive(_6);
60-
StorageLive(_5);
60+
StorageLive(_4);
6161
_3 = PtrMetadata(copy _1);
6262
_4 = &raw const (*_1);
63+
StorageLive(_5);
6364
_5 = copy _4 as *const T (PtrToPtr);
64-
_6 = NonNull::<T> { pointer: copy _5 };
65+
_6 = NonNull::<T> { pointer: move _5 };
66+
StorageDead(_5);
6567
StorageLive(_9);
6668
switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
6769
}
@@ -88,7 +90,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
8890
_11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> };
8991
StorageDead(_10);
9092
StorageDead(_9);
91-
StorageDead(_5);
93+
StorageDead(_4);
9294
StorageDead(_6);
9395
StorageDead(_3);
9496
StorageLive(_12);

‎tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,13 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
5757
bb0: {
5858
StorageLive(_3);
5959
StorageLive(_6);
60-
StorageLive(_5);
60+
StorageLive(_4);
6161
_3 = PtrMetadata(copy _1);
6262
_4 = &raw const (*_1);
63+
StorageLive(_5);
6364
_5 = copy _4 as *const T (PtrToPtr);
64-
_6 = NonNull::<T> { pointer: copy _5 };
65+
_6 = NonNull::<T> { pointer: move _5 };
66+
StorageDead(_5);
6567
StorageLive(_9);
6668
switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
6769
}
@@ -88,7 +90,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
8890
_11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> };
8991
StorageDead(_10);
9092
StorageDead(_9);
91-
StorageDead(_5);
93+
StorageDead(_4);
9294
StorageDead(_6);
9395
StorageDead(_3);
9496
StorageLive(_12);

‎tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,13 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
6565
StorageLive(_11);
6666
StorageLive(_3);
6767
StorageLive(_6);
68-
StorageLive(_5);
68+
StorageLive(_4);
6969
_3 = PtrMetadata(copy _1);
7070
_4 = &raw const (*_1);
71+
StorageLive(_5);
7172
_5 = copy _4 as *const T (PtrToPtr);
72-
_6 = NonNull::<T> { pointer: copy _5 };
73+
_6 = NonNull::<T> { pointer: move _5 };
74+
StorageDead(_5);
7375
StorageLive(_9);
7476
switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
7577
}
@@ -96,7 +98,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
9698
_11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> };
9799
StorageDead(_10);
98100
StorageDead(_9);
99-
StorageDead(_5);
101+
StorageDead(_4);
100102
StorageDead(_6);
101103
StorageDead(_3);
102104
_12 = Rev::<std::slice::Iter<'_, T>> { iter: copy _11 };

‎tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,13 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
6565
StorageLive(_11);
6666
StorageLive(_3);
6767
StorageLive(_6);
68-
StorageLive(_5);
68+
StorageLive(_4);
6969
_3 = PtrMetadata(copy _1);
7070
_4 = &raw const (*_1);
71+
StorageLive(_5);
7172
_5 = copy _4 as *const T (PtrToPtr);
72-
_6 = NonNull::<T> { pointer: copy _5 };
73+
_6 = NonNull::<T> { pointer: move _5 };
74+
StorageDead(_5);
7375
StorageLive(_9);
7476
switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
7577
}
@@ -96,7 +98,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
9698
_11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> };
9799
StorageDead(_10);
98100
StorageDead(_9);
99-
StorageDead(_5);
101+
StorageDead(_4);
100102
StorageDead(_6);
101103
StorageDead(_3);
102104
_12 = Rev::<std::slice::Iter<'_, T>> { iter: copy _11 };

0 commit comments

Comments
 (0)
Please sign in to comment.