From 4d980515d2accf33ca684524fbbeb31f098be6c4 Mon Sep 17 00:00:00 2001 From: Max Kazantsev Date: Fri, 27 Jul 2018 09:43:39 +0000 Subject: [PATCH] [SimplifyIndVar] Canonicalize comparisons to unsigned while eliminating truncs This is a follow-up for the patch rL335020. When we replace compares against trunc with compares against wide IV, we can also replace signed predicates with unsigned where it is legal. Reviewed By: reames Differential Revision: https://reviews.llvm.org/D48763 llvm-svn: 338115 --- llvm/lib/Transforms/Utils/SimplifyIndVar.cpp | 25 +++++++++++++++-- .../Transforms/IndVarSimplify/eliminate-trunc.ll | 31 ++++++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp b/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp index 7b07c9a..e381fbc 100644 --- a/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp @@ -555,6 +555,24 @@ bool SimplifyIndvar::eliminateTrunc(TruncInst *TI) { return false; } + 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. But in practice, we will never pass DoesZExtCollapse + // check for a negative value, because zext(trunc(x)) is non-negative. So + // it only make sense to check for non-negativity here. + const SCEV *SCEVOP1 = SE->getSCEV(ICI->getOperand(0)); + const SCEV *SCEVOP2 = SE->getSCEV(ICI->getOperand(1)); + return SE->isKnownNonNegative(SCEVOP1) && SE->isKnownNonNegative(SCEVOP2); + }; // Replace all comparisons against trunc with comparisons against IV. for (auto *ICI : ICmpUsers) { auto *Op1 = ICI->getOperand(1); @@ -565,17 +583,20 @@ bool SimplifyIndvar::eliminateTrunc(TruncInst *TI) { // 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); } diff --git a/llvm/test/Transforms/IndVarSimplify/eliminate-trunc.ll b/llvm/test/Transforms/IndVarSimplify/eliminate-trunc.ll index a95d156..7e0971f 100644 --- a/llvm/test/Transforms/IndVarSimplify/eliminate-trunc.ll +++ b/llvm/test/Transforms/IndVarSimplify/eliminate-trunc.ll @@ -531,3 +531,34 @@ bb6: ; preds = %bb4, %bb1 bb7: ; preds = %bb6 ret void } + +; Show that we can turn signed comparison to unsigned and use zext while +; comparing non-negative values. +define void @test_12(i32* %p) { +; CHECK-LABEL: @test_12( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[N:%.*]] = load i32, i32* [[P:%.*]], !range !0 +; 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 ult i64 [[IV_NEXT]], [[ZEXT]] +; CHECK-NEXT: br i1 [[TMP0]], label [[LOOP]], label [[EXIT:%.*]] +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + %n = load i32, i32* %p, !range !0 + br label %loop +loop: + %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] + %iv.next = add i64 %iv, 1 + %narrow.iv = trunc i64 %iv.next to i32 + %cmp = icmp slt i32 %narrow.iv, %n + br i1 %cmp, label %loop, label %exit +exit: + ret void +} + +!0 = !{i32 0, i32 1000} -- 2.7.4