codegen_test.cc revision 58a4c6198a71973ea589edebe0b3f17c72d55e29
1/* 2 * Copyright (C) 2014 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#include <functional> 18 19#include "arch/instruction_set.h" 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/mips/instruction_set_features_mips.h" 24#include "arch/mips/registers_mips.h" 25#include "arch/mips64/instruction_set_features_mips64.h" 26#include "arch/mips64/registers_mips64.h" 27#include "arch/x86/instruction_set_features_x86.h" 28#include "arch/x86/registers_x86.h" 29#include "arch/x86_64/instruction_set_features_x86_64.h" 30#include "base/macros.h" 31#include "builder.h" 32#include "code_simulator_container.h" 33#include "common_compiler_test.h" 34#include "dex_file.h" 35#include "dex_instruction.h" 36#include "driver/compiler_options.h" 37#include "graph_checker.h" 38#include "nodes.h" 39#include "optimizing_unit_test.h" 40#include "prepare_for_register_allocation.h" 41#include "register_allocator_linear_scan.h" 42#include "ssa_liveness_analysis.h" 43#include "utils.h" 44#include "utils/arm/assembler_arm_vixl.h" 45#include "utils/arm/managed_register_arm.h" 46#include "utils/mips/managed_register_mips.h" 47#include "utils/mips64/managed_register_mips64.h" 48#include "utils/x86/managed_register_x86.h" 49 50#ifdef ART_ENABLE_CODEGEN_arm 51#include "code_generator_arm.h" 52#include "code_generator_arm_vixl.h" 53#endif 54 55#ifdef ART_ENABLE_CODEGEN_arm64 56#include "code_generator_arm64.h" 57#endif 58 59#ifdef ART_ENABLE_CODEGEN_x86 60#include "code_generator_x86.h" 61#endif 62 63#ifdef ART_ENABLE_CODEGEN_x86_64 64#include "code_generator_x86_64.h" 65#endif 66 67#ifdef ART_ENABLE_CODEGEN_mips 68#include "code_generator_mips.h" 69#endif 70 71#ifdef ART_ENABLE_CODEGEN_mips64 72#include "code_generator_mips64.h" 73#endif 74 75#include "gtest/gtest.h" 76 77namespace art { 78 79typedef CodeGenerator* (*CreateCodegenFn)(HGraph*, const CompilerOptions&); 80 81class CodegenTargetConfig { 82 public: 83 CodegenTargetConfig(InstructionSet isa, CreateCodegenFn create_codegen) 84 : isa_(isa), create_codegen_(create_codegen) { 85 } 86 InstructionSet GetInstructionSet() const { return isa_; } 87 CodeGenerator* CreateCodeGenerator(HGraph* graph, const CompilerOptions& compiler_options) { 88 return create_codegen_(graph, compiler_options); 89 } 90 91 private: 92 CodegenTargetConfig() {} 93 InstructionSet isa_; 94 CreateCodegenFn create_codegen_; 95}; 96 97#ifdef ART_ENABLE_CODEGEN_arm 98// Provide our own codegen, that ensures the C calling conventions 99// are preserved. Currently, ART and C do not match as R4 is caller-save 100// in ART, and callee-save in C. Alternatively, we could use or write 101// the stub that saves and restores all registers, but it is easier 102// to just overwrite the code generator. 103class TestCodeGeneratorARM : public arm::CodeGeneratorARM { 104 public: 105 TestCodeGeneratorARM(HGraph* graph, 106 const ArmInstructionSetFeatures& isa_features, 107 const CompilerOptions& compiler_options) 108 : arm::CodeGeneratorARM(graph, isa_features, compiler_options) { 109 AddAllocatedRegister(Location::RegisterLocation(arm::R6)); 110 AddAllocatedRegister(Location::RegisterLocation(arm::R7)); 111 } 112 113 void SetupBlockedRegisters() const OVERRIDE { 114 arm::CodeGeneratorARM::SetupBlockedRegisters(); 115 blocked_core_registers_[arm::R4] = true; 116 blocked_core_registers_[arm::R6] = false; 117 blocked_core_registers_[arm::R7] = false; 118 } 119}; 120 121// A way to test the VIXL32-based code generator on ARM. This will replace 122// TestCodeGeneratorARM when the VIXL32-based backend replaces the existing one. 123class TestCodeGeneratorARMVIXL : public arm::CodeGeneratorARMVIXL { 124 public: 125 TestCodeGeneratorARMVIXL(HGraph* graph, 126 const ArmInstructionSetFeatures& isa_features, 127 const CompilerOptions& compiler_options) 128 : arm::CodeGeneratorARMVIXL(graph, isa_features, compiler_options) { 129 AddAllocatedRegister(Location::RegisterLocation(arm::R6)); 130 AddAllocatedRegister(Location::RegisterLocation(arm::R7)); 131 } 132 133 void SetupBlockedRegisters() const OVERRIDE { 134 arm::CodeGeneratorARMVIXL::SetupBlockedRegisters(); 135 blocked_core_registers_[arm::R4] = true; 136 blocked_core_registers_[arm::R6] = false; 137 blocked_core_registers_[arm::R7] = false; 138 } 139}; 140#endif 141 142#ifdef ART_ENABLE_CODEGEN_x86 143class TestCodeGeneratorX86 : public x86::CodeGeneratorX86 { 144 public: 145 TestCodeGeneratorX86(HGraph* graph, 146 const X86InstructionSetFeatures& isa_features, 147 const CompilerOptions& compiler_options) 148 : x86::CodeGeneratorX86(graph, isa_features, compiler_options) { 149 // Save edi, we need it for getting enough registers for long multiplication. 150 AddAllocatedRegister(Location::RegisterLocation(x86::EDI)); 151 } 152 153 void SetupBlockedRegisters() const OVERRIDE { 154 x86::CodeGeneratorX86::SetupBlockedRegisters(); 155 // ebx is a callee-save register in C, but caller-save for ART. 156 blocked_core_registers_[x86::EBX] = true; 157 158 // Make edi available. 159 blocked_core_registers_[x86::EDI] = false; 160 } 161}; 162#endif 163 164class InternalCodeAllocator : public CodeAllocator { 165 public: 166 InternalCodeAllocator() : size_(0) { } 167 168 virtual uint8_t* Allocate(size_t size) { 169 size_ = size; 170 memory_.reset(new uint8_t[size]); 171 return memory_.get(); 172 } 173 174 size_t GetSize() const { return size_; } 175 uint8_t* GetMemory() const { return memory_.get(); } 176 177 private: 178 size_t size_; 179 std::unique_ptr<uint8_t[]> memory_; 180 181 DISALLOW_COPY_AND_ASSIGN(InternalCodeAllocator); 182}; 183 184static bool CanExecuteOnHardware(InstructionSet target_isa) { 185 return (target_isa == kRuntimeISA) 186 // Handle the special case of ARM, with two instructions sets (ARM32 and Thumb-2). 187 || (kRuntimeISA == kArm && target_isa == kThumb2); 188} 189 190static bool CanExecute(InstructionSet target_isa) { 191 CodeSimulatorContainer simulator(target_isa); 192 return CanExecuteOnHardware(target_isa) || simulator.CanSimulate(); 193} 194 195template <typename Expected> 196static Expected SimulatorExecute(CodeSimulator* simulator, Expected (*f)()); 197 198template <> 199bool SimulatorExecute<bool>(CodeSimulator* simulator, bool (*f)()) { 200 simulator->RunFrom(reinterpret_cast<intptr_t>(f)); 201 return simulator->GetCReturnBool(); 202} 203 204template <> 205int32_t SimulatorExecute<int32_t>(CodeSimulator* simulator, int32_t (*f)()) { 206 simulator->RunFrom(reinterpret_cast<intptr_t>(f)); 207 return simulator->GetCReturnInt32(); 208} 209 210template <> 211int64_t SimulatorExecute<int64_t>(CodeSimulator* simulator, int64_t (*f)()) { 212 simulator->RunFrom(reinterpret_cast<intptr_t>(f)); 213 return simulator->GetCReturnInt64(); 214} 215 216template <typename Expected> 217static void VerifyGeneratedCode(InstructionSet target_isa, 218 Expected (*f)(), 219 bool has_result, 220 Expected expected) { 221 ASSERT_TRUE(CanExecute(target_isa)) << "Target isa is not executable."; 222 223 // Verify on simulator. 224 CodeSimulatorContainer simulator(target_isa); 225 if (simulator.CanSimulate()) { 226 Expected result = SimulatorExecute<Expected>(simulator.Get(), f); 227 if (has_result) { 228 ASSERT_EQ(expected, result); 229 } 230 } 231 232 // Verify on hardware. 233 if (CanExecuteOnHardware(target_isa)) { 234 Expected result = f(); 235 if (has_result) { 236 ASSERT_EQ(expected, result); 237 } 238 } 239} 240 241template <typename Expected> 242static void Run(const InternalCodeAllocator& allocator, 243 const CodeGenerator& codegen, 244 bool has_result, 245 Expected expected) { 246 InstructionSet target_isa = codegen.GetInstructionSet(); 247 248 typedef Expected (*fptr)(); 249 CommonCompilerTest::MakeExecutable(allocator.GetMemory(), allocator.GetSize()); 250 fptr f = reinterpret_cast<fptr>(allocator.GetMemory()); 251 if (target_isa == kThumb2) { 252 // For thumb we need the bottom bit set. 253 f = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(f) + 1); 254 } 255 VerifyGeneratedCode(target_isa, f, has_result, expected); 256} 257 258static void ValidateGraph(HGraph* graph) { 259 GraphChecker graph_checker(graph); 260 graph_checker.Run(); 261 if (!graph_checker.IsValid()) { 262 for (auto error : graph_checker.GetErrors()) { 263 std::cout << error << std::endl; 264 } 265 } 266 ASSERT_TRUE(graph_checker.IsValid()); 267} 268 269template <typename Expected> 270static void RunCodeNoCheck(CodeGenerator* codegen, 271 HGraph* graph, 272 std::function<void(HGraph*)> hook_before_codegen, 273 bool has_result, 274 Expected expected) { 275 SsaLivenessAnalysis liveness(graph, codegen); 276 PrepareForRegisterAllocation(graph).Run(); 277 liveness.Analyze(); 278 RegisterAllocator::Create(graph->GetArena(), codegen, liveness)->AllocateRegisters(); 279 hook_before_codegen(graph); 280 InternalCodeAllocator allocator; 281 codegen->Compile(&allocator); 282 Run(allocator, *codegen, has_result, expected); 283} 284 285template <typename Expected> 286static void RunCode(CodeGenerator* codegen, 287 HGraph* graph, 288 std::function<void(HGraph*)> hook_before_codegen, 289 bool has_result, 290 Expected expected) { 291 ValidateGraph(graph); 292 RunCodeNoCheck(codegen, graph, hook_before_codegen, has_result, expected); 293} 294 295template <typename Expected> 296static void RunCode(CodegenTargetConfig target_config, 297 HGraph* graph, 298 std::function<void(HGraph*)> hook_before_codegen, 299 bool has_result, 300 Expected expected) { 301 CompilerOptions compiler_options; 302 CodeGenerator* codegen = target_config.CreateCodeGenerator(graph, compiler_options); 303 RunCode(codegen, graph, hook_before_codegen, has_result, expected); 304} 305 306#ifdef ART_ENABLE_CODEGEN_arm 307CodeGenerator* create_codegen_arm(HGraph* graph, const CompilerOptions& compiler_options) { 308 std::unique_ptr<const ArmInstructionSetFeatures> features_arm( 309 ArmInstructionSetFeatures::FromCppDefines()); 310 return new (graph->GetArena()) TestCodeGeneratorARM(graph, 311 *features_arm.get(), 312 compiler_options); 313} 314 315CodeGenerator* create_codegen_arm_vixl32(HGraph* graph, const CompilerOptions& compiler_options) { 316 std::unique_ptr<const ArmInstructionSetFeatures> features_arm( 317 ArmInstructionSetFeatures::FromCppDefines()); 318 return new (graph->GetArena()) 319 TestCodeGeneratorARMVIXL(graph, *features_arm.get(), compiler_options); 320} 321#endif 322 323#ifdef ART_ENABLE_CODEGEN_arm64 324CodeGenerator* create_codegen_arm64(HGraph* graph, const CompilerOptions& compiler_options) { 325 std::unique_ptr<const Arm64InstructionSetFeatures> features_arm64( 326 Arm64InstructionSetFeatures::FromCppDefines()); 327 return new (graph->GetArena()) arm64::CodeGeneratorARM64(graph, 328 *features_arm64.get(), 329 compiler_options); 330} 331#endif 332 333#ifdef ART_ENABLE_CODEGEN_x86 334CodeGenerator* create_codegen_x86(HGraph* graph, const CompilerOptions& compiler_options) { 335 std::unique_ptr<const X86InstructionSetFeatures> features_x86( 336 X86InstructionSetFeatures::FromCppDefines()); 337 return new (graph->GetArena()) TestCodeGeneratorX86(graph, *features_x86.get(), compiler_options); 338} 339#endif 340 341#ifdef ART_ENABLE_CODEGEN_x86_64 342CodeGenerator* create_codegen_x86_64(HGraph* graph, const CompilerOptions& compiler_options) { 343 std::unique_ptr<const X86_64InstructionSetFeatures> features_x86_64( 344 X86_64InstructionSetFeatures::FromCppDefines()); 345 return new (graph->GetArena()) 346 x86_64::CodeGeneratorX86_64(graph, *features_x86_64.get(), compiler_options); 347} 348#endif 349 350#ifdef ART_ENABLE_CODEGEN_mips 351CodeGenerator* create_codegen_mips(HGraph* graph, const CompilerOptions& compiler_options) { 352 std::unique_ptr<const MipsInstructionSetFeatures> features_mips( 353 MipsInstructionSetFeatures::FromCppDefines()); 354 return new (graph->GetArena()) 355 mips::CodeGeneratorMIPS(graph, *features_mips.get(), compiler_options); 356} 357#endif 358 359#ifdef ART_ENABLE_CODEGEN_mips64 360CodeGenerator* create_codegen_mips64(HGraph* graph, const CompilerOptions& compiler_options) { 361 std::unique_ptr<const Mips64InstructionSetFeatures> features_mips64( 362 Mips64InstructionSetFeatures::FromCppDefines()); 363 return new (graph->GetArena()) 364 mips64::CodeGeneratorMIPS64(graph, *features_mips64.get(), compiler_options); 365} 366#endif 367 368// Return all combinations of ISA and code generator that are executable on 369// hardware, or on simulator, and that we'd like to test. 370static ::std::vector<CodegenTargetConfig> GetTargetConfigs() { 371 ::std::vector<CodegenTargetConfig> v; 372 ::std::vector<CodegenTargetConfig> test_config_candidates = { 373#ifdef ART_ENABLE_CODEGEN_arm 374 CodegenTargetConfig(kArm, create_codegen_arm), 375 CodegenTargetConfig(kThumb2, create_codegen_arm), 376 CodegenTargetConfig(kArm, create_codegen_arm_vixl32), 377#endif 378#ifdef ART_ENABLE_CODEGEN_arm64 379 CodegenTargetConfig(kArm64, create_codegen_arm64), 380#endif 381#ifdef ART_ENABLE_CODEGEN_x86 382 CodegenTargetConfig(kX86, create_codegen_x86), 383#endif 384#ifdef ART_ENABLE_CODEGEN_x86_64 385 CodegenTargetConfig(kX86_64, create_codegen_x86_64), 386#endif 387#ifdef ART_ENABLE_CODEGEN_mips 388 CodegenTargetConfig(kMips, create_codegen_mips), 389#endif 390#ifdef ART_ENABLE_CODEGEN_mips64 391 CodegenTargetConfig(kMips64, create_codegen_mips64) 392#endif 393 }; 394 395 for (auto test_config : test_config_candidates) { 396 if (CanExecute(test_config.GetInstructionSet())) { 397 v.push_back(test_config); 398 } 399 } 400 401 return v; 402} 403 404static void TestCode(const uint16_t* data, 405 bool has_result = false, 406 int32_t expected = 0) { 407 for (CodegenTargetConfig target_config : GetTargetConfigs()) { 408 ArenaPool pool; 409 ArenaAllocator arena(&pool); 410 HGraph* graph = CreateCFG(&arena, data); 411 // Remove suspend checks, they cannot be executed in this context. 412 RemoveSuspendChecks(graph); 413 RunCode(target_config, graph, [](HGraph*) {}, has_result, expected); 414 } 415} 416 417static void TestCodeLong(const uint16_t* data, 418 bool has_result, 419 int64_t expected) { 420 for (CodegenTargetConfig target_config : GetTargetConfigs()) { 421 ArenaPool pool; 422 ArenaAllocator arena(&pool); 423 HGraph* graph = CreateCFG(&arena, data, Primitive::kPrimLong); 424 // Remove suspend checks, they cannot be executed in this context. 425 RemoveSuspendChecks(graph); 426 RunCode(target_config, graph, [](HGraph*) {}, has_result, expected); 427 } 428} 429 430class CodegenTest : public CommonCompilerTest {}; 431 432TEST_F(CodegenTest, ReturnVoid) { 433 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(Instruction::RETURN_VOID); 434 TestCode(data); 435} 436 437TEST_F(CodegenTest, CFG1) { 438 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM( 439 Instruction::GOTO | 0x100, 440 Instruction::RETURN_VOID); 441 442 TestCode(data); 443} 444 445TEST_F(CodegenTest, CFG2) { 446 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM( 447 Instruction::GOTO | 0x100, 448 Instruction::GOTO | 0x100, 449 Instruction::RETURN_VOID); 450 451 TestCode(data); 452} 453 454TEST_F(CodegenTest, CFG3) { 455 const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM( 456 Instruction::GOTO | 0x200, 457 Instruction::RETURN_VOID, 458 Instruction::GOTO | 0xFF00); 459 460 TestCode(data1); 461 462 const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM( 463 Instruction::GOTO_16, 3, 464 Instruction::RETURN_VOID, 465 Instruction::GOTO_16, 0xFFFF); 466 467 TestCode(data2); 468 469 const uint16_t data3[] = ZERO_REGISTER_CODE_ITEM( 470 Instruction::GOTO_32, 4, 0, 471 Instruction::RETURN_VOID, 472 Instruction::GOTO_32, 0xFFFF, 0xFFFF); 473 474 TestCode(data3); 475} 476 477TEST_F(CodegenTest, CFG4) { 478 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM( 479 Instruction::RETURN_VOID, 480 Instruction::GOTO | 0x100, 481 Instruction::GOTO | 0xFE00); 482 483 TestCode(data); 484} 485 486TEST_F(CodegenTest, CFG5) { 487 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 488 Instruction::CONST_4 | 0 | 0, 489 Instruction::IF_EQ, 3, 490 Instruction::GOTO | 0x100, 491 Instruction::RETURN_VOID); 492 493 TestCode(data); 494} 495 496TEST_F(CodegenTest, IntConstant) { 497 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 498 Instruction::CONST_4 | 0 | 0, 499 Instruction::RETURN_VOID); 500 501 TestCode(data); 502} 503 504TEST_F(CodegenTest, Return1) { 505 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 506 Instruction::CONST_4 | 0 | 0, 507 Instruction::RETURN | 0); 508 509 TestCode(data, true, 0); 510} 511 512TEST_F(CodegenTest, Return2) { 513 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 514 Instruction::CONST_4 | 0 | 0, 515 Instruction::CONST_4 | 0 | 1 << 8, 516 Instruction::RETURN | 1 << 8); 517 518 TestCode(data, true, 0); 519} 520 521TEST_F(CodegenTest, Return3) { 522 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 523 Instruction::CONST_4 | 0 | 0, 524 Instruction::CONST_4 | 1 << 8 | 1 << 12, 525 Instruction::RETURN | 1 << 8); 526 527 TestCode(data, true, 1); 528} 529 530TEST_F(CodegenTest, ReturnIf1) { 531 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 532 Instruction::CONST_4 | 0 | 0, 533 Instruction::CONST_4 | 1 << 8 | 1 << 12, 534 Instruction::IF_EQ, 3, 535 Instruction::RETURN | 0 << 8, 536 Instruction::RETURN | 1 << 8); 537 538 TestCode(data, true, 1); 539} 540 541TEST_F(CodegenTest, ReturnIf2) { 542 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 543 Instruction::CONST_4 | 0 | 0, 544 Instruction::CONST_4 | 1 << 8 | 1 << 12, 545 Instruction::IF_EQ | 0 << 4 | 1 << 8, 3, 546 Instruction::RETURN | 0 << 8, 547 Instruction::RETURN | 1 << 8); 548 549 TestCode(data, true, 0); 550} 551 552// Exercise bit-wise (one's complement) not-int instruction. 553#define NOT_INT_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \ 554TEST_F(CodegenTest, TEST_NAME) { \ 555 const int32_t input = INPUT; \ 556 const uint16_t input_lo = Low16Bits(input); \ 557 const uint16_t input_hi = High16Bits(input); \ 558 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( \ 559 Instruction::CONST | 0 << 8, input_lo, input_hi, \ 560 Instruction::NOT_INT | 1 << 8 | 0 << 12 , \ 561 Instruction::RETURN | 1 << 8); \ 562 \ 563 TestCode(data, true, EXPECTED_OUTPUT); \ 564} 565 566NOT_INT_TEST(ReturnNotIntMinus2, -2, 1) 567NOT_INT_TEST(ReturnNotIntMinus1, -1, 0) 568NOT_INT_TEST(ReturnNotInt0, 0, -1) 569NOT_INT_TEST(ReturnNotInt1, 1, -2) 570NOT_INT_TEST(ReturnNotIntINT32_MIN, -2147483648, 2147483647) // (2^31) - 1 571NOT_INT_TEST(ReturnNotIntINT32_MINPlus1, -2147483647, 2147483646) // (2^31) - 2 572NOT_INT_TEST(ReturnNotIntINT32_MAXMinus1, 2147483646, -2147483647) // -(2^31) - 1 573NOT_INT_TEST(ReturnNotIntINT32_MAX, 2147483647, -2147483648) // -(2^31) 574 575#undef NOT_INT_TEST 576 577// Exercise bit-wise (one's complement) not-long instruction. 578#define NOT_LONG_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \ 579TEST_F(CodegenTest, TEST_NAME) { \ 580 const int64_t input = INPUT; \ 581 const uint16_t word0 = Low16Bits(Low32Bits(input)); /* LSW. */ \ 582 const uint16_t word1 = High16Bits(Low32Bits(input)); \ 583 const uint16_t word2 = Low16Bits(High32Bits(input)); \ 584 const uint16_t word3 = High16Bits(High32Bits(input)); /* MSW. */ \ 585 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM( \ 586 Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3, \ 587 Instruction::NOT_LONG | 2 << 8 | 0 << 12, \ 588 Instruction::RETURN_WIDE | 2 << 8); \ 589 \ 590 TestCodeLong(data, true, EXPECTED_OUTPUT); \ 591} 592 593NOT_LONG_TEST(ReturnNotLongMinus2, INT64_C(-2), INT64_C(1)) 594NOT_LONG_TEST(ReturnNotLongMinus1, INT64_C(-1), INT64_C(0)) 595NOT_LONG_TEST(ReturnNotLong0, INT64_C(0), INT64_C(-1)) 596NOT_LONG_TEST(ReturnNotLong1, INT64_C(1), INT64_C(-2)) 597 598NOT_LONG_TEST(ReturnNotLongINT32_MIN, 599 INT64_C(-2147483648), 600 INT64_C(2147483647)) // (2^31) - 1 601NOT_LONG_TEST(ReturnNotLongINT32_MINPlus1, 602 INT64_C(-2147483647), 603 INT64_C(2147483646)) // (2^31) - 2 604NOT_LONG_TEST(ReturnNotLongINT32_MAXMinus1, 605 INT64_C(2147483646), 606 INT64_C(-2147483647)) // -(2^31) - 1 607NOT_LONG_TEST(ReturnNotLongINT32_MAX, 608 INT64_C(2147483647), 609 INT64_C(-2147483648)) // -(2^31) 610 611// Note that the C++ compiler won't accept 612// INT64_C(-9223372036854775808) (that is, INT64_MIN) as a valid 613// int64_t literal, so we use INT64_C(-9223372036854775807)-1 instead. 614NOT_LONG_TEST(ReturnNotINT64_MIN, 615 INT64_C(-9223372036854775807)-1, 616 INT64_C(9223372036854775807)); // (2^63) - 1 617NOT_LONG_TEST(ReturnNotINT64_MINPlus1, 618 INT64_C(-9223372036854775807), 619 INT64_C(9223372036854775806)); // (2^63) - 2 620NOT_LONG_TEST(ReturnNotLongINT64_MAXMinus1, 621 INT64_C(9223372036854775806), 622 INT64_C(-9223372036854775807)); // -(2^63) - 1 623NOT_LONG_TEST(ReturnNotLongINT64_MAX, 624 INT64_C(9223372036854775807), 625 INT64_C(-9223372036854775807)-1); // -(2^63) 626 627#undef NOT_LONG_TEST 628 629TEST_F(CodegenTest, IntToLongOfLongToInt) { 630 const int64_t input = INT64_C(4294967296); // 2^32 631 const uint16_t word0 = Low16Bits(Low32Bits(input)); // LSW. 632 const uint16_t word1 = High16Bits(Low32Bits(input)); 633 const uint16_t word2 = Low16Bits(High32Bits(input)); 634 const uint16_t word3 = High16Bits(High32Bits(input)); // MSW. 635 const uint16_t data[] = FIVE_REGISTERS_CODE_ITEM( 636 Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3, 637 Instruction::CONST_WIDE | 2 << 8, 1, 0, 0, 0, 638 Instruction::ADD_LONG | 0, 0 << 8 | 2, // v0 <- 2^32 + 1 639 Instruction::LONG_TO_INT | 4 << 8 | 0 << 12, 640 Instruction::INT_TO_LONG | 2 << 8 | 4 << 12, 641 Instruction::RETURN_WIDE | 2 << 8); 642 643 TestCodeLong(data, true, 1); 644} 645 646TEST_F(CodegenTest, ReturnAdd1) { 647 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 648 Instruction::CONST_4 | 3 << 12 | 0, 649 Instruction::CONST_4 | 4 << 12 | 1 << 8, 650 Instruction::ADD_INT, 1 << 8 | 0, 651 Instruction::RETURN); 652 653 TestCode(data, true, 7); 654} 655 656TEST_F(CodegenTest, ReturnAdd2) { 657 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 658 Instruction::CONST_4 | 3 << 12 | 0, 659 Instruction::CONST_4 | 4 << 12 | 1 << 8, 660 Instruction::ADD_INT_2ADDR | 1 << 12, 661 Instruction::RETURN); 662 663 TestCode(data, true, 7); 664} 665 666TEST_F(CodegenTest, ReturnAdd3) { 667 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 668 Instruction::CONST_4 | 4 << 12 | 0 << 8, 669 Instruction::ADD_INT_LIT8, 3 << 8 | 0, 670 Instruction::RETURN); 671 672 TestCode(data, true, 7); 673} 674 675TEST_F(CodegenTest, ReturnAdd4) { 676 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 677 Instruction::CONST_4 | 4 << 12 | 0 << 8, 678 Instruction::ADD_INT_LIT16, 3, 679 Instruction::RETURN); 680 681 TestCode(data, true, 7); 682} 683 684TEST_F(CodegenTest, ReturnMulInt) { 685 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 686 Instruction::CONST_4 | 3 << 12 | 0, 687 Instruction::CONST_4 | 4 << 12 | 1 << 8, 688 Instruction::MUL_INT, 1 << 8 | 0, 689 Instruction::RETURN); 690 691 TestCode(data, true, 12); 692} 693 694TEST_F(CodegenTest, ReturnMulInt2addr) { 695 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 696 Instruction::CONST_4 | 3 << 12 | 0, 697 Instruction::CONST_4 | 4 << 12 | 1 << 8, 698 Instruction::MUL_INT_2ADDR | 1 << 12, 699 Instruction::RETURN); 700 701 TestCode(data, true, 12); 702} 703 704TEST_F(CodegenTest, ReturnMulLong) { 705 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM( 706 Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0, 707 Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0, 708 Instruction::MUL_LONG, 2 << 8 | 0, 709 Instruction::RETURN_WIDE); 710 711 TestCodeLong(data, true, 12); 712} 713 714TEST_F(CodegenTest, ReturnMulLong2addr) { 715 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM( 716 Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0, 717 Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0, 718 Instruction::MUL_LONG_2ADDR | 2 << 12, 719 Instruction::RETURN_WIDE); 720 721 TestCodeLong(data, true, 12); 722} 723 724TEST_F(CodegenTest, ReturnMulIntLit8) { 725 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 726 Instruction::CONST_4 | 4 << 12 | 0 << 8, 727 Instruction::MUL_INT_LIT8, 3 << 8 | 0, 728 Instruction::RETURN); 729 730 TestCode(data, true, 12); 731} 732 733TEST_F(CodegenTest, ReturnMulIntLit16) { 734 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 735 Instruction::CONST_4 | 4 << 12 | 0 << 8, 736 Instruction::MUL_INT_LIT16, 3, 737 Instruction::RETURN); 738 739 TestCode(data, true, 12); 740} 741 742TEST_F(CodegenTest, NonMaterializedCondition) { 743 for (CodegenTargetConfig target_config : GetTargetConfigs()) { 744 ArenaPool pool; 745 ArenaAllocator allocator(&pool); 746 747 HGraph* graph = CreateGraph(&allocator); 748 749 HBasicBlock* entry = new (&allocator) HBasicBlock(graph); 750 graph->AddBlock(entry); 751 graph->SetEntryBlock(entry); 752 entry->AddInstruction(new (&allocator) HGoto()); 753 754 HBasicBlock* first_block = new (&allocator) HBasicBlock(graph); 755 graph->AddBlock(first_block); 756 entry->AddSuccessor(first_block); 757 HIntConstant* constant0 = graph->GetIntConstant(0); 758 HIntConstant* constant1 = graph->GetIntConstant(1); 759 HEqual* equal = new (&allocator) HEqual(constant0, constant0); 760 first_block->AddInstruction(equal); 761 first_block->AddInstruction(new (&allocator) HIf(equal)); 762 763 HBasicBlock* then_block = new (&allocator) HBasicBlock(graph); 764 HBasicBlock* else_block = new (&allocator) HBasicBlock(graph); 765 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph); 766 graph->SetExitBlock(exit_block); 767 768 graph->AddBlock(then_block); 769 graph->AddBlock(else_block); 770 graph->AddBlock(exit_block); 771 first_block->AddSuccessor(then_block); 772 first_block->AddSuccessor(else_block); 773 then_block->AddSuccessor(exit_block); 774 else_block->AddSuccessor(exit_block); 775 776 exit_block->AddInstruction(new (&allocator) HExit()); 777 then_block->AddInstruction(new (&allocator) HReturn(constant0)); 778 else_block->AddInstruction(new (&allocator) HReturn(constant1)); 779 780 ASSERT_FALSE(equal->IsEmittedAtUseSite()); 781 graph->BuildDominatorTree(); 782 PrepareForRegisterAllocation(graph).Run(); 783 ASSERT_TRUE(equal->IsEmittedAtUseSite()); 784 785 auto hook_before_codegen = [](HGraph* graph_in) { 786 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0]; 787 HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena()); 788 block->InsertInstructionBefore(move, block->GetLastInstruction()); 789 }; 790 791 RunCode(target_config, graph, hook_before_codegen, true, 0); 792 } 793} 794 795TEST_F(CodegenTest, MaterializedCondition1) { 796 for (CodegenTargetConfig target_config : GetTargetConfigs()) { 797 // Check that condition are materialized correctly. A materialized condition 798 // should yield `1` if it evaluated to true, and `0` otherwise. 799 // We force the materialization of comparisons for different combinations of 800 801 // inputs and check the results. 802 803 int lhs[] = {1, 2, -1, 2, 0xabc}; 804 int rhs[] = {2, 1, 2, -1, 0xabc}; 805 806 for (size_t i = 0; i < arraysize(lhs); i++) { 807 ArenaPool pool; 808 ArenaAllocator allocator(&pool); 809 HGraph* graph = CreateGraph(&allocator); 810 811 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph); 812 graph->AddBlock(entry_block); 813 graph->SetEntryBlock(entry_block); 814 entry_block->AddInstruction(new (&allocator) HGoto()); 815 HBasicBlock* code_block = new (&allocator) HBasicBlock(graph); 816 graph->AddBlock(code_block); 817 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph); 818 graph->AddBlock(exit_block); 819 exit_block->AddInstruction(new (&allocator) HExit()); 820 821 entry_block->AddSuccessor(code_block); 822 code_block->AddSuccessor(exit_block); 823 graph->SetExitBlock(exit_block); 824 825 HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]); 826 HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]); 827 HLessThan cmp_lt(cst_lhs, cst_rhs); 828 code_block->AddInstruction(&cmp_lt); 829 HReturn ret(&cmp_lt); 830 code_block->AddInstruction(&ret); 831 832 graph->BuildDominatorTree(); 833 auto hook_before_codegen = [](HGraph* graph_in) { 834 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0]; 835 HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena()); 836 block->InsertInstructionBefore(move, block->GetLastInstruction()); 837 }; 838 RunCode(target_config, graph, hook_before_codegen, true, lhs[i] < rhs[i]); 839 } 840 } 841} 842 843TEST_F(CodegenTest, MaterializedCondition2) { 844 for (CodegenTargetConfig target_config : GetTargetConfigs()) { 845 // Check that HIf correctly interprets a materialized condition. 846 // We force the materialization of comparisons for different combinations of 847 // inputs. An HIf takes the materialized combination as input and returns a 848 // value that we verify. 849 850 int lhs[] = {1, 2, -1, 2, 0xabc}; 851 int rhs[] = {2, 1, 2, -1, 0xabc}; 852 853 854 for (size_t i = 0; i < arraysize(lhs); i++) { 855 ArenaPool pool; 856 ArenaAllocator allocator(&pool); 857 HGraph* graph = CreateGraph(&allocator); 858 859 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph); 860 graph->AddBlock(entry_block); 861 graph->SetEntryBlock(entry_block); 862 entry_block->AddInstruction(new (&allocator) HGoto()); 863 864 HBasicBlock* if_block = new (&allocator) HBasicBlock(graph); 865 graph->AddBlock(if_block); 866 HBasicBlock* if_true_block = new (&allocator) HBasicBlock(graph); 867 graph->AddBlock(if_true_block); 868 HBasicBlock* if_false_block = new (&allocator) HBasicBlock(graph); 869 graph->AddBlock(if_false_block); 870 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph); 871 graph->AddBlock(exit_block); 872 exit_block->AddInstruction(new (&allocator) HExit()); 873 874 graph->SetEntryBlock(entry_block); 875 entry_block->AddSuccessor(if_block); 876 if_block->AddSuccessor(if_true_block); 877 if_block->AddSuccessor(if_false_block); 878 if_true_block->AddSuccessor(exit_block); 879 if_false_block->AddSuccessor(exit_block); 880 graph->SetExitBlock(exit_block); 881 882 HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]); 883 HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]); 884 HLessThan cmp_lt(cst_lhs, cst_rhs); 885 if_block->AddInstruction(&cmp_lt); 886 // We insert a dummy instruction to separate the HIf from the HLessThan 887 // and force the materialization of the condition. 888 HMemoryBarrier force_materialization(MemBarrierKind::kAnyAny, 0); 889 if_block->AddInstruction(&force_materialization); 890 HIf if_lt(&cmp_lt); 891 if_block->AddInstruction(&if_lt); 892 893 HIntConstant* cst_lt = graph->GetIntConstant(1); 894 HReturn ret_lt(cst_lt); 895 if_true_block->AddInstruction(&ret_lt); 896 HIntConstant* cst_ge = graph->GetIntConstant(0); 897 HReturn ret_ge(cst_ge); 898 if_false_block->AddInstruction(&ret_ge); 899 900 graph->BuildDominatorTree(); 901 auto hook_before_codegen = [](HGraph* graph_in) { 902 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0]; 903 HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena()); 904 block->InsertInstructionBefore(move, block->GetLastInstruction()); 905 }; 906 RunCode(target_config, graph, hook_before_codegen, true, lhs[i] < rhs[i]); 907 } 908 } 909} 910 911TEST_F(CodegenTest, ReturnDivIntLit8) { 912 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 913 Instruction::CONST_4 | 4 << 12 | 0 << 8, 914 Instruction::DIV_INT_LIT8, 3 << 8 | 0, 915 Instruction::RETURN); 916 917 TestCode(data, true, 1); 918} 919 920TEST_F(CodegenTest, ReturnDivInt2Addr) { 921 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 922 Instruction::CONST_4 | 4 << 12 | 0, 923 Instruction::CONST_4 | 2 << 12 | 1 << 8, 924 Instruction::DIV_INT_2ADDR | 1 << 12, 925 Instruction::RETURN); 926 927 TestCode(data, true, 2); 928} 929 930// Helper method. 931static void TestComparison(IfCondition condition, 932 int64_t i, 933 int64_t j, 934 Primitive::Type type, 935 const CodegenTargetConfig target_config) { 936 ArenaPool pool; 937 ArenaAllocator allocator(&pool); 938 HGraph* graph = CreateGraph(&allocator); 939 940 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph); 941 graph->AddBlock(entry_block); 942 graph->SetEntryBlock(entry_block); 943 entry_block->AddInstruction(new (&allocator) HGoto()); 944 945 HBasicBlock* block = new (&allocator) HBasicBlock(graph); 946 graph->AddBlock(block); 947 948 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph); 949 graph->AddBlock(exit_block); 950 graph->SetExitBlock(exit_block); 951 exit_block->AddInstruction(new (&allocator) HExit()); 952 953 entry_block->AddSuccessor(block); 954 block->AddSuccessor(exit_block); 955 956 HInstruction* op1; 957 HInstruction* op2; 958 if (type == Primitive::kPrimInt) { 959 op1 = graph->GetIntConstant(i); 960 op2 = graph->GetIntConstant(j); 961 } else { 962 DCHECK_EQ(type, Primitive::kPrimLong); 963 op1 = graph->GetLongConstant(i); 964 op2 = graph->GetLongConstant(j); 965 } 966 967 HInstruction* comparison = nullptr; 968 bool expected_result = false; 969 const uint64_t x = i; 970 const uint64_t y = j; 971 switch (condition) { 972 case kCondEQ: 973 comparison = new (&allocator) HEqual(op1, op2); 974 expected_result = (i == j); 975 break; 976 case kCondNE: 977 comparison = new (&allocator) HNotEqual(op1, op2); 978 expected_result = (i != j); 979 break; 980 case kCondLT: 981 comparison = new (&allocator) HLessThan(op1, op2); 982 expected_result = (i < j); 983 break; 984 case kCondLE: 985 comparison = new (&allocator) HLessThanOrEqual(op1, op2); 986 expected_result = (i <= j); 987 break; 988 case kCondGT: 989 comparison = new (&allocator) HGreaterThan(op1, op2); 990 expected_result = (i > j); 991 break; 992 case kCondGE: 993 comparison = new (&allocator) HGreaterThanOrEqual(op1, op2); 994 expected_result = (i >= j); 995 break; 996 case kCondB: 997 comparison = new (&allocator) HBelow(op1, op2); 998 expected_result = (x < y); 999 break; 1000 case kCondBE: 1001 comparison = new (&allocator) HBelowOrEqual(op1, op2); 1002 expected_result = (x <= y); 1003 break; 1004 case kCondA: 1005 comparison = new (&allocator) HAbove(op1, op2); 1006 expected_result = (x > y); 1007 break; 1008 case kCondAE: 1009 comparison = new (&allocator) HAboveOrEqual(op1, op2); 1010 expected_result = (x >= y); 1011 break; 1012 } 1013 block->AddInstruction(comparison); 1014 block->AddInstruction(new (&allocator) HReturn(comparison)); 1015 1016 graph->BuildDominatorTree(); 1017 RunCode(target_config, graph, [](HGraph*) {}, true, expected_result); 1018} 1019 1020TEST_F(CodegenTest, ComparisonsInt) { 1021 for (CodegenTargetConfig target_config : GetTargetConfigs()) { 1022 for (int64_t i = -1; i <= 1; i++) { 1023 for (int64_t j = -1; j <= 1; j++) { 1024 for (int cond = kCondFirst; cond <= kCondLast; cond++) { 1025 TestComparison(static_cast<IfCondition>(cond), i, j, Primitive::kPrimInt, target_config); 1026 } 1027 } 1028 } 1029 } 1030} 1031 1032TEST_F(CodegenTest, ComparisonsLong) { 1033 for (CodegenTargetConfig target_config : GetTargetConfigs()) { 1034 for (int64_t i = -1; i <= 1; i++) { 1035 for (int64_t j = -1; j <= 1; j++) { 1036 for (int cond = kCondFirst; cond <= kCondLast; cond++) { 1037 TestComparison(static_cast<IfCondition>(cond), i, j, Primitive::kPrimLong, target_config); 1038 } 1039 } 1040 } 1041 } 1042} 1043 1044#ifdef ART_ENABLE_CODEGEN_mips 1045TEST_F(CodegenTest, MipsClobberRA) { 1046 std::unique_ptr<const MipsInstructionSetFeatures> features_mips( 1047 MipsInstructionSetFeatures::FromCppDefines()); 1048 if (!CanExecute(kMips) || features_mips->IsR6()) { 1049 // HMipsComputeBaseMethodAddress and the NAL instruction behind it 1050 // should only be generated on non-R6. 1051 return; 1052 } 1053 1054 ArenaPool pool; 1055 ArenaAllocator allocator(&pool); 1056 HGraph* graph = CreateGraph(&allocator); 1057 1058 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph); 1059 graph->AddBlock(entry_block); 1060 graph->SetEntryBlock(entry_block); 1061 entry_block->AddInstruction(new (&allocator) HGoto()); 1062 1063 HBasicBlock* block = new (&allocator) HBasicBlock(graph); 1064 graph->AddBlock(block); 1065 1066 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph); 1067 graph->AddBlock(exit_block); 1068 graph->SetExitBlock(exit_block); 1069 exit_block->AddInstruction(new (&allocator) HExit()); 1070 1071 entry_block->AddSuccessor(block); 1072 block->AddSuccessor(exit_block); 1073 1074 // To simplify matters, don't create PC-relative HLoadClass or HLoadString. 1075 // Instead, generate HMipsComputeBaseMethodAddress directly. 1076 HMipsComputeBaseMethodAddress* base = new (&allocator) HMipsComputeBaseMethodAddress(); 1077 block->AddInstruction(base); 1078 // HMipsComputeBaseMethodAddress is defined as int, so just make the 1079 // compiled method return it. 1080 block->AddInstruction(new (&allocator) HReturn(base)); 1081 1082 graph->BuildDominatorTree(); 1083 1084 mips::CodeGeneratorMIPS codegenMIPS(graph, *features_mips.get(), CompilerOptions()); 1085 // Since there isn't HLoadClass or HLoadString, we need to manually indicate 1086 // that RA is clobbered and the method entry code should generate a stack frame 1087 // and preserve RA in it. And this is what we're testing here. 1088 codegenMIPS.ClobberRA(); 1089 // Without ClobberRA() the code would be: 1090 // nal # Sets RA to point to the jr instruction below 1091 // move v0, ra # and the CPU falls into an infinite loop. 1092 // jr ra 1093 // nop 1094 // The expected code is: 1095 // addiu sp, sp, -16 1096 // sw ra, 12(sp) 1097 // sw a0, 0(sp) 1098 // nal # Sets RA to point to the lw instruction below. 1099 // move v0, ra 1100 // lw ra, 12(sp) 1101 // jr ra 1102 // addiu sp, sp, 16 1103 RunCode(&codegenMIPS, graph, [](HGraph*) {}, false, 0); 1104} 1105#endif 1106 1107} // namespace art 1108