@@ -2,7 +2,7 @@ use either::Either;
22use rustc_abi:: Endian ;
33use rustc_apfloat:: { Float , Round } ;
44use rustc_middle:: mir:: interpret:: { InterpErrorKind , UndefinedBehaviorInfo } ;
5- use rustc_middle:: ty:: FloatTy ;
5+ use rustc_middle:: ty:: { FloatTy , ScalarInt } ;
66use rustc_middle:: { bug, err_ub_format, mir, span_bug, throw_unsup_format, ty} ;
77use rustc_span:: { Symbol , sym} ;
88use tracing:: trace;
@@ -701,6 +701,44 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
701701 } ;
702702 }
703703 }
704+ sym:: simd_funnel_shl | sym:: simd_funnel_shr => {
705+ let ( left, _) = self . project_to_simd ( & args[ 0 ] ) ?;
706+ let ( right, _) = self . project_to_simd ( & args[ 1 ] ) ?;
707+ let ( shift, _) = self . project_to_simd ( & args[ 2 ] ) ?;
708+ let ( dest, _) = self . project_to_simd ( & dest) ?;
709+
710+ let ( len, elem_ty) = args[ 0 ] . layout . ty . simd_size_and_type ( * self . tcx ) ;
711+ let ( elem_size, _signed) = elem_ty. int_size_and_signed ( * self . tcx ) ;
712+ let elem_size_bits = elem_size. bits ( ) as u128 ;
713+
714+ let is_left = intrinsic_name == sym:: simd_funnel_shl;
715+
716+ for i in 0 ..len {
717+ let left =
718+ self . read_scalar ( & self . project_index ( & left, i) ?) ?. to_bits ( elem_size) ?;
719+ let right =
720+ self . read_scalar ( & self . project_index ( & right, i) ?) ?. to_bits ( elem_size) ?;
721+ let shift_bits =
722+ self . read_scalar ( & self . project_index ( & shift, i) ?) ?. to_bits ( elem_size) ?;
723+
724+ if shift_bits >= elem_size_bits {
725+ err_ub_format ! (
726+ "overflowing shift by {shift_bits} in `{intrinsic_name}` in lane {i}"
727+ ) ;
728+ }
729+ let inv_shift_bits = ( elem_size_bits - shift_bits) as u32 ;
730+
731+ let result_bits = if is_left {
732+ ( left << shift_bits) | right. unbounded_shr ( inv_shift_bits)
733+ } else {
734+ left. unbounded_shl ( inv_shift_bits) | ( right >> shift_bits)
735+ } ;
736+ let ( result, _overflow) = ScalarInt :: truncate_from_uint ( result_bits, elem_size) ;
737+
738+ let dest = self . project_index ( & dest, i) ?;
739+ self . write_scalar ( result, & dest) ?;
740+ }
741+ }
704742
705743 // Unsupported intrinsic: skip the return_to_block below.
706744 _ => return interp_ok ( false ) ,
0 commit comments