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_CODEGEN_TEST_UTILS_H_
     18 #define ART_COMPILER_OPTIMIZING_CODEGEN_TEST_UTILS_H_
     19 
     20 #include "arch/arm/instruction_set_features_arm.h"
     21 #include "arch/arm/registers_arm.h"
     22 #include "arch/arm64/instruction_set_features_arm64.h"
     23 #include "arch/instruction_set.h"
     24 #include "arch/mips/instruction_set_features_mips.h"
     25 #include "arch/mips/registers_mips.h"
     26 #include "arch/mips64/instruction_set_features_mips64.h"
     27 #include "arch/mips64/registers_mips64.h"
     28 #include "arch/x86/instruction_set_features_x86.h"
     29 #include "arch/x86/registers_x86.h"
     30 #include "arch/x86_64/instruction_set_features_x86_64.h"
     31 #include "code_simulator_container.h"
     32 #include "common_compiler_test.h"
     33 #include "graph_checker.h"
     34 #include "prepare_for_register_allocation.h"
     35 #include "ssa_liveness_analysis.h"
     36 
     37 #ifdef ART_ENABLE_CODEGEN_arm
     38 #include "code_generator_arm.h"
     39 #include "code_generator_arm_vixl.h"
     40 #endif
     41 
     42 #ifdef ART_ENABLE_CODEGEN_arm64
     43 #include "code_generator_arm64.h"
     44 #endif
     45 
     46 #ifdef ART_ENABLE_CODEGEN_x86
     47 #include "code_generator_x86.h"
     48 #endif
     49 
     50 #ifdef ART_ENABLE_CODEGEN_x86_64
     51 #include "code_generator_x86_64.h"
     52 #endif
     53 
     54 #ifdef ART_ENABLE_CODEGEN_mips
     55 #include "code_generator_mips.h"
     56 #endif
     57 
     58 #ifdef ART_ENABLE_CODEGEN_mips64
     59 #include "code_generator_mips64.h"
     60 #endif
     61 
     62 namespace art {
     63 
     64 typedef CodeGenerator* (*CreateCodegenFn)(HGraph*, const CompilerOptions&);
     65 
     66 class CodegenTargetConfig {
     67  public:
     68   CodegenTargetConfig(InstructionSet isa, CreateCodegenFn create_codegen)
     69       : isa_(isa), create_codegen_(create_codegen) {
     70   }
     71   InstructionSet GetInstructionSet() const { return isa_; }
     72   CodeGenerator* CreateCodeGenerator(HGraph* graph, const CompilerOptions& compiler_options) {
     73     return create_codegen_(graph, compiler_options);
     74   }
     75 
     76  private:
     77   InstructionSet isa_;
     78   CreateCodegenFn create_codegen_;
     79 };
     80 
     81 #ifdef ART_ENABLE_CODEGEN_arm
     82 // Provide our own codegen, that ensures the C calling conventions
     83 // are preserved. Currently, ART and C do not match as R4 is caller-save
     84 // in ART, and callee-save in C. Alternatively, we could use or write
     85 // the stub that saves and restores all registers, but it is easier
     86 // to just overwrite the code generator.
     87 class TestCodeGeneratorARM : public arm::CodeGeneratorARM {
     88  public:
     89   TestCodeGeneratorARM(HGraph* graph,
     90                        const ArmInstructionSetFeatures& isa_features,
     91                        const CompilerOptions& compiler_options)
     92       : arm::CodeGeneratorARM(graph, isa_features, compiler_options) {
     93     AddAllocatedRegister(Location::RegisterLocation(arm::R6));
     94     AddAllocatedRegister(Location::RegisterLocation(arm::R7));
     95   }
     96 
     97   void SetupBlockedRegisters() const OVERRIDE {
     98     arm::CodeGeneratorARM::SetupBlockedRegisters();
     99     blocked_core_registers_[arm::R4] = true;
    100     blocked_core_registers_[arm::R6] = false;
    101     blocked_core_registers_[arm::R7] = false;
    102   }
    103 };
    104 
    105 // A way to test the VIXL32-based code generator on ARM. This will replace
    106 // TestCodeGeneratorARM when the VIXL32-based backend replaces the existing one.
    107 class TestCodeGeneratorARMVIXL : public arm::CodeGeneratorARMVIXL {
    108  public:
    109   TestCodeGeneratorARMVIXL(HGraph* graph,
    110                            const ArmInstructionSetFeatures& isa_features,
    111                            const CompilerOptions& compiler_options)
    112       : arm::CodeGeneratorARMVIXL(graph, isa_features, compiler_options) {
    113     AddAllocatedRegister(Location::RegisterLocation(arm::R6));
    114     AddAllocatedRegister(Location::RegisterLocation(arm::R7));
    115   }
    116 
    117   void SetupBlockedRegisters() const OVERRIDE {
    118     arm::CodeGeneratorARMVIXL::SetupBlockedRegisters();
    119     blocked_core_registers_[arm::R4] = true;
    120     blocked_core_registers_[arm::R6] = false;
    121     blocked_core_registers_[arm::R7] = false;
    122   }
    123 };
    124 #endif
    125 
    126 #ifdef ART_ENABLE_CODEGEN_x86
    127 class TestCodeGeneratorX86 : public x86::CodeGeneratorX86 {
    128  public:
    129   TestCodeGeneratorX86(HGraph* graph,
    130                        const X86InstructionSetFeatures& isa_features,
    131                        const CompilerOptions& compiler_options)
    132       : x86::CodeGeneratorX86(graph, isa_features, compiler_options) {
    133     // Save edi, we need it for getting enough registers for long multiplication.
    134     AddAllocatedRegister(Location::RegisterLocation(x86::EDI));
    135   }
    136 
    137   void SetupBlockedRegisters() const OVERRIDE {
    138     x86::CodeGeneratorX86::SetupBlockedRegisters();
    139     // ebx is a callee-save register in C, but caller-save for ART.
    140     blocked_core_registers_[x86::EBX] = true;
    141 
    142     // Make edi available.
    143     blocked_core_registers_[x86::EDI] = false;
    144   }
    145 };
    146 #endif
    147 
    148 class InternalCodeAllocator : public CodeAllocator {
    149  public:
    150   InternalCodeAllocator() : size_(0) { }
    151 
    152   virtual uint8_t* Allocate(size_t size) {
    153     size_ = size;
    154     memory_.reset(new uint8_t[size]);
    155     return memory_.get();
    156   }
    157 
    158   size_t GetSize() const { return size_; }
    159   uint8_t* GetMemory() const { return memory_.get(); }
    160 
    161  private:
    162   size_t size_;
    163   std::unique_ptr<uint8_t[]> memory_;
    164 
    165   DISALLOW_COPY_AND_ASSIGN(InternalCodeAllocator);
    166 };
    167 
    168 static bool CanExecuteOnHardware(InstructionSet target_isa) {
    169   return (target_isa == kRuntimeISA)
    170       // Handle the special case of ARM, with two instructions sets (ARM32 and Thumb-2).
    171       || (kRuntimeISA == kArm && target_isa == kThumb2);
    172 }
    173 
    174 static bool CanExecute(InstructionSet target_isa) {
    175   CodeSimulatorContainer simulator(target_isa);
    176   return CanExecuteOnHardware(target_isa) || simulator.CanSimulate();
    177 }
    178 
    179 template <typename Expected>
    180 inline static Expected SimulatorExecute(CodeSimulator* simulator, Expected (*f)());
    181 
    182 template <>
    183 inline bool SimulatorExecute<bool>(CodeSimulator* simulator, bool (*f)()) {
    184   simulator->RunFrom(reinterpret_cast<intptr_t>(f));
    185   return simulator->GetCReturnBool();
    186 }
    187 
    188 template <>
    189 inline int32_t SimulatorExecute<int32_t>(CodeSimulator* simulator, int32_t (*f)()) {
    190   simulator->RunFrom(reinterpret_cast<intptr_t>(f));
    191   return simulator->GetCReturnInt32();
    192 }
    193 
    194 template <>
    195 inline int64_t SimulatorExecute<int64_t>(CodeSimulator* simulator, int64_t (*f)()) {
    196   simulator->RunFrom(reinterpret_cast<intptr_t>(f));
    197   return simulator->GetCReturnInt64();
    198 }
    199 
    200 template <typename Expected>
    201 static void VerifyGeneratedCode(InstructionSet target_isa,
    202                                 Expected (*f)(),
    203                                 bool has_result,
    204                                 Expected expected) {
    205   ASSERT_TRUE(CanExecute(target_isa)) << "Target isa is not executable.";
    206 
    207   // Verify on simulator.
    208   CodeSimulatorContainer simulator(target_isa);
    209   if (simulator.CanSimulate()) {
    210     Expected result = SimulatorExecute<Expected>(simulator.Get(), f);
    211     if (has_result) {
    212       ASSERT_EQ(expected, result);
    213     }
    214   }
    215 
    216   // Verify on hardware.
    217   if (CanExecuteOnHardware(target_isa)) {
    218     Expected result = f();
    219     if (has_result) {
    220       ASSERT_EQ(expected, result);
    221     }
    222   }
    223 }
    224 
    225 template <typename Expected>
    226 static void Run(const InternalCodeAllocator& allocator,
    227                 const CodeGenerator& codegen,
    228                 bool has_result,
    229                 Expected expected) {
    230   InstructionSet target_isa = codegen.GetInstructionSet();
    231 
    232   typedef Expected (*fptr)();
    233   CommonCompilerTest::MakeExecutable(allocator.GetMemory(), allocator.GetSize());
    234   fptr f = reinterpret_cast<fptr>(allocator.GetMemory());
    235   if (target_isa == kThumb2) {
    236     // For thumb we need the bottom bit set.
    237     f = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(f) + 1);
    238   }
    239   VerifyGeneratedCode(target_isa, f, has_result, expected);
    240 }
    241 
    242 static void ValidateGraph(HGraph* graph) {
    243   GraphChecker graph_checker(graph);
    244   graph_checker.Run();
    245   if (!graph_checker.IsValid()) {
    246     for (const auto& error : graph_checker.GetErrors()) {
    247       std::cout << error << std::endl;
    248     }
    249   }
    250   ASSERT_TRUE(graph_checker.IsValid());
    251 }
    252 
    253 template <typename Expected>
    254 static void RunCodeNoCheck(CodeGenerator* codegen,
    255                            HGraph* graph,
    256                            const std::function<void(HGraph*)>& hook_before_codegen,
    257                            bool has_result,
    258                            Expected expected) {
    259   SsaLivenessAnalysis liveness(graph, codegen);
    260   PrepareForRegisterAllocation(graph).Run();
    261   liveness.Analyze();
    262   RegisterAllocator::Create(graph->GetArena(), codegen, liveness)->AllocateRegisters();
    263   hook_before_codegen(graph);
    264   InternalCodeAllocator allocator;
    265   codegen->Compile(&allocator);
    266   Run(allocator, *codegen, has_result, expected);
    267 }
    268 
    269 template <typename Expected>
    270 static void RunCode(CodeGenerator* codegen,
    271                     HGraph* graph,
    272                     std::function<void(HGraph*)> hook_before_codegen,
    273                     bool has_result,
    274                     Expected expected) {
    275   ValidateGraph(graph);
    276   RunCodeNoCheck(codegen, graph, hook_before_codegen, has_result, expected);
    277 }
    278 
    279 template <typename Expected>
    280 static void RunCode(CodegenTargetConfig target_config,
    281                     HGraph* graph,
    282                     std::function<void(HGraph*)> hook_before_codegen,
    283                     bool has_result,
    284                     Expected expected) {
    285   CompilerOptions compiler_options;
    286   std::unique_ptr<CodeGenerator> codegen(target_config.CreateCodeGenerator(graph, compiler_options));
    287   RunCode(codegen.get(), graph, hook_before_codegen, has_result, expected);
    288 }
    289 
    290 #ifdef ART_ENABLE_CODEGEN_arm
    291 CodeGenerator* create_codegen_arm(HGraph* graph, const CompilerOptions& compiler_options) {
    292   std::unique_ptr<const ArmInstructionSetFeatures> features_arm(
    293       ArmInstructionSetFeatures::FromCppDefines());
    294   return new (graph->GetArena()) TestCodeGeneratorARM(graph,
    295                                                       *features_arm.get(),
    296                                                       compiler_options);
    297 }
    298 
    299 CodeGenerator* create_codegen_arm_vixl32(HGraph* graph, const CompilerOptions& compiler_options) {
    300   std::unique_ptr<const ArmInstructionSetFeatures> features_arm(
    301       ArmInstructionSetFeatures::FromCppDefines());
    302   return new (graph->GetArena())
    303       TestCodeGeneratorARMVIXL(graph, *features_arm.get(), compiler_options);
    304 }
    305 #endif
    306 
    307 #ifdef ART_ENABLE_CODEGEN_arm64
    308 CodeGenerator* create_codegen_arm64(HGraph* graph, const CompilerOptions& compiler_options) {
    309   std::unique_ptr<const Arm64InstructionSetFeatures> features_arm64(
    310       Arm64InstructionSetFeatures::FromCppDefines());
    311   return new (graph->GetArena()) arm64::CodeGeneratorARM64(graph,
    312                                                            *features_arm64.get(),
    313                                                            compiler_options);
    314 }
    315 #endif
    316 
    317 #ifdef ART_ENABLE_CODEGEN_x86
    318 CodeGenerator* create_codegen_x86(HGraph* graph, const CompilerOptions& compiler_options) {
    319   std::unique_ptr<const X86InstructionSetFeatures> features_x86(
    320       X86InstructionSetFeatures::FromCppDefines());
    321   return new (graph->GetArena()) TestCodeGeneratorX86(graph, *features_x86.get(), compiler_options);
    322 }
    323 #endif
    324 
    325 #ifdef ART_ENABLE_CODEGEN_x86_64
    326 CodeGenerator* create_codegen_x86_64(HGraph* graph, const CompilerOptions& compiler_options) {
    327   std::unique_ptr<const X86_64InstructionSetFeatures> features_x86_64(
    328      X86_64InstructionSetFeatures::FromCppDefines());
    329   return new (graph->GetArena())
    330       x86_64::CodeGeneratorX86_64(graph, *features_x86_64.get(), compiler_options);
    331 }
    332 #endif
    333 
    334 #ifdef ART_ENABLE_CODEGEN_mips
    335 CodeGenerator* create_codegen_mips(HGraph* graph, const CompilerOptions& compiler_options) {
    336   std::unique_ptr<const MipsInstructionSetFeatures> features_mips(
    337       MipsInstructionSetFeatures::FromCppDefines());
    338   return new (graph->GetArena())
    339       mips::CodeGeneratorMIPS(graph, *features_mips.get(), compiler_options);
    340 }
    341 #endif
    342 
    343 #ifdef ART_ENABLE_CODEGEN_mips64
    344 CodeGenerator* create_codegen_mips64(HGraph* graph, const CompilerOptions& compiler_options) {
    345   std::unique_ptr<const Mips64InstructionSetFeatures> features_mips64(
    346       Mips64InstructionSetFeatures::FromCppDefines());
    347   return new (graph->GetArena())
    348       mips64::CodeGeneratorMIPS64(graph, *features_mips64.get(), compiler_options);
    349 }
    350 #endif
    351 
    352 }  // namespace art
    353 
    354 #endif  // ART_COMPILER_OPTIMIZING_CODEGEN_TEST_UTILS_H_
    355