@@ -19,7 +19,7 @@ use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf};
1919use rustc_middle:: ty:: { self , Ty } ;
2020use rustc_middle:: { bug, span_bug} ;
2121use rustc_span:: { sym, symbol:: kw, Span , Symbol } ;
22- use rustc_target:: abi:: { self , HasDataLayout , Primitive } ;
22+ use rustc_target:: abi:: { self , Align , HasDataLayout , Primitive } ;
2323use rustc_target:: spec:: { HasTargetSpec , PanicStrategy } ;
2424
2525use std:: cmp:: Ordering ;
@@ -857,28 +857,39 @@ fn generic_simd_intrinsic(
857857 let arg_tys = sig. inputs ( ) ;
858858
859859 if name == sym:: simd_select_bitmask {
860- let in_ty = arg_tys[ 0 ] ;
861- let m_len = match in_ty. kind ( ) {
862- // Note that this `.unwrap()` crashes for isize/usize, that's sort
863- // of intentional as there's not currently a use case for that.
864- ty:: Int ( i) => i. bit_width ( ) . unwrap ( ) ,
865- ty:: Uint ( i) => i. bit_width ( ) . unwrap ( ) ,
866- _ => return_error ! ( "`{}` is not an integral type" , in_ty) ,
867- } ;
868860 require_simd ! ( arg_tys[ 1 ] , "argument" ) ;
869- let ( v_len, _) = arg_tys[ 1 ] . simd_size_and_type ( bx. tcx ( ) ) ;
870- require ! (
871- // Allow masks for vectors with fewer than 8 elements to be
872- // represented with a u8 or i8.
873- m_len == v_len || ( m_len == 8 && v_len < 8 ) ,
874- "mismatched lengths: mask length `{}` != other vector length `{}`" ,
875- m_len,
876- v_len
877- ) ;
861+ let ( len, _) = arg_tys[ 1 ] . simd_size_and_type ( bx. tcx ( ) ) ;
862+
863+ let expected_int_bits = ( len. max ( 8 ) - 1 ) . next_power_of_two ( ) ;
864+ let expected_bytes = len / 8 + ( ( len % 8 > 0 ) as u64 ) ;
865+
866+ let mask_ty = arg_tys[ 0 ] ;
867+ let mask = match mask_ty. kind ( ) {
868+ ty:: Int ( i) if i. bit_width ( ) == Some ( expected_int_bits) => args[ 0 ] . immediate ( ) ,
869+ ty:: Uint ( i) if i. bit_width ( ) == Some ( expected_int_bits) => args[ 0 ] . immediate ( ) ,
870+ ty:: Array ( elem, len)
871+ if matches ! ( elem. kind( ) , ty:: Uint ( ty:: UintTy :: U8 ) )
872+ && len. try_eval_usize ( bx. tcx , ty:: ParamEnv :: reveal_all ( ) )
873+ == Some ( expected_bytes) =>
874+ {
875+ let place = PlaceRef :: alloca ( bx, args[ 0 ] . layout ) ;
876+ args[ 0 ] . val . store ( bx, place) ;
877+ let int_ty = bx. type_ix ( expected_bytes * 8 ) ;
878+ let ptr = bx. pointercast ( place. llval , bx. cx . type_ptr_to ( int_ty) ) ;
879+ bx. load ( int_ty, ptr, Align :: ONE )
880+ }
881+ _ => return_error ! (
882+ "invalid bitmask `{}`, expected `u{}` or `[u8; {}]`" ,
883+ mask_ty,
884+ expected_int_bits,
885+ expected_bytes
886+ ) ,
887+ } ;
888+
878889 let i1 = bx. type_i1 ( ) ;
879- let im = bx. type_ix ( v_len ) ;
880- let i1xn = bx. type_vector ( i1, v_len ) ;
881- let m_im = bx. trunc ( args [ 0 ] . immediate ( ) , im) ;
890+ let im = bx. type_ix ( len ) ;
891+ let i1xn = bx. type_vector ( i1, len ) ;
892+ let m_im = bx. trunc ( mask , im) ;
882893 let m_i1s = bx. bitcast ( m_im, i1xn) ;
883894 return Ok ( bx. select ( m_i1s, args[ 1 ] . immediate ( ) , args[ 2 ] . immediate ( ) ) ) ;
884895 }
@@ -1056,16 +1067,16 @@ fn generic_simd_intrinsic(
10561067
10571068 if name == sym:: simd_bitmask {
10581069 // The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a
1059- // vector mask and returns an unsigned integer containing the most
1060- // significant bit (MSB) of each lane.
1061-
1062- // If the vector has less than 8 lanes, a u8 is returned with zeroed
1063- // trailing bits.
1070+ // vector mask and returns the most significant bit (MSB) of each lane in the form
1071+ // of either:
1072+ // * an unsigned integer
1073+ // * an array of `u8`
1074+ // If the vector has less than 8 lanes, a u8 is returned with zeroed trailing bits.
1075+ //
1076+ // The bit order of the result depends on the byte endianness, LSB-first for little
1077+ // endian and MSB-first for big endian.
10641078 let expected_int_bits = in_len. max ( 8 ) ;
1065- match ret_ty. kind ( ) {
1066- ty:: Uint ( i) if i. bit_width ( ) == Some ( expected_int_bits) => ( ) ,
1067- _ => return_error ! ( "bitmask `{}`, expected `u{}`" , ret_ty, expected_int_bits) ,
1068- }
1079+ let expected_bytes = expected_int_bits / 8 + ( ( expected_int_bits % 8 > 0 ) as u64 ) ;
10691080
10701081 // Integer vector <i{in_bitwidth} x in_len>:
10711082 let ( i_xn, in_elem_bitwidth) = match in_elem. kind ( ) {
@@ -1095,8 +1106,34 @@ fn generic_simd_intrinsic(
10951106 let i1xn = bx. trunc ( i_xn_msb, bx. type_vector ( bx. type_i1 ( ) , in_len) ) ;
10961107 // Bitcast <i1 x N> to iN:
10971108 let i_ = bx. bitcast ( i1xn, bx. type_ix ( in_len) ) ;
1098- // Zero-extend iN to the bitmask type:
1099- return Ok ( bx. zext ( i_, bx. type_ix ( expected_int_bits) ) ) ;
1109+
1110+ match ret_ty. kind ( ) {
1111+ ty:: Uint ( i) if i. bit_width ( ) == Some ( expected_int_bits) => {
1112+ // Zero-extend iN to the bitmask type:
1113+ return Ok ( bx. zext ( i_, bx. type_ix ( expected_int_bits) ) ) ;
1114+ }
1115+ ty:: Array ( elem, len)
1116+ if matches ! ( elem. kind( ) , ty:: Uint ( ty:: UintTy :: U8 ) )
1117+ && len. try_eval_usize ( bx. tcx , ty:: ParamEnv :: reveal_all ( ) )
1118+ == Some ( expected_bytes) =>
1119+ {
1120+ // Zero-extend iN to the array lengh:
1121+ let ze = bx. zext ( i_, bx. type_ix ( expected_bytes * 8 ) ) ;
1122+
1123+ // Convert the integer to a byte array
1124+ let ptr = bx. alloca ( bx. type_ix ( expected_bytes * 8 ) , Align :: ONE ) ;
1125+ bx. store ( ze, ptr, Align :: ONE ) ;
1126+ let array_ty = bx. type_array ( bx. type_i8 ( ) , expected_bytes) ;
1127+ let ptr = bx. pointercast ( ptr, bx. cx . type_ptr_to ( array_ty) ) ;
1128+ return Ok ( bx. load ( array_ty, ptr, Align :: ONE ) ) ;
1129+ }
1130+ _ => return_error ! (
1131+ "cannot return `{}`, expected `u{}` or `[u8; {}]`" ,
1132+ ret_ty,
1133+ expected_int_bits,
1134+ expected_bytes
1135+ ) ,
1136+ }
11001137 }
11011138
11021139 fn simd_simple_float_intrinsic (
0 commit comments