11use rustc_middle:: mir:: interpret:: ErrorHandled ;
22use rustc_middle:: ty:: layout:: HasTyCtxt ;
3- use rustc_middle:: ty:: { self , Ty } ;
3+ use rustc_middle:: ty:: { self , Ty , ValTree } ;
44use rustc_middle:: { bug, mir, span_bug} ;
55use rustc_target:: abi:: Abi ;
66
@@ -28,7 +28,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
2828 . expect ( "erroneous constant missed by mono item collection" )
2929 }
3030
31- /// This is a convenience helper for `simd_shuffle_indices `. It has the precondition
31+ /// This is a convenience helper for `immediate_const_vector `. It has the precondition
3232 /// that the given `constant` is an `Const::Unevaluated` and must be convertible to
3333 /// a `ValTree`. If you want a more general version of this, talk to `wg-const-eval` on zulip.
3434 ///
@@ -59,23 +59,42 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
5959 self . cx . tcx ( ) . const_eval_resolve_for_typeck ( ty:: ParamEnv :: reveal_all ( ) , uv, constant. span )
6060 }
6161
62- /// process constant containing SIMD shuffle indices
63- pub fn simd_shuffle_indices (
62+ /// process constant containing SIMD shuffle indices & constant vectors
63+ pub fn immediate_const_vector (
6464 & mut self ,
6565 bx : & Bx ,
6666 constant : & mir:: ConstOperand < ' tcx > ,
6767 ) -> ( Bx :: Value , Ty < ' tcx > ) {
6868 let ty = self . monomorphize ( constant. ty ( ) ) ;
69+ let ty_is_simd = ty. is_simd ( ) ;
70+ // FIXME: ideally we'd assert that this is a SIMD type, but simd_shuffle
71+ // in its current form relies on a regular array being passed as an
72+ // immediate argument. This hack can be removed once that is fixed.
73+ let field_ty = if ty_is_simd {
74+ ty. simd_size_and_type ( bx. tcx ( ) ) . 1
75+ } else {
76+ ty. builtin_index ( ) . unwrap ( )
77+ } ;
78+
6979 let val = self
7080 . eval_unevaluated_mir_constant_to_valtree ( constant)
7181 . ok ( )
7282 . map ( |x| x. ok ( ) )
7383 . flatten ( )
7484 . map ( |val| {
75- let field_ty = ty. builtin_index ( ) . unwrap ( ) ;
76- let values: Vec < _ > = val
77- . unwrap_branch ( )
78- . iter ( )
85+ // Depending on whether this is a SIMD type with an array field
86+ // or a type with many fields (one for each elements), the valtree
87+ // is either a single branch with N children, or a root node
88+ // with exactly one child which then in turn has many children.
89+ // So we look at the first child to determine whether it is a
90+ // leaf or whether we have to go one more layer down.
91+ let branch_or_leaf = val. unwrap_branch ( ) ;
92+ let first = branch_or_leaf. get ( 0 ) . unwrap ( ) ;
93+ let field_iter = match first {
94+ ValTree :: Branch ( _) => first. unwrap_branch ( ) . iter ( ) ,
95+ ValTree :: Leaf ( _) => branch_or_leaf. iter ( ) ,
96+ } ;
97+ let values: Vec < _ > = field_iter
7998 . map ( |field| {
8099 if let Some ( prim) = field. try_to_scalar ( ) {
81100 let layout = bx. layout_of ( field_ty) ;
@@ -84,11 +103,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
84103 } ;
85104 bx. scalar_to_backend ( prim, scalar, bx. immediate_backend_type ( layout) )
86105 } else {
87- bug ! ( "simd shuffle field {:?}" , field)
106+ bug ! ( "field is not a scalar {:?}" , field)
88107 }
89108 } )
90109 . collect ( ) ;
91- bx. const_struct ( & values, false )
110+ if ty_is_simd { bx. const_vector ( & values ) } else { bx . const_struct ( & values, false ) }
92111 } )
93112 . unwrap_or_else ( || {
94113 bx. tcx ( ) . dcx ( ) . emit_err ( errors:: ShuffleIndicesEvaluation { span : constant. span } ) ;
0 commit comments