@@ -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 ;
@@ -2455,12 +2455,10 @@ impl OverflowOpViaInputCheck {
24552455 // (since that is where the 32/64 distinction is relevant) but
24562456 // the mask's type must match the RHS type (since they will
24572457 // both be fed into a and-binop)
2458- let invert_mask = !shift_mask_val ( lhs_llty) ;
2459- let invert_mask = C_integral ( rhs_llty, invert_mask, true ) ;
2458+ let invert_mask = shift_mask_val ( bcx, lhs_llty, rhs_llty, true ) ;
24602459
24612460 let outer_bits = And ( bcx, rhs, invert_mask, binop_debug_loc) ;
2462- let cond = ICmp ( bcx, llvm:: IntNE , outer_bits,
2463- C_integral ( rhs_llty, 0 , false ) , binop_debug_loc) ;
2461+ let cond = build_nonzero_check ( bcx, outer_bits, binop_debug_loc) ;
24642462 let result = match * self {
24652463 OverflowOpViaInputCheck :: Shl =>
24662464 build_unchecked_lshift ( bcx, lhs, rhs, binop_debug_loc) ,
@@ -2476,9 +2474,46 @@ impl OverflowOpViaInputCheck {
24762474 }
24772475}
24782476
2479- fn shift_mask_val ( llty : Type ) -> u64 {
2480- // i8/u8 can shift by at most 7, i16/u16 by at most 15, etc.
2481- llty. int_width ( ) - 1
2477+ fn shift_mask_val < ' blk , ' tcx > ( bcx : Block < ' blk , ' tcx > ,
2478+ llty : Type ,
2479+ mask_llty : Type ,
2480+ invert : bool ) -> ValueRef {
2481+ let kind = llty. kind ( ) ;
2482+ match kind {
2483+ TypeKind :: Integer => {
2484+ // i8/u8 can shift by at most 7, i16/u16 by at most 15, etc.
2485+ let val = llty. int_width ( ) - 1 ;
2486+ if invert {
2487+ C_integral ( mask_llty, !val, true )
2488+ } else {
2489+ C_integral ( mask_llty, val, false )
2490+ }
2491+ } ,
2492+ TypeKind :: Vector => {
2493+ let mask = shift_mask_val ( bcx, llty. element_type ( ) , mask_llty. element_type ( ) , invert) ;
2494+ VectorSplat ( bcx, mask_llty. vector_length ( ) , mask)
2495+ } ,
2496+ _ => panic ! ( "shift_mask_val: expected Integer or Vector, found {:?}" , kind) ,
2497+ }
2498+ }
2499+
2500+ // Check if an integer or vector contains a nonzero element.
2501+ fn build_nonzero_check < ' blk , ' tcx > ( bcx : Block < ' blk , ' tcx > ,
2502+ value : ValueRef ,
2503+ binop_debug_loc : DebugLoc ) -> ValueRef {
2504+ let llty = val_ty ( value) ;
2505+ let kind = llty. kind ( ) ;
2506+ match kind {
2507+ TypeKind :: Integer => ICmp ( bcx, llvm:: IntNE , value, C_null ( llty) , binop_debug_loc) ,
2508+ TypeKind :: Vector => {
2509+ // Check if any elements of the vector are nonzero by treating
2510+ // it as a wide integer and checking if the integer is nonzero.
2511+ let width = llty. vector_length ( ) as u64 * llty. element_type ( ) . int_width ( ) ;
2512+ let int_value = BitCast ( bcx, value, Type :: ix ( bcx. ccx ( ) , width) ) ;
2513+ build_nonzero_check ( bcx, int_value, binop_debug_loc)
2514+ } ,
2515+ _ => panic ! ( "build_nonzero_check: expected Integer or Vector, found {:?}" , kind) ,
2516+ }
24822517}
24832518
24842519// To avoid UB from LLVM, these two functions mask RHS with an
@@ -2504,7 +2539,14 @@ fn build_unchecked_rshift<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
25042539 let rhs = base:: cast_shift_expr_rhs ( bcx, ast:: BinOp_ :: BiShr , lhs, rhs) ;
25052540 // #1877, #10183: Ensure that input is always valid
25062541 let rhs = shift_mask_rhs ( bcx, rhs, binop_debug_loc) ;
2507- let is_signed = ty:: type_is_signed ( lhs_t) ;
2542+ let tcx = bcx. tcx ( ) ;
2543+ let is_simd = ty:: type_is_simd ( tcx, lhs_t) ;
2544+ let intype = if is_simd {
2545+ ty:: simd_type ( tcx, lhs_t)
2546+ } else {
2547+ lhs_t
2548+ } ;
2549+ let is_signed = ty:: type_is_signed ( intype) ;
25082550 if is_signed {
25092551 AShr ( bcx, lhs, rhs, binop_debug_loc)
25102552 } else {
@@ -2516,8 +2558,7 @@ fn shift_mask_rhs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
25162558 rhs : ValueRef ,
25172559 debug_loc : DebugLoc ) -> ValueRef {
25182560 let rhs_llty = val_ty ( rhs) ;
2519- let mask = shift_mask_val ( rhs_llty) ;
2520- And ( bcx, rhs, C_integral ( rhs_llty, mask, false ) , debug_loc)
2561+ And ( bcx, rhs, shift_mask_val ( bcx, rhs_llty, rhs_llty, false ) , debug_loc)
25212562}
25222563
25232564fn with_overflow_check < ' blk , ' tcx > ( bcx : Block < ' blk , ' tcx > , oop : OverflowOp , info : NodeIdAndSpan ,
0 commit comments