Index: llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp =================================================================== --- llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -1950,6 +1950,23 @@ And, Constant::getNullValue(And->getType())); } + // When the shift is nuw and pred is >u or <=u, comparison only really happens + // in the pre-shifted bits. Since InstSimplify canoncalizes <=u into hasNoUnsignedWrap() && + (Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_ULT)) { + // Derivation for the ult case: + // (X << S) <=u C is equiv to X <=u (C >> S) for all C + // (X << S) > S) + 1 if C > S) + 1 if C >u 0 + assert((Pred != ICmpInst::ICMP_ULT || C->ugt(0)) && + "Encountered `ult 0` that should have been eliminated by " + "InstSimplify."); + APInt ShiftedC = Pred == ICmpInst::ICMP_ULT ? (*C - 1).lshr(*ShiftAmt) + 1 + : C->lshr(*ShiftAmt); + return new ICmpInst(Pred, X, ConstantInt::get(X->getType(), ShiftedC)); + } + // Transform (icmp pred iM (shl iM %v, N), C) // -> (icmp pred i(M-N) (trunc %v iM to i(M-N)), (trunc (C>>N)) // Transform the shl to a trunc if (trunc (C>>N)) has no loss and M-N. Index: llvm/trunk/test/Transforms/InstCombine/icmp-shl-nuw.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/icmp-shl-nuw.ll +++ llvm/trunk/test/Transforms/InstCombine/icmp-shl-nuw.ll @@ -3,8 +3,7 @@ define i1 @icmp_ugt_32(i64) { ; CHECK-LABEL: @icmp_ugt_32( -; CHECK-NEXT: [[C:%.*]] = shl nuw i64 %0, 32 -; CHECK-NEXT: [[D:%.*]] = icmp ugt i64 [[C]], 4294967295 +; CHECK-NEXT: [[D:%.*]] = icmp ne i64 %0, 0 ; CHECK-NEXT: ret i1 [[D]] ; %c = shl nuw i64 %0, 32 @@ -14,8 +13,7 @@ define i1 @icmp_ule_64(i128) { ; CHECK-LABEL: @icmp_ule_64( -; CHECK-NEXT: [[C:%.*]] = shl nuw i128 %0, 64 -; CHECK-NEXT: [[D:%.*]] = icmp ult i128 [[C]], 18446744073709551616 +; CHECK-NEXT: [[D:%.*]] = icmp eq i128 %0, 0 ; CHECK-NEXT: ret i1 [[D]] ; %c = shl nuw i128 %0, 64 @@ -25,8 +23,7 @@ define i1 @icmp_ugt_16(i64) { ; CHECK-LABEL: @icmp_ugt_16( -; CHECK-NEXT: [[C:%.*]] = shl nuw i64 %0, 16 -; CHECK-NEXT: [[D:%.*]] = icmp ugt i64 [[C]], 1048575 +; CHECK-NEXT: [[D:%.*]] = icmp ugt i64 %0, 15 ; CHECK-NEXT: ret i1 [[D]] ; %c = shl nuw i64 %0, 16 @@ -36,8 +33,7 @@ define <2 x i1> @icmp_ule_16x2(<2 x i64>) { ; CHECK-LABEL: @icmp_ule_16x2( -; CHECK-NEXT: [[C:%.*]] = shl nuw <2 x i64> %0, -; CHECK-NEXT: [[D:%.*]] = icmp ult <2 x i64> [[C]], +; CHECK-NEXT: [[D:%.*]] = icmp eq <2 x i64> %0, zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[D]] ; %c = shl nuw <2 x i64> %0, @@ -45,10 +41,29 @@ ret <2 x i1> %d } +define <2 x i1> @icmp_ule_16x2_nonzero(<2 x i64>) { +; CHECK-LABEL: @icmp_ule_16x2_nonzero( +; CHECK-NEXT: [[D:%.*]] = icmp ult <2 x i64> %0, +; CHECK-NEXT: ret <2 x i1> [[D]] +; + %c = shl nuw <2 x i64> %0, + %d = icmp ule <2 x i64> %c, ; 0x03_0000 + ret <2 x i1> %d +} + +define <2 x i1> @icmp_ule_12x2(<2 x i64>) { +; CHECK-LABEL: @icmp_ule_12x2( +; CHECK-NEXT: [[D:%.*]] = icmp ult <2 x i64> %0, +; CHECK-NEXT: ret <2 x i1> [[D]] +; + %c = shl nuw <2 x i64> %0, + %d = icmp ule <2 x i64> %c, ; 0x3000 + ret <2 x i1> %d +} + define i1 @icmp_ult_8(i64) { ; CHECK-LABEL: @icmp_ult_8( -; CHECK-NEXT: [[C:%.*]] = shl nuw i64 %0, 8 -; CHECK-NEXT: [[D:%.*]] = icmp ult i64 [[C]], 4095 +; CHECK-NEXT: [[D:%.*]] = icmp ult i64 %0, 16 ; CHECK-NEXT: ret i1 [[D]] ; %c = shl nuw i64 %0, 8 @@ -58,8 +73,7 @@ define <2 x i1> @icmp_uge_8x2(<2 x i16>) { ; CHECK-LABEL: @icmp_uge_8x2( -; CHECK-NEXT: [[C:%.*]] = shl nuw <2 x i16> %0, -; CHECK-NEXT: [[D:%.*]] = icmp ugt <2 x i16> [[C]], +; CHECK-NEXT: [[D:%.*]] = icmp ugt <2 x i16> %0, ; CHECK-NEXT: ret <2 x i1> [[D]] ; %c = shl nuw <2 x i16> %0, @@ -69,8 +83,7 @@ define <2 x i1> @icmp_ugt_16x2(<2 x i32>) { ; CHECK-LABEL: @icmp_ugt_16x2( -; CHECK-NEXT: [[C:%.*]] = shl nuw <2 x i32> %0, -; CHECK-NEXT: [[D:%.*]] = icmp ugt <2 x i32> [[C]], +; CHECK-NEXT: [[D:%.*]] = icmp ugt <2 x i32> %0, ; CHECK-NEXT: ret <2 x i1> [[D]] ; %c = shl nuw <2 x i32> %0,