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