@@ -14,6 +14,8 @@ use rustc_span::{Span, Symbol, sym};
1414use rustc_target:: abi:: Align ;
1515
1616use crate :: builder:: Builder ;
17+ #[ cfg( feature="master" ) ]
18+ use crate :: context:: CodegenCx ;
1719
1820pub 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 > , ( ) > {
1921 // macros for error handling:
@@ -507,6 +509,286 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
507509 return simd_simple_float_intrinsic ( name, in_elem, in_ty, in_len, bx, span, args) ;
508510 }
509511
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+
510792 arith_binary ! {
511793 simd_add: Uint , Int => add, Float => fadd;
512794 simd_sub: Uint , Int => sub, Float => fsub;
0 commit comments