diff options
| -rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 43 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 57 | ||||
| -rw-r--r-- | compiler/optimizing/register_allocator.cc | 52 | ||||
| -rw-r--r-- | test/415-optimizing-arith-neg/src/Main.java | 18 |
4 files changed, 112 insertions, 58 deletions
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 3f7a69a88f..ac2a084bb1 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -1250,11 +1250,16 @@ void LocationsBuilderX86::VisitNeg(HNeg* neg) { 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: @@ -1286,21 +1291,29 @@ void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) { __ 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 414894bae7..8d9145a16f 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -1256,9 +1256,9 @@ void LocationsBuilderX86_64::VisitNeg(HNeg* neg) { 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 @@ void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) { __ 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 2948496e15..5b151a1aca 100644 --- a/compiler/optimizing/register_allocator.cc +++ b/compiler/optimizing/register_allocator.cc @@ -189,11 +189,29 @@ void RegisterAllocator::ProcessInstruction(HInstruction* instruction) { 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 @@ void RegisterAllocator::Resolve() { 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(); + } } } diff --git a/test/415-optimizing-arith-neg/src/Main.java b/test/415-optimizing-arith-neg/src/Main.java index d9f8bcf0c2..bd8a1583d5 100644 --- a/test/415-optimizing-arith-neg/src/Main.java +++ b/test/415-optimizing-arith-neg/src/Main.java @@ -36,12 +36,24 @@ public class Main { } } + public static void assertEquals(String expected, float result) { + if (!expected.equals(new Float(result).toString())) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + public static void assertEquals(double expected, double result) { if (expected != result) { throw new Error("Expected: " + expected + ", found: " + result); } } + public static void assertEquals(String expected, double result) { + if (!expected.equals(new Double(result).toString())) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + public static void assertIsNaN(float result) { if (!Float.isNaN(result)) { throw new Error("Expected NaN: " + result); @@ -116,9 +128,10 @@ public class Main { } private static void negFloat() { + assertEquals("-0.0", $opt$NegFloat(0F)); + assertEquals("0.0", $opt$NegFloat(-0F)); assertEquals(-1F, $opt$NegFloat(1F)); assertEquals(1F, $opt$NegFloat(-1F)); - assertEquals(0F, $opt$NegFloat(0F)); assertEquals(51F, $opt$NegFloat(-51F)); assertEquals(-51F, $opt$NegFloat(51F)); @@ -140,9 +153,10 @@ public class Main { } private static void negDouble() { + assertEquals("-0.0", $opt$NegDouble(0D)); + assertEquals("0.0", $opt$NegDouble(-0D)); assertEquals(-1D, $opt$NegDouble(1D)); assertEquals(1D, $opt$NegDouble(-1D)); - assertEquals(0D, $opt$NegDouble(0D)); assertEquals(51D, $opt$NegDouble(-51D)); assertEquals(-51D, $opt$NegDouble(51D)); |