11use std:: cmp:: Ordering ;
22
3- use gccjit:: { RValue , Type , ToRValue } ;
3+ use gccjit:: { BinaryOp , RValue , Type , ToRValue } ;
44use rustc_codegen_ssa:: base:: compare_simd_types;
55use rustc_codegen_ssa:: common:: { TypeKind , span_invalid_monomorphization_error} ;
66use rustc_codegen_ssa:: mir:: operand:: OperandRef ;
@@ -222,6 +222,24 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
222222 return Ok ( bx. context . new_vector_access ( None , vector, args[ 1 ] . immediate ( ) ) . to_rvalue ( ) ) ;
223223 }
224224
225+ if name == sym:: simd_select {
226+ let m_elem_ty = in_elem;
227+ let m_len = in_len;
228+ require_simd ! ( arg_tys[ 1 ] , "argument" ) ;
229+ let ( v_len, _) = arg_tys[ 1 ] . simd_size_and_type ( bx. tcx ( ) ) ;
230+ require ! (
231+ m_len == v_len,
232+ "mismatched lengths: mask length `{}` != other vector length `{}`" ,
233+ m_len,
234+ v_len
235+ ) ;
236+ match m_elem_ty. kind ( ) {
237+ ty:: Int ( _) => { }
238+ _ => return_error ! ( "mask element type is `{}`, expected `i_`" , m_elem_ty) ,
239+ }
240+ return Ok ( bx. vector_select ( args[ 0 ] . immediate ( ) , args[ 1 ] . immediate ( ) , args[ 2 ] . immediate ( ) ) ) ;
241+ }
242+
225243 if name == sym:: simd_cast {
226244 require_simd ! ( ret_ty, "return" ) ;
227245 let ( out_len, out_elem) = ret_ty. simd_size_and_type ( bx. tcx ( ) ) ;
@@ -543,7 +561,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
543561 }
544562
545563 macro_rules! arith_red {
546- ( $name: ident : $integer_reduce : ident , $float_reduce: ident, $ordered: expr, $op: ident,
564+ ( $name: ident : $vec_op : expr , $float_reduce: ident, $ordered: expr, $op: ident,
547565 $identity: expr) => {
548566 if name == sym:: $name {
549567 require!(
@@ -555,36 +573,25 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
555573 ) ;
556574 return match in_elem. kind( ) {
557575 ty:: Int ( _) | ty:: Uint ( _) => {
558- let r = bx. $integer_reduce ( args[ 0 ] . immediate( ) ) ;
576+ let r = bx. vector_reduce_op ( args[ 0 ] . immediate( ) , $vec_op ) ;
559577 if $ordered {
560578 // if overflow occurs, the result is the
561579 // mathematical result modulo 2^n:
562580 Ok ( bx. $op( args[ 1 ] . immediate( ) , r) )
563- } else {
564- Ok ( bx. $integer_reduce( args[ 0 ] . immediate( ) ) )
581+ }
582+ else {
583+ Ok ( bx. vector_reduce_op( args[ 0 ] . immediate( ) , $vec_op) )
565584 }
566585 }
567- ty:: Float ( f ) => {
568- let acc = if $ordered {
586+ ty:: Float ( _ ) => {
587+ if $ordered {
569588 // ordered arithmetic reductions take an accumulator
570- args[ 1 ] . immediate( )
571- } else {
572- // unordered arithmetic reductions use the identity accumulator
573- match f. bit_width( ) {
574- 32 => bx. const_real( bx. type_f32( ) , $identity) ,
575- 64 => bx. const_real( bx. type_f64( ) , $identity) ,
576- v => return_error!(
577- r#"
578- unsupported {} from `{}` with element `{}` of size `{}` to `{}`"# ,
579- sym:: $name,
580- in_ty,
581- in_elem,
582- v,
583- ret_ty
584- ) ,
585- }
586- } ;
587- Ok ( bx. $float_reduce( acc, args[ 0 ] . immediate( ) ) )
589+ let acc = args[ 1 ] . immediate( ) ;
590+ Ok ( bx. $float_reduce( acc, args[ 0 ] . immediate( ) ) )
591+ }
592+ else {
593+ Ok ( bx. vector_reduce_op( args[ 0 ] . immediate( ) , $vec_op) )
594+ }
588595 }
589596 _ => return_error!(
590597 "unsupported {} from `{}` with element `{}` to `{}`" ,
@@ -598,14 +605,96 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
598605 } ;
599606 }
600607
601- // TODO: use a recursive algorithm a-la Hacker's Delight.
602608 arith_red ! (
603- simd_reduce_add_unordered: vector_reduce_add ,
609+ simd_reduce_add_unordered: BinaryOp :: Plus ,
604610 vector_reduce_fadd_fast,
605611 false ,
606612 add,
607- 0.0
613+ 0.0 // TODO: Use this argument.
614+ ) ;
615+ arith_red ! (
616+ simd_reduce_mul_unordered: BinaryOp :: Mult ,
617+ vector_reduce_fmul_fast,
618+ false ,
619+ mul,
620+ 1.0
608621 ) ;
609622
623+ macro_rules! minmax_red {
624+ ( $name: ident: $reduction: ident) => {
625+ if name == sym:: $name {
626+ require!(
627+ ret_ty == in_elem,
628+ "expected return type `{}` (element of input `{}`), found `{}`" ,
629+ in_elem,
630+ in_ty,
631+ ret_ty
632+ ) ;
633+ return match in_elem. kind( ) {
634+ ty:: Int ( _) | ty:: Uint ( _) | ty:: Float ( _) => Ok ( bx. $reduction( args[ 0 ] . immediate( ) ) ) ,
635+ _ => return_error!(
636+ "unsupported {} from `{}` with element `{}` to `{}`" ,
637+ sym:: $name,
638+ in_ty,
639+ in_elem,
640+ ret_ty
641+ ) ,
642+ } ;
643+ }
644+ } ;
645+ }
646+
647+ minmax_red ! ( simd_reduce_min: vector_reduce_min) ;
648+ minmax_red ! ( simd_reduce_max: vector_reduce_max) ;
649+
650+ macro_rules! bitwise_red {
651+ ( $name: ident : $op: expr, $boolean: expr) => {
652+ if name == sym:: $name {
653+ let input = if !$boolean {
654+ require!(
655+ ret_ty == in_elem,
656+ "expected return type `{}` (element of input `{}`), found `{}`" ,
657+ in_elem,
658+ in_ty,
659+ ret_ty
660+ ) ;
661+ args[ 0 ] . immediate( )
662+ } else {
663+ match in_elem. kind( ) {
664+ ty:: Int ( _) | ty:: Uint ( _) => { }
665+ _ => return_error!(
666+ "unsupported {} from `{}` with element `{}` to `{}`" ,
667+ sym:: $name,
668+ in_ty,
669+ in_elem,
670+ ret_ty
671+ ) ,
672+ }
673+
674+ // boolean reductions operate on vectors of i1s:
675+ let i1 = bx. type_i1( ) ;
676+ let i1xn = bx. type_vector( i1, in_len as u64 ) ;
677+ bx. trunc( args[ 0 ] . immediate( ) , i1xn)
678+ } ;
679+ return match in_elem. kind( ) {
680+ ty:: Int ( _) | ty:: Uint ( _) => {
681+ let r = bx. vector_reduce_op( input, $op) ;
682+ Ok ( if !$boolean { r } else { bx. zext( r, bx. type_bool( ) ) } )
683+ }
684+ _ => return_error!(
685+ "unsupported {} from `{}` with element `{}` to `{}`" ,
686+ sym:: $name,
687+ in_ty,
688+ in_elem,
689+ ret_ty
690+ ) ,
691+ } ;
692+ }
693+ } ;
694+ }
695+
696+ bitwise_red ! ( simd_reduce_and: BinaryOp :: BitwiseAnd , false ) ;
697+ bitwise_red ! ( simd_reduce_or: BinaryOp :: BitwiseOr , false ) ;
698+
610699 unimplemented ! ( "simd {}" , name) ;
611700}
0 commit comments