diff options
| author | 2014-10-23 16:38:33 +0100 | |
|---|---|---|
| committer | 2014-10-23 17:08:48 +0100 | |
| commit | 66ce173a40eff4392e9949ede169ccf3108be2db (patch) | |
| tree | 552bc6275388c3bc6ecd4f549ffcd1422c020f82 | |
| parent | e2b2cbf8bffdf9ee3ece487fde9ac78652b4abaf (diff) | |
Implement long negate instruction in the optimizing compiler.
- Add support for the neg-long (long integer two's
complement negate) instruction in the optimizing compiler.
- Add a 64-bit NEG instruction (negq) to the x86-64
assembler.
- Generate ARM, x86 and x86-64 code for integer HNeg nodes.
- Put neg-related tests into test/415-optimizing-arith-neg.
Change-Id: I1fbe9611e134408a6b8745d1df20ab6ffa5e50f2
| -rw-r--r-- | compiler/optimizing/builder.cc | 5 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 15 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 13 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 6 | ||||
| -rw-r--r-- | compiler/utils/x86_64/assembler_x86_64.cc | 7 | ||||
| -rw-r--r-- | compiler/utils/x86_64/assembler_x86_64.h | 1 | ||||
| -rw-r--r-- | test/411-optimizing-arith/src/Main.java | 34 | ||||
| -rw-r--r-- | test/415-optimizing-arith-neg/expected.txt | 0 | ||||
| -rw-r--r-- | test/415-optimizing-arith-neg/info.txt | 1 | ||||
| -rw-r--r-- | test/415-optimizing-arith-neg/src/Main.java | 133 | ||||
| -rw-r--r-- | test/Android.run-test.mk | 1 |
11 files changed, 178 insertions, 38 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 79cbd0ee21..0ab7782e2c 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -748,6 +748,11 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::NEG_LONG: { + Unop_12x<HNeg>(instruction, Primitive::kPrimLong); + break; + } + case Instruction::NOT_INT: { Unop_12x<HNot>(instruction, Primitive::kPrimInt); break; diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 7b00d2f523..5edf0f09fe 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -1043,11 +1043,13 @@ void LocationsBuilderARM::VisitNeg(HNeg* neg) { new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall); switch (neg->GetResultType()) { case Primitive::kPrimInt: + case Primitive::kPrimLong: { + bool output_overlaps = (neg->GetResultType() == Primitive::kPrimLong); locations->SetInAt(0, Location::RequiresRegister()); - locations->SetOut(Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), output_overlaps); break; + } - case Primitive::kPrimLong: case Primitive::kPrimFloat: case Primitive::kPrimDouble: LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType(); @@ -1069,6 +1071,15 @@ void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) { break; case Primitive::kPrimLong: + DCHECK(in.IsRegisterPair()); + __ rsbs(out.AsRegisterPairLow<Register>(), + in.AsRegisterPairLow<Register>(), + ShifterOperand(0)); + __ rsc(out.AsRegisterPairHigh<Register>(), + in.AsRegisterPairHigh<Register>(), + ShifterOperand(0)); + break; + case Primitive::kPrimFloat: case Primitive::kPrimDouble: LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType(); diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 61f0750c5c..aa0f06b67f 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -990,11 +990,11 @@ void LocationsBuilderX86::VisitNeg(HNeg* neg) { new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall); switch (neg->GetResultType()) { case Primitive::kPrimInt: + case Primitive::kPrimLong: locations->SetInAt(0, Location::RequiresRegister()); locations->SetOut(Location::SameAsFirstInput()); break; - case Primitive::kPrimLong: case Primitive::kPrimFloat: case Primitive::kPrimDouble: LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType(); @@ -1016,6 +1016,17 @@ void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) { break; case Primitive::kPrimLong: + DCHECK(in.IsRegisterPair()); + __ negl(out.AsRegisterPairLow<Register>()); + // Negation is similar to subtraction from zero. The least + // significant byte triggers a borrow when it is different from + // zero; to take it into account, add 1 to the most significant + // byte if the carry flag (CF) is set to 1 after the first NEGL + // operation. + __ adcl(out.AsRegisterPairHigh<Register>(), Immediate(0)); + __ negl(out.AsRegisterPairHigh<Register>()); + break; + case Primitive::kPrimFloat: case Primitive::kPrimDouble: LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType(); diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 4a05b89892..892ca9d9c7 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -976,11 +976,11 @@ void LocationsBuilderX86_64::VisitNeg(HNeg* neg) { new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall); switch (neg->GetResultType()) { case Primitive::kPrimInt: + case Primitive::kPrimLong: locations->SetInAt(0, Location::RequiresRegister()); locations->SetOut(Location::SameAsFirstInput()); break; - case Primitive::kPrimLong: case Primitive::kPrimFloat: case Primitive::kPrimDouble: LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType(); @@ -1002,6 +1002,10 @@ void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) { break; case Primitive::kPrimLong: + DCHECK(in.IsRegister()); + __ negq(out.As<CpuRegister>()); + break; + case Primitive::kPrimFloat: case Primitive::kPrimDouble: LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType(); diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc index f4c9862f93..f164138168 100644 --- a/compiler/utils/x86_64/assembler_x86_64.cc +++ b/compiler/utils/x86_64/assembler_x86_64.cc @@ -1340,6 +1340,13 @@ void X86_64Assembler::negl(CpuRegister reg) { EmitOperand(3, Operand(reg)); } +void X86_64Assembler::negq(CpuRegister reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitRex64(reg); + EmitUint8(0xF7); + EmitOperand(3, Operand(reg)); +} + void X86_64Assembler::notl(CpuRegister reg) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h index 92b81ec2e7..ec29271b5e 100644 --- a/compiler/utils/x86_64/assembler_x86_64.h +++ b/compiler/utils/x86_64/assembler_x86_64.h @@ -450,6 +450,7 @@ class X86_64Assembler FINAL : public Assembler { void shrq(CpuRegister reg, const Immediate& imm); void negl(CpuRegister reg); + void negq(CpuRegister reg); void notl(CpuRegister reg); void enter(const Immediate& imm); diff --git a/test/411-optimizing-arith/src/Main.java b/test/411-optimizing-arith/src/Main.java index 4de2271ebd..a22c516ff4 100644 --- a/test/411-optimizing-arith/src/Main.java +++ b/test/411-optimizing-arith/src/Main.java @@ -74,7 +74,6 @@ public class Main { public static void main(String[] args) { mul(); - neg(); } public static void mul() { @@ -164,34 +163,6 @@ public class Main { expectEquals(Double.POSITIVE_INFINITY, $opt$Mul(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY)); } - public static void neg() { - expectEquals(-1, $opt$Neg(1)); - expectEquals(1, $opt$Neg(-1)); - expectEquals(0, $opt$Neg(0)); - expectEquals(51, $opt$Neg(-51)); - expectEquals(-51, $opt$Neg(51)); - expectEquals(2147483647, $opt$Neg(-2147483647)); // (2^31 - 1) - expectEquals(-2147483647, $opt$Neg(2147483647)); // -(2^31 - 1) - // From the Java 7 SE Edition specification: - // http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.15.4 - // - // For integer values, negation is the same as subtraction from - // zero. The Java programming language uses two's-complement - // representation for integers, and the range of two's-complement - // values is not symmetric, so negation of the maximum negative - // int or long results in that same maximum negative number. - // Overflow occurs in this case, but no exception is thrown. - // For all integer values x, -x equals (~x)+1.'' - expectEquals(-2147483648, $opt$Neg(-2147483648)); // -(2^31) - - $opt$InplaceNegOne(1); - } - - public static void $opt$InplaceNegOne(int a) { - a = -a; - expectEquals(-1, a); - } - static int $opt$Mul(int a, int b) { return a * b; } @@ -207,9 +178,4 @@ public class Main { static double $opt$Mul(double a, double b) { return a * b; } - - static int $opt$Neg(int a){ - return -a; - } - } diff --git a/test/415-optimizing-arith-neg/expected.txt b/test/415-optimizing-arith-neg/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/415-optimizing-arith-neg/expected.txt diff --git a/test/415-optimizing-arith-neg/info.txt b/test/415-optimizing-arith-neg/info.txt new file mode 100644 index 0000000000..8494aad938 --- /dev/null +++ b/test/415-optimizing-arith-neg/info.txt @@ -0,0 +1 @@ +Tests for arithmetic negation operations. diff --git a/test/415-optimizing-arith-neg/src/Main.java b/test/415-optimizing-arith-neg/src/Main.java new file mode 100644 index 0000000000..3b25c9da39 --- /dev/null +++ b/test/415-optimizing-arith-neg/src/Main.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Note that $opt$ is a marker for the optimizing compiler to ensure +// it does compile the method. +public class Main { + + public static void expectEquals(int expected, int result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + public static void expectEquals(long expected, long result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + public static void expectEquals(float expected, float result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + public static void expectEquals(double expected, double result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + public static void expectApproxEquals(float a, float b, float maxDelta) { + boolean aproxEquals = (a > b) + ? ((a - b) < maxDelta) + : ((b - a) < maxDelta); + if (!aproxEquals) { + throw new Error("Expected: " + a + ", found: " + b + ", with delta: " + maxDelta); + } + } + + public static void expectApproxEquals(double a, double b, double maxDelta) { + boolean aproxEquals = (a > b) + ? ((a - b) < maxDelta) + : ((b - a) < maxDelta); + if (!aproxEquals) { + throw new Error("Expected: " + a + ", found: " + b + ", with delta: " + maxDelta); + } + } + + public static void expectNaN(float a) { + if (a == a) { + throw new Error("Expected NaN: " + a); + } + } + + public static void expectNaN(double a) { + if (a == a) { + throw new Error("Expected NaN: " + a); + } + } + + public static void main(String[] args) { + negInt(); + $opt$InplaceNegOneInt(1); + + negLong(); + $opt$InplaceNegOneLong(1L); + } + + private static void negInt() { + expectEquals(-1, $opt$NegInt(1)); + expectEquals(1, $opt$NegInt(-1)); + expectEquals(0, $opt$NegInt(0)); + expectEquals(51, $opt$NegInt(-51)); + expectEquals(-51, $opt$NegInt(51)); + expectEquals(2147483647, $opt$NegInt(-2147483647)); // (2^31 - 1) + expectEquals(-2147483647, $opt$NegInt(2147483647)); // -(2^31 - 1) + // From the Java 7 SE Edition specification: + // http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.15.4 + // + // For integer values, negation is the same as subtraction from + // zero. The Java programming language uses two's-complement + // representation for integers, and the range of two's-complement + // values is not symmetric, so negation of the maximum negative + // int or long results in that same maximum negative number. + // Overflow occurs in this case, but no exception is thrown. + // For all integer values x, -x equals (~x)+1.'' + expectEquals(-2147483648, $opt$NegInt(-2147483648)); // -(2^31) + } + + private static void $opt$InplaceNegOneInt(int a) { + a = -a; + expectEquals(-1, a); + } + + private static void negLong() { + expectEquals(-1L, $opt$NegLong(1L)); + expectEquals(1L, $opt$NegLong(-1L)); + expectEquals(0L, $opt$NegLong(0L)); + expectEquals(51L, $opt$NegLong(-51L)); + expectEquals(-51L, $opt$NegLong(51L)); + expectEquals(9223372036854775807L, $opt$NegLong(-9223372036854775807L)); // (2^63 - 1) + expectEquals(-9223372036854775807L, $opt$NegLong(9223372036854775807L)); // -(2^63 - 1) + // See comment in negInt(). + expectEquals(-9223372036854775808L, $opt$NegLong(-9223372036854775808L)); // -(2^63) + } + + private static void $opt$InplaceNegOneLong(long a) { + a = -a; + expectEquals(-1L, a); + } + + static int $opt$NegInt(int a){ + return -a; + } + + static long $opt$NegLong(long a){ + return -a; + } +} diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk index 682282532b..5b95beb96e 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -317,6 +317,7 @@ TEST_ART_BROKEN_OPTIMIZING_ARM64_RUN_TESTS := \ 412-new-array \ 413-regalloc-regression \ 414-optimizing-arith-sub \ + 415-optimizing-arith-neg \ 700-LoadArgRegs \ 800-smali |