83
83
//! that contain `AllocId`s.
84
84
85
85
use rustc_const_eval:: const_eval:: DummyMachine ;
86
- use rustc_const_eval:: interpret:: { intern_const_alloc_for_constprop, MemoryKind } ;
87
- use rustc_const_eval:: interpret:: { ImmTy , InterpCx , OpTy , Projectable , Scalar } ;
86
+ use rustc_const_eval:: interpret:: { intern_const_alloc_for_constprop, MemPlaceMeta , MemoryKind } ;
87
+ use rustc_const_eval:: interpret:: { ImmTy , Immediate , InterpCx , OpTy , Projectable , Scalar } ;
88
88
use rustc_data_structures:: fx:: FxIndexSet ;
89
89
use rustc_data_structures:: graph:: dominators:: Dominators ;
90
90
use rustc_hir:: def:: DefKind ;
@@ -99,7 +99,7 @@ use rustc_middle::ty::layout::{HasParamEnv, LayoutOf};
99
99
use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
100
100
use rustc_span:: def_id:: DefId ;
101
101
use rustc_span:: DUMMY_SP ;
102
- use rustc_target:: abi:: { self , Abi , Size , VariantIdx , FIRST_VARIANT } ;
102
+ use rustc_target:: abi:: { self , Abi , FieldIdx , Size , VariantIdx , FIRST_VARIANT } ;
103
103
use smallvec:: SmallVec ;
104
104
use std:: borrow:: Cow ;
105
105
@@ -177,6 +177,12 @@ enum AggregateTy<'tcx> {
177
177
Array ,
178
178
Tuple ,
179
179
Def ( DefId , ty:: GenericArgsRef < ' tcx > ) ,
180
+ RawPtr {
181
+ /// Needed for cast propagation.
182
+ data_pointer_ty : Ty < ' tcx > ,
183
+ /// The data pointer can be anything thin, so doesn't determine the output.
184
+ output_pointer_ty : Ty < ' tcx > ,
185
+ } ,
180
186
}
181
187
182
188
#[ derive( Copy , Clone , Debug , PartialEq , Eq , Hash ) ]
@@ -385,11 +391,22 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
385
391
AggregateTy :: Def ( def_id, args) => {
386
392
self . tcx . type_of ( def_id) . instantiate ( self . tcx , args)
387
393
}
394
+ AggregateTy :: RawPtr { output_pointer_ty, .. } => output_pointer_ty,
388
395
} ;
389
396
let variant = if ty. is_enum ( ) { Some ( variant) } else { None } ;
390
397
let ty = self . ecx . layout_of ( ty) . ok ( ) ?;
391
398
if ty. is_zst ( ) {
392
399
ImmTy :: uninit ( ty) . into ( )
400
+ } else if matches ! ( kind, AggregateTy :: RawPtr { .. } ) {
401
+ // Pointers don't have fields, so don't `project_field` them.
402
+ let data = self . ecx . read_pointer ( fields[ 0 ] ) . ok ( ) ?;
403
+ let meta = if fields[ 1 ] . layout . is_zst ( ) {
404
+ MemPlaceMeta :: None
405
+ } else {
406
+ MemPlaceMeta :: Meta ( self . ecx . read_scalar ( fields[ 1 ] ) . ok ( ) ?)
407
+ } ;
408
+ let ptr_imm = Immediate :: new_pointer_with_meta ( data, meta, & self . ecx ) ;
409
+ ImmTy :: from_immediate ( ptr_imm, ty) . into ( )
393
410
} else if matches ! ( ty. abi, Abi :: Scalar ( ..) | Abi :: ScalarPair ( ..) ) {
394
411
let dest = self . ecx . allocate ( ty, MemoryKind :: Stack ) . ok ( ) ?;
395
412
let variant_dest = if let Some ( variant) = variant {
@@ -864,10 +881,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
864
881
rvalue : & mut Rvalue < ' tcx > ,
865
882
location : Location ,
866
883
) -> Option < VnIndex > {
867
- let Rvalue :: Aggregate ( box ref kind, ref mut fields ) = * rvalue else { bug ! ( ) } ;
884
+ let Rvalue :: Aggregate ( box ref kind, ref mut field_ops ) = * rvalue else { bug ! ( ) } ;
868
885
869
886
let tcx = self . tcx ;
870
- if fields . is_empty ( ) {
887
+ if field_ops . is_empty ( ) {
871
888
let is_zst = match * kind {
872
889
AggregateKind :: Array ( ..)
873
890
| AggregateKind :: Tuple
@@ -886,13 +903,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
886
903
}
887
904
}
888
905
889
- let ( ty, variant_index) = match * kind {
906
+ let ( mut ty, variant_index) = match * kind {
890
907
AggregateKind :: Array ( ..) => {
891
- assert ! ( !fields . is_empty( ) ) ;
908
+ assert ! ( !field_ops . is_empty( ) ) ;
892
909
( AggregateTy :: Array , FIRST_VARIANT )
893
910
}
894
911
AggregateKind :: Tuple => {
895
- assert ! ( !fields . is_empty( ) ) ;
912
+ assert ! ( !field_ops . is_empty( ) ) ;
896
913
( AggregateTy :: Tuple , FIRST_VARIANT )
897
914
}
898
915
AggregateKind :: Closure ( did, args)
@@ -903,15 +920,49 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
903
920
}
904
921
// Do not track unions.
905
922
AggregateKind :: Adt ( _, _, _, _, Some ( _) ) => return None ,
906
- // FIXME: Do the extra work to GVN `from_raw_parts`
907
- AggregateKind :: RawPtr ( ..) => return None ,
923
+ AggregateKind :: RawPtr ( pointee_ty, mtbl) => {
924
+ assert_eq ! ( field_ops. len( ) , 2 ) ;
925
+ let data_pointer_ty = field_ops[ FieldIdx :: ZERO ] . ty ( self . local_decls , self . tcx ) ;
926
+ let output_pointer_ty = Ty :: new_ptr ( self . tcx , pointee_ty, mtbl) ;
927
+ ( AggregateTy :: RawPtr { data_pointer_ty, output_pointer_ty } , FIRST_VARIANT )
928
+ }
908
929
} ;
909
930
910
- let fields: Option < Vec < _ > > = fields
931
+ let fields: Option < Vec < _ > > = field_ops
911
932
. iter_mut ( )
912
933
. map ( |op| self . simplify_operand ( op, location) . or_else ( || self . new_opaque ( ) ) )
913
934
. collect ( ) ;
914
- let fields = fields?;
935
+ let mut fields = fields?;
936
+
937
+ if let AggregateTy :: RawPtr { data_pointer_ty, output_pointer_ty } = & mut ty {
938
+ let mut was_updated = false ;
939
+
940
+ // Any thin pointer of matching mutability is fine as the data pointer.
941
+ while let Value :: Cast {
942
+ kind : CastKind :: PtrToPtr ,
943
+ value : cast_value,
944
+ from : cast_from,
945
+ to : _,
946
+ } = self . get ( fields[ 0 ] )
947
+ && let ty:: RawPtr ( from_pointee_ty, from_mtbl) = cast_from. kind ( )
948
+ && let ty:: RawPtr ( _, output_mtbl) = output_pointer_ty. kind ( )
949
+ && from_mtbl == output_mtbl
950
+ && from_pointee_ty. is_sized ( self . tcx , self . param_env )
951
+ {
952
+ fields[ 0 ] = * cast_value;
953
+ * data_pointer_ty = * cast_from;
954
+ was_updated = true ;
955
+ }
956
+
957
+ if was_updated {
958
+ if let Some ( const_) = self . try_as_constant ( fields[ 0 ] ) {
959
+ field_ops[ FieldIdx :: ZERO ] = Operand :: Constant ( Box :: new ( const_) ) ;
960
+ } else if let Some ( local) = self . try_as_local ( fields[ 0 ] , location) {
961
+ field_ops[ FieldIdx :: ZERO ] = Operand :: Copy ( Place :: from ( local) ) ;
962
+ self . reused_locals . insert ( local) ;
963
+ }
964
+ }
965
+ }
915
966
916
967
if let AggregateTy :: Array = ty
917
968
&& fields. len ( ) > 4
@@ -943,6 +994,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
943
994
( UnOp :: Not , Value :: BinaryOp ( BinOp :: Ne , lhs, rhs) ) => {
944
995
Value :: BinaryOp ( BinOp :: Eq , * lhs, * rhs)
945
996
}
997
+ ( UnOp :: PtrMetadata , Value :: Aggregate ( AggregateTy :: RawPtr { .. } , _, fields) ) => {
998
+ return Some ( fields[ 1 ] ) ;
999
+ }
946
1000
_ => return None ,
947
1001
} ;
948
1002
@@ -1094,6 +1148,23 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
1094
1148
return self . new_opaque ( ) ;
1095
1149
}
1096
1150
1151
+ let mut was_updated = false ;
1152
+
1153
+ // If that cast just casts away the metadata again,
1154
+ if let PtrToPtr = kind
1155
+ && let Value :: Aggregate ( AggregateTy :: RawPtr { data_pointer_ty, .. } , _, fields) =
1156
+ self . get ( value)
1157
+ && let ty:: RawPtr ( to_pointee, _) = to. kind ( )
1158
+ && to_pointee. is_sized ( self . tcx , self . param_env )
1159
+ {
1160
+ from = * data_pointer_ty;
1161
+ value = fields[ 0 ] ;
1162
+ was_updated = true ;
1163
+ if * data_pointer_ty == to {
1164
+ return Some ( fields[ 0 ] ) ;
1165
+ }
1166
+ }
1167
+
1097
1168
if let PtrToPtr | PointerCoercion ( MutToConstPointer ) = kind
1098
1169
&& let Value :: Cast { kind : inner_kind, value : inner_value, from : inner_from, to : _ } =
1099
1170
* self . get ( value)
@@ -1102,9 +1173,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
1102
1173
from = inner_from;
1103
1174
value = inner_value;
1104
1175
* kind = PtrToPtr ;
1176
+ was_updated = true ;
1105
1177
if inner_from == to {
1106
1178
return Some ( inner_value) ;
1107
1179
}
1180
+ }
1181
+
1182
+ if was_updated {
1108
1183
if let Some ( const_) = self . try_as_constant ( value) {
1109
1184
* operand = Operand :: Constant ( Box :: new ( const_) ) ;
1110
1185
} else if let Some ( local) = self . try_as_local ( value, location) {
0 commit comments