[optimizing compiler] Add float/double subtraction
- for arm, x86, x86_64
- add tests
- a bit of clean up
Change-Id: I3761b0d908aca3e3c5d60da481fafb423ff7c9b9
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index b042beb..7b00d2f 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -1157,53 +1157,60 @@
locations->SetOut(Location::RequiresRegister(), output_overlaps);
break;
}
-
- case Primitive::kPrimBoolean:
- case Primitive::kPrimByte:
- case Primitive::kPrimChar:
- case Primitive::kPrimShort:
- LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble: {
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetInAt(1, Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresFpuRegister());
break;
-
+ }
default:
- LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
+ LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
}
}
void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
LocationSummary* locations = sub->GetLocations();
+ Location out = locations->Out();
+ Location first = locations->InAt(0);
+ Location second = locations->InAt(1);
switch (sub->GetResultType()) {
case Primitive::kPrimInt: {
- if (locations->InAt(1).IsRegister()) {
- __ sub(locations->Out().As<Register>(),
- locations->InAt(0).As<Register>(),
- ShifterOperand(locations->InAt(1).As<Register>()));
+ if (second.IsRegister()) {
+ __ sub(out.As<Register>(), first.As<Register>(), ShifterOperand(second.As<Register>()));
} else {
- __ AddConstant(locations->Out().As<Register>(),
- locations->InAt(0).As<Register>(),
- -locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
+ __ AddConstant(out.As<Register>(),
+ first.As<Register>(),
+ -second.GetConstant()->AsIntConstant()->GetValue());
}
break;
}
- case Primitive::kPrimLong:
- __ subs(locations->Out().AsRegisterPairLow<Register>(),
- locations->InAt(0).AsRegisterPairLow<Register>(),
- ShifterOperand(locations->InAt(1).AsRegisterPairLow<Register>()));
- __ sbc(locations->Out().AsRegisterPairHigh<Register>(),
- locations->InAt(0).AsRegisterPairHigh<Register>(),
- ShifterOperand(locations->InAt(1).AsRegisterPairHigh<Register>()));
+ case Primitive::kPrimLong: {
+ __ subs(out.AsRegisterPairLow<Register>(),
+ first.AsRegisterPairLow<Register>(),
+ ShifterOperand(second.AsRegisterPairLow<Register>()));
+ __ sbc(out.AsRegisterPairHigh<Register>(),
+ first.AsRegisterPairHigh<Register>(),
+ ShifterOperand(second.AsRegisterPairHigh<Register>()));
break;
+ }
- case Primitive::kPrimBoolean:
- case Primitive::kPrimByte:
- case Primitive::kPrimChar:
- case Primitive::kPrimShort:
- LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
+ case Primitive::kPrimFloat: {
+ __ vsubs(FromDToLowS(out.As<DRegister>()),
+ FromDToLowS(first.As<DRegister>()),
+ FromDToLowS(second.As<DRegister>()));
break;
+ }
+
+ case Primitive::kPrimDouble: {
+ __ vsubd(out.As<DRegister>(), first.As<DRegister>(), second.As<DRegister>());
+ break;
+ }
+
default:
- LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
+ LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
}
}
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 3b4b835..61f0750 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -1056,16 +1056,13 @@
LocationSummary* locations = add->GetLocations();
Location first = locations->InAt(0);
Location second = locations->InAt(1);
-
+ DCHECK(first.Equals(locations->Out()));
switch (add->GetResultType()) {
case Primitive::kPrimInt: {
- DCHECK_EQ(first.As<Register>(), locations->Out().As<Register>());
if (second.IsRegister()) {
__ addl(first.As<Register>(), second.As<Register>());
} else if (second.IsConstant()) {
- HConstant* instruction = second.GetConstant();
- Immediate imm(instruction->AsIntConstant()->GetValue());
- __ addl(first.As<Register>(), imm);
+ __ addl(first.As<Register>(), Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
} else {
__ addl(first.As<Register>(), Address(ESP, second.GetStackIndex()));
}
@@ -1073,10 +1070,6 @@
}
case Primitive::kPrimLong: {
- DCHECK_EQ(first.AsRegisterPairLow<Register>(),
- locations->Out().AsRegisterPairLow<Register>());
- DCHECK_EQ(first.AsRegisterPairHigh<Register>(),
- locations->Out().AsRegisterPairHigh<Register>());
if (second.IsRegister()) {
__ addl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
__ adcl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
@@ -1122,16 +1115,16 @@
locations->SetOut(Location::SameAsFirstInput());
break;
}
-
- case Primitive::kPrimBoolean:
- case Primitive::kPrimByte:
- case Primitive::kPrimChar:
- case Primitive::kPrimShort:
- LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble: {
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetInAt(1, Location::RequiresFpuRegister());
+ locations->SetOut(Location::SameAsFirstInput());
break;
+ }
default:
- LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
+ LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
}
}
@@ -1139,52 +1132,43 @@
LocationSummary* locations = sub->GetLocations();
Location first = locations->InAt(0);
Location second = locations->InAt(1);
+ DCHECK(first.Equals(locations->Out()));
switch (sub->GetResultType()) {
case Primitive::kPrimInt: {
- DCHECK_EQ(first.As<Register>(),
- locations->Out().As<Register>());
if (second.IsRegister()) {
- __ subl(first.As<Register>(),
- second.As<Register>());
+ __ subl(first.As<Register>(), second.As<Register>());
} else if (second.IsConstant()) {
- HConstant* instruction = second.GetConstant();
- Immediate imm(instruction->AsIntConstant()->GetValue());
- __ subl(first.As<Register>(), imm);
+ __ subl(first.As<Register>(), Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
} else {
- __ subl(first.As<Register>(),
- Address(ESP, second.GetStackIndex()));
+ __ subl(first.As<Register>(), Address(ESP, second.GetStackIndex()));
}
break;
}
case Primitive::kPrimLong: {
- DCHECK_EQ(first.AsRegisterPairLow<Register>(),
- locations->Out().AsRegisterPairLow<Register>());
- DCHECK_EQ(first.AsRegisterPairHigh<Register>(),
- locations->Out().AsRegisterPairHigh<Register>());
if (second.IsRegister()) {
- __ subl(first.AsRegisterPairLow<Register>(),
- second.AsRegisterPairLow<Register>());
- __ sbbl(first.AsRegisterPairHigh<Register>(),
- second.AsRegisterPairHigh<Register>());
+ __ subl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
+ __ sbbl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
} else {
- __ subl(first.AsRegisterPairLow<Register>(),
- Address(ESP, second.GetStackIndex()));
+ __ subl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
__ sbbl(first.AsRegisterPairHigh<Register>(),
Address(ESP, second.GetHighStackIndex(kX86WordSize)));
}
break;
}
- case Primitive::kPrimBoolean:
- case Primitive::kPrimByte:
- case Primitive::kPrimChar:
- case Primitive::kPrimShort:
- LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
+ case Primitive::kPrimFloat: {
+ __ subss(first.As<XmmRegister>(), second.As<XmmRegister>());
break;
+ }
+
+ case Primitive::kPrimDouble: {
+ __ subsd(first.As<XmmRegister>(), second.As<XmmRegister>());
+ break;
+ }
default:
- LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
+ LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
}
}
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index ac623f6..4a05b89 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -1047,19 +1047,17 @@
LocationSummary* locations = add->GetLocations();
Location first = locations->InAt(0);
Location second = locations->InAt(1);
-
DCHECK(first.Equals(locations->Out()));
+
switch (add->GetResultType()) {
case Primitive::kPrimInt: {
if (second.IsRegister()) {
__ addl(first.As<CpuRegister>(), second.As<CpuRegister>());
} else if (second.IsConstant()) {
- HConstant* instruction = second.GetConstant();
- Immediate imm(instruction->AsIntConstant()->GetValue());
+ Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
__ addl(first.As<CpuRegister>(), imm);
} else {
- __ addl(first.As<CpuRegister>(),
- Address(CpuRegister(RSP), second.GetStackIndex()));
+ __ addl(first.As<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
}
break;
}
@@ -1100,53 +1098,52 @@
locations->SetOut(Location::SameAsFirstInput());
break;
}
-
- case Primitive::kPrimBoolean:
- case Primitive::kPrimByte:
- case Primitive::kPrimChar:
- case Primitive::kPrimShort:
- LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble: {
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetInAt(1, Location::RequiresFpuRegister());
+ locations->SetOut(Location::SameAsFirstInput());
break;
-
+ }
default:
- LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
+ LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
}
}
void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
LocationSummary* locations = sub->GetLocations();
- DCHECK_EQ(locations->InAt(0).As<CpuRegister>().AsRegister(),
- locations->Out().As<CpuRegister>().AsRegister());
+ Location first = locations->InAt(0);
+ Location second = locations->InAt(1);
+ DCHECK(first.Equals(locations->Out()));
switch (sub->GetResultType()) {
case Primitive::kPrimInt: {
- if (locations->InAt(1).IsRegister()) {
- __ subl(locations->InAt(0).As<CpuRegister>(),
- locations->InAt(1).As<CpuRegister>());
- } else if (locations->InAt(1).IsConstant()) {
- HConstant* instruction = locations->InAt(1).GetConstant();
- Immediate imm(instruction->AsIntConstant()->GetValue());
- __ subl(locations->InAt(0).As<CpuRegister>(), imm);
+ if (second.IsRegister()) {
+ __ subl(first.As<CpuRegister>(), second.As<CpuRegister>());
+ } else if (second.IsConstant()) {
+ Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
+ __ subl(first.As<CpuRegister>(), imm);
} else {
- __ subl(locations->InAt(0).As<CpuRegister>(),
- Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
+ __ subl(first.As<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
}
break;
}
case Primitive::kPrimLong: {
- __ subq(locations->InAt(0).As<CpuRegister>(),
- locations->InAt(1).As<CpuRegister>());
+ __ subq(first.As<CpuRegister>(), second.As<CpuRegister>());
break;
}
- case Primitive::kPrimBoolean:
- case Primitive::kPrimByte:
- case Primitive::kPrimChar:
- case Primitive::kPrimShort:
- LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
+ case Primitive::kPrimFloat: {
+ __ subss(first.As<XmmRegister>(), second.As<XmmRegister>());
break;
+ }
+
+ case Primitive::kPrimDouble: {
+ __ subsd(first.As<XmmRegister>(), second.As<XmmRegister>());
+ break;
+ }
default:
- LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
+ LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
}
}
diff --git a/test/414-optimizing-arith-sub/expected.txt b/test/414-optimizing-arith-sub/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/414-optimizing-arith-sub/expected.txt
diff --git a/test/414-optimizing-arith-sub/info.txt b/test/414-optimizing-arith-sub/info.txt
new file mode 100644
index 0000000..1eaa148
--- /dev/null
+++ b/test/414-optimizing-arith-sub/info.txt
@@ -0,0 +1 @@
+Subtraction tests.
diff --git a/test/414-optimizing-arith-sub/src/Main.java b/test/414-optimizing-arith-sub/src/Main.java
new file mode 100644
index 0000000..30e8436
--- /dev/null
+++ b/test/414-optimizing-arith-sub/src/Main.java
@@ -0,0 +1,170 @@
+/*
+ * 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 = 0.0001F;
+ boolean aproxEquals = (a > b) ? ((a - b) < maxDelta) : ((b - a) < maxDelta);
+ if (!aproxEquals) {
+ throw new Error("Expected: " + a + ", found: " + b + ", with delta: " + maxDelta + " " + (a - b));
+ }
+ }
+
+ public static void expectApproxEquals(double a, double b) {
+ double maxDelta = 0.00001D;
+ boolean aproxEquals = (a > b) ? ((a - b) < maxDelta) : ((b - a) < maxDelta);
+ if (!aproxEquals) {
+ throw new Error("Expected: " + a + ", found: " + b + ", with delta: " + maxDelta + " " + (a - b));
+ }
+ }
+
+ 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) {
+ subInt();
+ subLong();
+ subFloat();
+ subDouble();
+ }
+
+ private static void subInt() {
+ expectEquals(2, $opt$Sub(5, 3));
+ expectEquals(0, $opt$Sub(0, 0));
+ expectEquals(-3, $opt$Sub(0, 3));
+ expectEquals(3, $opt$Sub(3, 0));
+ expectEquals(4, $opt$Sub(1, -3));
+ expectEquals(-9, $opt$Sub(-12, -3));
+ expectEquals(134217724, $opt$Sub(134217729, 5)); // (2^27 + 1) - 5
+ }
+
+ private static void subLong() {
+ expectEquals(2L, $opt$Sub(5L, 3L));
+ expectEquals(0L, $opt$Sub(0L, 0L));
+ expectEquals(-3L, $opt$Sub(0L, 3L));
+ expectEquals(3L, $opt$Sub(3L, 0L));
+ expectEquals(4L, $opt$Sub(1L, -3L));
+ expectEquals(-9L, $opt$Sub(-12L, -3L));
+ expectEquals(134217724L, $opt$Sub(134217729L, 5L)); // (2^27 + 1) - 5
+ expectEquals(34359738362L, $opt$Sub(34359738369L, 7L)); // (2^35 + 1) - 7
+ }
+
+ private static void subFloat() {
+ expectApproxEquals(2F, $opt$Sub(5F, 3F));
+ expectApproxEquals(0F, $opt$Sub(0F, 0F));
+ expectApproxEquals(-3F, $opt$Sub(0F, 3F));
+ expectApproxEquals(3F, $opt$Sub(3F, 0F));
+ expectApproxEquals(4F, $opt$Sub(1F, -3F));
+ expectApproxEquals(-9F, $opt$Sub(-12F, -3F));
+ expectApproxEquals(34359738362F, $opt$Sub(34359738369F, 7F)); // (2^35 + 1) - 7
+ expectApproxEquals(-0.1F, $opt$Sub(0.1F, 0.2F));
+ expectApproxEquals(0.2F, $opt$Sub(-0.5F, -0.7F));
+
+ expectNaN($opt$Sub(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY));
+ expectNaN($opt$Sub(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY));
+ expectNaN($opt$Sub(Float.NaN, 11F));
+ expectNaN($opt$Sub(Float.NaN, -11F));
+ expectNaN($opt$Sub(Float.NaN, Float.NEGATIVE_INFINITY));
+ expectNaN($opt$Sub(Float.NaN, Float.POSITIVE_INFINITY));
+
+ expectEquals(Float.NEGATIVE_INFINITY, $opt$Sub(-Float.MAX_VALUE, Float.MAX_VALUE));
+ expectEquals(Float.NEGATIVE_INFINITY, $opt$Sub(2F, Float.POSITIVE_INFINITY));
+ expectEquals(Float.POSITIVE_INFINITY, $opt$Sub(Float.MAX_VALUE, -Float.MAX_VALUE));
+ expectEquals(Float.POSITIVE_INFINITY, $opt$Sub(2F, Float.NEGATIVE_INFINITY));
+ expectEquals(Float.POSITIVE_INFINITY, $opt$Sub(Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY));
+ expectEquals(Float.NEGATIVE_INFINITY, $opt$Sub(Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY));
+ }
+
+ private static void subDouble() {
+ expectApproxEquals(2D, $opt$Sub(5D, 3D));
+ expectApproxEquals(0D, $opt$Sub(0D, 0D));
+ expectApproxEquals(-3D, $opt$Sub(0D, 3D));
+ expectApproxEquals(3D, $opt$Sub(3D, 0D));
+ expectApproxEquals(4D, $opt$Sub(1D, -3D));
+ expectApproxEquals(-9D, $opt$Sub(-12D, -3D));
+ expectApproxEquals(134217724D, $opt$Sub(134217729D, 5D)); // (2^27 + 1) - 5
+ expectApproxEquals(34359738362D, $opt$Sub(34359738369D, 7D)); // (2^35 + 1) - 7
+ expectApproxEquals(-0.1D, $opt$Sub(0.1D, 0.2D));
+ expectApproxEquals(0.2D, $opt$Sub(-0.5D, -0.7D));
+
+ expectNaN($opt$Sub(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY));
+ expectNaN($opt$Sub(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY));
+ expectNaN($opt$Sub(Double.NaN, 11D));
+ expectNaN($opt$Sub(Double.NaN, -11D));
+ expectNaN($opt$Sub(Double.NaN, Double.NEGATIVE_INFINITY));
+ expectNaN($opt$Sub(Double.NaN, Double.POSITIVE_INFINITY));
+
+ expectEquals(Double.NEGATIVE_INFINITY, $opt$Sub(-Double.MAX_VALUE, Double.MAX_VALUE));
+ expectEquals(Double.NEGATIVE_INFINITY, $opt$Sub(2D, Double.POSITIVE_INFINITY));
+ expectEquals(Double.POSITIVE_INFINITY, $opt$Sub(Double.MAX_VALUE, -Double.MAX_VALUE));
+ expectEquals(Double.POSITIVE_INFINITY, $opt$Sub(2D, Double.NEGATIVE_INFINITY));
+ expectEquals(Double.POSITIVE_INFINITY, $opt$Sub(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY));
+ expectEquals(Double.NEGATIVE_INFINITY, $opt$Sub(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
+ }
+
+ static int $opt$Sub(int a, int b) {
+ return a - b;
+ }
+
+ static long $opt$Sub(long a, long b) {
+ return a - b;
+ }
+
+ static float $opt$Sub(float a, float b) {
+ return a - b;
+ }
+
+ static double $opt$Sub(double a, double b) {
+ return a - b;
+ }
+
+}