@@ -52,7 +52,7 @@ pub use self::Dest::*;
5252use self :: lazy_binop_ty:: * ;
5353
5454use back:: abi;
55- use llvm:: { self , ValueRef } ;
55+ use llvm:: { self , ValueRef , TypeKind } ;
5656use middle:: check_const;
5757use middle:: def;
5858use middle:: lang_items:: CoerceUnsizedTraitLangItem ;
@@ -2458,12 +2458,10 @@ impl OverflowOpViaInputCheck {
24582458 // (since that is where the 32/64 distinction is relevant) but
24592459 // the mask's type must match the RHS type (since they will
24602460 // both be fed into a and-binop)
2461- let invert_mask = !shift_mask_val ( lhs_llty) ;
2462- let invert_mask = C_integral ( rhs_llty, invert_mask, true ) ;
2461+ let invert_mask = shift_mask_val ( bcx, lhs_llty, rhs_llty, true ) ;
24632462
24642463 let outer_bits = And ( bcx, rhs, invert_mask, binop_debug_loc) ;
2465- let cond = ICmp ( bcx, llvm:: IntNE , outer_bits,
2466- C_integral ( rhs_llty, 0 , false ) , binop_debug_loc) ;
2464+ let cond = build_nonzero_check ( bcx, outer_bits, binop_debug_loc) ;
24672465 let result = match * self {
24682466 OverflowOpViaInputCheck :: Shl =>
24692467 build_unchecked_lshift ( bcx, lhs, rhs, binop_debug_loc) ,
@@ -2479,9 +2477,46 @@ impl OverflowOpViaInputCheck {
24792477 }
24802478}
24812479
2482- fn shift_mask_val ( llty : Type ) -> u64 {
2483- // i8/u8 can shift by at most 7, i16/u16 by at most 15, etc.
2484- llty. int_width ( ) - 1
2480+ fn shift_mask_val < ' blk , ' tcx > ( bcx : Block < ' blk , ' tcx > ,
2481+ llty : Type ,
2482+ mask_llty : Type ,
2483+ invert : bool ) -> ValueRef {
2484+ let kind = llty. kind ( ) ;
2485+ match kind {
2486+ TypeKind :: Integer => {
2487+ // i8/u8 can shift by at most 7, i16/u16 by at most 15, etc.
2488+ let val = llty. int_width ( ) - 1 ;
2489+ if invert {
2490+ C_integral ( mask_llty, !val, true )
2491+ } else {
2492+ C_integral ( mask_llty, val, false )
2493+ }
2494+ } ,
2495+ TypeKind :: Vector => {
2496+ let mask = shift_mask_val ( bcx, llty. element_type ( ) , mask_llty. element_type ( ) , invert) ;
2497+ VectorSplat ( bcx, mask_llty. vector_length ( ) , mask)
2498+ } ,
2499+ _ => panic ! ( "shift_mask_val: expected Integer or Vector, found {:?}" , kind) ,
2500+ }
2501+ }
2502+
2503+ // Check if an integer or vector contains a nonzero element.
2504+ fn build_nonzero_check < ' blk , ' tcx > ( bcx : Block < ' blk , ' tcx > ,
2505+ value : ValueRef ,
2506+ binop_debug_loc : DebugLoc ) -> ValueRef {
2507+ let llty = val_ty ( value) ;
2508+ let kind = llty. kind ( ) ;
2509+ match kind {
2510+ TypeKind :: Integer => ICmp ( bcx, llvm:: IntNE , value, C_null ( llty) , binop_debug_loc) ,
2511+ TypeKind :: Vector => {
2512+ // Check if any elements of the vector are nonzero by treating
2513+ // it as a wide integer and checking if the integer is nonzero.
2514+ let width = llty. vector_length ( ) as u64 * llty. element_type ( ) . int_width ( ) ;
2515+ let int_value = BitCast ( bcx, value, Type :: ix ( bcx. ccx ( ) , width) ) ;
2516+ build_nonzero_check ( bcx, int_value, binop_debug_loc)
2517+ } ,
2518+ _ => panic ! ( "build_nonzero_check: expected Integer or Vector, found {:?}" , kind) ,
2519+ }
24852520}
24862521
24872522// To avoid UB from LLVM, these two functions mask RHS with an
@@ -2507,7 +2542,14 @@ fn build_unchecked_rshift<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
25072542 let rhs = base:: cast_shift_expr_rhs ( bcx, ast:: BinOp_ :: BiShr , lhs, rhs) ;
25082543 // #1877, #10183: Ensure that input is always valid
25092544 let rhs = shift_mask_rhs ( bcx, rhs, binop_debug_loc) ;
2510- let is_signed = ty:: type_is_signed ( lhs_t) ;
2545+ let tcx = bcx. tcx ( ) ;
2546+ let is_simd = ty:: type_is_simd ( tcx, lhs_t) ;
2547+ let intype = if is_simd {
2548+ ty:: simd_type ( tcx, lhs_t)
2549+ } else {
2550+ lhs_t
2551+ } ;
2552+ let is_signed = ty:: type_is_signed ( intype) ;
25112553 if is_signed {
25122554 AShr ( bcx, lhs, rhs, binop_debug_loc)
25132555 } else {
@@ -2519,8 +2561,7 @@ fn shift_mask_rhs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
25192561 rhs : ValueRef ,
25202562 debug_loc : DebugLoc ) -> ValueRef {
25212563 let rhs_llty = val_ty ( rhs) ;
2522- let mask = shift_mask_val ( rhs_llty) ;
2523- And ( bcx, rhs, C_integral ( rhs_llty, mask, false ) , debug_loc)
2564+ And ( bcx, rhs, shift_mask_val ( bcx, rhs_llty, rhs_llty, false ) , debug_loc)
25242565}
25252566
25262567fn with_overflow_check < ' blk , ' tcx > ( bcx : Block < ' blk , ' tcx > , oop : OverflowOp , info : NodeIdAndSpan ,
0 commit comments