[llvm] [indvars] Allow widenWithVariantUse to succeed without extend users (PR #71557)

Philip Reames via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 7 08:26:07 PST 2023


https://github.com/preames created https://github.com/llvm/llvm-project/pull/71557

We were considering the IV to be potentially dead and returning as-if the transform had succeeded when there were no extend users.  This is quite odd as there might be e.g. icmp users - in particular, icmp users which we've already proven we can widen.  We can instead simply go ahead and perform the transform for all users, and avoid the need to retain the original IV.

>From 616ab41a7a325a8c6160abae2e09ade94d0e41ad Mon Sep 17 00:00:00 2001
From: Philip Reames <preames at rivosinc.com>
Date: Tue, 7 Nov 2023 08:21:10 -0800
Subject: [PATCH] [indvars] Allow widenWithVariantUse to succeed without extend
 users

We were considering the IV to be potentially dead and returning as-if
the transform had succeeded when there were no extend users.  This is
quite odd as there might be e.g. icmp users - in particular, icmp
users which we've already provien we can widen.  We can instead simply
go ahead and perform the transform for all users, and avoid the need
to retain the original IV.
---
 llvm/lib/Transforms/Utils/SimplifyIndVar.cpp  | 58 +++++++++----------
 .../Transforms/IndVarSimplify/X86/pr57187.ll  |  5 +-
 .../widen-nonnegative-countdown.ll            | 21 +++----
 llvm/test/Transforms/LoopFlatten/widen-iv3.ll | 10 ++--
 4 files changed, 45 insertions(+), 49 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp b/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp
index 0b40d44c7443763..37735a0442ce205 100644
--- a/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp
@@ -1611,37 +1611,33 @@ bool WidenIV::widenWithVariantUse(WidenIV::NarrowIVDefUse DU) {
       return false;
     ExtUsers.push_back(User);
   }
-  if (ExtUsers.empty()) {
-    DeadInsts.emplace_back(NarrowUse);
-    return true;
-  }
-
-  // We'll prove some facts that should be true in the context of ext users. If
-  // there is no users, we are done now. If there are some, pick their common
-  // dominator as context.
-  const Instruction *CtxI = findCommonDominator(ExtUsers, *DT);
-
-  if (!CanSignExtend && !CanZeroExtend) {
-    // Because InstCombine turns 'sub nuw' to 'add' losing the no-wrap flag, we
-    // will most likely not see it. Let's try to prove it.
-    if (OpCode != Instruction::Add)
-      return false;
-    if (ExtKind != ExtendKind::Zero)
-      return false;
-    const SCEV *LHS = SE->getSCEV(OBO->getOperand(0));
-    const SCEV *RHS = SE->getSCEV(OBO->getOperand(1));
-    // TODO: Support case for NarrowDef = NarrowUse->getOperand(1).
-    if (NarrowUse->getOperand(0) != NarrowDef)
-      return false;
-    if (!SE->isKnownNegative(RHS))
-      return false;
-    bool ProvedSubNUW = SE->isKnownPredicateAt(ICmpInst::ICMP_UGE, LHS,
-                                               SE->getNegativeSCEV(RHS), CtxI);
-    if (!ProvedSubNUW)
-      return false;
-    // In fact, our 'add' is 'sub nuw'. We will need to widen the 2nd operand as
-    // neg(zext(neg(op))), which is basically sext(op).
-    AnotherOpExtKind = ExtendKind::Sign;
+  if (!ExtUsers.empty()) {
+    // We'll prove some facts that should be true in the context of ext users.
+    // Pick their common dominator as context.
+    const Instruction *CtxI = findCommonDominator(ExtUsers, *DT);
+
+    if (!CanSignExtend && !CanZeroExtend) {
+      // Because InstCombine turns 'sub nuw' to 'add' losing the no-wrap flag, we
+      // will most likely not see it. Let's try to prove it.
+      if (OpCode != Instruction::Add)
+        return false;
+      if (ExtKind != ExtendKind::Zero)
+        return false;
+      const SCEV *LHS = SE->getSCEV(OBO->getOperand(0));
+      const SCEV *RHS = SE->getSCEV(OBO->getOperand(1));
+      // TODO: Support case for NarrowDef = NarrowUse->getOperand(1).
+      if (NarrowUse->getOperand(0) != NarrowDef)
+        return false;
+      if (!SE->isKnownNegative(RHS))
+        return false;
+      bool ProvedSubNUW = SE->isKnownPredicateAt(ICmpInst::ICMP_UGE, LHS,
+                                                 SE->getNegativeSCEV(RHS), CtxI);
+      if (!ProvedSubNUW)
+        return false;
+      // In fact, our 'add' is 'sub nuw'. We will need to widen the 2nd operand as
+      // neg(zext(neg(op))), which is basically sext(op).
+      AnotherOpExtKind = ExtendKind::Sign;
+    }
   }
 
   // Verifying that Defining operand is an AddRec
diff --git a/llvm/test/Transforms/IndVarSimplify/X86/pr57187.ll b/llvm/test/Transforms/IndVarSimplify/X86/pr57187.ll
index 620b0adaebfe584..7a3c829c3b0b628 100644
--- a/llvm/test/Transforms/IndVarSimplify/X86/pr57187.ll
+++ b/llvm/test/Transforms/IndVarSimplify/X86/pr57187.ll
@@ -15,14 +15,15 @@ define void @test(i32 %start) {
 ; CHECK-NEXT:    br label [[LOOP]]
 ; CHECK:       loop:
 ; CHECK-NEXT:    [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ [[TMP1]], [[ENTRY:%.*]] ]
+; CHECK-NEXT:    [[TMP2:%.*]] = add nuw nsw i64 [[INDVARS_IV]], 4294967295
 ; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nsw i64 [[INDVARS_IV]], -1
-; CHECK-NEXT:    [[INDVARS:%.*]] = trunc i64 [[INDVARS_IV_NEXT]] to i32
 ; CHECK-NEXT:    [[LOOP_EXIT_COND:%.*]] = icmp slt i32 [[TMP0]], 11
 ; CHECK-NEXT:    br i1 [[LOOP_EXIT_COND]], label [[EXIT:%.*]], label [[STUCK_PREHEADER:%.*]]
 ; CHECK:       stuck.preheader:
 ; CHECK-NEXT:    br label [[STUCK:%.*]]
 ; CHECK:       exit:
-; CHECK-NEXT:    [[IV_NEXT_LCSSA:%.*]] = phi i32 [ [[INDVARS]], [[LOOP]] ]
+; CHECK-NEXT:    [[IV_NEXT_LCSSA_WIDE:%.*]] = phi i64 [ [[TMP2]], [[LOOP]] ]
+; CHECK-NEXT:    [[TMP3:%.*]] = trunc i64 [[IV_NEXT_LCSSA_WIDE]] to i32
 ; CHECK-NEXT:    ret void
 ; CHECK:       stuck:
 ; CHECK-NEXT:    br i1 false, label [[BACKEDGE]], label [[STUCK]]
diff --git a/llvm/test/Transforms/IndVarSimplify/widen-nonnegative-countdown.ll b/llvm/test/Transforms/IndVarSimplify/widen-nonnegative-countdown.ll
index d473103f5824e62..c9d84f1a5a63d24 100644
--- a/llvm/test/Transforms/IndVarSimplify/widen-nonnegative-countdown.ll
+++ b/llvm/test/Transforms/IndVarSimplify/widen-nonnegative-countdown.ll
@@ -82,13 +82,12 @@ define void @zext_postinc(ptr %A, i32 %start) {
 ; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
 ; CHECK:       for.body:
 ; CHECK-NEXT:    [[INDVARS_IV:%.*]] = phi i64 [ [[TMP0]], [[FOR_BODY_PREHEADER]] ], [ [[INDVARS_IV_NEXT:%.*]], [[FOR_BODY]] ]
-; CHECK-NEXT:    [[J_016_US:%.*]] = phi i32 [ [[INC_US:%.*]], [[FOR_BODY]] ], [ [[START]], [[FOR_BODY_PREHEADER]] ]
 ; CHECK-NEXT:    [[ARRAYIDX_US:%.*]] = getelementptr inbounds i32, ptr [[A:%.*]], i64 [[INDVARS_IV]]
 ; CHECK-NEXT:    tail call void @use_ptr(ptr [[ARRAYIDX_US]])
-; CHECK-NEXT:    [[INC_US]] = add nsw i32 [[J_016_US]], -1
-; CHECK-NEXT:    [[CMP2_US:%.*]] = icmp ugt i32 [[INC_US]], 6
+; CHECK-NEXT:    [[TMP1:%.*]] = add nsw i64 [[INDVARS_IV]], 4294967295
+; CHECK-NEXT:    [[CMP2_US_WIDE:%.*]] = icmp ugt i64 [[TMP1]], 6
 ; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nsw i64 [[INDVARS_IV]], -1
-; CHECK-NEXT:    br i1 [[CMP2_US]], label [[FOR_BODY]], label [[EXIT_LOOPEXIT:%.*]]
+; CHECK-NEXT:    br i1 [[CMP2_US_WIDE]], label [[FOR_BODY]], label [[EXIT_LOOPEXIT:%.*]]
 ; CHECK:       exit.loopexit:
 ; CHECK-NEXT:    br label [[EXIT]]
 ; CHECK:       exit:
@@ -365,16 +364,15 @@ define void @zext_postinc_offset_constant_one(ptr %A, i32 %start) {
 ; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
 ; CHECK:       for.body:
 ; CHECK-NEXT:    [[INDVARS_IV:%.*]] = phi i64 [ [[TMP0]], [[FOR_BODY_PREHEADER]] ], [ [[INDVARS_IV_NEXT:%.*]], [[FOR_BODY]] ]
-; CHECK-NEXT:    [[J_016_US:%.*]] = phi i32 [ [[INC_US:%.*]], [[FOR_BODY]] ], [ [[START]], [[FOR_BODY_PREHEADER]] ]
 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc i64 [[INDVARS_IV]] to i32
 ; CHECK-NEXT:    [[ADD_US:%.*]] = add i32 [[TMP1]], 1
 ; CHECK-NEXT:    [[IDXPROM_US:%.*]] = zext i32 [[ADD_US]] to i64
 ; CHECK-NEXT:    [[ARRAYIDX_US:%.*]] = getelementptr inbounds i32, ptr [[A:%.*]], i64 [[IDXPROM_US]]
 ; CHECK-NEXT:    tail call void @use_ptr(ptr [[ARRAYIDX_US]])
-; CHECK-NEXT:    [[INC_US]] = add nsw i32 [[J_016_US]], -1
-; CHECK-NEXT:    [[CMP2_US:%.*]] = icmp ugt i32 [[INC_US]], 6
+; CHECK-NEXT:    [[TMP2:%.*]] = add nsw i64 [[INDVARS_IV]], 4294967295
+; CHECK-NEXT:    [[CMP2_US_WIDE:%.*]] = icmp ugt i64 [[TMP2]], 6
 ; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nsw i64 [[INDVARS_IV]], -1
-; CHECK-NEXT:    br i1 [[CMP2_US]], label [[FOR_BODY]], label [[EXIT_LOOPEXIT:%.*]]
+; CHECK-NEXT:    br i1 [[CMP2_US_WIDE]], label [[FOR_BODY]], label [[EXIT_LOOPEXIT:%.*]]
 ; CHECK:       exit.loopexit:
 ; CHECK-NEXT:    br label [[EXIT]]
 ; CHECK:       exit:
@@ -664,14 +662,13 @@ define void @zext_postinc_offset_constant_minus_one(ptr %A, i32 %start) {
 ; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
 ; CHECK:       for.body:
 ; CHECK-NEXT:    [[INDVARS_IV:%.*]] = phi i64 [ [[TMP0]], [[FOR_BODY_PREHEADER]] ], [ [[INDVARS_IV_NEXT:%.*]], [[FOR_BODY]] ]
-; CHECK-NEXT:    [[J_016_US:%.*]] = phi i32 [ [[INC_US:%.*]], [[FOR_BODY]] ], [ [[START]], [[FOR_BODY_PREHEADER]] ]
 ; CHECK-NEXT:    [[TMP1:%.*]] = add nsw i64 [[INDVARS_IV]], -1
 ; CHECK-NEXT:    [[ARRAYIDX_US:%.*]] = getelementptr inbounds i32, ptr [[A:%.*]], i64 [[TMP1]]
 ; CHECK-NEXT:    tail call void @use_ptr(ptr [[ARRAYIDX_US]])
-; CHECK-NEXT:    [[INC_US]] = add nsw i32 [[J_016_US]], -1
-; CHECK-NEXT:    [[CMP2_US:%.*]] = icmp ugt i32 [[INC_US]], 6
+; CHECK-NEXT:    [[TMP2:%.*]] = add nsw i64 [[INDVARS_IV]], 4294967295
+; CHECK-NEXT:    [[CMP2_US_WIDE:%.*]] = icmp ugt i64 [[TMP2]], 6
 ; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nsw i64 [[INDVARS_IV]], -1
-; CHECK-NEXT:    br i1 [[CMP2_US]], label [[FOR_BODY]], label [[EXIT_LOOPEXIT:%.*]]
+; CHECK-NEXT:    br i1 [[CMP2_US_WIDE]], label [[FOR_BODY]], label [[EXIT_LOOPEXIT:%.*]]
 ; CHECK:       exit.loopexit:
 ; CHECK-NEXT:    br label [[EXIT]]
 ; CHECK:       exit:
diff --git a/llvm/test/Transforms/LoopFlatten/widen-iv3.ll b/llvm/test/Transforms/LoopFlatten/widen-iv3.ll
index df8ee6ff0750574..12c30c271f07df4 100644
--- a/llvm/test/Transforms/LoopFlatten/widen-iv3.ll
+++ b/llvm/test/Transforms/LoopFlatten/widen-iv3.ll
@@ -34,11 +34,13 @@ define i16 @foo() {
 ; CHECK-NEXT:    [[J_011:%.*]] = phi i16 [ 0, [[FOR_COND1_PREHEADER]] ], [ [[INC:%.*]], [[FOR_BODY4]] ]
 ; CHECK-NEXT:    [[SUM_110:%.*]] = phi i16 [ [[SUM_012]], [[FOR_COND1_PREHEADER]] ], [ [[ADD5]], [[FOR_BODY4]] ]
 ; CHECK-NEXT:    [[TMP2:%.*]] = add nuw nsw i32 [[INDVAR]], [[TMP0]]
+; CHECK-NEXT:    [[TMP3:%.*]] = sext i16 [[J_011]] to i32
+; CHECK-NEXT:    [[TMP4:%.*]] = add nuw nsw i32 [[TMP3]], [[TMP0]]
 ; CHECK-NEXT:    [[ADD:%.*]] = add nuw nsw i16 [[J_011]], [[MUL]]
-; CHECK-NEXT:    [[TMP3:%.*]] = trunc i32 [[TMP2]] to i16
-; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [64 x i16], ptr @v, i16 0, i16 [[TMP3]]
-; CHECK-NEXT:    [[TMP4:%.*]] = load i16, ptr [[ARRAYIDX]], align 1
-; CHECK-NEXT:    [[ADD5]] = add nsw i16 [[TMP4]], [[SUM_110]]
+; CHECK-NEXT:    [[TMP5:%.*]] = trunc i32 [[TMP2]] to i16
+; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [64 x i16], ptr @v, i16 0, i16 [[TMP5]]
+; CHECK-NEXT:    [[TMP6:%.*]] = load i16, ptr [[ARRAYIDX]], align 1
+; CHECK-NEXT:    [[ADD5]] = add nsw i16 [[TMP6]], [[SUM_110]]
 ; CHECK-NEXT:    [[INDVAR_NEXT]] = add i32 [[INDVAR]], 1
 ; CHECK-NEXT:    [[INC]] = add nuw nsw i16 [[J_011]], 1
 ; CHECK-NEXT:    [[EXITCOND_NOT:%.*]] = icmp eq i32 [[INDVAR_NEXT]], 16



More information about the llvm-commits mailing list