Look at instruction set features when generating volatiles code

Change-Id: Ia882405719fdd60b63e4102af7e085f7cbe0bb2a
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 063dc7c..2f49107 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -16,6 +16,7 @@
 
 #include "code_generator_arm.h"
 
+#include "arch/arm/instruction_set_features_arm.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "gc/accounting/card_table.h"
 #include "mirror/array-inl.h"
@@ -372,13 +373,15 @@
   return kArmWordSize;
 }
 
-CodeGeneratorARM::CodeGeneratorARM(HGraph* graph)
+CodeGeneratorARM::CodeGeneratorARM(HGraph* graph,
+                                   const ArmInstructionSetFeatures* isa_features)
     : CodeGenerator(graph, kNumberOfCoreRegisters, kNumberOfSRegisters, kNumberOfRegisterPairs),
       block_labels_(graph->GetArena(), 0),
       location_builder_(graph, this),
       instruction_visitor_(graph, this),
       move_resolver_(graph->GetArena(), this),
-      assembler_(true) {}
+      assembler_(true),
+      isa_features_(isa_features) {}
 
 size_t CodeGeneratorARM::FrameEntrySpillSize() const {
   return kNumberOfPushedRegistersAtEntry * kArmWordSize;
@@ -2615,16 +2618,18 @@
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RequiresRegister());
 
-  bool is_volatile = field_info.IsVolatile();
+
   Primitive::Type field_type = field_info.GetFieldType();
   bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
-
+  bool generate_volatile = field_info.IsVolatile()
+      && is_wide
+      && !codegen_->GetInstructionSetFeatures()->HasAtomicLdrdAndStrd();
   // Temporary registers for the write barrier.
   // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
   if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
     locations->AddTemp(Location::RequiresRegister());
     locations->AddTemp(Location::RequiresRegister());
-  } else if (is_volatile && is_wide) {
+  } else if (generate_volatile) {
     // Arm encoding have some additional constraints for ldrexd/strexd:
     // - registers need to be consecutive
     // - the first register should be even but not R14.
@@ -2651,6 +2656,7 @@
   Location value = locations->InAt(1);
 
   bool is_volatile = field_info.IsVolatile();
+  bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures()->HasAtomicLdrdAndStrd();
   Primitive::Type field_type = field_info.GetFieldType();
   uint32_t offset = field_info.GetFieldOffset().Uint32Value();
 
@@ -2684,10 +2690,7 @@
     }
 
     case Primitive::kPrimLong: {
-      if (is_volatile) {
-        // TODO: We could use ldrd and strd that are atomic with Large Physical Address Extension
-        // support. This info is stored in the compiler driver (HasAtomicLdrdAndStrd) and we should
-        // pass it around to be able to optimize.
+      if (is_volatile && !atomic_ldrd_strd) {
         GenerateWideAtomicStore(base, offset,
                                 value.AsRegisterPairLow<Register>(),
                                 value.AsRegisterPairHigh<Register>(),
@@ -2706,7 +2709,7 @@
 
     case Primitive::kPrimDouble: {
       DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
-      if (is_volatile) {
+      if (is_volatile && !atomic_ldrd_strd) {
         Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
         Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
 
@@ -2740,7 +2743,10 @@
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
 
-  if (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimDouble)) {
+  bool generate_volatile = field_info.IsVolatile()
+      && (field_info.GetFieldType() == Primitive::kPrimDouble)
+      && !codegen_->GetInstructionSetFeatures()->HasAtomicLdrdAndStrd();
+  if (generate_volatile) {
     // Arm encoding have some additional constraints for ldrexd/strexd:
     // - registers need to be consecutive
     // - the first register should be even but not R14.
@@ -2760,6 +2766,7 @@
   Register base = locations->InAt(0).AsRegister<Register>();
   Location out = locations->Out();
   bool is_volatile = field_info.IsVolatile();
+  bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures()->HasAtomicLdrdAndStrd();
   Primitive::Type field_type = field_info.GetFieldType();
   uint32_t offset = field_info.GetFieldOffset().Uint32Value();
 
@@ -2791,7 +2798,7 @@
     }
 
     case Primitive::kPrimLong: {
-      if (is_volatile) {
+      if (is_volatile && !atomic_ldrd_strd) {
         GenerateWideAtomicLoad(base, offset,
                                out.AsRegisterPairLow<Register>(),
                                out.AsRegisterPairHigh<Register>());
@@ -2808,7 +2815,7 @@
 
     case Primitive::kPrimDouble: {
       DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
-      if (is_volatile) {
+      if (is_volatile && !atomic_ldrd_strd) {
         Register lo = locations->GetTemp(0).AsRegister<Register>();
         Register hi = locations->GetTemp(1).AsRegister<Register>();
         GenerateWideAtomicLoad(base, offset, lo, hi);