ARM64: Support interm. address for object arrays.

Support IntermediateAddress on arm64 for object
array reads in Baker read barrier configuration.

The patch brings minor boot.oat size reduction and
performance improvement on Puzzle benchmark.

Test: test-art-target, test-art-host, gc_stress.
Test: 527-checker-array-access-split.

Bug: 26601270
Bug: 32578862

Change-Id: I781a911905038b36428964a990771fdf74e99bbd
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 3f4fb15..12d2393 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -2317,9 +2317,10 @@
       if (offset >= kReferenceLoadMinFarOffset) {
         locations->AddTemp(FixedTempLocation());
       }
-    } else {
+    } else if (!instruction->GetArray()->IsIntermediateAddress()) {
       // We need a non-scratch temporary for the array data pointer in
-      // CodeGeneratorARM64::GenerateArrayLoadWithBakerReadBarrier().
+      // CodeGeneratorARM64::GenerateArrayLoadWithBakerReadBarrier() for the case with no
+      // intermediate address.
       locations->AddTemp(Location::RequiresRegister());
     }
   }
@@ -2349,11 +2350,12 @@
   MacroAssembler* masm = GetVIXLAssembler();
   UseScratchRegisterScope temps(masm);
 
-  // The read barrier instrumentation of object ArrayGet instructions
+  // The non-Baker read barrier instrumentation of object ArrayGet instructions
   // does not support the HIntermediateAddress instruction.
   DCHECK(!((type == DataType::Type::kReference) &&
            instruction->GetArray()->IsIntermediateAddress() &&
-           kEmitCompilerReadBarrier));
+           kEmitCompilerReadBarrier &&
+           !kUseBakerReadBarrier));
 
   if (type == DataType::Type::kReference && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
     // Object ArrayGet with Baker's read barrier case.
@@ -2361,6 +2363,7 @@
     // CodeGeneratorARM64::GenerateArrayLoadWithBakerReadBarrier call.
     DCHECK(!instruction->CanDoImplicitNullCheckOn(instruction->InputAt(0)));
     if (index.IsConstant()) {
+      DCHECK(!instruction->GetArray()->IsIntermediateAddress());
       // Array load with a constant index can be treated as a field load.
       offset += Int64FromLocation(index) << DataType::SizeShift(type);
       Location maybe_temp =
@@ -2373,9 +2376,8 @@
                                                       /* needs_null_check */ false,
                                                       /* use_load_acquire */ false);
     } else {
-      Register temp = WRegisterFrom(locations->GetTemp(0));
       codegen_->GenerateArrayLoadWithBakerReadBarrier(
-          out, obj.W(), offset, index, temp, /* needs_null_check */ false);
+          instruction, out, obj.W(), offset, index, /* needs_null_check */ false);
     }
   } else {
     // General case.
@@ -2424,8 +2426,8 @@
         // input instruction has done it already. See the comment in
         // `TryExtractArrayAccessAddress()`.
         if (kIsDebugBuild) {
-          HIntermediateAddress* tmp = instruction->GetArray()->AsIntermediateAddress();
-          DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), offset);
+          HIntermediateAddress* interm_addr = instruction->GetArray()->AsIntermediateAddress();
+          DCHECK_EQ(interm_addr->GetOffset()->AsIntConstant()->GetValueAsUint64(), offset);
         }
         temp = obj;
       } else {
@@ -2537,8 +2539,8 @@
         // input instruction has done it already. See the comment in
         // `TryExtractArrayAccessAddress()`.
         if (kIsDebugBuild) {
-          HIntermediateAddress* tmp = instruction->GetArray()->AsIntermediateAddress();
-          DCHECK(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64() == offset);
+          HIntermediateAddress* interm_addr = instruction->GetArray()->AsIntermediateAddress();
+          DCHECK(interm_addr->GetOffset()->AsIntConstant()->GetValueAsUint64() == offset);
         }
         temp = array;
       } else {
@@ -5955,11 +5957,11 @@
       instruction, ref, obj, src, needs_null_check, use_load_acquire);
 }
 
-void CodeGeneratorARM64::GenerateArrayLoadWithBakerReadBarrier(Location ref,
+void CodeGeneratorARM64::GenerateArrayLoadWithBakerReadBarrier(HArrayGet* instruction,
+                                                               Location ref,
                                                                Register obj,
                                                                uint32_t data_offset,
                                                                Location index,
-                                                               Register temp,
                                                                bool needs_null_check) {
   DCHECK(kEmitCompilerReadBarrier);
   DCHECK(kUseBakerReadBarrier);
@@ -5998,9 +6000,24 @@
   DCHECK(temps.IsAvailable(ip0));
   DCHECK(temps.IsAvailable(ip1));
   temps.Exclude(ip0, ip1);
+
+  Register temp;
+  if (instruction->GetArray()->IsIntermediateAddress()) {
+    // We do not need to compute the intermediate address from the array: the
+    // input instruction has done it already. See the comment in
+    // `TryExtractArrayAccessAddress()`.
+    if (kIsDebugBuild) {
+      HIntermediateAddress* interm_addr = instruction->GetArray()->AsIntermediateAddress();
+      DCHECK_EQ(interm_addr->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
+    }
+    temp = obj;
+  } else {
+    temp = WRegisterFrom(instruction->GetLocations()->GetTemp(0));
+    __ Add(temp.X(), obj.X(), Operand(data_offset));
+  }
+
   uint32_t custom_data = EncodeBakerReadBarrierArrayData(temp.GetCode());
 
-  __ Add(temp.X(), obj.X(), Operand(data_offset));
   {
     ExactAssemblyScope guard(GetVIXLAssembler(),
                              (kPoisonHeapReferences ? 4u : 3u) * vixl::aarch64::kInstructionSize);
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index 1ba58b1..ada5742 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -694,11 +694,11 @@
                                              bool use_load_acquire);
   // Fast path implementation of ReadBarrier::Barrier for a heap
   // reference array load when Baker's read barriers are used.
-  void GenerateArrayLoadWithBakerReadBarrier(Location ref,
+  void GenerateArrayLoadWithBakerReadBarrier(HArrayGet* instruction,
+                                             Location ref,
                                              vixl::aarch64::Register obj,
                                              uint32_t data_offset,
                                              Location index,
-                                             vixl::aarch64::Register temp,
                                              bool needs_null_check);
 
   // Emit code checking the status of the Marking Register, and
diff --git a/compiler/optimizing/instruction_simplifier_arm.cc b/compiler/optimizing/instruction_simplifier_arm.cc
index 24fbb6c..f968c19 100644
--- a/compiler/optimizing/instruction_simplifier_arm.cc
+++ b/compiler/optimizing/instruction_simplifier_arm.cc
@@ -202,6 +202,11 @@
     return;
   }
 
+  // TODO: Support intermediate address for object arrays on arm.
+  if (type == DataType::Type::kReference) {
+    return;
+  }
+
   if (type == DataType::Type::kInt64
       || type == DataType::Type::kFloat32
       || type == DataType::Type::kFloat64) {
diff --git a/compiler/optimizing/instruction_simplifier_shared.cc b/compiler/optimizing/instruction_simplifier_shared.cc
index ccdcb35..0f30f66 100644
--- a/compiler/optimizing/instruction_simplifier_shared.cc
+++ b/compiler/optimizing/instruction_simplifier_shared.cc
@@ -245,11 +245,11 @@
     return false;
   }
   if (kEmitCompilerReadBarrier &&
+      !kUseBakerReadBarrier &&
       access->IsArrayGet() &&
       access->GetType() == DataType::Type::kReference) {
-    // For object arrays, the read barrier instrumentation requires
+    // For object arrays, the non-Baker read barrier instrumentation requires
     // the original array pointer.
-    // TODO: This can be relaxed for Baker CC.
     return false;
   }