Fix neg-float & neg-double for null values in opt. compiler.
- Implement float and double negation as an exclusive or
with a bit sign mask in x86 and x86-64 code generators.
- Enable requests of temporary FPU (double) registers during
register allocation.
- Update test cases in test/415-optimizing-arith-neg.
Change-Id: I9572c24b27c645ba698825e60cd5b3956b4895fa
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 6423793..01fd701 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -1239,11 +1239,16 @@
break;
case Primitive::kPrimFloat:
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetOut(Location::SameAsFirstInput());
+ locations->AddTemp(Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresFpuRegister());
+ break;
+
case Primitive::kPrimDouble:
locations->SetInAt(0, Location::RequiresFpuRegister());
- // Output overlaps as we need a fresh (zero-initialized)
- // register to perform subtraction from zero.
- locations->SetOut(Location::RequiresFpuRegister());
+ locations->SetOut(Location::SameAsFirstInput());
+ locations->AddTemp(Location::RequiresFpuRegister());
break;
default:
@@ -1275,21 +1280,29 @@
__ negl(out.AsRegisterPairHigh<Register>());
break;
- case Primitive::kPrimFloat:
- DCHECK(!in.Equals(out));
- // out = 0
- __ xorps(out.As<XmmRegister>(), out.As<XmmRegister>());
- // out = out - in
- __ subss(out.As<XmmRegister>(), in.As<XmmRegister>());
+ case Primitive::kPrimFloat: {
+ DCHECK(in.Equals(out));
+ Register constant = locations->GetTemp(0).As<Register>();
+ XmmRegister mask = locations->GetTemp(1).As<XmmRegister>();
+ // Implement float negation with an exclusive or with value
+ // 0x80000000 (mask for bit 31, representing the sign of a
+ // single-precision floating-point number).
+ __ movl(constant, Immediate(INT32_C(0x80000000)));
+ __ movd(mask, constant);
+ __ xorps(out.As<XmmRegister>(), mask);
break;
+ }
- case Primitive::kPrimDouble:
- DCHECK(!in.Equals(out));
- // out = 0
- __ xorpd(out.As<XmmRegister>(), out.As<XmmRegister>());
- // out = out - in
- __ subsd(out.As<XmmRegister>(), in.As<XmmRegister>());
+ case Primitive::kPrimDouble: {
+ DCHECK(in.Equals(out));
+ XmmRegister mask = locations->GetTemp(0).As<XmmRegister>();
+ // Implement double negation with an exclusive or with value
+ // 0x8000000000000000 (mask for bit 63, representing the sign of
+ // a double-precision floating-point number).
+ __ LoadLongConstant(mask, INT64_C(0x8000000000000000));
+ __ xorpd(out.As<XmmRegister>(), mask);
break;
+ }
default:
LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 414894b..8d9145a 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -1256,9 +1256,9 @@
case Primitive::kPrimFloat:
case Primitive::kPrimDouble:
locations->SetInAt(0, Location::RequiresFpuRegister());
- // Output overlaps as we need a fresh (zero-initialized)
- // register to perform subtraction from zero.
- locations->SetOut(Location::RequiresFpuRegister());
+ locations->SetOut(Location::SameAsFirstInput());
+ locations->AddTemp(Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresFpuRegister());
break;
default:
@@ -1283,40 +1283,31 @@
__ negq(out.As<CpuRegister>());
break;
- case Primitive::kPrimFloat:
- DCHECK(in.IsFpuRegister());
- DCHECK(out.IsFpuRegister());
- DCHECK(!in.Equals(out));
- // TODO: Instead of computing negation as a subtraction from
- // zero, implement it with an exclusive or with value 0x80000000
- // (mask for bit 31, representing the sign of a single-precision
- // floating-point number), fetched from a constant pool:
- //
- // xorps out, [RIP:...] // value at RIP is 0x80 00 00 00
-
- // out = 0
- __ xorps(out.As<XmmRegister>(), out.As<XmmRegister>());
- // out = out - in
- __ subss(out.As<XmmRegister>(), in.As<XmmRegister>());
+ case Primitive::kPrimFloat: {
+ DCHECK(in.Equals(out));
+ CpuRegister constant = locations->GetTemp(0).As<CpuRegister>();
+ XmmRegister mask = locations->GetTemp(1).As<XmmRegister>();
+ // Implement float negation with an exclusive or with value
+ // 0x80000000 (mask for bit 31, representing the sign of a
+ // single-precision floating-point number).
+ __ movq(constant, Immediate(INT64_C(0x80000000)));
+ __ movd(mask, constant);
+ __ xorps(out.As<XmmRegister>(), mask);
break;
+ }
- case Primitive::kPrimDouble:
- DCHECK(in.IsFpuRegister());
- DCHECK(out.IsFpuRegister());
- DCHECK(!in.Equals(out));
- // TODO: Instead of computing negation as a subtraction from
- // zero, implement it with an exclusive or with value
+ case Primitive::kPrimDouble: {
+ DCHECK(in.Equals(out));
+ CpuRegister constant = locations->GetTemp(0).As<CpuRegister>();
+ XmmRegister mask = locations->GetTemp(1).As<XmmRegister>();
+ // Implement double negation with an exclusive or with value
// 0x8000000000000000 (mask for bit 63, representing the sign of
- // a double-precision floating-point number), fetched from a
- // constant pool:
- //
- // xorpd out, [RIP:...] // value at RIP is 0x80 00 00 00 00 00 00 00
-
- // out = 0
- __ xorpd(out.As<XmmRegister>(), out.As<XmmRegister>());
- // out = out - in
- __ subsd(out.As<XmmRegister>(), in.As<XmmRegister>());
+ // a double-precision floating-point number).
+ __ movq(constant, Immediate(INT64_C(0x8000000000000000)));
+ __ movd(mask, constant);
+ __ xorpd(out.As<XmmRegister>(), mask);
break;
+ }
default:
LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc
index 2948496..5b151a1 100644
--- a/compiler/optimizing/register_allocator.cc
+++ b/compiler/optimizing/register_allocator.cc
@@ -189,11 +189,29 @@
BlockRegister(temp, position, position + 1);
} else {
DCHECK(temp.IsUnallocated());
- DCHECK(temp.GetPolicy() == Location::kRequiresRegister);
- LiveInterval* interval = LiveInterval::MakeTempInterval(allocator_, Primitive::kPrimInt);
- temp_intervals_.Add(interval);
- interval->AddRange(position, position + 1);
- unhandled_core_intervals_.Add(interval);
+ switch (temp.GetPolicy()) {
+ case Location::kRequiresRegister: {
+ LiveInterval* interval =
+ LiveInterval::MakeTempInterval(allocator_, Primitive::kPrimInt);
+ temp_intervals_.Add(interval);
+ interval->AddRange(position, position + 1);
+ unhandled_core_intervals_.Add(interval);
+ break;
+ }
+
+ case Location::kRequiresFpuRegister: {
+ LiveInterval* interval =
+ LiveInterval::MakeTempInterval(allocator_, Primitive::kPrimDouble);
+ temp_intervals_.Add(interval);
+ interval->AddRange(position, position + 1);
+ unhandled_fp_intervals_.Add(interval);
+ break;
+ }
+
+ default:
+ LOG(FATAL) << "Unexpected policy for temporary location "
+ << temp.GetPolicy();
+ }
}
}
@@ -1250,9 +1268,27 @@
current = at;
}
LocationSummary* locations = at->GetLocations();
- DCHECK(temp->GetType() == Primitive::kPrimInt);
- locations->SetTempAt(
- temp_index++, Location::RegisterLocation(temp->GetRegister()));
+ switch (temp->GetType()) {
+ case Primitive::kPrimInt:
+ locations->SetTempAt(
+ temp_index++, Location::RegisterLocation(temp->GetRegister()));
+ break;
+
+ case Primitive::kPrimDouble:
+ // TODO: Support the case of ARM, where a double value
+ // requires an FPU register pair (note that the ARM back end
+ // does not yet use this register allocator when a method uses
+ // floats or doubles).
+ DCHECK(codegen_->GetInstructionSet() != kArm
+ && codegen_->GetInstructionSet() != kThumb2);
+ locations->SetTempAt(
+ temp_index++, Location::FpuRegisterLocation(temp->GetRegister()));
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type for temporary location "
+ << temp->GetType();
+ }
}
}