summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author buzbee <buzbee@google.com> 2014-09-26 15:09:06 -0700
committer buzbee <buzbee@google.com> 2014-09-26 15:09:06 -0700
commitb504d2f89fdd5c01816bcbad752797cb78de0e99 (patch)
tree621edb6674f4e46bf19584ef14f4380d7263c736
parent266b4689731f2c69af0f2854aaab947cf6e89f84 (diff)
Quick compiler: aarch64 codegen & long_min literal
Int64 overflow during instruction selection caused incorrect code patterns to emitted in some cases of long operations with an immediate value of 0x8000000000000000. The code in question was attempting to determine if the immediate operand would fit in aarch64 immediate instruction variants. Internal b/17630605 Change-Id: I8177021b73e51302bc1032387d83b1dd567ed6db
-rw-r--r--compiler/dex/quick/arm64/utility_arm64.cc6
-rw-r--r--test/083-compiler-regressions/expected.txt1
-rw-r--r--test/083-compiler-regressions/src/Main.java13
3 files changed, 17 insertions, 3 deletions
diff --git a/compiler/dex/quick/arm64/utility_arm64.cc b/compiler/dex/quick/arm64/utility_arm64.cc
index 5326e74e16..f58f83070b 100644
--- a/compiler/dex/quick/arm64/utility_arm64.cc
+++ b/compiler/dex/quick/arm64/utility_arm64.cc
@@ -345,7 +345,7 @@ bool Arm64Mir2Lir::InexpensiveConstantInt(int32_t value, Instruction::Code opcod
case Instruction::SUB_INT_2ADDR:
// The code below is consistent with the implementation of OpRegRegImm().
{
- int32_t abs_value = std::abs(value);
+ uint32_t abs_value = (value == INT_MIN) ? value : std::abs(value);
if (abs_value < 0x1000) {
return true;
} else if ((abs_value & UINT64_C(0xfff)) == 0 && ((abs_value >> 12) < 0x1000)) {
@@ -809,7 +809,7 @@ LIR* Arm64Mir2Lir::OpRegRegImm(OpKind op, RegStorage r_dest, RegStorage r_src1,
LIR* Arm64Mir2Lir::OpRegRegImm64(OpKind op, RegStorage r_dest, RegStorage r_src1, int64_t value) {
LIR* res;
bool neg = (value < 0);
- int64_t abs_value = (neg) ? -value : value;
+ uint64_t abs_value = (neg & !(value == LLONG_MIN)) ? -value : value;
ArmOpcode opcode = kA64Brk1d;
ArmOpcode alt_opcode = kA64Brk1d;
bool is_logical = false;
@@ -942,7 +942,7 @@ LIR* Arm64Mir2Lir::OpRegImm64(OpKind op, RegStorage r_dest_src1, int64_t value)
ArmOpcode neg_opcode = kA64Brk1d;
bool shift;
bool neg = (value < 0);
- uint64_t abs_value = (neg) ? -value : value;
+ uint64_t abs_value = (neg & !(value == LLONG_MIN)) ? -value : value;
if (LIKELY(abs_value < 0x1000)) {
// abs_value is a 12-bit immediate.
diff --git a/test/083-compiler-regressions/expected.txt b/test/083-compiler-regressions/expected.txt
index e907fd1d58..5251c17335 100644
--- a/test/083-compiler-regressions/expected.txt
+++ b/test/083-compiler-regressions/expected.txt
@@ -1,3 +1,4 @@
+b17630605 passes
b17411468 passes
b2296099 passes
b2302318 passes
diff --git a/test/083-compiler-regressions/src/Main.java b/test/083-compiler-regressions/src/Main.java
index 8d7bf01192..8010711725 100644
--- a/test/083-compiler-regressions/src/Main.java
+++ b/test/083-compiler-regressions/src/Main.java
@@ -30,6 +30,7 @@ public class Main {
}
public static void main(String args[]) throws Exception {
+ b17630605();
b17411468();
b2296099Test();
b2302318Test();
@@ -62,6 +63,18 @@ public class Main {
minDoubleWith3ConstsTest();
}
+ public static void b17630605() {
+ // b/17630605 - failure to properly handle min long immediates.
+ long a1 = 40455547223404749L;
+ long a2 = Long.MIN_VALUE;
+ long answer = a1 + a2;
+ if (answer == -9182916489631371059L) {
+ System.out.println("b17630605 passes");
+ } else {
+ System.out.println("b17630605 fails: " + answer);
+ }
+ }
+
public static void b17411468() {
// b/17411468 - inline Math.round failure.
double d1 = 1.0;