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.h"
     32 #include "code_simulator_container.h"
     33 #include "common_compiler_test.h"
     34 #include "graph_checker.h"
     35 #include "prepare_for_register_allocation.h"
     36 #include "ssa_liveness_analysis.h"
     37 
     38 #ifdef ART_ENABLE_CODEGEN_arm
     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 // Special ARM code generator for codegen testing in a limited code
     83 // generation environment (i.e. with no runtime support).
     84 //
     85 // Note: If we want to exercise certains HIR constructions
     86 // (e.g. reference field load in Baker read barrier configuration) in
     87 // codegen tests in the future, we should also:
     88 // - save the Thread Register (R9) and possibly the Marking Register
     89 //   (R8) before entering the generated function (both registers are
     90 //   callee-save in AAPCS);
     91 // - set these registers to meaningful values before or upon entering
     92 //   the generated function (so that generated code using them is
     93 //   correct);
     94 // - restore their original values before leaving the generated
     95 //   function.
     96 
     97 // Provide our own codegen, that ensures the C calling conventions
     98 // are preserved. Currently, ART and C do not match as R4 is caller-save
     99 // in ART, and callee-save in C. Alternatively, we could use or write
    100 // the stub that saves and restores all registers, but it is easier
    101 // to just overwrite the code generator.
    102 class TestCodeGeneratorARMVIXL : public arm::CodeGeneratorARMVIXL {
    103  public:
    104   TestCodeGeneratorARMVIXL(HGraph* graph,
    105                            const ArmInstructionSetFeatures& isa_features,
    106                            const CompilerOptions& compiler_options)
    107       : arm::CodeGeneratorARMVIXL(graph, isa_features, compiler_options) {
    108     AddAllocatedRegister(Location::RegisterLocation(arm::R6));
    109     AddAllocatedRegister(Location::RegisterLocation(arm::R7));
    110   }
    111 
    112   void SetupBlockedRegisters() const OVERRIDE {
    113     arm::CodeGeneratorARMVIXL::SetupBlockedRegisters();
    114     blocked_core_registers_[arm::R4] = true;
    115     blocked_core_registers_[arm::R6] = false;
    116     blocked_core_registers_[arm::R7] = false;
    117   }
    118 
    119   void MaybeGenerateMarkingRegisterCheck(int code ATTRIBUTE_UNUSED,
    120                                          Location temp_loc ATTRIBUTE_UNUSED) OVERRIDE {
    121     // When turned on, the marking register checks in
    122     // CodeGeneratorARMVIXL::MaybeGenerateMarkingRegisterCheck expects the
    123     // Thread Register and the Marking Register to be set to
    124     // meaningful values. This is not the case in codegen testing, so
    125     // just disable them entirely here (by doing nothing in this
    126     // method).
    127   }
    128 };
    129 #endif
    130 
    131 #ifdef ART_ENABLE_CODEGEN_arm64
    132 // Special ARM64 code generator for codegen testing in a limited code
    133 // generation environment (i.e. with no runtime support).
    134 //
    135 // Note: If we want to exercise certains HIR constructions
    136 // (e.g. reference field load in Baker read barrier configuration) in
    137 // codegen tests in the future, we should also:
    138 // - save the Thread Register (X19) and possibly the Marking Register
    139 //   (X20) before entering the generated function (both registers are
    140 //   callee-save in AAPCS64);
    141 // - set these registers to meaningful values before or upon entering
    142 //   the generated function (so that generated code using them is
    143 //   correct);
    144 // - restore their original values before leaving the generated
    145 //   function.
    146 class TestCodeGeneratorARM64 : public arm64::CodeGeneratorARM64 {
    147  public:
    148   TestCodeGeneratorARM64(HGraph* graph,
    149                          const Arm64InstructionSetFeatures& isa_features,
    150                          const CompilerOptions& compiler_options)
    151       : arm64::CodeGeneratorARM64(graph, isa_features, compiler_options) {}
    152 
    153   void MaybeGenerateMarkingRegisterCheck(int codem ATTRIBUTE_UNUSED,
    154                                          Location temp_loc ATTRIBUTE_UNUSED) OVERRIDE {
    155     // When turned on, the marking register checks in
    156     // CodeGeneratorARM64::MaybeGenerateMarkingRegisterCheck expect the
    157     // Thread Register and the Marking Register to be set to
    158     // meaningful values. This is not the case in codegen testing, so
    159     // just disable them entirely here (by doing nothing in this
    160     // method).
    161   }
    162 };
    163 #endif
    164 
    165 #ifdef ART_ENABLE_CODEGEN_x86
    166 class TestCodeGeneratorX86 : public x86::CodeGeneratorX86 {
    167  public:
    168   TestCodeGeneratorX86(HGraph* graph,
    169                        const X86InstructionSetFeatures& isa_features,
    170                        const CompilerOptions& compiler_options)
    171       : x86::CodeGeneratorX86(graph, isa_features, compiler_options) {
    172     // Save edi, we need it for getting enough registers for long multiplication.
    173     AddAllocatedRegister(Location::RegisterLocation(x86::EDI));
    174   }
    175 
    176   void SetupBlockedRegisters() const OVERRIDE {
    177     x86::CodeGeneratorX86::SetupBlockedRegisters();
    178     // ebx is a callee-save register in C, but caller-save for ART.
    179     blocked_core_registers_[x86::EBX] = true;
    180 
    181     // Make edi available.
    182     blocked_core_registers_[x86::EDI] = false;
    183   }
    184 };
    185 #endif
    186 
    187 class InternalCodeAllocator : public CodeAllocator {
    188  public:
    189   InternalCodeAllocator() : size_(0) { }
    190 
    191   virtual uint8_t* Allocate(size_t size) {
    192     size_ = size;
    193     memory_.reset(new uint8_t[size]);
    194     return memory_.get();
    195   }
    196 
    197   size_t GetSize() const { return size_; }
    198   uint8_t* GetMemory() const { return memory_.get(); }
    199 
    200  private:
    201   size_t size_;
    202   std::unique_ptr<uint8_t[]> memory_;
    203 
    204   DISALLOW_COPY_AND_ASSIGN(InternalCodeAllocator);
    205 };
    206 
    207 static bool CanExecuteOnHardware(InstructionSet target_isa) {
    208   return (target_isa == kRuntimeISA)
    209       // Handle the special case of ARM, with two instructions sets (ARM32 and Thumb-2).
    210       || (kRuntimeISA == InstructionSet::kArm && target_isa == InstructionSet::kThumb2);
    211 }
    212 
    213 static bool CanExecute(InstructionSet target_isa) {
    214   CodeSimulatorContainer simulator(target_isa);
    215   return CanExecuteOnHardware(target_isa) || simulator.CanSimulate();
    216 }
    217 
    218 template <typename Expected>
    219 inline static Expected SimulatorExecute(CodeSimulator* simulator, Expected (*f)());
    220 
    221 template <>
    222 inline bool SimulatorExecute<bool>(CodeSimulator* simulator, bool (*f)()) {
    223   simulator->RunFrom(reinterpret_cast<intptr_t>(f));
    224   return simulator->GetCReturnBool();
    225 }
    226 
    227 template <>
    228 inline int32_t SimulatorExecute<int32_t>(CodeSimulator* simulator, int32_t (*f)()) {
    229   simulator->RunFrom(reinterpret_cast<intptr_t>(f));
    230   return simulator->GetCReturnInt32();
    231 }
    232 
    233 template <>
    234 inline int64_t SimulatorExecute<int64_t>(CodeSimulator* simulator, int64_t (*f)()) {
    235   simulator->RunFrom(reinterpret_cast<intptr_t>(f));
    236   return simulator->GetCReturnInt64();
    237 }
    238 
    239 template <typename Expected>
    240 static void VerifyGeneratedCode(InstructionSet target_isa,
    241                                 Expected (*f)(),
    242                                 bool has_result,
    243                                 Expected expected) {
    244   ASSERT_TRUE(CanExecute(target_isa)) << "Target isa is not executable.";
    245 
    246   // Verify on simulator.
    247   CodeSimulatorContainer simulator(target_isa);
    248   if (simulator.CanSimulate()) {
    249     Expected result = SimulatorExecute<Expected>(simulator.Get(), f);
    250     if (has_result) {
    251       ASSERT_EQ(expected, result);
    252     }
    253   }
    254 
    255   // Verify on hardware.
    256   if (CanExecuteOnHardware(target_isa)) {
    257     Expected result = f();
    258     if (has_result) {
    259       ASSERT_EQ(expected, result);
    260     }
    261   }
    262 }
    263 
    264 template <typename Expected>
    265 static void Run(const InternalCodeAllocator& allocator,
    266                 const CodeGenerator& codegen,
    267                 bool has_result,
    268                 Expected expected) {
    269   InstructionSet target_isa = codegen.GetInstructionSet();
    270 
    271   typedef Expected (*fptr)();
    272   CommonCompilerTest::MakeExecutable(allocator.GetMemory(), allocator.GetSize());
    273   fptr f = reinterpret_cast<fptr>(allocator.GetMemory());
    274   if (target_isa == InstructionSet::kThumb2) {
    275     // For thumb we need the bottom bit set.
    276     f = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(f) + 1);
    277   }
    278   VerifyGeneratedCode(target_isa, f, has_result, expected);
    279 }
    280 
    281 static void ValidateGraph(HGraph* graph) {
    282   GraphChecker graph_checker(graph);
    283   graph_checker.Run();
    284   if (!graph_checker.IsValid()) {
    285     for (const std::string& error : graph_checker.GetErrors()) {
    286       std::cout << error << std::endl;
    287     }
    288   }
    289   ASSERT_TRUE(graph_checker.IsValid());
    290 }
    291 
    292 template <typename Expected>
    293 static void RunCodeNoCheck(CodeGenerator* codegen,
    294                            HGraph* graph,
    295                            const std::function<void(HGraph*)>& hook_before_codegen,
    296                            bool has_result,
    297                            Expected expected) {
    298   {
    299     ScopedArenaAllocator local_allocator(graph->GetArenaStack());
    300     SsaLivenessAnalysis liveness(graph, codegen, &local_allocator);
    301     PrepareForRegisterAllocation(graph).Run();
    302     liveness.Analyze();
    303     std::unique_ptr<RegisterAllocator> register_allocator =
    304         RegisterAllocator::Create(&local_allocator, codegen, liveness);
    305     register_allocator->AllocateRegisters();
    306   }
    307   hook_before_codegen(graph);
    308   InternalCodeAllocator allocator;
    309   codegen->Compile(&allocator);
    310   Run(allocator, *codegen, has_result, expected);
    311 }
    312 
    313 template <typename Expected>
    314 static void RunCode(CodeGenerator* codegen,
    315                     HGraph* graph,
    316                     std::function<void(HGraph*)> hook_before_codegen,
    317                     bool has_result,
    318                     Expected expected) {
    319   ValidateGraph(graph);
    320   RunCodeNoCheck(codegen, graph, hook_before_codegen, has_result, expected);
    321 }
    322 
    323 template <typename Expected>
    324 static void RunCode(CodegenTargetConfig target_config,
    325                     HGraph* graph,
    326                     std::function<void(HGraph*)> hook_before_codegen,
    327                     bool has_result,
    328                     Expected expected) {
    329   CompilerOptions compiler_options;
    330   std::unique_ptr<CodeGenerator> codegen(target_config.CreateCodeGenerator(graph,
    331                                                                            compiler_options));
    332   RunCode(codegen.get(), graph, hook_before_codegen, has_result, expected);
    333 }
    334 
    335 #ifdef ART_ENABLE_CODEGEN_arm
    336 CodeGenerator* create_codegen_arm_vixl32(HGraph* graph, const CompilerOptions& compiler_options) {
    337   std::unique_ptr<const ArmInstructionSetFeatures> features_arm(
    338       ArmInstructionSetFeatures::FromCppDefines());
    339   return new (graph->GetAllocator())
    340       TestCodeGeneratorARMVIXL(graph, *features_arm.get(), compiler_options);
    341 }
    342 #endif
    343 
    344 #ifdef ART_ENABLE_CODEGEN_arm64
    345 CodeGenerator* create_codegen_arm64(HGraph* graph, const CompilerOptions& compiler_options) {
    346   std::unique_ptr<const Arm64InstructionSetFeatures> features_arm64(
    347       Arm64InstructionSetFeatures::FromCppDefines());
    348   return new (graph->GetAllocator())
    349       TestCodeGeneratorARM64(graph, *features_arm64.get(), compiler_options);
    350 }
    351 #endif
    352 
    353 #ifdef ART_ENABLE_CODEGEN_x86
    354 CodeGenerator* create_codegen_x86(HGraph* graph, const CompilerOptions& compiler_options) {
    355   std::unique_ptr<const X86InstructionSetFeatures> features_x86(
    356       X86InstructionSetFeatures::FromCppDefines());
    357   return new (graph->GetAllocator()) TestCodeGeneratorX86(
    358       graph, *features_x86.get(), compiler_options);
    359 }
    360 #endif
    361 
    362 #ifdef ART_ENABLE_CODEGEN_x86_64
    363 CodeGenerator* create_codegen_x86_64(HGraph* graph, const CompilerOptions& compiler_options) {
    364   std::unique_ptr<const X86_64InstructionSetFeatures> features_x86_64(
    365      X86_64InstructionSetFeatures::FromCppDefines());
    366   return new (graph->GetAllocator())
    367       x86_64::CodeGeneratorX86_64(graph, *features_x86_64.get(), compiler_options);
    368 }
    369 #endif
    370 
    371 #ifdef ART_ENABLE_CODEGEN_mips
    372 CodeGenerator* create_codegen_mips(HGraph* graph, const CompilerOptions& compiler_options) {
    373   std::unique_ptr<const MipsInstructionSetFeatures> features_mips(
    374       MipsInstructionSetFeatures::FromCppDefines());
    375   return new (graph->GetAllocator())
    376       mips::CodeGeneratorMIPS(graph, *features_mips.get(), compiler_options);
    377 }
    378 #endif
    379 
    380 #ifdef ART_ENABLE_CODEGEN_mips64
    381 CodeGenerator* create_codegen_mips64(HGraph* graph, const CompilerOptions& compiler_options) {
    382   std::unique_ptr<const Mips64InstructionSetFeatures> features_mips64(
    383       Mips64InstructionSetFeatures::FromCppDefines());
    384   return new (graph->GetAllocator())
    385       mips64::CodeGeneratorMIPS64(graph, *features_mips64.get(), compiler_options);
    386 }
    387 #endif
    388 
    389 }  // namespace art
    390 
    391 #endif  // ART_COMPILER_OPTIMIZING_CODEGEN_TEST_UTILS_H_
    392