Home | History | Annotate | Download | only in optimizing
      1 /*
      2  * Copyright (C) 2015 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_MIPS_H_
     18 #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_MIPS_H_
     19 
     20 #include "code_generator.h"
     21 #include "dex/compiler_enums.h"
     22 #include "driver/compiler_options.h"
     23 #include "nodes.h"
     24 #include "parallel_move_resolver.h"
     25 #include "utils/mips/assembler_mips.h"
     26 
     27 namespace art {
     28 namespace mips {
     29 
     30 // InvokeDexCallingConvention registers
     31 
     32 static constexpr Register kParameterCoreRegisters[] =
     33     { A1, A2, A3 };
     34 static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
     35 
     36 static constexpr FRegister kParameterFpuRegisters[] =
     37     { F12, F14 };
     38 static constexpr size_t kParameterFpuRegistersLength = arraysize(kParameterFpuRegisters);
     39 
     40 
     41 // InvokeRuntimeCallingConvention registers
     42 
     43 static constexpr Register kRuntimeParameterCoreRegisters[] =
     44     { A0, A1, A2, A3 };
     45 static constexpr size_t kRuntimeParameterCoreRegistersLength =
     46     arraysize(kRuntimeParameterCoreRegisters);
     47 
     48 static constexpr FRegister kRuntimeParameterFpuRegisters[] =
     49     { F12, F14};
     50 static constexpr size_t kRuntimeParameterFpuRegistersLength =
     51     arraysize(kRuntimeParameterFpuRegisters);
     52 
     53 
     54 static constexpr Register kCoreCalleeSaves[] =
     55     { S0, S1, S2, S3, S4, S5, S6, S7, FP, RA };
     56 static constexpr FRegister kFpuCalleeSaves[] =
     57     { F20, F22, F24, F26, F28, F30 };
     58 
     59 
     60 class CodeGeneratorMIPS;
     61 
     62 class InvokeDexCallingConvention : public CallingConvention<Register, FRegister> {
     63  public:
     64   InvokeDexCallingConvention()
     65       : CallingConvention(kParameterCoreRegisters,
     66                           kParameterCoreRegistersLength,
     67                           kParameterFpuRegisters,
     68                           kParameterFpuRegistersLength,
     69                           kMipsPointerSize) {}
     70 
     71  private:
     72   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention);
     73 };
     74 
     75 class InvokeDexCallingConventionVisitorMIPS : public InvokeDexCallingConventionVisitor {
     76  public:
     77   InvokeDexCallingConventionVisitorMIPS() {}
     78   virtual ~InvokeDexCallingConventionVisitorMIPS() {}
     79 
     80   Location GetNextLocation(Primitive::Type type) OVERRIDE;
     81   Location GetReturnLocation(Primitive::Type type) const OVERRIDE;
     82   Location GetMethodLocation() const OVERRIDE;
     83 
     84  private:
     85   InvokeDexCallingConvention calling_convention;
     86 
     87   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitorMIPS);
     88 };
     89 
     90 class InvokeRuntimeCallingConvention : public CallingConvention<Register, FRegister> {
     91  public:
     92   InvokeRuntimeCallingConvention()
     93       : CallingConvention(kRuntimeParameterCoreRegisters,
     94                           kRuntimeParameterCoreRegistersLength,
     95                           kRuntimeParameterFpuRegisters,
     96                           kRuntimeParameterFpuRegistersLength,
     97                           kMipsPointerSize) {}
     98 
     99   Location GetReturnLocation(Primitive::Type return_type);
    100 
    101  private:
    102   DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
    103 };
    104 
    105 class FieldAccessCallingConventionMIPS : public FieldAccessCallingConvention {
    106  public:
    107   FieldAccessCallingConventionMIPS() {}
    108 
    109   Location GetObjectLocation() const OVERRIDE {
    110     return Location::RegisterLocation(A1);
    111   }
    112   Location GetFieldIndexLocation() const OVERRIDE {
    113     return Location::RegisterLocation(A0);
    114   }
    115   Location GetReturnLocation(Primitive::Type type) const OVERRIDE {
    116     return Primitive::Is64BitType(type)
    117         ? Location::RegisterPairLocation(V0, V1)
    118         : Location::RegisterLocation(V0);
    119   }
    120   Location GetSetValueLocation(Primitive::Type type, bool is_instance) const OVERRIDE {
    121     return Primitive::Is64BitType(type)
    122         ? Location::RegisterPairLocation(A2, A3)
    123         : (is_instance ? Location::RegisterLocation(A2) : Location::RegisterLocation(A1));
    124   }
    125   Location GetFpuLocation(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
    126     return Location::FpuRegisterLocation(F0);
    127   }
    128 
    129  private:
    130   DISALLOW_COPY_AND_ASSIGN(FieldAccessCallingConventionMIPS);
    131 };
    132 
    133 class ParallelMoveResolverMIPS : public ParallelMoveResolverWithSwap {
    134  public:
    135   ParallelMoveResolverMIPS(ArenaAllocator* allocator, CodeGeneratorMIPS* codegen)
    136       : ParallelMoveResolverWithSwap(allocator), codegen_(codegen) {}
    137 
    138   void EmitMove(size_t index) OVERRIDE;
    139   void EmitSwap(size_t index) OVERRIDE;
    140   void SpillScratch(int reg) OVERRIDE;
    141   void RestoreScratch(int reg) OVERRIDE;
    142 
    143   void Exchange(int index1, int index2, bool double_slot);
    144 
    145   MipsAssembler* GetAssembler() const;
    146 
    147  private:
    148   CodeGeneratorMIPS* const codegen_;
    149 
    150   DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverMIPS);
    151 };
    152 
    153 class SlowPathCodeMIPS : public SlowPathCode {
    154  public:
    155   explicit SlowPathCodeMIPS(HInstruction* instruction)
    156       : SlowPathCode(instruction), entry_label_(), exit_label_() {}
    157 
    158   MipsLabel* GetEntryLabel() { return &entry_label_; }
    159   MipsLabel* GetExitLabel() { return &exit_label_; }
    160 
    161  private:
    162   MipsLabel entry_label_;
    163   MipsLabel exit_label_;
    164 
    165   DISALLOW_COPY_AND_ASSIGN(SlowPathCodeMIPS);
    166 };
    167 
    168 class LocationsBuilderMIPS : public HGraphVisitor {
    169  public:
    170   LocationsBuilderMIPS(HGraph* graph, CodeGeneratorMIPS* codegen)
    171       : HGraphVisitor(graph), codegen_(codegen) {}
    172 
    173 #define DECLARE_VISIT_INSTRUCTION(name, super)     \
    174   void Visit##name(H##name* instr) OVERRIDE;
    175 
    176   FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
    177   FOR_EACH_CONCRETE_INSTRUCTION_MIPS(DECLARE_VISIT_INSTRUCTION)
    178 
    179 #undef DECLARE_VISIT_INSTRUCTION
    180 
    181   void VisitInstruction(HInstruction* instruction) OVERRIDE {
    182     LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
    183                << " (id " << instruction->GetId() << ")";
    184   }
    185 
    186  private:
    187   void HandleInvoke(HInvoke* invoke);
    188   void HandleBinaryOp(HBinaryOperation* operation);
    189   void HandleCondition(HCondition* instruction);
    190   void HandleShift(HBinaryOperation* operation);
    191   void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
    192   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
    193 
    194   InvokeDexCallingConventionVisitorMIPS parameter_visitor_;
    195 
    196   CodeGeneratorMIPS* const codegen_;
    197 
    198   DISALLOW_COPY_AND_ASSIGN(LocationsBuilderMIPS);
    199 };
    200 
    201 class InstructionCodeGeneratorMIPS : public InstructionCodeGenerator {
    202  public:
    203   InstructionCodeGeneratorMIPS(HGraph* graph, CodeGeneratorMIPS* codegen);
    204 
    205 #define DECLARE_VISIT_INSTRUCTION(name, super)     \
    206   void Visit##name(H##name* instr) OVERRIDE;
    207 
    208   FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
    209   FOR_EACH_CONCRETE_INSTRUCTION_MIPS(DECLARE_VISIT_INSTRUCTION)
    210 
    211 #undef DECLARE_VISIT_INSTRUCTION
    212 
    213   void VisitInstruction(HInstruction* instruction) OVERRIDE {
    214     LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
    215                << " (id " << instruction->GetId() << ")";
    216   }
    217 
    218   MipsAssembler* GetAssembler() const { return assembler_; }
    219 
    220  private:
    221   void GenerateClassInitializationCheck(SlowPathCodeMIPS* slow_path, Register class_reg);
    222   void GenerateMemoryBarrier(MemBarrierKind kind);
    223   void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor);
    224   void HandleBinaryOp(HBinaryOperation* operation);
    225   void HandleCondition(HCondition* instruction);
    226   void HandleShift(HBinaryOperation* operation);
    227   void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info, uint32_t dex_pc);
    228   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info, uint32_t dex_pc);
    229   void GenerateIntCompare(IfCondition cond, LocationSummary* locations);
    230   void GenerateIntCompareAndBranch(IfCondition cond,
    231                                    LocationSummary* locations,
    232                                    MipsLabel* label);
    233   void GenerateLongCompareAndBranch(IfCondition cond,
    234                                     LocationSummary* locations,
    235                                     MipsLabel* label);
    236   void GenerateFpCompareAndBranch(IfCondition cond,
    237                                   bool gt_bias,
    238                                   Primitive::Type type,
    239                                   LocationSummary* locations,
    240                                   MipsLabel* label);
    241   void GenerateTestAndBranch(HInstruction* instruction,
    242                              size_t condition_input_index,
    243                              MipsLabel* true_target,
    244                              MipsLabel* false_target);
    245   void DivRemOneOrMinusOne(HBinaryOperation* instruction);
    246   void DivRemByPowerOfTwo(HBinaryOperation* instruction);
    247   void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction);
    248   void GenerateDivRemIntegral(HBinaryOperation* instruction);
    249   void HandleGoto(HInstruction* got, HBasicBlock* successor);
    250 
    251   MipsAssembler* const assembler_;
    252   CodeGeneratorMIPS* const codegen_;
    253 
    254   DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorMIPS);
    255 };
    256 
    257 class CodeGeneratorMIPS : public CodeGenerator {
    258  public:
    259   CodeGeneratorMIPS(HGraph* graph,
    260                     const MipsInstructionSetFeatures& isa_features,
    261                     const CompilerOptions& compiler_options,
    262                     OptimizingCompilerStats* stats = nullptr);
    263   virtual ~CodeGeneratorMIPS() {}
    264 
    265   void GenerateFrameEntry() OVERRIDE;
    266   void GenerateFrameExit() OVERRIDE;
    267 
    268   void Bind(HBasicBlock* block) OVERRIDE;
    269 
    270   void Move32(Location destination, Location source);
    271   void Move64(Location destination, Location source);
    272   void MoveConstant(Location location, HConstant* c);
    273 
    274   size_t GetWordSize() const OVERRIDE { return kMipsWordSize; }
    275 
    276   size_t GetFloatingPointSpillSlotSize() const OVERRIDE { return kMipsDoublewordSize; }
    277 
    278   uintptr_t GetAddressOf(HBasicBlock* block) OVERRIDE {
    279     return assembler_.GetLabelLocation(GetLabelOf(block));
    280   }
    281 
    282   HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; }
    283   HGraphVisitor* GetInstructionVisitor() OVERRIDE { return &instruction_visitor_; }
    284   MipsAssembler* GetAssembler() OVERRIDE { return &assembler_; }
    285   const MipsAssembler& GetAssembler() const OVERRIDE { return assembler_; }
    286 
    287   void MarkGCCard(Register object, Register value);
    288 
    289   // Register allocation.
    290 
    291   void SetupBlockedRegisters() const OVERRIDE;
    292 
    293   size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id);
    294   size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id);
    295   size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id);
    296   size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id);
    297 
    298   void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
    299   void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
    300 
    301   // Blocks all register pairs made out of blocked core registers.
    302   void UpdateBlockedPairRegisters() const;
    303 
    304   InstructionSet GetInstructionSet() const OVERRIDE { return InstructionSet::kMips; }
    305 
    306   const MipsInstructionSetFeatures& GetInstructionSetFeatures() const {
    307     return isa_features_;
    308   }
    309 
    310   MipsLabel* GetLabelOf(HBasicBlock* block) const {
    311     return CommonGetLabelOf<MipsLabel>(block_labels_, block);
    312   }
    313 
    314   void Initialize() OVERRIDE {
    315     block_labels_ = CommonInitializeLabels<MipsLabel>();
    316   }
    317 
    318   void Finalize(CodeAllocator* allocator) OVERRIDE;
    319 
    320   // Code generation helpers.
    321 
    322   void MoveLocation(Location dst, Location src, Primitive::Type dst_type) OVERRIDE;
    323 
    324   void MoveConstant(Location destination, int32_t value);
    325 
    326   void AddLocationAsTemp(Location location, LocationSummary* locations) OVERRIDE;
    327 
    328   // Generate code to invoke a runtime entry point.
    329   void InvokeRuntime(QuickEntrypointEnum entrypoint,
    330                      HInstruction* instruction,
    331                      uint32_t dex_pc,
    332                      SlowPathCode* slow_path) OVERRIDE;
    333 
    334   void InvokeRuntime(int32_t offset,
    335                      HInstruction* instruction,
    336                      uint32_t dex_pc,
    337                      SlowPathCode* slow_path,
    338                      bool is_direct_entrypoint);
    339 
    340   ParallelMoveResolver* GetMoveResolver() OVERRIDE { return &move_resolver_; }
    341 
    342   bool NeedsTwoRegisters(Primitive::Type type) const {
    343     return type == Primitive::kPrimLong;
    344   }
    345 
    346   // Check if the desired_string_load_kind is supported. If it is, return it,
    347   // otherwise return a fall-back kind that should be used instead.
    348   HLoadString::LoadKind GetSupportedLoadStringKind(
    349       HLoadString::LoadKind desired_string_load_kind) OVERRIDE;
    350 
    351   // Check if the desired_dispatch_info is supported. If it is, return it,
    352   // otherwise return a fall-back info that should be used instead.
    353   HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
    354       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
    355       MethodReference target_method) OVERRIDE;
    356 
    357   void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
    358   void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
    359 
    360   void MoveFromReturnRegister(Location trg ATTRIBUTE_UNUSED,
    361                               Primitive::Type type ATTRIBUTE_UNUSED) OVERRIDE {
    362     UNIMPLEMENTED(FATAL) << "Not implemented on MIPS";
    363   }
    364 
    365   void GenerateNop();
    366   void GenerateImplicitNullCheck(HNullCheck* instruction);
    367   void GenerateExplicitNullCheck(HNullCheck* instruction);
    368 
    369  private:
    370   // Labels for each block that will be compiled.
    371   MipsLabel* block_labels_;
    372   MipsLabel frame_entry_label_;
    373   LocationsBuilderMIPS location_builder_;
    374   InstructionCodeGeneratorMIPS instruction_visitor_;
    375   ParallelMoveResolverMIPS move_resolver_;
    376   MipsAssembler assembler_;
    377   const MipsInstructionSetFeatures& isa_features_;
    378 
    379   DISALLOW_COPY_AND_ASSIGN(CodeGeneratorMIPS);
    380 };
    381 
    382 }  // namespace mips
    383 }  // namespace art
    384 
    385 #endif  // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_MIPS_H_
    386