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