1
1
use std:: cmp:: Ordering ;
2
2
3
- use gccjit:: { RValue , Type , ToRValue } ;
3
+ 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 ;
@@ -222,6 +222,24 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
222
222
return Ok ( bx. context . new_vector_access ( None , vector, args[ 1 ] . immediate ( ) ) . to_rvalue ( ) ) ;
223
223
}
224
224
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
+
225
243
if name == sym:: simd_cast {
226
244
require_simd ! ( ret_ty, "return" ) ;
227
245
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>,
543
561
}
544
562
545
563
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,
547
565
$identity: expr) => {
548
566
if name == sym:: $name {
549
567
require!(
@@ -555,36 +573,25 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
555
573
) ;
556
574
return match in_elem. kind( ) {
557
575
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 ) ;
559
577
if $ordered {
560
578
// if overflow occurs, the result is the
561
579
// mathematical result modulo 2^n:
562
580
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) )
565
584
}
566
585
}
567
- ty:: Float ( f ) => {
568
- let acc = if $ordered {
586
+ ty:: Float ( _ ) => {
587
+ if $ordered {
569
588
// 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
+ }
588
595
}
589
596
_ => return_error!(
590
597
"unsupported {} from `{}` with element `{}` to `{}`" ,
@@ -598,14 +605,96 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
598
605
} ;
599
606
}
600
607
601
- // TODO: use a recursive algorithm a-la Hacker's Delight.
602
608
arith_red ! (
603
- simd_reduce_add_unordered: vector_reduce_add ,
609
+ simd_reduce_add_unordered: BinaryOp :: Plus ,
604
610
vector_reduce_fadd_fast,
605
611
false ,
606
612
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
608
621
) ;
609
622
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
+
610
699
unimplemented ! ( "simd {}" , name) ;
611
700
}
0 commit comments