Fixed missing context while detecting unit strides.

With regression test (found by fuzz testing).

Bug: 37033123
Test: test-art-target
Change-Id: Id738b2a3a353985c3d0bf3beeb581a31f1fcbc3f
diff --git a/compiler/optimizing/induction_var_range.cc b/compiler/optimizing/induction_var_range.cc
index d6513c8..1c8674d 100644
--- a/compiler/optimizing/induction_var_range.cc
+++ b/compiler/optimizing/induction_var_range.cc
@@ -383,12 +383,13 @@
   return false;
 }
 
-bool InductionVarRange::IsUnitStride(HInstruction* instruction,
+bool InductionVarRange::IsUnitStride(HInstruction* context,
+                                     HInstruction* instruction,
                                      /*out*/ HInstruction** offset) const {
   HLoopInformation* loop = nullptr;
   HInductionVarAnalysis::InductionInfo* info = nullptr;
   HInductionVarAnalysis::InductionInfo* trip = nullptr;
-  if (HasInductionInfo(instruction, instruction, &loop, &info, &trip)) {
+  if (HasInductionInfo(context, instruction, &loop, &info, &trip)) {
     if (info->induction_class == HInductionVarAnalysis::kLinear &&
         info->op_b->operation == HInductionVarAnalysis::kFetch &&
         !HInductionVarAnalysis::IsNarrowingLinear(info)) {
diff --git a/compiler/optimizing/induction_var_range.h b/compiler/optimizing/induction_var_range.h
index 0858d73..a8ee829 100644
--- a/compiler/optimizing/induction_var_range.h
+++ b/compiler/optimizing/induction_var_range.h
@@ -156,10 +156,14 @@
   bool IsFinite(HLoopInformation* loop, /*out*/ int64_t* tc) const;
 
   /**
-   * Checks if instruction is a unit stride induction inside the closest enveloping loop.
-   * Returns invariant offset on success.
+   * Checks if the given instruction is a unit stride induction inside the closest enveloping
+   * loop of the context that is defined by the first parameter (e.g. pass an array reference
+   * as context and the index as instruction to make sure the stride is tested against the
+   * loop that envelops the reference the closest). Returns invariant offset on success.
    */
-  bool IsUnitStride(HInstruction* instruction, /*out*/ HInstruction** offset) const;
+  bool IsUnitStride(HInstruction* context,
+                    HInstruction* instruction,
+                    /*out*/ HInstruction** offset) const;
 
   /**
    * Generates the trip count expression for the given loop. Code is generated in given block
diff --git a/compiler/optimizing/induction_var_range_test.cc b/compiler/optimizing/induction_var_range_test.cc
index fcdf8eb..d01d314 100644
--- a/compiler/optimizing/induction_var_range_test.cc
+++ b/compiler/optimizing/induction_var_range_test.cc
@@ -770,7 +770,7 @@
   EXPECT_TRUE(range_.IsFinite(loop_header_->GetLoopInformation(), &tc));
   EXPECT_EQ(1000, tc);
   HInstruction* offset = nullptr;
-  EXPECT_TRUE(range_.IsUnitStride(phi, &offset));
+  EXPECT_TRUE(range_.IsUnitStride(phi, phi, &offset));
   EXPECT_TRUE(offset == nullptr);
   HInstruction* tce = range_.GenerateTripCount(
       loop_header_->GetLoopInformation(), graph_, loop_preheader_);
@@ -826,7 +826,7 @@
   EXPECT_TRUE(range_.IsFinite(loop_header_->GetLoopInformation(), &tc));
   EXPECT_EQ(1000, tc);
   HInstruction* offset = nullptr;
-  EXPECT_FALSE(range_.IsUnitStride(phi, &offset));
+  EXPECT_FALSE(range_.IsUnitStride(phi, phi, &offset));
   HInstruction* tce = range_.GenerateTripCount(
       loop_header_->GetLoopInformation(), graph_, loop_preheader_);
   ASSERT_TRUE(tce != nullptr);
@@ -908,7 +908,7 @@
   EXPECT_TRUE(range_.IsFinite(loop_header_->GetLoopInformation(), &tc));
   EXPECT_EQ(0, tc);  // unknown
   HInstruction* offset = nullptr;
-  EXPECT_TRUE(range_.IsUnitStride(phi, &offset));
+  EXPECT_TRUE(range_.IsUnitStride(phi, phi, &offset));
   EXPECT_TRUE(offset == nullptr);
   HInstruction* tce = range_.GenerateTripCount(
       loop_header_->GetLoopInformation(), graph_, loop_preheader_);
@@ -994,7 +994,7 @@
   EXPECT_TRUE(range_.IsFinite(loop_header_->GetLoopInformation(), &tc));
   EXPECT_EQ(0, tc);  // unknown
   HInstruction* offset = nullptr;
-  EXPECT_FALSE(range_.IsUnitStride(phi, &offset));
+  EXPECT_FALSE(range_.IsUnitStride(phi, phi, &offset));
   HInstruction* tce = range_.GenerateTripCount(
       loop_header_->GetLoopInformation(), graph_, loop_preheader_);
   ASSERT_TRUE(tce != nullptr);
diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc
index 1a79601..bf18cc9 100644
--- a/compiler/optimizing/loop_optimization.cc
+++ b/compiler/optimizing/loop_optimization.cc
@@ -580,7 +580,7 @@
     HInstruction* offset = nullptr;
     if (TrySetVectorType(type, &restrictions) &&
         node->loop_info->IsDefinedOutOfTheLoop(base) &&
-        induction_range_.IsUnitStride(index, &offset) &&
+        induction_range_.IsUnitStride(instruction, index, &offset) &&
         VectorizeUse(node, value, generate_code, type, restrictions)) {
       if (generate_code) {
         GenerateVecSub(index, offset);
@@ -633,7 +633,7 @@
     HInstruction* offset = nullptr;
     if (type == instruction->GetType() &&
         node->loop_info->IsDefinedOutOfTheLoop(base) &&
-        induction_range_.IsUnitStride(index, &offset)) {
+        induction_range_.IsUnitStride(instruction, index, &offset)) {
       if (generate_code) {
         GenerateVecSub(index, offset);
         GenerateVecMem(instruction, vector_map_->Get(index), nullptr, type);
diff --git a/test/623-checker-loop-regressions/src/Main.java b/test/623-checker-loop-regressions/src/Main.java
index eee90ab..182c07d 100644
--- a/test/623-checker-loop-regressions/src/Main.java
+++ b/test/623-checker-loop-regressions/src/Main.java
@@ -270,6 +270,16 @@
     }
   }
 
+  // If vectorized, invariant stride should be recognized
+  // as a reduction, not a unit stride in outer loop.
+  static void reduc(int[] xx, int[] yy) {
+    for (int i0 = 0; i0 < 2; i0++) {
+      for (int i1 = 0; i1 < 469; i1++) {
+        xx[i0] -= (++yy[i1]);
+      }
+    }
+  }
+
   public static void main(String[] args) {
     expectEquals(10, earlyExitFirst(-1));
     for (int i = 0; i <= 10; i++) {
@@ -335,6 +345,15 @@
       expectEquals(2.0f, a[i]);
     }
 
+    int[] xx = new int[2];
+    int[] yy = new int[469];
+    reduc(xx, yy);
+    expectEquals(-469, xx[0]);
+    expectEquals(-938, xx[1]);
+    for (int i = 0; i < 469; i++) {
+      expectEquals(2, yy[i]);
+    }
+
     System.out.println("passed");
   }