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