OSDN Git Service

Fix neg-float & neg-double for null values in opt. compiler.
authorRoland Levillain <rpl@google.com>
Thu, 27 Nov 2014 15:03:41 +0000 (15:03 +0000)
committerRoland Levillain <rpl@google.com>
Thu, 27 Nov 2014 15:03:41 +0000 (15:03 +0000)
- 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

compiler/optimizing/code_generator_x86.cc
compiler/optimizing/code_generator_x86_64.cc
compiler/optimizing/register_allocator.cc
test/415-optimizing-arith-neg/src/Main.java

index 6423793..01fd701 100644 (file)
@@ -1239,11 +1239,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:
@@ -1275,21 +1280,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();
index 414894b..8d9145a 100644 (file)
@@ -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();
index 2948496..5b151a1 100644 (file)
@@ -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();
+    }
   }
 }
 
index d9f8bcf..bd8a158 100644 (file)
@@ -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));