Generalize range analysis.

Rationale:
obvious case x+-1 vs x-1 was missing

Test: test-art-host
Bug: 63631713
Change-Id: I0a97548a509239bee34a099b1ce9856bac311dba
diff --git a/compiler/optimizing/induction_var_range.cc b/compiler/optimizing/induction_var_range.cc
index 089340e..191d3d1 100644
--- a/compiler/optimizing/induction_var_range.cc
+++ b/compiler/optimizing/induction_var_range.cc
@@ -670,6 +670,15 @@
       return AddValue(GetFetch(instruction->InputAt(0), trip, in_body, is_min),
                       Value(static_cast<int32_t>(value)));
     }
+  } else if (instruction->IsSub()) {
+    // Incorporate suitable constants in the chased value.
+    if (IsInt64AndGet(instruction->InputAt(0), &value) && CanLongValueFitIntoInt(value)) {
+      return SubValue(Value(static_cast<int32_t>(value)),
+                      GetFetch(instruction->InputAt(1), trip, in_body, !is_min));
+    } else if (IsInt64AndGet(instruction->InputAt(1), &value) && CanLongValueFitIntoInt(value)) {
+      return SubValue(GetFetch(instruction->InputAt(0), trip, in_body, is_min),
+                      Value(static_cast<int32_t>(value)));
+    }
   } else if (instruction->IsArrayLength()) {
     // Exploit length properties when chasing constants or chase into a new array declaration.
     if (chase_hint_ == nullptr) {
diff --git a/compiler/optimizing/induction_var_range_test.cc b/compiler/optimizing/induction_var_range_test.cc
index 2b82b33..9437014 100644
--- a/compiler/optimizing/induction_var_range_test.cc
+++ b/compiler/optimizing/induction_var_range_test.cc
@@ -723,6 +723,29 @@
   ExpectEqual(Value(x_, 1, 0), GetMax(CreateFetch(array_length), nullptr));
 }
 
+TEST_F(InductionVarRangeTest, AddOrSubAndConstant) {
+  HInstruction* add = new (&allocator_)
+      HAdd(Primitive::kPrimInt, x_, graph_->GetIntConstant(-1));
+  HInstruction* alt = new (&allocator_)
+      HAdd(Primitive::kPrimInt, graph_->GetIntConstant(-1), x_);
+  HInstruction* sub = new (&allocator_)
+      HSub(Primitive::kPrimInt, x_, graph_->GetIntConstant(1));
+  HInstruction* rev = new (&allocator_)
+      HSub(Primitive::kPrimInt, graph_->GetIntConstant(1), x_);
+  entry_block_->AddInstruction(add);
+  entry_block_->AddInstruction(alt);
+  entry_block_->AddInstruction(sub);
+  entry_block_->AddInstruction(rev);
+  ExpectEqual(Value(x_, 1, -1), GetMin(CreateFetch(add), nullptr));
+  ExpectEqual(Value(x_, 1, -1), GetMax(CreateFetch(add), nullptr));
+  ExpectEqual(Value(x_, 1, -1), GetMin(CreateFetch(alt), nullptr));
+  ExpectEqual(Value(x_, 1, -1), GetMax(CreateFetch(alt), nullptr));
+  ExpectEqual(Value(x_, 1, -1), GetMin(CreateFetch(sub), nullptr));
+  ExpectEqual(Value(x_, 1, -1), GetMax(CreateFetch(sub), nullptr));
+  ExpectEqual(Value(x_, -1, 1), GetMin(CreateFetch(rev), nullptr));
+  ExpectEqual(Value(x_, -1, 1), GetMax(CreateFetch(rev), nullptr));
+}
+
 //
 // Tests on public methods.
 //