Index: lib/Transforms/Utils/SimplifyIndVar.cpp =================================================================== --- lib/Transforms/Utils/SimplifyIndVar.cpp +++ lib/Transforms/Utils/SimplifyIndVar.cpp @@ -555,6 +555,26 @@ return false; } + auto HighestBitsMatch = [&](Value *X, Value *Y) { + const SCEV *SCEVX = SE->getSCEV(X); + const SCEV *SCEVY = SE->getSCEV(X); + return (SE->isKnownNonNegative(SCEVX) && SE->isKnownNonNegative(SCEVY)) || + (SE->isKnownNegative(SCEVX) && SE->isKnownNegative(SCEVY)); + }; + auto CanUseZExt = [&](ICmpInst *ICI) { + // Unsigned comparison can be widened as unsigned. + if (ICI->isUnsigned()) + return true; + // Is it profitable to do zext? + if (!DoesZExtCollapse) + return false; + // For equality, we can safely zext both parts. + if (ICI->isEquality()) + return true; + // Otherwise we can only use zext when comparing two non-negative or two + // negative values. + return HighestBitsMatch(ICI->getOperand(0), ICI->getOperand(1)); + }; // Replace all comparisons against trunc with comparisons against IV. for (auto *ICI : ICmpUsers) { auto *Op1 = ICI->getOperand(1); @@ -565,17 +585,20 @@ // then prefer zext as a more canonical form. // TODO: If we see a signed comparison which can be turned into unsigned, // we can do it here for canonicalization purposes. - if (ICI->isUnsigned() || (ICI->isEquality() && DoesZExtCollapse)) { + ICmpInst::Predicate Pred = ICI->getPredicate(); + if (CanUseZExt(ICI)) { assert(DoesZExtCollapse && "Unprofitable zext?"); Ext = new ZExtInst(Op1, IVTy, "zext", ICI); + Pred = ICmpInst::getUnsignedPredicate(Pred); } else { assert(DoesSExtCollapse && "Unprofitable sext?"); Ext = new SExtInst(Op1, IVTy, "sext", ICI); + assert(Pred == ICmpInst::getSignedPredicate(Pred) && "Must be signed!"); } bool Changed; L->makeLoopInvariant(Ext, Changed); (void)Changed; - ICmpInst *NewICI = new ICmpInst(ICI, ICI->getPredicate(), IV, Ext); + ICmpInst *NewICI = new ICmpInst(ICI, Pred, IV, Ext); ICI->replaceAllUsesWith(NewICI); DeadInsts.emplace_back(ICI); } Index: test/Transforms/IndVarSimplify/eliminate-trunc.ll =================================================================== --- test/Transforms/IndVarSimplify/eliminate-trunc.ll +++ test/Transforms/IndVarSimplify/eliminate-trunc.ll @@ -36,12 +36,12 @@ ; ; CHECK-LABEL: @test_01( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[SEXT:%.*]] = sext i32 [[N:%.*]] to i64 +; CHECK-NEXT: [[ZEXT:%.*]] = zext i32 [[N:%.*]] to i64 ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 -; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i64 [[IV]], [[SEXT]] +; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i64 [[IV]], [[ZEXT]] ; CHECK-NEXT: br i1 [[TMP0]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK: exit: ; CHECK-NEXT: ret void @@ -63,12 +63,12 @@ ; ; CHECK-LABEL: @test_02( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[SEXT:%.*]] = sext i32 [[N:%.*]] to i64 +; CHECK-NEXT: [[ZEXT:%.*]] = zext i32 [[N:%.*]] to i64 ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 2147483646, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 -; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i64 [[IV]], [[SEXT]] +; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i64 [[IV]], [[ZEXT]] ; CHECK-NEXT: br i1 [[TMP0]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK: exit: ; CHECK-NEXT: ret void @@ -90,9 +90,11 @@ ; ; CHECK-LABEL: @test_03( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[ZEXT:%.*]] = zext i32 [[N:%.*]] to i64 ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: -; CHECK-NEXT: br i1 false, label [[LOOP]], label [[EXIT:%.*]] +; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i64 2147483647, [[ZEXT]] +; CHECK-NEXT: br i1 [[TMP0]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK: exit: ; CHECK-NEXT: ret void ; @@ -403,12 +405,12 @@ ; CHECK-LABEL: @test_08( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ZEXT:%.*]] = zext i32 [[N:%.*]] to i64 -; CHECK-NEXT: [[SEXT:%.*]] = sext i32 [[N]] to i64 +; CHECK-NEXT: [[ZEXT1:%.*]] = zext i32 [[N]] to i64 ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 1, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 -; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i64 [[IV]], [[SEXT]] +; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i64 [[IV]], [[ZEXT1]] ; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i64 [[IV]], [[ZEXT]] ; CHECK-NEXT: [[CMP:%.*]] = and i1 [[TMP0]], [[TMP1]] ; CHECK-NEXT: br i1 [[CMP]], label [[LOOP]], label [[EXIT:%.*]]