[SimplifyIndVar] Constant fold IV users
authorHongbin Zheng <etherzhhb@gmail.com>
Wed, 27 Sep 2017 03:11:46 +0000 (03:11 +0000)
committerHongbin Zheng <etherzhhb@gmail.com>
Wed, 27 Sep 2017 03:11:46 +0000 (03:11 +0000)
This patch tries to transform cases like:

for (unsigned i = 0; i < N; i += 2) {
  bool c0 = (i & 0x1) == 0;
  bool c1 = ((i + 1) & 0x1) == 1;
}
To

for (unsigned i = 0; i < N; i += 2) {
  bool c0 = true;
  bool c1 = true;
}

This commit also update test/Transforms/IndVarSimplify/replace-srem-by-urem.ll to prevent constant folding.

Differential Revision: https://reviews.llvm.org/D38272

llvm-svn: 314266

llvm/lib/Transforms/Utils/SimplifyIndVar.cpp
llvm/test/Transforms/IndVarSimplify/constant-fold.ll [new file with mode: 0644]
llvm/test/Transforms/IndVarSimplify/replace-srem-by-urem.ll

index 5228f06..cef8fe1 100644 (file)
@@ -35,6 +35,7 @@ using namespace llvm;
 
 STATISTIC(NumElimIdentity, "Number of IV identities eliminated");
 STATISTIC(NumElimOperand,  "Number of IV operands folded into a use");
+STATISTIC(NumFoldedUser, "Number of IV users folded into a constant");
 STATISTIC(NumElimRem     , "Number of IV remainder operations eliminated");
 STATISTIC(
     NumSimplifiedSDiv,
@@ -76,6 +77,7 @@ namespace {
     Value *foldIVUser(Instruction *UseInst, Instruction *IVOperand);
 
     bool eliminateIdentitySCEV(Instruction *UseInst, Instruction *IVOperand);
+    bool foldConstantSCEV(Instruction *UseInst);
 
     bool eliminateOverflowIntrinsic(CallInst *CI);
     bool eliminateIVUser(Instruction *UseInst, Instruction *IVOperand);
@@ -534,6 +536,30 @@ bool SimplifyIndvar::eliminateIVUser(Instruction *UseInst,
   return false;
 }
 
+/// Replace the UseInst with a constant if possible
+bool SimplifyIndvar::foldConstantSCEV(Instruction *I) {
+  if (!SE->isSCEVable(I->getType()))
+    return false;
+
+  // Get the symbolic expression for this instruction.
+  const SCEV *S = SE->getSCEV(I);
+
+  const Loop *L = LI->getLoopFor(I->getParent());
+  S = SE->getSCEVAtScope(S, L);
+
+  if (auto *C = dyn_cast<SCEVConstant>(S)) {
+    I->replaceAllUsesWith(C->getValue());
+    DEBUG(dbgs() << "INDVARS: Replace IV user: " << *I
+                 << " with constant: " << *C << '\n');
+    ++NumFoldedUser;
+    Changed = true;
+    DeadInsts.emplace_back(I);
+    return true;
+  }
+
+  return false;
+}
+
 /// Eliminate any operation that SCEV can prove is an identity function.
 bool SimplifyIndvar::eliminateIdentitySCEV(Instruction *UseInst,
                                            Instruction *IVOperand) {
@@ -741,6 +767,10 @@ void SimplifyIndvar::simplifyUsers(PHINode *CurrIV, IVVisitor *V) {
     // Bypass back edges to avoid extra work.
     if (UseInst == CurrIV) continue;
 
+    // Try to replace UseInst with a constant before any other simplifications
+    if (foldConstantSCEV(UseInst))
+      continue;
+
     Instruction *IVOperand = UseOper.second;
     for (unsigned N = 0; IVOperand; ++N) {
       assert(N <= Simplified.size() && "runaway iteration");
diff --git a/llvm/test/Transforms/IndVarSimplify/constant-fold.ll b/llvm/test/Transforms/IndVarSimplify/constant-fold.ll
new file mode 100644 (file)
index 0000000..a35349a
--- /dev/null
@@ -0,0 +1,47 @@
+; RUN: opt -indvars -S < %s | FileCheck %s
+
+define void @test0(i32* %x) {
+entry:
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.inc, %entry
+  %i.01 = phi i32 [ 0, %entry ], [ %add, %for.inc ]
+  %and = and i32 %i.01, 3
+  %cmp1 = icmp eq i32 %and, 0
+  %cond = select i1 %cmp1, i32 0, i32 1
+  store i32 %cond, i32* %x, align 4
+  %add = add i32 %i.01, 4
+  %cmp = icmp ult i32 %add, 8
+  br i1 %cmp, label %for.inc, label %for.end
+
+for.end:                                          ; preds = %for.inc
+  ret void
+}
+
+; Should fold the condition of the select into constant
+; CHECK-LABEL: void @test
+; CHECK:         icmp eq i32 0, 0
+
+define void @test1(i32* %a) {
+entry:
+  br label %for.body
+
+for.body:                                         ; preds = %entry, %for.body
+  %i.01 = phi i32 [ 0, %entry ], [ %inc, %for.body ]
+  %mul = mul nsw i32 %i.01, 64
+  %rem = srem i32 %mul, 8
+  %idxprom = sext i32 %rem to i64
+  %arrayidx = getelementptr inbounds i32, i32* %a, i64 %idxprom
+  store i32 %i.01, i32* %arrayidx, align 4
+  %inc = add nsw i32 %i.01, 1
+  %cmp = icmp slt i32 %inc, 64
+  br i1 %cmp, label %for.body, label %for.end
+
+for.end:                                          ; preds = %for.body
+  ret void
+}
+
+; Should fold the rem since %mul is multiple of 8
+; CHECK-LABEL: @test1(
+; CHECK-NOT:     rem
+; CHECK:         sext i32 0 to i64
index 6629420..ec1ccff 100644 (file)
@@ -71,7 +71,7 @@ entry:
 for.body:                                         ; preds = %entry, %for.body
   %i.01 = phi i32 [ 0, %entry ], [ %inc, %for.body ]
   %mul = mul nsw i32 %i.01, 64
-  %rem = srem i32 %mul, 8
+  %rem = srem i32 %mul, 7
 ; CHECK:     urem
 ; CHECK-NOT: srem
   %idxprom = sext i32 %rem to i64