@@ -823,18 +823,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
823
823
return self . simplify_cast ( kind, value, to, location) ;
824
824
}
825
825
Rvalue :: BinaryOp ( op, box ( ref mut lhs, ref mut rhs) ) => {
826
- let ty = lhs. ty ( self . local_decls , self . tcx ) ;
827
- let lhs = self . simplify_operand ( lhs, location) ;
828
- let rhs = self . simplify_operand ( rhs, location) ;
829
- // Only short-circuit options after we called `simplify_operand`
830
- // on both operands for side effect.
831
- let lhs = lhs?;
832
- let rhs = rhs?;
833
-
834
- if let Some ( value) = self . simplify_binary ( op, ty, lhs, rhs) {
835
- return Some ( value) ;
836
- }
837
- Value :: BinaryOp ( op, lhs, rhs)
826
+ return self . simplify_binary ( op, lhs, rhs, location) ;
838
827
}
839
828
Rvalue :: UnaryOp ( op, ref mut arg_op) => {
840
829
return self . simplify_unary ( op, arg_op, location) ;
@@ -987,23 +976,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
987
976
// `*const [T]` -> `*const T` which remove metadata.
988
977
// We run on potentially-generic MIR, though, so unlike codegen
989
978
// we can't always know exactly what the metadata are.
990
- // Thankfully, equality on `ptr_metadata_ty_or_tail` gives us
991
- // what we need: `Ok(meta_ty)` if the metadata is known, or
992
- // `Err(tail_ty)` if not. Matching metadata is ok, but if
993
- // that's not known, then matching tail types is also ok,
994
- // allowing things like `*mut (?A, ?T)` <-> `*mut (?B, ?T)`.
995
- // FIXME: Would it be worth trying to normalize, rather than
996
- // passing the identity closure? Or are the types in the
997
- // Cast realistically about as normalized as we can get anyway?
979
+ // To allow things like `*mut (?A, ?T)` <-> `*mut (?B, ?T)`,
980
+ // it's fine to get a projection as the type.
998
981
Value :: Cast { kind : CastKind :: PtrToPtr , value : inner, from, to }
999
- if from
1000
- . builtin_deref ( true )
1001
- . unwrap ( )
1002
- . ptr_metadata_ty_or_tail ( self . tcx , |t| t)
1003
- == to
1004
- . builtin_deref ( true )
1005
- . unwrap ( )
1006
- . ptr_metadata_ty_or_tail ( self . tcx , |t| t) =>
982
+ if self . pointers_have_same_metadata ( * from, * to) =>
1007
983
{
1008
984
arg_index = * inner;
1009
985
was_updated = true ;
@@ -1068,6 +1044,52 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
1068
1044
1069
1045
#[ instrument( level = "trace" , skip( self ) , ret) ]
1070
1046
fn simplify_binary (
1047
+ & mut self ,
1048
+ op : BinOp ,
1049
+ lhs_operand : & mut Operand < ' tcx > ,
1050
+ rhs_operand : & mut Operand < ' tcx > ,
1051
+ location : Location ,
1052
+ ) -> Option < VnIndex > {
1053
+ let lhs = self . simplify_operand ( lhs_operand, location) ;
1054
+ let rhs = self . simplify_operand ( rhs_operand, location) ;
1055
+ // Only short-circuit options after we called `simplify_operand`
1056
+ // on both operands for side effect.
1057
+ let mut lhs = lhs?;
1058
+ let mut rhs = rhs?;
1059
+
1060
+ let lhs_ty = lhs_operand. ty ( self . local_decls , self . tcx ) ;
1061
+
1062
+ // If we're comparing pointers, remove `PtrToPtr` casts if the from
1063
+ // types of both casts and the metadata all match.
1064
+ if let BinOp :: Eq | BinOp :: Ne | BinOp :: Lt | BinOp :: Le | BinOp :: Gt | BinOp :: Ge = op
1065
+ && lhs_ty. is_any_ptr ( )
1066
+ && let Value :: Cast {
1067
+ kind : CastKind :: PtrToPtr , value : lhs_value, from : lhs_from, ..
1068
+ } = self . get ( lhs)
1069
+ && let Value :: Cast {
1070
+ kind : CastKind :: PtrToPtr , value : rhs_value, from : rhs_from, ..
1071
+ } = self . get ( rhs)
1072
+ && lhs_from == rhs_from
1073
+ && self . pointers_have_same_metadata ( * lhs_from, lhs_ty)
1074
+ {
1075
+ lhs = * lhs_value;
1076
+ rhs = * rhs_value;
1077
+ if let Some ( op) = self . try_as_operand ( lhs, location) {
1078
+ * lhs_operand = op;
1079
+ }
1080
+ if let Some ( op) = self . try_as_operand ( rhs, location) {
1081
+ * rhs_operand = op;
1082
+ }
1083
+ }
1084
+
1085
+ if let Some ( value) = self . simplify_binary_inner ( op, lhs_ty, lhs, rhs) {
1086
+ return Some ( value) ;
1087
+ }
1088
+ let value = Value :: BinaryOp ( op, lhs, rhs) ;
1089
+ Some ( self . insert ( value) )
1090
+ }
1091
+
1092
+ fn simplify_binary_inner (
1071
1093
& mut self ,
1072
1094
op : BinOp ,
1073
1095
lhs_ty : Ty < ' tcx > ,
@@ -1228,14 +1250,33 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
1228
1250
}
1229
1251
}
1230
1252
1253
+ // PtrToPtr-then-PtrToPtr can skip the intermediate step
1231
1254
if let PtrToPtr = kind
1232
1255
&& let Value :: Cast { kind : inner_kind, value : inner_value, from : inner_from, to : _ } =
1233
1256
* self . get ( value)
1234
1257
&& let PtrToPtr = inner_kind
1235
1258
{
1236
1259
from = inner_from;
1237
1260
value = inner_value;
1238
- * kind = PtrToPtr ;
1261
+ was_updated = true ;
1262
+ if inner_from == to {
1263
+ return Some ( inner_value) ;
1264
+ }
1265
+ }
1266
+
1267
+ // PtrToPtr-then-Transmute can just transmute the original, so long as the
1268
+ // PtrToPtr didn't change metadata (and thus the size of the pointer)
1269
+ if let Transmute = kind
1270
+ && let Value :: Cast {
1271
+ kind : PtrToPtr ,
1272
+ value : inner_value,
1273
+ from : inner_from,
1274
+ to : inner_to,
1275
+ } = * self . get ( value)
1276
+ && self . pointers_have_same_metadata ( inner_from, inner_to)
1277
+ {
1278
+ from = inner_from;
1279
+ value = inner_value;
1239
1280
was_updated = true ;
1240
1281
if inner_from == to {
1241
1282
return Some ( inner_value) ;
@@ -1289,6 +1330,21 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
1289
1330
// Fallback: a symbolic `Len`.
1290
1331
Some ( self . insert ( Value :: Len ( inner) ) )
1291
1332
}
1333
+
1334
+ fn pointers_have_same_metadata ( & self , left_ptr_ty : Ty < ' tcx > , right_ptr_ty : Ty < ' tcx > ) -> bool {
1335
+ let left_meta_ty = left_ptr_ty. pointee_metadata_ty_or_projection ( self . tcx ) ;
1336
+ let right_meta_ty = right_ptr_ty. pointee_metadata_ty_or_projection ( self . tcx ) ;
1337
+ if left_meta_ty == right_meta_ty {
1338
+ true
1339
+ } else if let Ok ( left) =
1340
+ self . tcx . try_normalize_erasing_regions ( self . param_env , left_meta_ty)
1341
+ && let Ok ( right) = self . tcx . try_normalize_erasing_regions ( self . param_env , right_meta_ty)
1342
+ {
1343
+ left == right
1344
+ } else {
1345
+ false
1346
+ }
1347
+ }
1292
1348
}
1293
1349
1294
1350
fn op_to_prop_const < ' tcx > (
0 commit comments