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