Fix a thinko in the code that adapted SCEVMulExpr operands for
authorDan Gohman <gohman@apple.com>
Fri, 22 May 2009 07:14:20 +0000 (07:14 +0000)
committerDan Gohman <gohman@apple.com>
Fri, 22 May 2009 07:14:20 +0000 (07:14 +0000)
use in expanding SCEVAddExprs with GEPs. The operands of a
SCEVMulExpr need to be multiplied together, not added.

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

lib/Analysis/ScalarEvolutionExpander.cpp
test/Transforms/IndVarSimplify/gep-with-mul-base.ll [new file with mode: 0644]

index d110385fb3ef447d5cd64e9e028d0311e52115ff..507ced74fd1e889393c3adb38e69a82fe3b00abc 100644 (file)
@@ -168,6 +168,8 @@ Value *SCEVExpander::expandAddToGEP(const SCEVAddExpr *S,
     std::vector<SCEVHandle> ScaledOps;
     for (unsigned i = 0, e = Ops.size(); i != e; ++i) {
       if (ElSize != 0) {
+        // For a Constant, check for a multiple of the pointer type's
+        // scale size.
         if (const SCEVConstant *C = dyn_cast<SCEVConstant>(Ops[i]))
           if (!C->getValue()->getValue().srem(ElSize)) {
             ConstantInt *CI =
@@ -176,13 +178,19 @@ Value *SCEVExpander::expandAddToGEP(const SCEVAddExpr *S,
             ScaledOps.push_back(Div);
             continue;
           }
+        // In a Mul, check if there is a constant operand which is a multiple
+        // of the pointer type's scale size.
         if (const SCEVMulExpr *M = dyn_cast<SCEVMulExpr>(Ops[i]))
           if (const SCEVConstant *C = dyn_cast<SCEVConstant>(M->getOperand(0)))
-            if (C->getValue()->getValue() == ElSize) {
-              for (unsigned j = 1, f = M->getNumOperands(); j != f; ++j)
-                ScaledOps.push_back(M->getOperand(j));
+            if (!C->getValue()->getValue().srem(ElSize)) {
+              std::vector<SCEVHandle> NewMulOps(M->getOperands());
+              NewMulOps[0] =
+                SE.getConstant(C->getValue()->getValue().sdiv(ElSize));
+              ScaledOps.push_back(SE.getMulExpr(NewMulOps));
               continue;
             }
+        // In an Unknown, check if the underlying value is a Mul by a constant
+        // which is equal to the pointer type's scale size.
         if (const SCEVUnknown *U = dyn_cast<SCEVUnknown>(Ops[i]))
           if (BinaryOperator *BO = dyn_cast<BinaryOperator>(U->getValue()))
             if (BO->getOpcode() == Instruction::Mul)
@@ -191,6 +199,8 @@ Value *SCEVExpander::expandAddToGEP(const SCEVAddExpr *S,
                   ScaledOps.push_back(SE.getUnknown(BO->getOperand(0)));
                   continue;
                 }
+        // If the pointer type's scale size is 1, no scaling is necessary
+        // and any value can be used.
         if (ElSize == 1) {
           ScaledOps.push_back(Ops[i]);
           continue;
diff --git a/test/Transforms/IndVarSimplify/gep-with-mul-base.ll b/test/Transforms/IndVarSimplify/gep-with-mul-base.ll
new file mode 100644 (file)
index 0000000..0e5e106
--- /dev/null
@@ -0,0 +1,58 @@
+; RUN: llvm-as < %s | opt -indvars | llvm-dis > %t
+; RUN: grep add %t | count 8
+; RUN: grep mul %t | count 9
+
+define void @foo(i64 %n, i64 %m, i64 %o, double* nocapture %p) nounwind {
+entry:
+       %tmp = icmp sgt i64 %n, 0               ; <i1> [#uses=1]
+       br i1 %tmp, label %bb.nph, label %return
+
+bb.nph:                ; preds = %entry
+       %tmp1 = mul i64 %n, 37          ; <i64> [#uses=1]
+       %tmp2 = mul i64 %tmp1, %m               ; <i64> [#uses=1]
+       %tmp3 = mul i64 %tmp2, %o               ; <i64> [#uses=1]
+       br label %bb
+
+bb:            ; preds = %bb, %bb.nph
+       %i.01 = phi i64 [ %tmp3, %bb.nph ], [ %tmp13, %bb ]             ; <i64> [#uses=3]
+       %tmp9 = getelementptr double* %p, i64 %i.01             ; <double*> [#uses=1]
+       %tmp10 = load double* %tmp9, align 8            ; <double> [#uses=1]
+       %tmp11 = fdiv double %tmp10, 2.100000e+00               ; <double> [#uses=1]
+       store double %tmp11, double* %tmp9, align 8
+       %tmp13 = add i64 %i.01, 1               ; <i64> [#uses=2]
+       %tmp14 = icmp slt i64 %tmp13, %n                ; <i1> [#uses=1]
+       br i1 %tmp14, label %bb, label %return.loopexit
+
+return.loopexit:               ; preds = %bb
+       br label %return
+
+return:                ; preds = %return.loopexit, %entry
+       ret void
+}
+define void @bar(i64 %n, i64 %m, i64 %o, i64 %q, double* nocapture %p) nounwind {
+entry:
+       %tmp = icmp sgt i64 %n, 0               ; <i1> [#uses=1]
+       br i1 %tmp, label %bb.nph, label %return
+
+bb.nph:                ; preds = %entry
+       %tmp1 = mul i64 %n, %q          ; <i64> [#uses=1]
+       %tmp2 = mul i64 %tmp1, %m               ; <i64> [#uses=1]
+       %tmp3 = mul i64 %tmp2, %o               ; <i64> [#uses=1]
+       br label %bb
+
+bb:            ; preds = %bb, %bb.nph
+       %i.01 = phi i64 [ %tmp3, %bb.nph ], [ %tmp13, %bb ]             ; <i64> [#uses=3]
+       %tmp9 = getelementptr double* %p, i64 %i.01             ; <double*> [#uses=1]
+       %tmp10 = load double* %tmp9, align 8            ; <double> [#uses=1]
+       %tmp11 = fdiv double %tmp10, 2.100000e+00               ; <double> [#uses=1]
+       store double %tmp11, double* %tmp9, align 8
+       %tmp13 = add i64 %i.01, 1               ; <i64> [#uses=2]
+       %tmp14 = icmp slt i64 %tmp13, %n                ; <i1> [#uses=1]
+       br i1 %tmp14, label %bb, label %return.loopexit
+
+return.loopexit:               ; preds = %bb
+       br label %return
+
+return:                ; preds = %return.loopexit, %entry
+       ret void
+}