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