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