@@ -4,12 +4,14 @@ use gccjit::{BinaryOp, RValue, Type, ToRValue};
4
4
use rustc_codegen_ssa:: base:: compare_simd_types;
5
5
use rustc_codegen_ssa:: common:: { TypeKind , span_invalid_monomorphization_error} ;
6
6
use rustc_codegen_ssa:: mir:: operand:: OperandRef ;
7
+ use rustc_codegen_ssa:: mir:: place:: PlaceRef ;
7
8
use rustc_codegen_ssa:: traits:: { BaseTypeMethods , BuilderMethods } ;
8
9
use rustc_hir as hir;
9
10
use rustc_middle:: span_bug;
10
11
use rustc_middle:: ty:: layout:: HasTyCtxt ;
11
12
use rustc_middle:: ty:: { self , Ty } ;
12
13
use rustc_span:: { Span , Symbol , sym} ;
14
+ use rustc_target:: abi:: Align ;
13
15
14
16
use crate :: builder:: Builder ;
15
17
use crate :: intrinsic;
@@ -55,7 +57,53 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
55
57
let sig =
56
58
tcx. normalize_erasing_late_bound_regions ( ty:: ParamEnv :: reveal_all ( ) , callee_ty. fn_sig ( tcx) ) ;
57
59
let arg_tys = sig. inputs ( ) ;
58
- let name_str = name. as_str ( ) ;
60
+
61
+ if name == sym:: simd_select_bitmask {
62
+ require_simd ! ( arg_tys[ 1 ] , "argument" ) ;
63
+ let ( len, _) = arg_tys[ 1 ] . simd_size_and_type ( bx. tcx ( ) ) ;
64
+
65
+ let expected_int_bits = ( len. max ( 8 ) - 1 ) . next_power_of_two ( ) ;
66
+ let expected_bytes = len / 8 + ( ( len % 8 > 0 ) as u64 ) ;
67
+
68
+ let mask_ty = arg_tys[ 0 ] ;
69
+ let mut mask = match mask_ty. kind ( ) {
70
+ ty:: Int ( i) if i. bit_width ( ) == Some ( expected_int_bits) => args[ 0 ] . immediate ( ) ,
71
+ ty:: Uint ( i) if i. bit_width ( ) == Some ( expected_int_bits) => args[ 0 ] . immediate ( ) ,
72
+ ty:: Array ( elem, len)
73
+ if matches ! ( elem. kind( ) , ty:: Uint ( ty:: UintTy :: U8 ) )
74
+ && len. try_eval_usize ( bx. tcx , ty:: ParamEnv :: reveal_all ( ) )
75
+ == Some ( expected_bytes) =>
76
+ {
77
+ let place = PlaceRef :: alloca ( bx, args[ 0 ] . layout ) ;
78
+ args[ 0 ] . val . store ( bx, place) ;
79
+ let int_ty = bx. type_ix ( expected_bytes * 8 ) ;
80
+ let ptr = bx. pointercast ( place. llval , bx. cx . type_ptr_to ( int_ty) ) ;
81
+ bx. load ( int_ty, ptr, Align :: ONE )
82
+ }
83
+ _ => return_error ! (
84
+ "invalid bitmask `{}`, expected `u{}` or `[u8; {}]`" ,
85
+ mask_ty,
86
+ expected_int_bits,
87
+ expected_bytes
88
+ ) ,
89
+ } ;
90
+
91
+ let arg1 = args[ 1 ] . immediate ( ) ;
92
+ let arg1_type = arg1. get_type ( ) ;
93
+ let arg1_vector_type = arg1_type. unqualified ( ) . dyncast_vector ( ) . expect ( "vector type" ) ;
94
+ let arg1_element_type = arg1_vector_type. get_element_type ( ) ;
95
+
96
+ let mut elements = vec ! [ ] ;
97
+ let one = bx. context . new_rvalue_one ( mask. get_type ( ) ) ;
98
+ for _ in 0 ..len {
99
+ let element = bx. context . new_cast ( None , mask & one, arg1_element_type) ;
100
+ elements. push ( element) ;
101
+ mask = mask >> one;
102
+ }
103
+ let vector_mask = bx. context . new_rvalue_from_vector ( None , arg1_type, & elements) ;
104
+
105
+ return Ok ( bx. vector_select ( vector_mask, arg1, args[ 2 ] . immediate ( ) ) ) ;
106
+ }
59
107
60
108
// every intrinsic below takes a SIMD vector as its first argument
61
109
require_simd ! ( arg_tys[ 0 ] , "input" ) ;
@@ -102,7 +150,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
102
150
) ) ;
103
151
}
104
152
105
- if let Some ( stripped) = name_str . strip_prefix ( "simd_shuffle" ) {
153
+ if let Some ( stripped) = name . as_str ( ) . strip_prefix ( "simd_shuffle" ) {
106
154
let n: u64 =
107
155
if stripped. is_empty ( ) {
108
156
// Make sure this is actually an array, since typeck only checks the length-suffixed
0 commit comments