[llvm] 0836a10 - Extend transform introduced in D111896 to multiple exits

Philip Reames via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 19 12:15:03 PDT 2021


Author: Philip Reames
Date: 2021-10-19T12:12:19-07:00
New Revision: 0836a1059dcf8e4fbf408248bf5eed13dfd93f7b

URL: https://github.com/llvm/llvm-project/commit/0836a1059dcf8e4fbf408248bf5eed13dfd93f7b
DIFF: https://github.com/llvm/llvm-project/commit/0836a1059dcf8e4fbf408248bf5eed13dfd93f7b.diff

LOG: Extend transform introduced in D111896 to multiple exits

This is trivial.  It was left out of the original review only because we had multiple copies of the same code in review at the same time, and keeping them in sync was easiest if the structure was kept in sync.

Added: 
    

Modified: 
    llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
    llvm/test/Transforms/IndVarSimplify/finite-exit-comparisons.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
index bf776b1cfd7f6..57253abb1be50 100644
--- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
+++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
@@ -1420,43 +1420,45 @@ bool IndVarSimplify::canonicalizeExitCondition(Loop *L) {
   // rely on them which results in SCEV caching sub-optimal answers.  The
   // concern about caching sub-optimal results is why we only query SCEVs of
   // the loop invariant RHS here.
+  SmallVector<BasicBlock*, 16> ExitingBlocks;
+  L->getExitingBlocks(ExitingBlocks);
+  bool Changed = false;
+  for (auto *ExitingBB : ExitingBlocks) {
+    auto *BI = dyn_cast<BranchInst>(ExitingBB->getTerminator());
+    if (!BI)
+      continue;
+    assert(BI->isConditional() && "exit branch must be conditional");
 
-  auto *ExitingBB = L->getExitingBlock();
-  if (!ExitingBB)
-    return false;
-  auto *BI = dyn_cast<BranchInst>(ExitingBB->getTerminator());
-  if (!BI)
-    return false;
-  assert(BI->isConditional() && "exit branch must be conditional");
-
-  auto *ICmp = dyn_cast<ICmpInst>(BI->getCondition());
-  if (!ICmp)
-    return false;
+    auto *ICmp = dyn_cast<ICmpInst>(BI->getCondition());
+    if (!ICmp)
+      continue;
 
-  auto *LHS = ICmp->getOperand(0);
-  auto *RHS = ICmp->getOperand(1);
-  // Avoid computing SCEVs in the loop to avoid poisoning cache with
-  // sub-optimal results.
-  if (!L->isLoopInvariant(RHS))
-    return false;
+    auto *LHS = ICmp->getOperand(0);
+    auto *RHS = ICmp->getOperand(1);
+    // Avoid computing SCEVs in the loop to avoid poisoning cache with
+    // sub-optimal results.
+    if (!L->isLoopInvariant(RHS))
+      continue;
 
-  // Match (icmp signed-cond zext, RHS)
-  Value *LHSOp = nullptr;
-  if (!match(LHS, m_ZExt(m_Value(LHSOp))) || !ICmp->isSigned())
-    return false;
+    // Match (icmp signed-cond zext, RHS)
+    Value *LHSOp = nullptr;
+    if (!match(LHS, m_ZExt(m_Value(LHSOp))) || !ICmp->isSigned())
+      continue;
 
-  const DataLayout &DL = ExitingBB->getModule()->getDataLayout();
-  const unsigned InnerBitWidth = DL.getTypeSizeInBits(LHSOp->getType());
-  const unsigned OuterBitWidth = DL.getTypeSizeInBits(RHS->getType());
-  auto FullCR = ConstantRange::getFull(InnerBitWidth);
-  FullCR = FullCR.zeroExtend(OuterBitWidth);
-  if (!FullCR.contains(SE->getUnsignedRange(SE->getSCEV(RHS))))
-    return false;
+    const DataLayout &DL = ExitingBB->getModule()->getDataLayout();
+    const unsigned InnerBitWidth = DL.getTypeSizeInBits(LHSOp->getType());
+    const unsigned OuterBitWidth = DL.getTypeSizeInBits(RHS->getType());
+    auto FullCR = ConstantRange::getFull(InnerBitWidth);
+    FullCR = FullCR.zeroExtend(OuterBitWidth);
+    if (!FullCR.contains(SE->getUnsignedRange(SE->getSCEV(RHS))))
+      continue;
 
-  // We have now matched icmp signed-cond zext(X), zext(Y'), and can thus
-  // replace the signed condition with the unsigned version.
-  ICmp->setPredicate(ICmp->getUnsignedPredicate());
-  return true;
+    // We have now matched icmp signed-cond zext(X), zext(Y'), and can thus
+    // replace the signed condition with the unsigned version.
+    ICmp->setPredicate(ICmp->getUnsignedPredicate());
+    Changed = true;
+  }
+  return Changed;
 }
 
 bool IndVarSimplify::optimizeLoopExits(Loop *L, SCEVExpander &Rewriter) {

diff  --git a/llvm/test/Transforms/IndVarSimplify/finite-exit-comparisons.ll b/llvm/test/Transforms/IndVarSimplify/finite-exit-comparisons.ll
index c803a54963a91..e9192f34f0685 100644
--- a/llvm/test/Transforms/IndVarSimplify/finite-exit-comparisons.ll
+++ b/llvm/test/Transforms/IndVarSimplify/finite-exit-comparisons.ll
@@ -34,6 +34,69 @@ for.end:                                          ; preds = %for.body, %entry
   ret void
 }
 
+;; Range logic doesn't depend on must execute
+define void @slt_constant_rhs_maythrow(i16 %n.raw, i8 %start) mustprogress {
+; CHECK-LABEL: @slt_constant_rhs_maythrow(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
+; CHECK:       for.body:
+; CHECK-NEXT:    [[IV:%.*]] = phi i8 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ [[START:%.*]], [[ENTRY:%.*]] ]
+; CHECK-NEXT:    [[IV_NEXT]] = add i8 [[IV]], 1
+; CHECK-NEXT:    call void @unknown()
+; CHECK-NEXT:    [[ZEXT:%.*]] = zext i8 [[IV_NEXT]] to i16
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i16 [[ZEXT]], 254
+; CHECK-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]]
+; CHECK:       for.end:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %for.body
+
+for.body:                                         ; preds = %entry, %for.body
+  %iv = phi i8 [ %iv.next, %for.body ], [ %start, %entry ]
+  %iv.next = add i8 %iv, 1
+  call void @unknown()
+  %zext = zext i8 %iv.next to i16
+  %cmp = icmp slt i16 %zext, 254
+  br i1 %cmp, label %for.body, label %for.end
+
+for.end:                                          ; preds = %for.body, %entry
+  ret void
+}
+
+;; Range logic doesn't depend on must execute
+define void @slt_constant_rhs_multiexit(i16 %n.raw, i8 %start, i1 %c) mustprogress {
+; CHECK-LABEL: @slt_constant_rhs_multiexit(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
+; CHECK:       for.body:
+; CHECK-NEXT:    [[IV:%.*]] = phi i8 [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ], [ [[START:%.*]], [[ENTRY:%.*]] ]
+; CHECK-NEXT:    [[IV_NEXT]] = add i8 [[IV]], 1
+; CHECK-NEXT:    br i1 [[C:%.*]], label [[LATCH]], label [[FOR_END:%.*]]
+; CHECK:       latch:
+; CHECK-NEXT:    [[ZEXT:%.*]] = zext i8 [[IV_NEXT]] to i16
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i16 [[ZEXT]], 254
+; CHECK-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END]]
+; CHECK:       for.end:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %for.body
+
+for.body:                                         ; preds = %entry, %for.body
+  %iv = phi i8 [ %iv.next, %latch ], [ %start, %entry ]
+  %iv.next = add i8 %iv, 1
+  br i1 %c, label %latch, label %for.end
+
+latch:
+  %zext = zext i8 %iv.next to i16
+  %cmp = icmp slt i16 %zext, 254
+  br i1 %cmp, label %for.body, label %for.end
+
+for.end:                                          ; preds = %for.body, %entry
+  ret void
+}
+
 define void @slt_non_constant_rhs(i16 %n) mustprogress {
 ; CHECK-LABEL: @slt_non_constant_rhs(
 ; CHECK-NEXT:  entry:


        


More information about the llvm-commits mailing list