@@ -14,6 +14,7 @@ use rustc_span::{Span, Symbol, sym};
14
14
use rustc_target:: abi:: Align ;
15
15
16
16
use crate :: builder:: Builder ;
17
+ use crate :: context:: CodegenCx ;
17
18
18
19
pub fn generic_simd_intrinsic < ' a , ' gcc , ' tcx > ( bx : & mut Builder < ' a , ' gcc , ' tcx > , name : Symbol , callee_ty : Ty < ' tcx > , args : & [ OperandRef < ' tcx , RValue < ' gcc > > ] , ret_ty : Ty < ' tcx > , llret_ty : Type < ' gcc > , span : Span ) -> Result < RValue < ' gcc > , ( ) > {
19
20
// macros for error handling:
@@ -507,6 +508,156 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
507
508
return simd_simple_float_intrinsic ( name, in_elem, in_ty, in_len, bx, span, args) ;
508
509
}
509
510
511
+ fn vector_ty < ' gcc , ' tcx > ( cx : & CodegenCx < ' gcc , ' tcx > , elem_ty : Ty < ' tcx > , vec_len : u64 ) -> Type < ' gcc > {
512
+ // FIXME: use cx.layout_of(ty).llvm_type() ?
513
+ let elem_ty = match * elem_ty. kind ( ) {
514
+ ty:: Int ( v) => cx. type_int_from_ty ( v) ,
515
+ ty:: Uint ( v) => cx. type_uint_from_ty ( v) ,
516
+ ty:: Float ( v) => cx. type_float_from_ty ( v) ,
517
+ _ => unreachable ! ( ) ,
518
+ } ;
519
+ cx. type_vector ( elem_ty, vec_len)
520
+ }
521
+
522
+ if name == sym:: simd_gather {
523
+ // simd_gather(values: <N x T>, pointers: <N x *_ T>,
524
+ // mask: <N x i{M}>) -> <N x T>
525
+ // * N: number of elements in the input vectors
526
+ // * T: type of the element to load
527
+ // * M: any integer width is supported, will be truncated to i1
528
+
529
+ // All types must be simd vector types
530
+ require_simd ! ( in_ty, "first" ) ;
531
+ require_simd ! ( arg_tys[ 1 ] , "second" ) ;
532
+ require_simd ! ( arg_tys[ 2 ] , "third" ) ;
533
+ require_simd ! ( ret_ty, "return" ) ;
534
+
535
+ // Of the same length:
536
+ let ( out_len, _) = arg_tys[ 1 ] . simd_size_and_type ( bx. tcx ( ) ) ;
537
+ let ( out_len2, _) = arg_tys[ 2 ] . simd_size_and_type ( bx. tcx ( ) ) ;
538
+ require ! (
539
+ in_len == out_len,
540
+ "expected {} argument with length {} (same as input type `{}`), \
541
+ found `{}` with length {}",
542
+ "second" ,
543
+ in_len,
544
+ in_ty,
545
+ arg_tys[ 1 ] ,
546
+ out_len
547
+ ) ;
548
+ require ! (
549
+ in_len == out_len2,
550
+ "expected {} argument with length {} (same as input type `{}`), \
551
+ found `{}` with length {}",
552
+ "third" ,
553
+ in_len,
554
+ in_ty,
555
+ arg_tys[ 2 ] ,
556
+ out_len2
557
+ ) ;
558
+
559
+ // The return type must match the first argument type
560
+ require ! ( ret_ty == in_ty, "expected return type `{}`, found `{}`" , in_ty, ret_ty) ;
561
+
562
+ // This counts how many pointers
563
+ fn ptr_count ( t : Ty < ' _ > ) -> usize {
564
+ match t. kind ( ) {
565
+ ty:: RawPtr ( p) => 1 + ptr_count ( p. ty ) ,
566
+ _ => 0 ,
567
+ }
568
+ }
569
+
570
+ // Non-ptr type
571
+ fn non_ptr ( t : Ty < ' _ > ) -> Ty < ' _ > {
572
+ match t. kind ( ) {
573
+ ty:: RawPtr ( p) => non_ptr ( p. ty ) ,
574
+ _ => t,
575
+ }
576
+ }
577
+
578
+ // The second argument must be a simd vector with an element type that's a pointer
579
+ // to the element type of the first argument
580
+ let ( _, element_ty0) = arg_tys[ 0 ] . simd_size_and_type ( bx. tcx ( ) ) ;
581
+ let ( _, element_ty1) = arg_tys[ 1 ] . simd_size_and_type ( bx. tcx ( ) ) ;
582
+ let ( pointer_count, underlying_ty) = match element_ty1. kind ( ) {
583
+ ty:: RawPtr ( p) if p. ty == in_elem => ( ptr_count ( element_ty1) , non_ptr ( element_ty1) ) ,
584
+ _ => {
585
+ require ! (
586
+ false ,
587
+ "expected element type `{}` of second argument `{}` \
588
+ to be a pointer to the element type `{}` of the first \
589
+ argument `{}`, found `{}` != `*_ {}`",
590
+ element_ty1,
591
+ arg_tys[ 1 ] ,
592
+ in_elem,
593
+ in_ty,
594
+ element_ty1,
595
+ in_elem
596
+ ) ;
597
+ unreachable ! ( ) ;
598
+ }
599
+ } ;
600
+ assert ! ( pointer_count > 0 ) ;
601
+ assert_eq ! ( pointer_count - 1 , ptr_count( element_ty0) ) ;
602
+ assert_eq ! ( underlying_ty, non_ptr( element_ty0) ) ;
603
+
604
+ // The element type of the third argument must be a signed integer type of any width:
605
+ let ( _, element_ty2) = arg_tys[ 2 ] . simd_size_and_type ( bx. tcx ( ) ) ;
606
+ match element_ty2. kind ( ) {
607
+ ty:: Int ( _) => ( ) ,
608
+ _ => {
609
+ require ! (
610
+ false ,
611
+ "expected element type `{}` of third argument `{}` \
612
+ to be a signed integer type",
613
+ element_ty2,
614
+ arg_tys[ 2 ]
615
+ ) ;
616
+ }
617
+ }
618
+
619
+ let vector_type =
620
+ if pointer_count > 1 {
621
+ bx. context . new_vector_type ( bx. usize_type , in_len)
622
+ }
623
+ else {
624
+ vector_ty ( bx, underlying_ty, in_len)
625
+ } ;
626
+ let elem_type = vector_type. dyncast_vector ( ) . expect ( "vector type" ) . get_element_type ( ) ;
627
+
628
+ let mut values = vec ! [ ] ;
629
+ let pointers = args[ 1 ] . immediate ( ) ;
630
+ for i in 0 ..in_len {
631
+ let index = bx. context . new_rvalue_from_long ( bx. i32_type , i as i64 ) ;
632
+ let int = bx. context . new_vector_access ( None , pointers, index) . to_rvalue ( ) ;
633
+
634
+ let ptr_type = elem_type. make_pointer ( ) ;
635
+
636
+ let ptr = bx. context . new_bitcast ( None , int, ptr_type) ;
637
+ let value = ptr. dereference ( None ) . to_rvalue ( ) ;
638
+ values. push ( value) ;
639
+ }
640
+
641
+ let vector = bx. context . new_rvalue_from_vector ( None , vector_type, & values) ;
642
+ let default = args[ 0 ] . immediate ( ) ;
643
+ let mask = args[ 2 ] . immediate ( ) ;
644
+
645
+ let mut mask_types = vec ! [ ] ;
646
+ let mut mask_values = vec ! [ ] ;
647
+ for i in 0 ..in_len {
648
+ let index = bx. context . new_rvalue_from_long ( bx. i32_type , i as i64 ) ;
649
+ mask_types. push ( bx. context . new_field ( None , bx. i32_type , "m" ) ) ; // TODO: choose an integer based on the size of the vector element type.
650
+ let mask_value = bx. context . new_vector_access ( None , mask, index) . to_rvalue ( ) ;
651
+ let masked = bx. context . new_rvalue_from_int ( bx. i32_type , in_len as i32 ) & mask_value;
652
+ let value = index + masked;
653
+ mask_values. push ( value) ;
654
+ }
655
+ let mask_type = bx. context . new_struct_type ( None , "mask_type" , & mask_types) ;
656
+ let mask = bx. context . new_struct_constructor ( None , mask_type. as_type ( ) , None , & mask_values) ;
657
+
658
+ return Ok ( bx. shuffle_vector ( default, vector, mask) ) ;
659
+ }
660
+
510
661
arith_binary ! {
511
662
simd_add: Uint , Int => add, Float => fadd;
512
663
simd_sub: Uint , Int => sub, Float => fsub;
0 commit comments