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 ) ]
@@ -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 {
@@ -862,10 +879,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
862
879
rvalue : & mut Rvalue < ' tcx > ,
863
880
location : Location ,
864
881
) -> Option < VnIndex > {
865
- let Rvalue :: Aggregate ( box ref kind, ref mut fields ) = * rvalue else { bug ! ( ) } ;
882
+ let Rvalue :: Aggregate ( box ref kind, ref mut field_ops ) = * rvalue else { bug ! ( ) } ;
866
883
867
884
let tcx = self . tcx ;
868
- if fields . is_empty ( ) {
885
+ if field_ops . is_empty ( ) {
869
886
let is_zst = match * kind {
870
887
AggregateKind :: Array ( ..)
871
888
| AggregateKind :: Tuple
@@ -884,13 +901,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
884
901
}
885
902
}
886
903
887
- let ( ty, variant_index) = match * kind {
904
+ let ( mut ty, variant_index) = match * kind {
888
905
AggregateKind :: Array ( ..) => {
889
- assert ! ( !fields . is_empty( ) ) ;
906
+ assert ! ( !field_ops . is_empty( ) ) ;
890
907
( AggregateTy :: Array , FIRST_VARIANT )
891
908
}
892
909
AggregateKind :: Tuple => {
893
- assert ! ( !fields . is_empty( ) ) ;
910
+ assert ! ( !field_ops . is_empty( ) ) ;
894
911
( AggregateTy :: Tuple , FIRST_VARIANT )
895
912
}
896
913
AggregateKind :: Closure ( did, args)
@@ -901,15 +918,49 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
901
918
}
902
919
// Do not track unions.
903
920
AggregateKind :: Adt ( _, _, _, _, Some ( _) ) => return None ,
904
- // FIXME: Do the extra work to GVN `from_raw_parts`
905
- AggregateKind :: RawPtr ( ..) => return None ,
921
+ AggregateKind :: RawPtr ( pointee_ty, mtbl) => {
922
+ assert_eq ! ( field_ops. len( ) , 2 ) ;
923
+ let data_pointer_ty = field_ops[ FieldIdx :: ZERO ] . ty ( self . local_decls , self . tcx ) ;
924
+ let output_pointer_ty = Ty :: new_ptr ( self . tcx , pointee_ty, mtbl) ;
925
+ ( AggregateTy :: RawPtr { data_pointer_ty, output_pointer_ty } , FIRST_VARIANT )
926
+ }
906
927
} ;
907
928
908
- let fields: Option < Vec < _ > > = fields
929
+ let fields: Option < Vec < _ > > = field_ops
909
930
. iter_mut ( )
910
931
. map ( |op| self . simplify_operand ( op, location) . or_else ( || self . new_opaque ( ) ) )
911
932
. collect ( ) ;
912
- let fields = fields?;
933
+ let mut fields = fields?;
934
+
935
+ if let AggregateTy :: RawPtr { data_pointer_ty, output_pointer_ty } = & mut ty {
936
+ let mut was_updated = false ;
937
+
938
+ // Any thin pointer of matching mutability is fine as the data pointer.
939
+ while let Value :: Cast {
940
+ kind : CastKind :: PtrToPtr ,
941
+ value : cast_value,
942
+ from : cast_from,
943
+ to : _,
944
+ } = self . get ( fields[ 0 ] )
945
+ && let ty:: RawPtr ( from_pointee_ty, from_mtbl) = cast_from. kind ( )
946
+ && let ty:: RawPtr ( _, output_mtbl) = output_pointer_ty. kind ( )
947
+ && from_mtbl == output_mtbl
948
+ && from_pointee_ty. is_sized ( self . tcx , self . param_env )
949
+ {
950
+ fields[ 0 ] = * cast_value;
951
+ * data_pointer_ty = * cast_from;
952
+ was_updated = true ;
953
+ }
954
+
955
+ if was_updated {
956
+ if let Some ( const_) = self . try_as_constant ( fields[ 0 ] ) {
957
+ field_ops[ FieldIdx :: ZERO ] = Operand :: Constant ( Box :: new ( const_) ) ;
958
+ } else if let Some ( local) = self . try_as_local ( fields[ 0 ] , location) {
959
+ field_ops[ FieldIdx :: ZERO ] = Operand :: Copy ( Place :: from ( local) ) ;
960
+ self . reused_locals . insert ( local) ;
961
+ }
962
+ }
963
+ }
913
964
914
965
if let AggregateTy :: Array = ty
915
966
&& fields. len ( ) > 4
@@ -941,6 +992,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
941
992
( UnOp :: Not , Value :: BinaryOp ( BinOp :: Ne , lhs, rhs) ) => {
942
993
Value :: BinaryOp ( BinOp :: Eq , * lhs, * rhs)
943
994
}
995
+ ( UnOp :: PtrMetadata , Value :: Aggregate ( AggregateTy :: RawPtr { .. } , _, fields) ) => {
996
+ return Some ( fields[ 1 ] ) ;
997
+ }
944
998
_ => return None ,
945
999
} ;
946
1000
@@ -1092,6 +1146,23 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
1092
1146
return self . new_opaque ( ) ;
1093
1147
}
1094
1148
1149
+ let mut was_updated = false ;
1150
+
1151
+ // If that cast just casts away the metadata again,
1152
+ if let PtrToPtr = kind
1153
+ && let Value :: Aggregate ( AggregateTy :: RawPtr { data_pointer_ty, .. } , _, fields) =
1154
+ self . get ( value)
1155
+ && let ty:: RawPtr ( to_pointee, _) = to. kind ( )
1156
+ && to_pointee. is_sized ( self . tcx , self . param_env )
1157
+ {
1158
+ from = * data_pointer_ty;
1159
+ value = fields[ 0 ] ;
1160
+ was_updated = true ;
1161
+ if * data_pointer_ty == to {
1162
+ return Some ( fields[ 0 ] ) ;
1163
+ }
1164
+ }
1165
+
1095
1166
if let PtrToPtr | PointerCoercion ( MutToConstPointer ) = kind
1096
1167
&& let Value :: Cast { kind : inner_kind, value : inner_value, from : inner_from, to : _ } =
1097
1168
* self . get ( value)
@@ -1100,9 +1171,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
1100
1171
from = inner_from;
1101
1172
value = inner_value;
1102
1173
* kind = PtrToPtr ;
1174
+ was_updated = true ;
1103
1175
if inner_from == to {
1104
1176
return Some ( inner_value) ;
1105
1177
}
1178
+ }
1179
+
1180
+ if was_updated {
1106
1181
if let Some ( const_) = self . try_as_constant ( value) {
1107
1182
* operand = Operand :: Constant ( Box :: new ( const_) ) ;
1108
1183
} else if let Some ( local) = self . try_as_local ( value, location) {
0 commit comments