diff options
| -rw-r--r-- | compiler/optimizing/bounds_check_elimination.cc | 24 | ||||
| -rw-r--r-- | test/449-checker-bce/src/Main.java | 36 |
2 files changed, 52 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. diff --git a/test/449-checker-bce/src/Main.java b/test/449-checker-bce/src/Main.java index 31bb94cb8c..32bbc5b61d 100644 --- a/test/449-checker-bce/src/Main.java +++ b/test/449-checker-bce/src/Main.java @@ -391,6 +391,36 @@ public class Main { array[base + 1] = 1; } + /// CHECK-START: void Main.constantIndexing10(int[], int) BCE (before) + /// CHECK: BoundsCheck + /// CHECK: ArraySet + /// CHECK: BoundsCheck + /// CHECK: ArraySet + /// CHECK: BoundsCheck + /// CHECK: ArraySet + /// CHECK: BoundsCheck + /// CHECK: ArraySet + + /// CHECK-START: void Main.constantIndexing10(int[], int) BCE (after) + /// CHECK: Deoptimize + /// CHECK: Deoptimize + /// CHECK-NOT: BoundsCheck + /// CHECK: ArraySet + /// CHECK-NOT: BoundsCheck + /// CHECK: ArraySet + /// CHECK-NOT: BoundsCheck + /// CHECK: ArraySet + /// CHECK-NOT: BoundsCheck + /// CHECK: ArraySet + + static void constantIndexing10(int[] array, int base) { + // Offset hidden in incremented base. + array[base] = 1; + array[++base] = 2; + array[++base] = 3; + array[++base] = 4; + } + static void runAllConstantIndices() { int[] a1 = { 0 }; int[] a6 = { 0, 0, 0, 0, 0, 0 }; @@ -502,6 +532,12 @@ public class Main { a6[3] != 3 || a6[4] != 40 || a6[5] != 10) { System.out.println("constant indices 9 failed!"); } + + constantIndexing10(a6, 0); + if (a6[0] != 1 || a6[1] != 2 || a6[2] != 3 || + a6[3] != 4 || a6[4] != 40 || a6[5] != 10) { + System.out.println("constant indices 10 failed!"); + } } // A helper into which the actual throwing function should be inlined. |