Home | History | Annotate | Download | only in optimizing
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef ART_COMPILER_OPTIMIZING_CODE_GENERATOR_ARM_VIXL_H_
     18 #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_ARM_VIXL_H_
     19 
     20 #include "base/enums.h"
     21 #include "code_generator.h"
     22 #include "common_arm.h"
     23 #include "dex/string_reference.h"
     24 #include "dex/type_reference.h"
     25 #include "driver/compiler_options.h"
     26 #include "nodes.h"
     27 #include "parallel_move_resolver.h"
     28 #include "utils/arm/assembler_arm_vixl.h"
     29 
     30 // TODO(VIXL): make vixl clean wrt -Wshadow.
     31 #pragma GCC diagnostic push
     32 #pragma GCC diagnostic ignored "-Wshadow"
     33 #include "aarch32/constants-aarch32.h"
     34 #include "aarch32/instructions-aarch32.h"
     35 #include "aarch32/macro-assembler-aarch32.h"
     36 #pragma GCC diagnostic pop
     37 
     38 namespace art {
     39 namespace arm {
     40 
     41 // This constant is used as an approximate margin when emission of veneer and literal pools
     42 // must be blocked.
     43 static constexpr int kMaxMacroInstructionSizeInBytes =
     44     15 * vixl::aarch32::kMaxInstructionSizeInBytes;
     45 
     46 static const vixl::aarch32::Register kParameterCoreRegistersVIXL[] = {
     47     vixl::aarch32::r1,
     48     vixl::aarch32::r2,
     49     vixl::aarch32::r3
     50 };
     51 static const size_t kParameterCoreRegistersLengthVIXL = arraysize(kParameterCoreRegistersVIXL);
     52 static const vixl::aarch32::SRegister kParameterFpuRegistersVIXL[] = {
     53     vixl::aarch32::s0,
     54     vixl::aarch32::s1,
     55     vixl::aarch32::s2,
     56     vixl::aarch32::s3,
     57     vixl::aarch32::s4,
     58     vixl::aarch32::s5,
     59     vixl::aarch32::s6,
     60     vixl::aarch32::s7,
     61     vixl::aarch32::s8,
     62     vixl::aarch32::s9,
     63     vixl::aarch32::s10,
     64     vixl::aarch32::s11,
     65     vixl::aarch32::s12,
     66     vixl::aarch32::s13,
     67     vixl::aarch32::s14,
     68     vixl::aarch32::s15
     69 };
     70 static const size_t kParameterFpuRegistersLengthVIXL = arraysize(kParameterFpuRegistersVIXL);
     71 
     72 static const vixl::aarch32::Register kMethodRegister = vixl::aarch32::r0;
     73 
     74 static const vixl::aarch32::Register kCoreAlwaysSpillRegister = vixl::aarch32::r5;
     75 
     76 // Callee saves core registers r5, r6, r7, r8 (except when emitting Baker
     77 // read barriers, where it is used as Marking Register), r10, r11, and lr.
     78 static const vixl::aarch32::RegisterList kCoreCalleeSaves = vixl::aarch32::RegisterList::Union(
     79     vixl::aarch32::RegisterList(vixl::aarch32::r5,
     80                                 vixl::aarch32::r6,
     81                                 vixl::aarch32::r7),
     82     // Do not consider r8 as a callee-save register with Baker read barriers.
     83     ((kEmitCompilerReadBarrier && kUseBakerReadBarrier)
     84          ? vixl::aarch32::RegisterList()
     85          : vixl::aarch32::RegisterList(vixl::aarch32::r8)),
     86     vixl::aarch32::RegisterList(vixl::aarch32::r10,
     87                                 vixl::aarch32::r11,
     88                                 vixl::aarch32::lr));
     89 
     90 // Callee saves FP registers s16 to s31 inclusive.
     91 static const vixl::aarch32::SRegisterList kFpuCalleeSaves =
     92     vixl::aarch32::SRegisterList(vixl::aarch32::s16, 16);
     93 
     94 static const vixl::aarch32::Register kRuntimeParameterCoreRegistersVIXL[] = {
     95     vixl::aarch32::r0,
     96     vixl::aarch32::r1,
     97     vixl::aarch32::r2,
     98     vixl::aarch32::r3
     99 };
    100 static const size_t kRuntimeParameterCoreRegistersLengthVIXL =
    101     arraysize(kRuntimeParameterCoreRegistersVIXL);
    102 static const vixl::aarch32::SRegister kRuntimeParameterFpuRegistersVIXL[] = {
    103     vixl::aarch32::s0,
    104     vixl::aarch32::s1,
    105     vixl::aarch32::s2,
    106     vixl::aarch32::s3
    107 };
    108 static const size_t kRuntimeParameterFpuRegistersLengthVIXL =
    109     arraysize(kRuntimeParameterFpuRegistersVIXL);
    110 
    111 class LoadClassSlowPathARMVIXL;
    112 class CodeGeneratorARMVIXL;
    113 
    114 using VIXLInt32Literal = vixl::aarch32::Literal<int32_t>;
    115 using VIXLUInt32Literal = vixl::aarch32::Literal<uint32_t>;
    116 
    117 class JumpTableARMVIXL : public DeletableArenaObject<kArenaAllocSwitchTable> {
    118  public:
    119   explicit JumpTableARMVIXL(HPackedSwitch* switch_instr)
    120       : switch_instr_(switch_instr),
    121         table_start_(),
    122         bb_addresses_(switch_instr->GetAllocator()->Adapter(kArenaAllocCodeGenerator)) {
    123     uint32_t num_entries = switch_instr_->GetNumEntries();
    124     for (uint32_t i = 0; i < num_entries; i++) {
    125       VIXLInt32Literal *lit = new VIXLInt32Literal(0, vixl32::RawLiteral::kManuallyPlaced);
    126       bb_addresses_.emplace_back(lit);
    127     }
    128   }
    129 
    130   vixl::aarch32::Label* GetTableStartLabel() { return &table_start_; }
    131 
    132   void EmitTable(CodeGeneratorARMVIXL* codegen);
    133   void FixTable(CodeGeneratorARMVIXL* codegen);
    134 
    135  private:
    136   HPackedSwitch* const switch_instr_;
    137   vixl::aarch32::Label table_start_;
    138   ArenaVector<std::unique_ptr<VIXLInt32Literal>> bb_addresses_;
    139 
    140   DISALLOW_COPY_AND_ASSIGN(JumpTableARMVIXL);
    141 };
    142 
    143 class InvokeRuntimeCallingConventionARMVIXL
    144     : public CallingConvention<vixl::aarch32::Register, vixl::aarch32::SRegister> {
    145  public:
    146   InvokeRuntimeCallingConventionARMVIXL()
    147       : CallingConvention(kRuntimeParameterCoreRegistersVIXL,
    148                           kRuntimeParameterCoreRegistersLengthVIXL,
    149                           kRuntimeParameterFpuRegistersVIXL,
    150                           kRuntimeParameterFpuRegistersLengthVIXL,
    151                           kArmPointerSize) {}
    152 
    153  private:
    154   DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConventionARMVIXL);
    155 };
    156 
    157 class InvokeDexCallingConventionARMVIXL
    158     : public CallingConvention<vixl::aarch32::Register, vixl::aarch32::SRegister> {
    159  public:
    160   InvokeDexCallingConventionARMVIXL()
    161       : CallingConvention(kParameterCoreRegistersVIXL,
    162                           kParameterCoreRegistersLengthVIXL,
    163                           kParameterFpuRegistersVIXL,
    164                           kParameterFpuRegistersLengthVIXL,
    165                           kArmPointerSize) {}
    166 
    167  private:
    168   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionARMVIXL);
    169 };
    170 
    171 class InvokeDexCallingConventionVisitorARMVIXL : public InvokeDexCallingConventionVisitor {
    172  public:
    173   InvokeDexCallingConventionVisitorARMVIXL() {}
    174   virtual ~InvokeDexCallingConventionVisitorARMVIXL() {}
    175 
    176   Location GetNextLocation(DataType::Type type) OVERRIDE;
    177   Location GetReturnLocation(DataType::Type type) const OVERRIDE;
    178   Location GetMethodLocation() const OVERRIDE;
    179 
    180  private:
    181   InvokeDexCallingConventionARMVIXL calling_convention;
    182   uint32_t double_index_ = 0;
    183 
    184   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitorARMVIXL);
    185 };
    186 
    187 class FieldAccessCallingConventionARMVIXL : public FieldAccessCallingConvention {
    188  public:
    189   FieldAccessCallingConventionARMVIXL() {}
    190 
    191   Location GetObjectLocation() const OVERRIDE {
    192     return helpers::LocationFrom(vixl::aarch32::r1);
    193   }
    194   Location GetFieldIndexLocation() const OVERRIDE {
    195     return helpers::LocationFrom(vixl::aarch32::r0);
    196   }
    197   Location GetReturnLocation(DataType::Type type) const OVERRIDE {
    198     return DataType::Is64BitType(type)
    199         ? helpers::LocationFrom(vixl::aarch32::r0, vixl::aarch32::r1)
    200         : helpers::LocationFrom(vixl::aarch32::r0);
    201   }
    202   Location GetSetValueLocation(DataType::Type type, bool is_instance) const OVERRIDE {
    203     return DataType::Is64BitType(type)
    204         ? helpers::LocationFrom(vixl::aarch32::r2, vixl::aarch32::r3)
    205         : (is_instance
    206             ? helpers::LocationFrom(vixl::aarch32::r2)
    207             : helpers::LocationFrom(vixl::aarch32::r1));
    208   }
    209   Location GetFpuLocation(DataType::Type type) const OVERRIDE {
    210     return DataType::Is64BitType(type)
    211         ? helpers::LocationFrom(vixl::aarch32::s0, vixl::aarch32::s1)
    212         : helpers::LocationFrom(vixl::aarch32::s0);
    213   }
    214 
    215  private:
    216   DISALLOW_COPY_AND_ASSIGN(FieldAccessCallingConventionARMVIXL);
    217 };
    218 
    219 class SlowPathCodeARMVIXL : public SlowPathCode {
    220  public:
    221   explicit SlowPathCodeARMVIXL(HInstruction* instruction)
    222       : SlowPathCode(instruction), entry_label_(), exit_label_() {}
    223 
    224   vixl::aarch32::Label* GetEntryLabel() { return &entry_label_; }
    225   vixl::aarch32::Label* GetExitLabel() { return &exit_label_; }
    226 
    227   void SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) OVERRIDE;
    228   void RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) OVERRIDE;
    229 
    230  private:
    231   vixl::aarch32::Label entry_label_;
    232   vixl::aarch32::Label exit_label_;
    233 
    234   DISALLOW_COPY_AND_ASSIGN(SlowPathCodeARMVIXL);
    235 };
    236 
    237 class ParallelMoveResolverARMVIXL : public ParallelMoveResolverWithSwap {
    238  public:
    239   ParallelMoveResolverARMVIXL(ArenaAllocator* allocator, CodeGeneratorARMVIXL* codegen)
    240       : ParallelMoveResolverWithSwap(allocator), codegen_(codegen) {}
    241 
    242   void EmitMove(size_t index) OVERRIDE;
    243   void EmitSwap(size_t index) OVERRIDE;
    244   void SpillScratch(int reg) OVERRIDE;
    245   void RestoreScratch(int reg) OVERRIDE;
    246 
    247   ArmVIXLAssembler* GetAssembler() const;
    248 
    249  private:
    250   void Exchange(vixl32::Register reg, int mem);
    251   void Exchange(int mem1, int mem2);
    252 
    253   CodeGeneratorARMVIXL* const codegen_;
    254 
    255   DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverARMVIXL);
    256 };
    257 
    258 class LocationsBuilderARMVIXL : public HGraphVisitor {
    259  public:
    260   LocationsBuilderARMVIXL(HGraph* graph, CodeGeneratorARMVIXL* codegen)
    261       : HGraphVisitor(graph), codegen_(codegen) {}
    262 
    263 #define DECLARE_VISIT_INSTRUCTION(name, super)     \
    264   void Visit##name(H##name* instr) OVERRIDE;
    265 
    266   FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
    267   FOR_EACH_CONCRETE_INSTRUCTION_ARM(DECLARE_VISIT_INSTRUCTION)
    268   FOR_EACH_CONCRETE_INSTRUCTION_SHARED(DECLARE_VISIT_INSTRUCTION)
    269 
    270 #undef DECLARE_VISIT_INSTRUCTION
    271 
    272   void VisitInstruction(HInstruction* instruction) OVERRIDE {
    273     LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
    274                << " (id " << instruction->GetId() << ")";
    275   }
    276 
    277  private:
    278   void HandleInvoke(HInvoke* invoke);
    279   void HandleBitwiseOperation(HBinaryOperation* operation, Opcode opcode);
    280   void HandleCondition(HCondition* condition);
    281   void HandleIntegerRotate(LocationSummary* locations);
    282   void HandleLongRotate(LocationSummary* locations);
    283   void HandleShift(HBinaryOperation* operation);
    284   void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
    285   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
    286 
    287   Location ArithmeticZeroOrFpuRegister(HInstruction* input);
    288   Location ArmEncodableConstantOrRegister(HInstruction* constant, Opcode opcode);
    289   bool CanEncodeConstantAsImmediate(HConstant* input_cst, Opcode opcode);
    290 
    291   CodeGeneratorARMVIXL* const codegen_;
    292   InvokeDexCallingConventionVisitorARMVIXL parameter_visitor_;
    293 
    294   DISALLOW_COPY_AND_ASSIGN(LocationsBuilderARMVIXL);
    295 };
    296 
    297 class InstructionCodeGeneratorARMVIXL : public InstructionCodeGenerator {
    298  public:
    299   InstructionCodeGeneratorARMVIXL(HGraph* graph, CodeGeneratorARMVIXL* codegen);
    300 
    301 #define DECLARE_VISIT_INSTRUCTION(name, super)     \
    302   void Visit##name(H##name* instr) OVERRIDE;
    303 
    304   FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
    305   FOR_EACH_CONCRETE_INSTRUCTION_ARM(DECLARE_VISIT_INSTRUCTION)
    306   FOR_EACH_CONCRETE_INSTRUCTION_SHARED(DECLARE_VISIT_INSTRUCTION)
    307 
    308 #undef DECLARE_VISIT_INSTRUCTION
    309 
    310   void VisitInstruction(HInstruction* instruction) OVERRIDE {
    311     LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
    312                << " (id " << instruction->GetId() << ")";
    313   }
    314 
    315   ArmVIXLAssembler* GetAssembler() const { return assembler_; }
    316   ArmVIXLMacroAssembler* GetVIXLAssembler() { return GetAssembler()->GetVIXLAssembler(); }
    317 
    318  private:
    319   // Generate code for the given suspend check. If not null, `successor`
    320   // is the block to branch to if the suspend check is not needed, and after
    321   // the suspend call.
    322   void GenerateSuspendCheck(HSuspendCheck* instruction, HBasicBlock* successor);
    323   void GenerateClassInitializationCheck(LoadClassSlowPathARMVIXL* slow_path,
    324                                         vixl32::Register class_reg);
    325   void GenerateAndConst(vixl::aarch32::Register out, vixl::aarch32::Register first, uint32_t value);
    326   void GenerateOrrConst(vixl::aarch32::Register out, vixl::aarch32::Register first, uint32_t value);
    327   void GenerateEorConst(vixl::aarch32::Register out, vixl::aarch32::Register first, uint32_t value);
    328   void GenerateAddLongConst(Location out, Location first, uint64_t value);
    329   void HandleBitwiseOperation(HBinaryOperation* operation);
    330   void HandleCondition(HCondition* condition);
    331   void HandleIntegerRotate(HRor* ror);
    332   void HandleLongRotate(HRor* ror);
    333   void HandleShift(HBinaryOperation* operation);
    334 
    335   void GenerateWideAtomicStore(vixl::aarch32::Register addr,
    336                                uint32_t offset,
    337                                vixl::aarch32::Register value_lo,
    338                                vixl::aarch32::Register value_hi,
    339                                vixl::aarch32::Register temp1,
    340                                vixl::aarch32::Register temp2,
    341                                HInstruction* instruction);
    342   void GenerateWideAtomicLoad(vixl::aarch32::Register addr,
    343                               uint32_t offset,
    344                               vixl::aarch32::Register out_lo,
    345                               vixl::aarch32::Register out_hi);
    346 
    347   void HandleFieldSet(HInstruction* instruction,
    348                       const FieldInfo& field_info,
    349                       bool value_can_be_null);
    350   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
    351 
    352   // Generate a heap reference load using one register `out`:
    353   //
    354   //   out <- *(out + offset)
    355   //
    356   // while honoring heap poisoning and/or read barriers (if any).
    357   //
    358   // Location `maybe_temp` is used when generating a read barrier and
    359   // shall be a register in that case; it may be an invalid location
    360   // otherwise.
    361   void GenerateReferenceLoadOneRegister(HInstruction* instruction,
    362                                         Location out,
    363                                         uint32_t offset,
    364                                         Location maybe_temp,
    365                                         ReadBarrierOption read_barrier_option);
    366   // Generate a heap reference load using two different registers
    367   // `out` and `obj`:
    368   //
    369   //   out <- *(obj + offset)
    370   //
    371   // while honoring heap poisoning and/or read barriers (if any).
    372   //
    373   // Location `maybe_temp` is used when generating a Baker's (fast
    374   // path) read barrier and shall be a register in that case; it may
    375   // be an invalid location otherwise.
    376   void GenerateReferenceLoadTwoRegisters(HInstruction* instruction,
    377                                          Location out,
    378                                          Location obj,
    379                                          uint32_t offset,
    380                                          Location maybe_temp,
    381                                          ReadBarrierOption read_barrier_option);
    382   // Generate a GC root reference load:
    383   //
    384   //   root <- *(obj + offset)
    385   //
    386   // while honoring read barriers based on read_barrier_option.
    387   void GenerateGcRootFieldLoad(HInstruction* instruction,
    388                                Location root,
    389                                vixl::aarch32::Register obj,
    390                                uint32_t offset,
    391                                ReadBarrierOption read_barrier_option);
    392   void GenerateTestAndBranch(HInstruction* instruction,
    393                              size_t condition_input_index,
    394                              vixl::aarch32::Label* true_target,
    395                              vixl::aarch32::Label* false_target,
    396                              bool far_target = true);
    397   void GenerateCompareTestAndBranch(HCondition* condition,
    398                                     vixl::aarch32::Label* true_target,
    399                                     vixl::aarch32::Label* false_target,
    400                                     bool is_far_target = true);
    401   void DivRemOneOrMinusOne(HBinaryOperation* instruction);
    402   void DivRemByPowerOfTwo(HBinaryOperation* instruction);
    403   void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction);
    404   void GenerateDivRemConstantIntegral(HBinaryOperation* instruction);
    405   void HandleGoto(HInstruction* got, HBasicBlock* successor);
    406 
    407   vixl::aarch32::MemOperand VecAddress(
    408       HVecMemoryOperation* instruction,
    409       // This function may acquire a scratch register.
    410       vixl::aarch32::UseScratchRegisterScope* temps_scope,
    411       /*out*/ vixl32::Register* scratch);
    412   vixl::aarch32::AlignedMemOperand VecAddressUnaligned(
    413       HVecMemoryOperation* instruction,
    414       // This function may acquire a scratch register.
    415       vixl::aarch32::UseScratchRegisterScope* temps_scope,
    416       /*out*/ vixl32::Register* scratch);
    417 
    418   ArmVIXLAssembler* const assembler_;
    419   CodeGeneratorARMVIXL* const codegen_;
    420 
    421   DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorARMVIXL);
    422 };
    423 
    424 class CodeGeneratorARMVIXL : public CodeGenerator {
    425  public:
    426   CodeGeneratorARMVIXL(HGraph* graph,
    427                        const ArmInstructionSetFeatures& isa_features,
    428                        const CompilerOptions& compiler_options,
    429                        OptimizingCompilerStats* stats = nullptr);
    430   virtual ~CodeGeneratorARMVIXL() {}
    431 
    432   void GenerateFrameEntry() OVERRIDE;
    433   void GenerateFrameExit() OVERRIDE;
    434   void Bind(HBasicBlock* block) OVERRIDE;
    435   void MoveConstant(Location destination, int32_t value) OVERRIDE;
    436   void MoveLocation(Location dst, Location src, DataType::Type dst_type) OVERRIDE;
    437   void AddLocationAsTemp(Location location, LocationSummary* locations) OVERRIDE;
    438 
    439   size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
    440   size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
    441   size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
    442   size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
    443 
    444   size_t GetWordSize() const OVERRIDE {
    445     return static_cast<size_t>(kArmPointerSize);
    446   }
    447 
    448   size_t GetFloatingPointSpillSlotSize() const OVERRIDE { return vixl::aarch32::kRegSizeInBytes; }
    449 
    450   HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; }
    451 
    452   HGraphVisitor* GetInstructionVisitor() OVERRIDE { return &instruction_visitor_; }
    453 
    454   ArmVIXLAssembler* GetAssembler() OVERRIDE { return &assembler_; }
    455 
    456   const ArmVIXLAssembler& GetAssembler() const OVERRIDE { return assembler_; }
    457 
    458   ArmVIXLMacroAssembler* GetVIXLAssembler() { return GetAssembler()->GetVIXLAssembler(); }
    459 
    460   uintptr_t GetAddressOf(HBasicBlock* block) OVERRIDE {
    461     vixl::aarch32::Label* block_entry_label = GetLabelOf(block);
    462     DCHECK(block_entry_label->IsBound());
    463     return block_entry_label->GetLocation();
    464   }
    465 
    466   void FixJumpTables();
    467   void SetupBlockedRegisters() const OVERRIDE;
    468 
    469   void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
    470   void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
    471 
    472   ParallelMoveResolver* GetMoveResolver() OVERRIDE { return &move_resolver_; }
    473   InstructionSet GetInstructionSet() const OVERRIDE { return InstructionSet::kThumb2; }
    474   // Helper method to move a 32-bit value between two locations.
    475   void Move32(Location destination, Location source);
    476 
    477   void LoadFromShiftedRegOffset(DataType::Type type,
    478                                 Location out_loc,
    479                                 vixl::aarch32::Register base,
    480                                 vixl::aarch32::Register reg_index,
    481                                 vixl::aarch32::Condition cond = vixl::aarch32::al);
    482   void StoreToShiftedRegOffset(DataType::Type type,
    483                                Location out_loc,
    484                                vixl::aarch32::Register base,
    485                                vixl::aarch32::Register reg_index,
    486                                vixl::aarch32::Condition cond = vixl::aarch32::al);
    487 
    488   // Generate code to invoke a runtime entry point.
    489   void InvokeRuntime(QuickEntrypointEnum entrypoint,
    490                      HInstruction* instruction,
    491                      uint32_t dex_pc,
    492                      SlowPathCode* slow_path = nullptr) OVERRIDE;
    493 
    494   // Generate code to invoke a runtime entry point, but do not record
    495   // PC-related information in a stack map.
    496   void InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
    497                                            HInstruction* instruction,
    498                                            SlowPathCode* slow_path);
    499 
    500   // Emit a write barrier.
    501   void MarkGCCard(vixl::aarch32::Register temp,
    502                   vixl::aarch32::Register card,
    503                   vixl::aarch32::Register object,
    504                   vixl::aarch32::Register value,
    505                   bool can_be_null);
    506 
    507   void GenerateMemoryBarrier(MemBarrierKind kind);
    508 
    509   vixl::aarch32::Label* GetLabelOf(HBasicBlock* block) {
    510     block = FirstNonEmptyBlock(block);
    511     return &(block_labels_[block->GetBlockId()]);
    512   }
    513 
    514   vixl32::Label* GetFinalLabel(HInstruction* instruction, vixl32::Label* final_label);
    515 
    516   void Initialize() OVERRIDE {
    517     block_labels_.resize(GetGraph()->GetBlocks().size());
    518   }
    519 
    520   void Finalize(CodeAllocator* allocator) OVERRIDE;
    521 
    522   const ArmInstructionSetFeatures& GetInstructionSetFeatures() const { return isa_features_; }
    523 
    524   bool NeedsTwoRegisters(DataType::Type type) const OVERRIDE {
    525     return type == DataType::Type::kFloat64 || type == DataType::Type::kInt64;
    526   }
    527 
    528   void ComputeSpillMask() OVERRIDE;
    529 
    530   vixl::aarch32::Label* GetFrameEntryLabel() { return &frame_entry_label_; }
    531 
    532   // Check if the desired_string_load_kind is supported. If it is, return it,
    533   // otherwise return a fall-back kind that should be used instead.
    534   HLoadString::LoadKind GetSupportedLoadStringKind(
    535       HLoadString::LoadKind desired_string_load_kind) OVERRIDE;
    536 
    537   // Check if the desired_class_load_kind is supported. If it is, return it,
    538   // otherwise return a fall-back kind that should be used instead.
    539   HLoadClass::LoadKind GetSupportedLoadClassKind(
    540       HLoadClass::LoadKind desired_class_load_kind) OVERRIDE;
    541 
    542   // Check if the desired_dispatch_info is supported. If it is, return it,
    543   // otherwise return a fall-back info that should be used instead.
    544   HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
    545       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
    546       HInvokeStaticOrDirect* invoke) OVERRIDE;
    547 
    548   void GenerateStaticOrDirectCall(
    549       HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
    550   void GenerateVirtualCall(
    551       HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
    552 
    553   void MoveFromReturnRegister(Location trg, DataType::Type type) OVERRIDE;
    554 
    555   // The PcRelativePatchInfo is used for PC-relative addressing of methods/strings/types,
    556   // whether through .data.bimg.rel.ro, .bss, or directly in the boot image.
    557   //
    558   // The PC-relative address is loaded with three instructions,
    559   // MOVW+MOVT to load the offset to base_reg and then ADD base_reg, PC. The offset
    560   // is calculated from the ADD's effective PC, i.e. PC+4 on Thumb2. Though we
    561   // currently emit these 3 instructions together, instruction scheduling could
    562   // split this sequence apart, so we keep separate labels for each of them.
    563   struct PcRelativePatchInfo {
    564     PcRelativePatchInfo(const DexFile* dex_file, uint32_t off_or_idx)
    565         : target_dex_file(dex_file), offset_or_index(off_or_idx) { }
    566     PcRelativePatchInfo(PcRelativePatchInfo&& other) = default;
    567 
    568     // Target dex file or null for .data.bmig.rel.ro patches.
    569     const DexFile* target_dex_file;
    570     // Either the boot image offset (to write to .data.bmig.rel.ro) or string/type/method index.
    571     uint32_t offset_or_index;
    572     vixl::aarch32::Label movw_label;
    573     vixl::aarch32::Label movt_label;
    574     vixl::aarch32::Label add_pc_label;
    575   };
    576 
    577   PcRelativePatchInfo* NewBootImageMethodPatch(MethodReference target_method);
    578   PcRelativePatchInfo* NewMethodBssEntryPatch(MethodReference target_method);
    579   PcRelativePatchInfo* NewBootImageTypePatch(const DexFile& dex_file, dex::TypeIndex type_index);
    580   PcRelativePatchInfo* NewTypeBssEntryPatch(const DexFile& dex_file, dex::TypeIndex type_index);
    581   PcRelativePatchInfo* NewBootImageStringPatch(const DexFile& dex_file,
    582                                                dex::StringIndex string_index);
    583   PcRelativePatchInfo* NewStringBssEntryPatch(const DexFile& dex_file,
    584                                               dex::StringIndex string_index);
    585 
    586   // Add a new baker read barrier patch and return the label to be bound
    587   // before the BNE instruction.
    588   vixl::aarch32::Label* NewBakerReadBarrierPatch(uint32_t custom_data);
    589 
    590   VIXLUInt32Literal* DeduplicateBootImageAddressLiteral(uint32_t address);
    591   VIXLUInt32Literal* DeduplicateJitStringLiteral(const DexFile& dex_file,
    592                                                  dex::StringIndex string_index,
    593                                                  Handle<mirror::String> handle);
    594   VIXLUInt32Literal* DeduplicateJitClassLiteral(const DexFile& dex_file,
    595                                                 dex::TypeIndex type_index,
    596                                                 Handle<mirror::Class> handle);
    597 
    598   void EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) OVERRIDE;
    599 
    600   void EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) OVERRIDE;
    601 
    602   // Maybe add the reserved entrypoint register as a temporary for field load. This temp
    603   // is added only for AOT compilation if link-time generated thunks for fields are enabled.
    604   void MaybeAddBakerCcEntrypointTempForFields(LocationSummary* locations);
    605 
    606   // Fast path implementation of ReadBarrier::Barrier for a heap
    607   // reference field load when Baker's read barriers are used.
    608   void GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
    609                                              Location ref,
    610                                              vixl::aarch32::Register obj,
    611                                              uint32_t offset,
    612                                              Location temp,
    613                                              bool needs_null_check);
    614   // Fast path implementation of ReadBarrier::Barrier for a heap
    615   // reference array load when Baker's read barriers are used.
    616   void GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
    617                                              Location ref,
    618                                              vixl::aarch32::Register obj,
    619                                              uint32_t data_offset,
    620                                              Location index,
    621                                              Location temp,
    622                                              bool needs_null_check);
    623   // Factored implementation, used by GenerateFieldLoadWithBakerReadBarrier,
    624   // GenerateArrayLoadWithBakerReadBarrier and some intrinsics.
    625   //
    626   // Load the object reference located at the address
    627   // `obj + offset + (index << scale_factor)`, held by object `obj`, into
    628   // `ref`, and mark it if needed.
    629   void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
    630                                                  Location ref,
    631                                                  vixl::aarch32::Register obj,
    632                                                  uint32_t offset,
    633                                                  Location index,
    634                                                  ScaleFactor scale_factor,
    635                                                  Location temp,
    636                                                  bool needs_null_check);
    637 
    638   // Generate code checking whether the the reference field at the
    639   // address `obj + field_offset`, held by object `obj`, needs to be
    640   // marked, and if so, marking it and updating the field within `obj`
    641   // with the marked value.
    642   //
    643   // This routine is used for the implementation of the
    644   // UnsafeCASObject intrinsic with Baker read barriers.
    645   //
    646   // This method has a structure similar to
    647   // GenerateReferenceLoadWithBakerReadBarrier, but note that argument
    648   // `ref` is only as a temporary here, and thus its value should not
    649   // be used afterwards.
    650   void UpdateReferenceFieldWithBakerReadBarrier(HInstruction* instruction,
    651                                                 Location ref,
    652                                                 vixl::aarch32::Register obj,
    653                                                 Location field_offset,
    654                                                 Location temp,
    655                                                 bool needs_null_check,
    656                                                 vixl::aarch32::Register temp2);
    657 
    658   // Generate a heap reference load (with no read barrier).
    659   void GenerateRawReferenceLoad(HInstruction* instruction,
    660                                 Location ref,
    661                                 vixl::aarch32::Register obj,
    662                                 uint32_t offset,
    663                                 Location index,
    664                                 ScaleFactor scale_factor,
    665                                 bool needs_null_check);
    666 
    667   // Emit code checking the status of the Marking Register, and
    668   // aborting the program if MR does not match the value stored in the
    669   // art::Thread object. Code is only emitted in debug mode and if
    670   // CompilerOptions::EmitRunTimeChecksInDebugMode returns true.
    671   //
    672   // Argument `code` is used to identify the different occurrences of
    673   // MaybeGenerateMarkingRegisterCheck in the code generator, and is
    674   // used together with kMarkingRegisterCheckBreakCodeBaseCode to
    675   // create the value passed to the BKPT instruction. Note that unlike
    676   // in the ARM64 code generator, where `__LINE__` is passed as `code`
    677   // argument to
    678   // CodeGeneratorARM64::MaybeGenerateMarkingRegisterCheck, we cannot
    679   // realistically do that here, as Encoding T1 for the BKPT
    680   // instruction only accepts 8-bit immediate values.
    681   //
    682   // If `temp_loc` is a valid location, it is expected to be a
    683   // register and will be used as a temporary to generate code;
    684   // otherwise, a temporary will be fetched from the core register
    685   // scratch pool.
    686   virtual void MaybeGenerateMarkingRegisterCheck(int code,
    687                                                  Location temp_loc = Location::NoLocation());
    688 
    689   // Generate a read barrier for a heap reference within `instruction`
    690   // using a slow path.
    691   //
    692   // A read barrier for an object reference read from the heap is
    693   // implemented as a call to the artReadBarrierSlow runtime entry
    694   // point, which is passed the values in locations `ref`, `obj`, and
    695   // `offset`:
    696   //
    697   //   mirror::Object* artReadBarrierSlow(mirror::Object* ref,
    698   //                                      mirror::Object* obj,
    699   //                                      uint32_t offset);
    700   //
    701   // The `out` location contains the value returned by
    702   // artReadBarrierSlow.
    703   //
    704   // When `index` is provided (i.e. for array accesses), the offset
    705   // value passed to artReadBarrierSlow is adjusted to take `index`
    706   // into account.
    707   void GenerateReadBarrierSlow(HInstruction* instruction,
    708                                Location out,
    709                                Location ref,
    710                                Location obj,
    711                                uint32_t offset,
    712                                Location index = Location::NoLocation());
    713 
    714   // If read barriers are enabled, generate a read barrier for a heap
    715   // reference using a slow path. If heap poisoning is enabled, also
    716   // unpoison the reference in `out`.
    717   void MaybeGenerateReadBarrierSlow(HInstruction* instruction,
    718                                     Location out,
    719                                     Location ref,
    720                                     Location obj,
    721                                     uint32_t offset,
    722                                     Location index = Location::NoLocation());
    723 
    724   // Generate a read barrier for a GC root within `instruction` using
    725   // a slow path.
    726   //
    727   // A read barrier for an object reference GC root is implemented as
    728   // a call to the artReadBarrierForRootSlow runtime entry point,
    729   // which is passed the value in location `root`:
    730   //
    731   //   mirror::Object* artReadBarrierForRootSlow(GcRoot<mirror::Object>* root);
    732   //
    733   // The `out` location contains the value returned by
    734   // artReadBarrierForRootSlow.
    735   void GenerateReadBarrierForRootSlow(HInstruction* instruction, Location out, Location root);
    736 
    737   void GenerateNop() OVERRIDE;
    738 
    739   void GenerateImplicitNullCheck(HNullCheck* instruction) OVERRIDE;
    740   void GenerateExplicitNullCheck(HNullCheck* instruction) OVERRIDE;
    741 
    742   JumpTableARMVIXL* CreateJumpTable(HPackedSwitch* switch_instr) {
    743     jump_tables_.emplace_back(new (GetGraph()->GetAllocator()) JumpTableARMVIXL(switch_instr));
    744     return jump_tables_.back().get();
    745   }
    746   void EmitJumpTables();
    747 
    748   void EmitMovwMovtPlaceholder(CodeGeneratorARMVIXL::PcRelativePatchInfo* labels,
    749                                vixl::aarch32::Register out);
    750 
    751   // `temp` is an extra temporary register that is used for some conditions;
    752   // callers may not specify it, in which case the method will use a scratch
    753   // register instead.
    754   void GenerateConditionWithZero(IfCondition condition,
    755                                  vixl::aarch32::Register out,
    756                                  vixl::aarch32::Register in,
    757                                  vixl::aarch32::Register temp = vixl32::Register());
    758 
    759  private:
    760   vixl::aarch32::Register GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
    761                                                                 vixl::aarch32::Register temp);
    762 
    763   using Uint32ToLiteralMap = ArenaSafeMap<uint32_t, VIXLUInt32Literal*>;
    764   using StringToLiteralMap = ArenaSafeMap<StringReference,
    765                                           VIXLUInt32Literal*,
    766                                           StringReferenceValueComparator>;
    767   using TypeToLiteralMap = ArenaSafeMap<TypeReference,
    768                                         VIXLUInt32Literal*,
    769                                         TypeReferenceValueComparator>;
    770 
    771   struct BakerReadBarrierPatchInfo {
    772     explicit BakerReadBarrierPatchInfo(uint32_t data) : label(), custom_data(data) { }
    773 
    774     vixl::aarch32::Label label;
    775     uint32_t custom_data;
    776   };
    777 
    778   VIXLUInt32Literal* DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map);
    779   PcRelativePatchInfo* NewPcRelativePatch(const DexFile* dex_file,
    780                                           uint32_t offset_or_index,
    781                                           ArenaDeque<PcRelativePatchInfo>* patches);
    782   template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
    783   static void EmitPcRelativeLinkerPatches(const ArenaDeque<PcRelativePatchInfo>& infos,
    784                                           ArenaVector<linker::LinkerPatch>* linker_patches);
    785 
    786   // Labels for each block that will be compiled.
    787   // We use a deque so that the `vixl::aarch32::Label` objects do not move in memory.
    788   ArenaDeque<vixl::aarch32::Label> block_labels_;  // Indexed by block id.
    789   vixl::aarch32::Label frame_entry_label_;
    790 
    791   ArenaVector<std::unique_ptr<JumpTableARMVIXL>> jump_tables_;
    792   LocationsBuilderARMVIXL location_builder_;
    793   InstructionCodeGeneratorARMVIXL instruction_visitor_;
    794   ParallelMoveResolverARMVIXL move_resolver_;
    795 
    796   ArmVIXLAssembler assembler_;
    797   const ArmInstructionSetFeatures& isa_features_;
    798 
    799   // Deduplication map for 32-bit literals, used for non-patchable boot image addresses.
    800   Uint32ToLiteralMap uint32_literals_;
    801   // PC-relative method patch info for kBootImageLinkTimePcRelative.
    802   ArenaDeque<PcRelativePatchInfo> boot_image_method_patches_;
    803   // PC-relative method patch info for kBssEntry.
    804   ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_;
    805   // PC-relative type patch info for kBootImageLinkTimePcRelative.
    806   ArenaDeque<PcRelativePatchInfo> boot_image_type_patches_;
    807   // PC-relative type patch info for kBssEntry.
    808   ArenaDeque<PcRelativePatchInfo> type_bss_entry_patches_;
    809   // PC-relative String patch info; type depends on configuration (intern table or boot image PIC).
    810   ArenaDeque<PcRelativePatchInfo> boot_image_string_patches_;
    811   // PC-relative String patch info for kBssEntry.
    812   ArenaDeque<PcRelativePatchInfo> string_bss_entry_patches_;
    813   // Baker read barrier patch info.
    814   ArenaDeque<BakerReadBarrierPatchInfo> baker_read_barrier_patches_;
    815 
    816   // Patches for string literals in JIT compiled code.
    817   StringToLiteralMap jit_string_patches_;
    818   // Patches for class literals in JIT compiled code.
    819   TypeToLiteralMap jit_class_patches_;
    820 
    821   DISALLOW_COPY_AND_ASSIGN(CodeGeneratorARMVIXL);
    822 };
    823 
    824 }  // namespace arm
    825 }  // namespace art
    826 
    827 #endif  // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_ARM_VIXL_H_
    828