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