@@ -19,7 +19,7 @@ use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf};
19
19
use rustc_middle:: ty:: { self , Ty } ;
20
20
use rustc_middle:: { bug, span_bug} ;
21
21
use rustc_span:: { sym, symbol:: kw, Span , Symbol } ;
22
- use rustc_target:: abi:: { self , HasDataLayout , Primitive } ;
22
+ use rustc_target:: abi:: { self , Align , HasDataLayout , Primitive } ;
23
23
use rustc_target:: spec:: { HasTargetSpec , PanicStrategy } ;
24
24
25
25
use std:: cmp:: Ordering ;
@@ -857,28 +857,39 @@ fn generic_simd_intrinsic(
857
857
let arg_tys = sig. inputs ( ) ;
858
858
859
859
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
- } ;
868
860
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
+
878
889
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) ;
882
893
let m_i1s = bx. bitcast ( m_im, i1xn) ;
883
894
return Ok ( bx. select ( m_i1s, args[ 1 ] . immediate ( ) , args[ 2 ] . immediate ( ) ) ) ;
884
895
}
@@ -1056,16 +1067,16 @@ fn generic_simd_intrinsic(
1056
1067
1057
1068
if name == sym:: simd_bitmask {
1058
1069
// 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.
1064
1078
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 ) ;
1069
1080
1070
1081
// Integer vector <i{in_bitwidth} x in_len>:
1071
1082
let ( i_xn, in_elem_bitwidth) = match in_elem. kind ( ) {
@@ -1095,8 +1106,34 @@ fn generic_simd_intrinsic(
1095
1106
let i1xn = bx. trunc ( i_xn_msb, bx. type_vector ( bx. type_i1 ( ) , in_len) ) ;
1096
1107
// Bitcast <i1 x N> to iN:
1097
1108
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
+ }
1100
1137
}
1101
1138
1102
1139
fn simd_simple_float_intrinsic (
0 commit comments