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