Index: lib/Transforms/InstCombine/InstCombineCompares.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCompares.cpp +++ lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -1950,6 +1950,30 @@ 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. + if (Shl->hasNoUnsignedWrap()) { + Type *CTy = IntegerType::get(Cmp.getContext(), C->getBitWidth()); + if (X->getType()->isVectorTy()) + CTy = VectorType::get(CTy, X->getType()->getVectorNumElements()); + + APInt C_ = *C; + // If C is positive, pre-transform >=u/u/<=u. + if (C_.ugt(0)) { + if (Pred == ICmpInst::ICMP_UGE) { + C_ = C_ - 1; + Pred = ICmpInst::ICMP_UGT; + } + if (Pred == ICmpInst::ICMP_ULT) { + C_ = C_ - 1; + Pred = ICmpInst::ICMP_ULE; + } + } + + if (Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_ULE) + return new ICmpInst(Pred, X, ConstantInt::get(CTy, C_.lshr(*ShiftAmt))); + } + // 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: test/Transforms/InstCombine/icmp-shl-zext-simplify.ll =================================================================== --- /dev/null +++ test/Transforms/InstCombine/icmp-shl-zext-simplify.ll @@ -0,0 +1,72 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt %s -instcombine -S | FileCheck %s + +define i1 @icmp_ugt_32(i64) { +; CHECK-LABEL: @icmp_ugt_32( +; CHECK-NEXT: [[D:%.*]] = icmp ne i64 %0, 0 +; CHECK-NEXT: ret i1 [[D]] +; + %c = shl nuw i64 %0, 32 + %d = icmp ugt i64 %c, 4294967295 + ret i1 %d +} + +define i1 @icmp_ule_64(i128) { +; CHECK-LABEL: @icmp_ule_64( +; CHECK-NEXT: [[D:%.*]] = icmp eq i128 %0, 0 +; CHECK-NEXT: ret i1 [[D]] +; + %c = shl nuw i128 %0, 64 + %d = icmp ule i128 %c, 18446744073709551615 + ret i1 %d +} + +define i1 @icmp_ugt_16(i64) { +; CHECK-LABEL: @icmp_ugt_16( +; CHECK-NEXT: [[D:%.*]] = icmp ugt i64 %0, 15 +; CHECK-NEXT: ret i1 [[D]] +; + %c = shl nuw i64 %0, 16 + %d = icmp ugt i64 %c, 1048575 ; 0x0f_ffff + ret i1 %d +} + +define <2 x i1> @icmp_ule_16x2(<2 x i64>) { +; CHECK-LABEL: @icmp_ule_16x2( +; CHECK-NEXT: [[D:%.*]] = icmp eq <2 x i64> %0, zeroinitializer +; CHECK-NEXT: ret <2 x i1> [[D]] +; + %c = shl nuw <2 x i64> %0, + %d = icmp ule <2 x i64> %c, + ret <2 x i1> %d +} + +define i1 @icmp_ult_8(i64) { +; CHECK-LABEL: @icmp_ult_8( +; CHECK-NEXT: [[D:%.*]] = icmp ult i64 %0, 16 +; CHECK-NEXT: ret i1 [[D]] +; + %c = shl nuw i64 %0, 8 + %d = icmp ult i64 %c, 4095 ; 0x0fff + ret i1 %d +} + +define <2 x i1> @icmp_uge_8x2(<2 x i16>) { +; CHECK-LABEL: @icmp_uge_8x2( +; CHECK-NEXT: [[D:%.*]] = icmp ugt <2 x i16> %0, +; CHECK-NEXT: ret <2 x i1> [[D]] +; + %c = shl nuw <2 x i16> %0, + %d = icmp uge <2 x i16> %c, + ret <2 x i1> %d +} + +define <2 x i1> @icmp_ugt_16x2(<2 x i32>) { +; CHECK-LABEL: @icmp_ugt_16x2( +; CHECK-NEXT: [[D:%.*]] = icmp ugt <2 x i32> %0, +; CHECK-NEXT: ret <2 x i1> [[D]] +; + %c = shl nuw <2 x i32> %0, + %d = icmp ugt <2 x i32> %c, + ret <2 x i1> %d +}