@@ -14,6 +14,8 @@ use rustc_span::{Span, Symbol, sym};
14
14
use rustc_target:: abi:: Align ;
15
15
16
16
use crate :: builder:: Builder ;
17
+ #[ cfg( feature="master" ) ]
18
+ use crate :: context:: CodegenCx ;
17
19
18
20
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
21
// macros for error handling:
@@ -507,6 +509,286 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
507
509
return simd_simple_float_intrinsic ( name, in_elem, in_ty, in_len, bx, span, args) ;
508
510
}
509
511
512
+ #[ cfg( feature="master" ) ]
513
+ fn vector_ty < ' gcc , ' tcx > ( cx : & CodegenCx < ' gcc , ' tcx > , elem_ty : Ty < ' tcx > , vec_len : u64 ) -> Type < ' gcc > {
514
+ // FIXME: use cx.layout_of(ty).llvm_type() ?
515
+ let elem_ty = match * elem_ty. kind ( ) {
516
+ ty:: Int ( v) => cx. type_int_from_ty ( v) ,
517
+ ty:: Uint ( v) => cx. type_uint_from_ty ( v) ,
518
+ ty:: Float ( v) => cx. type_float_from_ty ( v) ,
519
+ _ => unreachable ! ( ) ,
520
+ } ;
521
+ cx. type_vector ( elem_ty, vec_len)
522
+ }
523
+
524
+ #[ cfg( feature="master" ) ]
525
+ fn gather < ' a , ' gcc , ' tcx > ( default : RValue < ' gcc > , pointers : RValue < ' gcc > , mask : RValue < ' gcc > , pointer_count : usize , bx : & mut Builder < ' a , ' gcc , ' tcx > , in_len : u64 , underlying_ty : Ty < ' tcx > , invert : bool ) -> RValue < ' gcc > {
526
+ let vector_type =
527
+ if pointer_count > 1 {
528
+ bx. context . new_vector_type ( bx. usize_type , in_len)
529
+ }
530
+ else {
531
+ vector_ty ( bx, underlying_ty, in_len)
532
+ } ;
533
+ let elem_type = vector_type. dyncast_vector ( ) . expect ( "vector type" ) . get_element_type ( ) ;
534
+
535
+ let mut values = vec ! [ ] ;
536
+ for i in 0 ..in_len {
537
+ let index = bx. context . new_rvalue_from_long ( bx. i32_type , i as i64 ) ;
538
+ let int = bx. context . new_vector_access ( None , pointers, index) . to_rvalue ( ) ;
539
+
540
+ let ptr_type = elem_type. make_pointer ( ) ;
541
+ let ptr = bx. context . new_bitcast ( None , int, ptr_type) ;
542
+ let value = ptr. dereference ( None ) . to_rvalue ( ) ;
543
+ values. push ( value) ;
544
+ }
545
+
546
+ let vector = bx. context . new_rvalue_from_vector ( None , vector_type, & values) ;
547
+
548
+ let mut mask_types = vec ! [ ] ;
549
+ let mut mask_values = vec ! [ ] ;
550
+ for i in 0 ..in_len {
551
+ let index = bx. context . new_rvalue_from_long ( bx. i32_type , i as i64 ) ;
552
+ mask_types. push ( bx. context . new_field ( None , bx. i32_type , "m" ) ) ;
553
+ let mask_value = bx. context . new_vector_access ( None , mask, index) . to_rvalue ( ) ;
554
+ let masked = bx. context . new_rvalue_from_int ( bx. i32_type , in_len as i32 ) & mask_value;
555
+ let value = index + masked;
556
+ mask_values. push ( value) ;
557
+ }
558
+ let mask_type = bx. context . new_struct_type ( None , "mask_type" , & mask_types) ;
559
+ let mask = bx. context . new_struct_constructor ( None , mask_type. as_type ( ) , None , & mask_values) ;
560
+
561
+ if invert {
562
+ bx. shuffle_vector ( vector, default, mask)
563
+ }
564
+ else {
565
+ bx. shuffle_vector ( default, vector, mask)
566
+ }
567
+ }
568
+
569
+ #[ cfg( feature="master" ) ]
570
+ if name == sym:: simd_gather {
571
+ // simd_gather(values: <N x T>, pointers: <N x *_ T>,
572
+ // mask: <N x i{M}>) -> <N x T>
573
+ // * N: number of elements in the input vectors
574
+ // * T: type of the element to load
575
+ // * M: any integer width is supported, will be truncated to i1
576
+
577
+ // All types must be simd vector types
578
+ require_simd ! ( in_ty, "first" ) ;
579
+ require_simd ! ( arg_tys[ 1 ] , "second" ) ;
580
+ require_simd ! ( arg_tys[ 2 ] , "third" ) ;
581
+ require_simd ! ( ret_ty, "return" ) ;
582
+
583
+ // Of the same length:
584
+ let ( out_len, _) = arg_tys[ 1 ] . simd_size_and_type ( bx. tcx ( ) ) ;
585
+ let ( out_len2, _) = arg_tys[ 2 ] . simd_size_and_type ( bx. tcx ( ) ) ;
586
+ require ! (
587
+ in_len == out_len,
588
+ "expected {} argument with length {} (same as input type `{}`), \
589
+ found `{}` with length {}",
590
+ "second" ,
591
+ in_len,
592
+ in_ty,
593
+ arg_tys[ 1 ] ,
594
+ out_len
595
+ ) ;
596
+ require ! (
597
+ in_len == out_len2,
598
+ "expected {} argument with length {} (same as input type `{}`), \
599
+ found `{}` with length {}",
600
+ "third" ,
601
+ in_len,
602
+ in_ty,
603
+ arg_tys[ 2 ] ,
604
+ out_len2
605
+ ) ;
606
+
607
+ // The return type must match the first argument type
608
+ require ! ( ret_ty == in_ty, "expected return type `{}`, found `{}`" , in_ty, ret_ty) ;
609
+
610
+ // This counts how many pointers
611
+ fn ptr_count ( t : Ty < ' _ > ) -> usize {
612
+ match t. kind ( ) {
613
+ ty:: RawPtr ( p) => 1 + ptr_count ( p. ty ) ,
614
+ _ => 0 ,
615
+ }
616
+ }
617
+
618
+ // Non-ptr type
619
+ fn non_ptr ( t : Ty < ' _ > ) -> Ty < ' _ > {
620
+ match t. kind ( ) {
621
+ ty:: RawPtr ( p) => non_ptr ( p. ty ) ,
622
+ _ => t,
623
+ }
624
+ }
625
+
626
+ // The second argument must be a simd vector with an element type that's a pointer
627
+ // to the element type of the first argument
628
+ let ( _, element_ty0) = arg_tys[ 0 ] . simd_size_and_type ( bx. tcx ( ) ) ;
629
+ let ( _, element_ty1) = arg_tys[ 1 ] . simd_size_and_type ( bx. tcx ( ) ) ;
630
+ let ( pointer_count, underlying_ty) = match element_ty1. kind ( ) {
631
+ ty:: RawPtr ( p) if p. ty == in_elem => ( ptr_count ( element_ty1) , non_ptr ( element_ty1) ) ,
632
+ _ => {
633
+ require ! (
634
+ false ,
635
+ "expected element type `{}` of second argument `{}` \
636
+ to be a pointer to the element type `{}` of the first \
637
+ argument `{}`, found `{}` != `*_ {}`",
638
+ element_ty1,
639
+ arg_tys[ 1 ] ,
640
+ in_elem,
641
+ in_ty,
642
+ element_ty1,
643
+ in_elem
644
+ ) ;
645
+ unreachable ! ( ) ;
646
+ }
647
+ } ;
648
+ assert ! ( pointer_count > 0 ) ;
649
+ assert_eq ! ( pointer_count - 1 , ptr_count( element_ty0) ) ;
650
+ assert_eq ! ( underlying_ty, non_ptr( element_ty0) ) ;
651
+
652
+ // The element type of the third argument must be a signed integer type of any width:
653
+ let ( _, element_ty2) = arg_tys[ 2 ] . simd_size_and_type ( bx. tcx ( ) ) ;
654
+ match element_ty2. kind ( ) {
655
+ ty:: Int ( _) => ( ) ,
656
+ _ => {
657
+ require ! (
658
+ false ,
659
+ "expected element type `{}` of third argument `{}` \
660
+ to be a signed integer type",
661
+ element_ty2,
662
+ arg_tys[ 2 ]
663
+ ) ;
664
+ }
665
+ }
666
+
667
+ return Ok ( gather ( args[ 0 ] . immediate ( ) , args[ 1 ] . immediate ( ) , args[ 2 ] . immediate ( ) , pointer_count, bx, in_len, underlying_ty, false ) ) ;
668
+ }
669
+
670
+ #[ cfg( feature="master" ) ]
671
+ if name == sym:: simd_scatter {
672
+ // simd_scatter(values: <N x T>, pointers: <N x *mut T>,
673
+ // mask: <N x i{M}>) -> ()
674
+ // * N: number of elements in the input vectors
675
+ // * T: type of the element to load
676
+ // * M: any integer width is supported, will be truncated to i1
677
+
678
+ // All types must be simd vector types
679
+ require_simd ! ( in_ty, "first" ) ;
680
+ require_simd ! ( arg_tys[ 1 ] , "second" ) ;
681
+ require_simd ! ( arg_tys[ 2 ] , "third" ) ;
682
+
683
+ // Of the same length:
684
+ let ( element_len1, _) = arg_tys[ 1 ] . simd_size_and_type ( bx. tcx ( ) ) ;
685
+ let ( element_len2, _) = arg_tys[ 2 ] . simd_size_and_type ( bx. tcx ( ) ) ;
686
+ require ! (
687
+ in_len == element_len1,
688
+ "expected {} argument with length {} (same as input type `{}`), \
689
+ found `{}` with length {}",
690
+ "second" ,
691
+ in_len,
692
+ in_ty,
693
+ arg_tys[ 1 ] ,
694
+ element_len1
695
+ ) ;
696
+ require ! (
697
+ in_len == element_len2,
698
+ "expected {} argument with length {} (same as input type `{}`), \
699
+ found `{}` with length {}",
700
+ "third" ,
701
+ in_len,
702
+ in_ty,
703
+ arg_tys[ 2 ] ,
704
+ element_len2
705
+ ) ;
706
+
707
+ // This counts how many pointers
708
+ fn ptr_count ( t : Ty < ' _ > ) -> usize {
709
+ match t. kind ( ) {
710
+ ty:: RawPtr ( p) => 1 + ptr_count ( p. ty ) ,
711
+ _ => 0 ,
712
+ }
713
+ }
714
+
715
+ // Non-ptr type
716
+ fn non_ptr ( t : Ty < ' _ > ) -> Ty < ' _ > {
717
+ match t. kind ( ) {
718
+ ty:: RawPtr ( p) => non_ptr ( p. ty ) ,
719
+ _ => t,
720
+ }
721
+ }
722
+
723
+ // The second argument must be a simd vector with an element type that's a pointer
724
+ // to the element type of the first argument
725
+ let ( _, element_ty0) = arg_tys[ 0 ] . simd_size_and_type ( bx. tcx ( ) ) ;
726
+ let ( _, element_ty1) = arg_tys[ 1 ] . simd_size_and_type ( bx. tcx ( ) ) ;
727
+ let ( _, element_ty2) = arg_tys[ 2 ] . simd_size_and_type ( bx. tcx ( ) ) ;
728
+ let ( pointer_count, underlying_ty) = match element_ty1. kind ( ) {
729
+ ty:: RawPtr ( p) if p. ty == in_elem && p. mutbl == hir:: Mutability :: Mut => {
730
+ ( ptr_count ( element_ty1) , non_ptr ( element_ty1) )
731
+ }
732
+ _ => {
733
+ require ! (
734
+ false ,
735
+ "expected element type `{}` of second argument `{}` \
736
+ to be a pointer to the element type `{}` of the first \
737
+ argument `{}`, found `{}` != `*mut {}`",
738
+ element_ty1,
739
+ arg_tys[ 1 ] ,
740
+ in_elem,
741
+ in_ty,
742
+ element_ty1,
743
+ in_elem
744
+ ) ;
745
+ unreachable ! ( ) ;
746
+ }
747
+ } ;
748
+ assert ! ( pointer_count > 0 ) ;
749
+ assert_eq ! ( pointer_count - 1 , ptr_count( element_ty0) ) ;
750
+ assert_eq ! ( underlying_ty, non_ptr( element_ty0) ) ;
751
+
752
+ // The element type of the third argument must be a signed integer type of any width:
753
+ match element_ty2. kind ( ) {
754
+ ty:: Int ( _) => ( ) ,
755
+ _ => {
756
+ require ! (
757
+ false ,
758
+ "expected element type `{}` of third argument `{}` \
759
+ be a signed integer type",
760
+ element_ty2,
761
+ arg_tys[ 2 ]
762
+ ) ;
763
+ }
764
+ }
765
+
766
+ let result = gather ( args[ 0 ] . immediate ( ) , args[ 1 ] . immediate ( ) , args[ 2 ] . immediate ( ) , pointer_count, bx, in_len, underlying_ty, true ) ;
767
+
768
+ let pointers = args[ 1 ] . immediate ( ) ;
769
+
770
+ let vector_type =
771
+ if pointer_count > 1 {
772
+ bx. context . new_vector_type ( bx. usize_type , in_len)
773
+ }
774
+ else {
775
+ vector_ty ( bx, underlying_ty, in_len)
776
+ } ;
777
+ let elem_type = vector_type. dyncast_vector ( ) . expect ( "vector type" ) . get_element_type ( ) ;
778
+
779
+ for i in 0 ..in_len {
780
+ let index = bx. context . new_rvalue_from_int ( bx. int_type , i as i32 ) ;
781
+ let value = bx. context . new_vector_access ( None , result, index) ;
782
+
783
+ let int = bx. context . new_vector_access ( None , pointers, index) . to_rvalue ( ) ;
784
+ let ptr_type = elem_type. make_pointer ( ) ;
785
+ let ptr = bx. context . new_bitcast ( None , int, ptr_type) ;
786
+ bx. llbb ( ) . add_assignment ( None , ptr. dereference ( None ) , value) ;
787
+ }
788
+
789
+ return Ok ( bx. context . new_rvalue_zero ( bx. i32_type ) ) ;
790
+ }
791
+
510
792
arith_binary ! {
511
793
simd_add: Uint , Int => add, Float => fadd;
512
794
simd_sub: Uint , Int => sub, Float => fsub;
0 commit comments