summaryrefslogtreecommitdiff
path: root/compiler/optimizing
diff options
context:
space:
mode:
author Aart Bik <ajcbik@google.com> 2016-02-22 16:22:33 -0800
committer Aart Bik <ajcbik@google.com> 2016-02-23 11:11:29 -0800
commitbf3f1cf15a021ea1ff8ae860c55e8281da4619b3 (patch)
treea3d5b50502673d96d270d97c6406d616a8d9b858 /compiler/optimizing
parent07f7affb338b529d34e4e18b7e8a631c16bd9765 (diff)
Improved instruction + offset hunting.
Rationale: This is generally useful for anything using this method but in particular for deopting something like bs[ off] = (byte)(n >>> 24); bs[++off] = (byte)(n >>> 16); bs[++off] = (byte)(n >>> 8); bs[++off] = (byte)(n ); where the base + offset is hidden in the increments. Occurs quite often in real-life code. Change-Id: I3fa7d285a7368a179a26e590e8eee37f3b64c25d
Diffstat (limited to 'compiler/optimizing')
-rw-r--r--compiler/optimizing/bounds_check_elimination.cc24
1 files changed, 16 insertions, 8 deletions
diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc
index ba1b1683d7..a7a1c0f2c4 100644
--- a/compiler/optimizing/bounds_check_elimination.cc
+++ b/compiler/optimizing/bounds_check_elimination.cc
@@ -67,20 +67,28 @@ class ValueBound : public ValueObject {
static bool IsAddOrSubAConstant(HInstruction* instruction,
/* out */ HInstruction** left_instruction,
/* out */ int32_t* right_constant) {
- if (instruction->IsAdd() || instruction->IsSub()) {
+ HInstruction* left_so_far = nullptr;
+ int32_t right_so_far = 0;
+ while (instruction->IsAdd() || instruction->IsSub()) {
HBinaryOperation* bin_op = instruction->AsBinaryOperation();
HInstruction* left = bin_op->GetLeft();
HInstruction* right = bin_op->GetRight();
if (right->IsIntConstant()) {
- *left_instruction = left;
- int32_t c = right->AsIntConstant()->GetValue();
- *right_constant = instruction->IsAdd() ? c : -c;
- return true;
+ int32_t v = right->AsIntConstant()->GetValue();
+ int32_t c = instruction->IsAdd() ? v : -v;
+ if (!WouldAddOverflowOrUnderflow(right_so_far, c)) {
+ instruction = left;
+ left_so_far = left;
+ right_so_far += c;
+ continue;
+ }
}
+ break;
}
- *left_instruction = nullptr;
- *right_constant = 0;
- return false;
+ // Return result: either false and "null+0" or true and "instr+constant".
+ *left_instruction = left_so_far;
+ *right_constant = right_so_far;
+ return left_so_far != nullptr;
}
// Expresses any instruction as a value bound.