diff options
| author | 2017-03-07 21:22:58 +0000 | |
|---|---|---|
| committer | 2017-03-07 21:23:00 +0000 | |
| commit | e6a60bff7a78efe7c2c4365984f1f7f036c12158 (patch) | |
| tree | 04a83a2361a9103f2968c8f608980563cadcc343 | |
| parent | 7ba6ed786aa21257cfeefb917157d7d4768b9501 (diff) | |
| parent | b603a5cdff7c1fb300b83175bfb3cd990fdd6265 (diff) | |
Merge "Bug fix in overflow detection on pow. With regression test."
| -rw-r--r-- | compiler/optimizing/induction_var_range.cc | 24 | ||||
| -rw-r--r-- | test/623-checker-loop-regressions/src/Main.java | 24 |
2 files changed, 39 insertions, 9 deletions
diff --git a/compiler/optimizing/induction_var_range.cc b/compiler/optimizing/induction_var_range.cc index 1cd65c1c66..3dfe17647c 100644 --- a/compiler/optimizing/induction_var_range.cc +++ b/compiler/optimizing/induction_var_range.cc @@ -57,21 +57,27 @@ static bool IsIntAndGet(HInstruction* instruction, int64_t* value) { return false; } -/** Returns b^e for b,e >= 1. Sets overflow if arithmetic wrap-around occurred. */ +/** Computes a * b for a,b > 0 (at least until first overflow happens). */ +static int64_t SafeMul(int64_t a, int64_t b, /*out*/ bool* overflow) { + if (a > 0 && b > 0 && a > (std::numeric_limits<int64_t>::max() / b)) { + *overflow = true; + } + return a * b; +} + +/** Returns b^e for b,e > 0. Sets overflow if arithmetic wrap-around occurred. */ static int64_t IntPow(int64_t b, int64_t e, /*out*/ bool* overflow) { - DCHECK_GE(b, 1); - DCHECK_GE(e, 1); + DCHECK_LT(0, b); + DCHECK_LT(0, e); int64_t pow = 1; while (e) { if (e & 1) { - int64_t oldpow = pow; - pow *= b; - if (pow < oldpow) { - *overflow = true; - } + pow = SafeMul(pow, b, overflow); } e >>= 1; - b *= b; + if (e) { + b = SafeMul(b, b, overflow); + } } return pow; } diff --git a/test/623-checker-loop-regressions/src/Main.java b/test/623-checker-loop-regressions/src/Main.java index 7509d9b4f3..2a7be2fbc1 100644 --- a/test/623-checker-loop-regressions/src/Main.java +++ b/test/623-checker-loop-regressions/src/Main.java @@ -213,6 +213,8 @@ public class Main { /// CHECK-START: long Main.geoLongDivLastValue(long) instruction_simplifier$after_bce (after) /// CHECK-DAG: <<Long:j\d+>> LongConstant 0 loop:none /// CHECK-DAG: Return [<<Long>>] loop:none + // + // Tests overflow in the divisor (while updating intermediate result). static long geoLongDivLastValue(long x) { for (int i = 0; i < 10; i++) { x /= 1081788608; @@ -220,6 +222,26 @@ public class Main { return x; } + /// CHECK-START: long Main.geoLongDivLastValue() loop_optimization (before) + /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none + // + /// CHECK-START: long Main.geoLongDivLastValue() loop_optimization (after) + /// CHECK-NOT: Phi + // + /// CHECK-START: long Main.geoLongDivLastValue() instruction_simplifier$after_bce (after) + /// CHECK-DAG: <<Long:j\d+>> LongConstant 0 loop:none + /// CHECK-DAG: Return [<<Long>>] loop:none + // + // Tests overflow in the divisor (while updating base). + static long geoLongDivLastValue() { + long x = -1; + for (int i2 = 0; i2 < 2; i2++) { + x /= (Long.MAX_VALUE); + } + return x; + } + /// CHECK-START: long Main.geoLongMulLastValue(long) loop_optimization (before) /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none @@ -286,6 +308,8 @@ public class Main { expectEquals(0L, geoLongDivLastValue(9223372036854775807L)); expectEquals(0L, geoLongDivLastValue(-9223372036854775808L)); + expectEquals(0L, geoLongDivLastValue()); + expectEquals( 0L, geoLongMulLastValue(0L)); expectEquals(-8070450532247928832L, geoLongMulLastValue(1L)); expectEquals( 2305843009213693952L, geoLongMulLastValue(2L)); |