ARM64: Use the zero register for field and array set operations.

Test: Run ART test suite on host and Nexus 9.
Change-Id: I4e2a81570ecc57530249672df704eb0bb780acce
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index cc8985d..8084e49 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -46,16 +46,20 @@
 
 namespace arm64 {
 
+using helpers::ARM64EncodableConstantOrRegister;
+using helpers::ArtVixlRegCodeCoherentForRegSet;
 using helpers::CPURegisterFrom;
 using helpers::DRegisterFrom;
 using helpers::FPRegisterFrom;
 using helpers::HeapOperand;
 using helpers::HeapOperandFrom;
 using helpers::InputCPURegisterAt;
+using helpers::InputCPURegisterOrZeroRegAt;
 using helpers::InputFPRegisterAt;
-using helpers::InputRegisterAt;
 using helpers::InputOperandAt;
+using helpers::InputRegisterAt;
 using helpers::Int64ConstantFrom;
+using helpers::IsConstantZeroBitPattern;
 using helpers::LocationFrom;
 using helpers::OperandFromMemOperand;
 using helpers::OutputCPURegister;
@@ -66,8 +70,6 @@
 using helpers::VIXLRegCodeFromART;
 using helpers::WRegisterFrom;
 using helpers::XRegisterFrom;
-using helpers::ARM64EncodableConstantOrRegister;
-using helpers::ArtVixlRegCodeCoherentForRegSet;
 
 static constexpr int kCurrentMethodStackOffset = 0;
 // The compare/jump sequence will generate about (1.5 * num_entries + 3) instructions. While jump
@@ -1465,12 +1467,18 @@
       break;
     case Primitive::kPrimFloat:
     case Primitive::kPrimDouble: {
-      DCHECK(src.IsFPRegister());
       DCHECK_EQ(src.Is64Bits(), Primitive::Is64BitType(type));
+      Register temp_src;
+      if (src.IsZero()) {
+        // The zero register is used to avoid synthesizing zero constants.
+        temp_src = Register(src);
+      } else {
+        DCHECK(src.IsFPRegister());
+        temp_src = src.Is64Bits() ? temps.AcquireX() : temps.AcquireW();
+        __ Fmov(temp_src, FPRegister(src));
+      }
 
-      Register temp = src.Is64Bits() ? temps.AcquireX() : temps.AcquireW();
-      __ Fmov(temp, FPRegister(src));
-      __ Stlr(temp, base);
+      __ Stlr(temp_src, base);
       break;
     }
     case Primitive::kPrimVoid:
@@ -1709,7 +1717,9 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
-  if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
+  if (IsConstantZeroBitPattern(instruction->InputAt(1))) {
+    locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
+  } else if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
     locations->SetInAt(1, Location::RequiresFpuRegister());
   } else {
     locations->SetInAt(1, Location::RequiresRegister());
@@ -1723,7 +1733,7 @@
   BlockPoolsScope block_pools(GetVIXLAssembler());
 
   Register obj = InputRegisterAt(instruction, 0);
-  CPURegister value = InputCPURegisterAt(instruction, 1);
+  CPURegister value = InputCPURegisterOrZeroRegAt(instruction, 1);
   CPURegister source = value;
   Offset offset = field_info.GetFieldOffset();
   Primitive::Type field_type = field_info.GetFieldType();
@@ -2171,7 +2181,9 @@
           LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
-  if (Primitive::IsFloatingPointType(value_type)) {
+  if (IsConstantZeroBitPattern(instruction->InputAt(2))) {
+    locations->SetInAt(2, Location::ConstantLocation(instruction->InputAt(2)->AsConstant()));
+  } else if (Primitive::IsFloatingPointType(value_type)) {
     locations->SetInAt(2, Location::RequiresFpuRegister());
   } else {
     locations->SetInAt(2, Location::RequiresRegister());
@@ -2186,7 +2198,7 @@
       CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
 
   Register array = InputRegisterAt(instruction, 0);
-  CPURegister value = InputCPURegisterAt(instruction, 2);
+  CPURegister value = InputCPURegisterOrZeroRegAt(instruction, 2);
   CPURegister source = value;
   Location index = locations->InAt(1);
   size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value();