[SCEV] identical instructions don't compute equal values
authorSanjoy Das <sanjoy@playingwithpointers.com>
Sun, 27 Sep 2015 21:09:48 +0000 (21:09 +0000)
committerSanjoy Das <sanjoy@playingwithpointers.com>
Sun, 27 Sep 2015 21:09:48 +0000 (21:09 +0000)
Before this change `HasSameValue` would return true for distinct
`alloca` instructions if they happened to be allocating the same
type (`alloca` instructions are not specified as reading memory).  This
change adds an explicit whitelist of instruction types for which
"identical" instructions compute the same value.

Fixes PR24952.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@248690 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/ScalarEvolution.cpp
test/Transforms/IndVarSimplify/pr24952.ll [new file with mode: 0644]

index 32d3d36c7393c5196cafa0e3538cd79ebb1bd420..57caa9d368af3736cfce9271f18650ea8c9ac10f 100644 (file)
@@ -6412,13 +6412,20 @@ static bool HasSameValue(const SCEV *A, const SCEV *B) {
   // Quick check to see if they are the same SCEV.
   if (A == B) return true;
 
+  auto ComputesEqualValues = [](const Instruction *A, const Instruction *B) {
+    // Not all instructions that are "identical" compute the same value.  For
+    // instance, two distinct alloca instructions allocating the same type are
+    // identical and do not read memory; but compute distinct values.
+    return A->isIdenticalTo(B) && (isa<BinaryOperator>(A) || isa<GetElementPtrInst>(A));
+  };
+
   // Otherwise, if they're both SCEVUnknown, it's possible that they hold
   // two different instructions with the same value. Check for this case.
   if (const SCEVUnknown *AU = dyn_cast<SCEVUnknown>(A))
     if (const SCEVUnknown *BU = dyn_cast<SCEVUnknown>(B))
       if (const Instruction *AI = dyn_cast<Instruction>(AU->getValue()))
         if (const Instruction *BI = dyn_cast<Instruction>(BU->getValue()))
-          if (AI->isIdenticalTo(BI) && !AI->mayReadFromMemory())
+          if (ComputesEqualValues(AI, BI))
             return true;
 
   // Otherwise assume they may have a different value.
diff --git a/test/Transforms/IndVarSimplify/pr24952.ll b/test/Transforms/IndVarSimplify/pr24952.ll
new file mode 100644 (file)
index 0000000..c430cae
--- /dev/null
@@ -0,0 +1,27 @@
+; RUN: opt -indvars -S < %s | FileCheck %s
+
+declare void @use(i1)
+
+define void @f() {
+; CHECK-LABEL: @f(
+ entry:
+  %x = alloca i32
+  %y = alloca i32
+  br label %loop
+
+ loop:
+  %iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
+  %iv.inc = add i32 %iv, 1
+
+  %x.gep = getelementptr i32, i32* %x, i32 %iv
+  %eql = icmp eq i32* %x.gep, %y
+; CHECK-NOT: @use(i1 true)
+  call void @use(i1 %eql)
+
+  ; %be.cond deliberately 'false' -- we want want the trip count to be 0.
+  %be.cond = icmp ult i32 %iv, 0
+  br i1 %be.cond, label %loop, label %leave
+
+ leave:
+  ret void
+}