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::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 ) ]
@@ -386,11 +392,22 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
386
392
AggregateTy :: Def ( def_id, args) => {
387
393
self . tcx . type_of ( def_id) . instantiate ( self . tcx , args)
388
394
}
395
+ AggregateTy :: RawPtr { output_pointer_ty, .. } => output_pointer_ty,
389
396
} ;
390
397
let variant = if ty. is_enum ( ) { Some ( variant) } else { None } ;
391
398
let ty = self . ecx . layout_of ( ty) . ok ( ) ?;
392
399
if ty. is_zst ( ) {
393
400
ImmTy :: uninit ( ty) . into ( )
401
+ } else if matches ! ( kind, AggregateTy :: RawPtr { .. } ) {
402
+ // Pointers don't have fields, so don't `project_field` them.
403
+ let data = self . ecx . read_pointer ( fields[ 0 ] ) . ok ( ) ?;
404
+ let meta = if fields[ 1 ] . layout . is_zst ( ) {
405
+ MemPlaceMeta :: None
406
+ } else {
407
+ MemPlaceMeta :: Meta ( self . ecx . read_scalar ( fields[ 1 ] ) . ok ( ) ?)
408
+ } ;
409
+ let ptr_imm = Immediate :: new_pointer_with_meta ( data, meta, & self . ecx ) ;
410
+ ImmTy :: from_immediate ( ptr_imm, ty) . into ( )
394
411
} else if matches ! ( ty. abi, Abi :: Scalar ( ..) | Abi :: ScalarPair ( ..) ) {
395
412
let dest = self . ecx . allocate ( ty, MemoryKind :: Stack ) . ok ( ) ?;
396
413
let variant_dest = if let Some ( variant) = variant {
@@ -881,10 +898,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
881
898
rvalue : & mut Rvalue < ' tcx > ,
882
899
location : Location ,
883
900
) -> Option < VnIndex > {
884
- let Rvalue :: Aggregate ( box ref kind, ref mut fields ) = * rvalue else { bug ! ( ) } ;
901
+ let Rvalue :: Aggregate ( box ref kind, ref mut field_ops ) = * rvalue else { bug ! ( ) } ;
885
902
886
903
let tcx = self . tcx ;
887
- if fields . is_empty ( ) {
904
+ if field_ops . is_empty ( ) {
888
905
let is_zst = match * kind {
889
906
AggregateKind :: Array ( ..)
890
907
| AggregateKind :: Tuple
@@ -905,11 +922,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
905
922
906
923
let ( ty, variant_index) = match * kind {
907
924
AggregateKind :: Array ( ..) => {
908
- assert ! ( !fields . is_empty( ) ) ;
925
+ assert ! ( !field_ops . is_empty( ) ) ;
909
926
( AggregateTy :: Array , FIRST_VARIANT )
910
927
}
911
928
AggregateKind :: Tuple => {
912
- assert ! ( !fields . is_empty( ) ) ;
929
+ assert ! ( !field_ops . is_empty( ) ) ;
913
930
( AggregateTy :: Tuple , FIRST_VARIANT )
914
931
}
915
932
AggregateKind :: Closure ( did, args)
@@ -920,15 +937,40 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
920
937
}
921
938
// Do not track unions.
922
939
AggregateKind :: Adt ( _, _, _, _, Some ( _) ) => return None ,
923
- // FIXME: Do the extra work to GVN `from_raw_parts`
924
- AggregateKind :: RawPtr ( ..) => return None ,
940
+ AggregateKind :: RawPtr ( pointee_ty, mtbl) => {
941
+ assert_eq ! ( field_ops. len( ) , 2 ) ;
942
+ let data_pointer_ty = field_ops[ FieldIdx :: ZERO ] . ty ( self . local_decls , self . tcx ) ;
943
+ let output_pointer_ty = Ty :: new_ptr ( self . tcx , pointee_ty, mtbl) ;
944
+ ( AggregateTy :: RawPtr { data_pointer_ty, output_pointer_ty } , FIRST_VARIANT )
945
+ }
925
946
} ;
926
947
927
- let fields: Option < Vec < _ > > = fields
948
+ let fields: Option < Vec < _ > > = field_ops
928
949
. iter_mut ( )
929
950
. map ( |op| self . simplify_operand ( op, location) . or_else ( || self . new_opaque ( ) ) )
930
951
. collect ( ) ;
931
- let fields = fields?;
952
+ let mut fields = fields?;
953
+
954
+ if let AggregateTy :: RawPtr { output_pointer_ty, .. } = ty {
955
+ let mut was_updated = false ;
956
+
957
+ // Any thin pointer of matching mutability is fine as the data pointer.
958
+ while let Value :: Cast { kind, value : cast_value, from : cast_from, to : _ } = self . get ( fields[ 0 ] )
959
+ && matches ! ( kind, CastKind :: PtrToPtr | CastKind :: PointerCoercion ( ty:: adjustment:: PointerCoercion :: ArrayToPointer ) )
960
+ && let ty:: RawPtr ( from_pointee_ty, from_mtbl) = cast_from. kind ( )
961
+ && let ty:: RawPtr ( _, output_mtbl) = output_pointer_ty. kind ( )
962
+ && from_mtbl == output_mtbl
963
+ && from_pointee_ty. is_sized ( self . tcx , self . param_env )
964
+ {
965
+ fields[ 0 ] = * cast_value;
966
+ was_updated = true ;
967
+ }
968
+
969
+ if was_updated && let Some ( local) = self . try_as_local ( fields[ 0 ] , location) {
970
+ field_ops[ FieldIdx :: ZERO ] = Operand :: Copy ( Place :: from ( local) ) ;
971
+ self . reused_locals . insert ( local) ;
972
+ }
973
+ }
932
974
933
975
if let AggregateTy :: Array = ty
934
976
&& fields. len ( ) > 4
@@ -960,6 +1002,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
960
1002
( UnOp :: Not , Value :: BinaryOp ( BinOp :: Ne , lhs, rhs) ) => {
961
1003
Value :: BinaryOp ( BinOp :: Eq , * lhs, * rhs)
962
1004
}
1005
+ ( UnOp :: PtrMetadata , Value :: Aggregate ( AggregateTy :: RawPtr { .. } , _, fields) ) => {
1006
+ return Some ( fields[ 1 ] ) ;
1007
+ }
963
1008
_ => return None ,
964
1009
} ;
965
1010
@@ -1082,6 +1127,22 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
1082
1127
return self . new_opaque ( ) ;
1083
1128
}
1084
1129
1130
+ let mut was_updated = false ;
1131
+
1132
+ // If that cast just casts away the metadata again,
1133
+ if let PtrToPtr = kind
1134
+ && let Value :: Aggregate ( AggregateTy :: RawPtr { data_pointer_ty, .. } , _, fields) = self . get ( value)
1135
+ && let ty:: RawPtr ( to_pointee, _) = to. kind ( )
1136
+ && to_pointee. is_sized ( self . tcx , self . param_env )
1137
+ {
1138
+ from = * data_pointer_ty;
1139
+ value = fields[ 0 ] ;
1140
+ was_updated = true ;
1141
+ if * data_pointer_ty == to {
1142
+ return Some ( fields[ 0 ] ) ;
1143
+ }
1144
+ }
1145
+
1085
1146
if let PtrToPtr | PointerCoercion ( MutToConstPointer ) = kind
1086
1147
&& let Value :: Cast { kind : inner_kind, value : inner_value, from : inner_from, to : _ } =
1087
1148
* self . get ( value)
@@ -1090,9 +1151,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
1090
1151
from = inner_from;
1091
1152
value = inner_value;
1092
1153
* kind = PtrToPtr ;
1154
+ was_updated = true ;
1093
1155
if inner_from == to {
1094
1156
return Some ( inner_value) ;
1095
1157
}
1158
+ }
1159
+
1160
+ if was_updated {
1096
1161
if let Some ( const_) = self . try_as_constant ( value) {
1097
1162
* operand = Operand :: Constant ( Box :: new ( const_) ) ;
1098
1163
} else if let Some ( local) = self . try_as_local ( value, location) {
0 commit comments