codegen_test.cc revision 3416601a9e9be81bb7494864287fd3602d18ef13
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 "base/macros.h" 22#include "builder.h" 23#include "code_generator_arm.h" 24#include "code_generator_arm64.h" 25#include "code_generator_x86.h" 26#include "code_generator_x86_64.h" 27#include "common_compiler_test.h" 28#include "dex_file.h" 29#include "dex_instruction.h" 30#include "nodes.h" 31#include "optimizing_unit_test.h" 32#include "prepare_for_register_allocation.h" 33#include "register_allocator.h" 34#include "ssa_liveness_analysis.h" 35#include "utils.h" 36 37#include "gtest/gtest.h" 38 39namespace art { 40 41class InternalCodeAllocator : public CodeAllocator { 42 public: 43 InternalCodeAllocator() : size_(0) { } 44 45 virtual uint8_t* Allocate(size_t size) { 46 size_ = size; 47 memory_.reset(new uint8_t[size]); 48 return memory_.get(); 49 } 50 51 size_t GetSize() const { return size_; } 52 uint8_t* GetMemory() const { return memory_.get(); } 53 54 private: 55 size_t size_; 56 std::unique_ptr<uint8_t[]> memory_; 57 58 DISALLOW_COPY_AND_ASSIGN(InternalCodeAllocator); 59}; 60 61template <typename Expected> 62static void Run(const InternalCodeAllocator& allocator, 63 const CodeGenerator& codegen, 64 bool has_result, 65 Expected expected) { 66 typedef Expected (*fptr)(); 67 CommonCompilerTest::MakeExecutable(allocator.GetMemory(), allocator.GetSize()); 68 fptr f = reinterpret_cast<fptr>(allocator.GetMemory()); 69 if (codegen.GetInstructionSet() == kThumb2) { 70 // For thumb we need the bottom bit set. 71 f = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(f) + 1); 72 } 73 Expected result = f(); 74 if (has_result) { 75 ASSERT_EQ(result, expected); 76 } 77} 78 79template <typename Expected> 80static void RunCodeBaseline(HGraph* graph, bool has_result, Expected expected) { 81 InternalCodeAllocator allocator; 82 83 x86::CodeGeneratorX86 codegenX86(graph); 84 // We avoid doing a stack overflow check that requires the runtime being setup, 85 // by making sure the compiler knows the methods we are running are leaf methods. 86 codegenX86.CompileBaseline(&allocator, true); 87 if (kRuntimeISA == kX86) { 88 Run(allocator, codegenX86, has_result, expected); 89 } 90 91 arm::CodeGeneratorARM codegenARM(graph, ArmInstructionSetFeatures::FromCppDefines()); 92 codegenARM.CompileBaseline(&allocator, true); 93 if (kRuntimeISA == kArm || kRuntimeISA == kThumb2) { 94 Run(allocator, codegenARM, has_result, expected); 95 } 96 97 x86_64::CodeGeneratorX86_64 codegenX86_64(graph); 98 codegenX86_64.CompileBaseline(&allocator, true); 99 if (kRuntimeISA == kX86_64) { 100 Run(allocator, codegenX86_64, has_result, expected); 101 } 102 103 arm64::CodeGeneratorARM64 codegenARM64(graph); 104 codegenARM64.CompileBaseline(&allocator, true); 105 if (kRuntimeISA == kArm64) { 106 Run(allocator, codegenARM64, has_result, expected); 107 } 108} 109 110template <typename Expected> 111static void RunCodeOptimized(CodeGenerator* codegen, 112 HGraph* graph, 113 std::function<void(HGraph*)> hook_before_codegen, 114 bool has_result, 115 Expected expected) { 116 SsaLivenessAnalysis liveness(*graph, codegen); 117 liveness.Analyze(); 118 119 RegisterAllocator register_allocator(graph->GetArena(), codegen, liveness); 120 register_allocator.AllocateRegisters(); 121 hook_before_codegen(graph); 122 123 InternalCodeAllocator allocator; 124 codegen->CompileOptimized(&allocator); 125 Run(allocator, *codegen, has_result, expected); 126} 127 128template <typename Expected> 129static void RunCodeOptimized(HGraph* graph, 130 std::function<void(HGraph*)> hook_before_codegen, 131 bool has_result, 132 Expected expected) { 133 if (kRuntimeISA == kArm || kRuntimeISA == kThumb2) { 134 arm::CodeGeneratorARM codegenARM(graph, ArmInstructionSetFeatures::FromCppDefines()); 135 RunCodeOptimized(&codegenARM, graph, hook_before_codegen, has_result, expected); 136 } else if (kRuntimeISA == kArm64) { 137 arm64::CodeGeneratorARM64 codegenARM64(graph); 138 RunCodeOptimized(&codegenARM64, graph, hook_before_codegen, has_result, expected); 139 } else if (kRuntimeISA == kX86) { 140 x86::CodeGeneratorX86 codegenX86(graph); 141 RunCodeOptimized(&codegenX86, graph, hook_before_codegen, has_result, expected); 142 } else if (kRuntimeISA == kX86_64) { 143 x86_64::CodeGeneratorX86_64 codegenX86_64(graph); 144 RunCodeOptimized(&codegenX86_64, graph, hook_before_codegen, has_result, expected); 145 } 146} 147 148static void TestCode(const uint16_t* data, bool has_result = false, int32_t expected = 0) { 149 ArenaPool pool; 150 ArenaAllocator arena(&pool); 151 HGraphBuilder builder(&arena); 152 const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data); 153 HGraph* graph = builder.BuildGraph(*item); 154 ASSERT_NE(graph, nullptr); 155 // Remove suspend checks, they cannot be executed in this context. 156 RemoveSuspendChecks(graph); 157 RunCodeBaseline(graph, has_result, expected); 158} 159 160static void TestCodeLong(const uint16_t* data, bool has_result, int64_t expected) { 161 ArenaPool pool; 162 ArenaAllocator arena(&pool); 163 HGraphBuilder builder(&arena, Primitive::kPrimLong); 164 const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data); 165 HGraph* graph = builder.BuildGraph(*item); 166 ASSERT_NE(graph, nullptr); 167 // Remove suspend checks, they cannot be executed in this context. 168 RemoveSuspendChecks(graph); 169 RunCodeBaseline(graph, has_result, expected); 170} 171 172TEST(CodegenTest, ReturnVoid) { 173 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(Instruction::RETURN_VOID); 174 TestCode(data); 175} 176 177TEST(CodegenTest, CFG1) { 178 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM( 179 Instruction::GOTO | 0x100, 180 Instruction::RETURN_VOID); 181 182 TestCode(data); 183} 184 185TEST(CodegenTest, CFG2) { 186 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM( 187 Instruction::GOTO | 0x100, 188 Instruction::GOTO | 0x100, 189 Instruction::RETURN_VOID); 190 191 TestCode(data); 192} 193 194TEST(CodegenTest, CFG3) { 195 const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM( 196 Instruction::GOTO | 0x200, 197 Instruction::RETURN_VOID, 198 Instruction::GOTO | 0xFF00); 199 200 TestCode(data1); 201 202 const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM( 203 Instruction::GOTO_16, 3, 204 Instruction::RETURN_VOID, 205 Instruction::GOTO_16, 0xFFFF); 206 207 TestCode(data2); 208 209 const uint16_t data3[] = ZERO_REGISTER_CODE_ITEM( 210 Instruction::GOTO_32, 4, 0, 211 Instruction::RETURN_VOID, 212 Instruction::GOTO_32, 0xFFFF, 0xFFFF); 213 214 TestCode(data3); 215} 216 217TEST(CodegenTest, CFG4) { 218 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM( 219 Instruction::RETURN_VOID, 220 Instruction::GOTO | 0x100, 221 Instruction::GOTO | 0xFE00); 222 223 TestCode(data); 224} 225 226TEST(CodegenTest, CFG5) { 227 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 228 Instruction::CONST_4 | 0 | 0, 229 Instruction::IF_EQ, 3, 230 Instruction::GOTO | 0x100, 231 Instruction::RETURN_VOID); 232 233 TestCode(data); 234} 235 236TEST(CodegenTest, IntConstant) { 237 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 238 Instruction::CONST_4 | 0 | 0, 239 Instruction::RETURN_VOID); 240 241 TestCode(data); 242} 243 244TEST(CodegenTest, Return1) { 245 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 246 Instruction::CONST_4 | 0 | 0, 247 Instruction::RETURN | 0); 248 249 TestCode(data, true, 0); 250} 251 252TEST(CodegenTest, Return2) { 253 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 254 Instruction::CONST_4 | 0 | 0, 255 Instruction::CONST_4 | 0 | 1 << 8, 256 Instruction::RETURN | 1 << 8); 257 258 TestCode(data, true, 0); 259} 260 261TEST(CodegenTest, Return3) { 262 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 263 Instruction::CONST_4 | 0 | 0, 264 Instruction::CONST_4 | 1 << 8 | 1 << 12, 265 Instruction::RETURN | 1 << 8); 266 267 TestCode(data, true, 1); 268} 269 270TEST(CodegenTest, ReturnIf1) { 271 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 272 Instruction::CONST_4 | 0 | 0, 273 Instruction::CONST_4 | 1 << 8 | 1 << 12, 274 Instruction::IF_EQ, 3, 275 Instruction::RETURN | 0 << 8, 276 Instruction::RETURN | 1 << 8); 277 278 TestCode(data, true, 1); 279} 280 281TEST(CodegenTest, ReturnIf2) { 282 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 283 Instruction::CONST_4 | 0 | 0, 284 Instruction::CONST_4 | 1 << 8 | 1 << 12, 285 Instruction::IF_EQ | 0 << 4 | 1 << 8, 3, 286 Instruction::RETURN | 0 << 8, 287 Instruction::RETURN | 1 << 8); 288 289 TestCode(data, true, 0); 290} 291 292// Exercise bit-wise (one's complement) not-int instruction. 293#define NOT_INT_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \ 294TEST(CodegenTest, TEST_NAME) { \ 295 const int32_t input = INPUT; \ 296 const uint16_t input_lo = Low16Bits(input); \ 297 const uint16_t input_hi = High16Bits(input); \ 298 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( \ 299 Instruction::CONST | 0 << 8, input_lo, input_hi, \ 300 Instruction::NOT_INT | 1 << 8 | 0 << 12 , \ 301 Instruction::RETURN | 1 << 8); \ 302 \ 303 TestCode(data, true, EXPECTED_OUTPUT); \ 304} 305 306NOT_INT_TEST(ReturnNotIntMinus2, -2, 1) 307NOT_INT_TEST(ReturnNotIntMinus1, -1, 0) 308NOT_INT_TEST(ReturnNotInt0, 0, -1) 309NOT_INT_TEST(ReturnNotInt1, 1, -2) 310NOT_INT_TEST(ReturnNotIntINT32_MIN, -2147483648, 2147483647) // (2^31) - 1 311NOT_INT_TEST(ReturnNotIntINT32_MINPlus1, -2147483647, 2147483646) // (2^31) - 2 312NOT_INT_TEST(ReturnNotIntINT32_MAXMinus1, 2147483646, -2147483647) // -(2^31) - 1 313NOT_INT_TEST(ReturnNotIntINT32_MAX, 2147483647, -2147483648) // -(2^31) 314 315#undef NOT_INT_TEST 316 317// Exercise bit-wise (one's complement) not-long instruction. 318#define NOT_LONG_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \ 319TEST(CodegenTest, TEST_NAME) { \ 320 const int64_t input = INPUT; \ 321 const uint16_t word0 = Low16Bits(Low32Bits(input)); /* LSW. */ \ 322 const uint16_t word1 = High16Bits(Low32Bits(input)); \ 323 const uint16_t word2 = Low16Bits(High32Bits(input)); \ 324 const uint16_t word3 = High16Bits(High32Bits(input)); /* MSW. */ \ 325 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM( \ 326 Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3, \ 327 Instruction::NOT_LONG | 2 << 8 | 0 << 12, \ 328 Instruction::RETURN_WIDE | 2 << 8); \ 329 \ 330 TestCodeLong(data, true, EXPECTED_OUTPUT); \ 331} 332 333NOT_LONG_TEST(ReturnNotLongMinus2, INT64_C(-2), INT64_C(1)) 334NOT_LONG_TEST(ReturnNotLongMinus1, INT64_C(-1), INT64_C(0)) 335NOT_LONG_TEST(ReturnNotLong0, INT64_C(0), INT64_C(-1)) 336NOT_LONG_TEST(ReturnNotLong1, INT64_C(1), INT64_C(-2)) 337 338NOT_LONG_TEST(ReturnNotLongINT32_MIN, 339 INT64_C(-2147483648), 340 INT64_C(2147483647)) // (2^31) - 1 341NOT_LONG_TEST(ReturnNotLongINT32_MINPlus1, 342 INT64_C(-2147483647), 343 INT64_C(2147483646)) // (2^31) - 2 344NOT_LONG_TEST(ReturnNotLongINT32_MAXMinus1, 345 INT64_C(2147483646), 346 INT64_C(-2147483647)) // -(2^31) - 1 347NOT_LONG_TEST(ReturnNotLongINT32_MAX, 348 INT64_C(2147483647), 349 INT64_C(-2147483648)) // -(2^31) 350 351// Note that the C++ compiler won't accept 352// INT64_C(-9223372036854775808) (that is, INT64_MIN) as a valid 353// int64_t literal, so we use INT64_C(-9223372036854775807)-1 instead. 354NOT_LONG_TEST(ReturnNotINT64_MIN, 355 INT64_C(-9223372036854775807)-1, 356 INT64_C(9223372036854775807)); // (2^63) - 1 357NOT_LONG_TEST(ReturnNotINT64_MINPlus1, 358 INT64_C(-9223372036854775807), 359 INT64_C(9223372036854775806)); // (2^63) - 2 360NOT_LONG_TEST(ReturnNotLongINT64_MAXMinus1, 361 INT64_C(9223372036854775806), 362 INT64_C(-9223372036854775807)); // -(2^63) - 1 363NOT_LONG_TEST(ReturnNotLongINT64_MAX, 364 INT64_C(9223372036854775807), 365 INT64_C(-9223372036854775807)-1); // -(2^63) 366 367#undef NOT_LONG_TEST 368 369TEST(CodegenTest, IntToLongOfLongToInt) { 370 const int64_t input = INT64_C(4294967296); // 2^32 371 const uint16_t word0 = Low16Bits(Low32Bits(input)); // LSW. 372 const uint16_t word1 = High16Bits(Low32Bits(input)); 373 const uint16_t word2 = Low16Bits(High32Bits(input)); 374 const uint16_t word3 = High16Bits(High32Bits(input)); // MSW. 375 const uint16_t data[] = FIVE_REGISTERS_CODE_ITEM( 376 Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3, 377 Instruction::CONST_WIDE | 2 << 8, 1, 0, 0, 0, 378 Instruction::ADD_LONG | 0, 0 << 8 | 2, // v0 <- 2^32 + 1 379 Instruction::LONG_TO_INT | 4 << 8 | 0 << 12, 380 Instruction::INT_TO_LONG | 2 << 8 | 4 << 12, 381 Instruction::RETURN_WIDE | 2 << 8); 382 383 TestCodeLong(data, true, 1); 384} 385 386TEST(CodegenTest, ReturnAdd1) { 387 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 388 Instruction::CONST_4 | 3 << 12 | 0, 389 Instruction::CONST_4 | 4 << 12 | 1 << 8, 390 Instruction::ADD_INT, 1 << 8 | 0, 391 Instruction::RETURN); 392 393 TestCode(data, true, 7); 394} 395 396TEST(CodegenTest, ReturnAdd2) { 397 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 398 Instruction::CONST_4 | 3 << 12 | 0, 399 Instruction::CONST_4 | 4 << 12 | 1 << 8, 400 Instruction::ADD_INT_2ADDR | 1 << 12, 401 Instruction::RETURN); 402 403 TestCode(data, true, 7); 404} 405 406TEST(CodegenTest, ReturnAdd3) { 407 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 408 Instruction::CONST_4 | 4 << 12 | 0 << 8, 409 Instruction::ADD_INT_LIT8, 3 << 8 | 0, 410 Instruction::RETURN); 411 412 TestCode(data, true, 7); 413} 414 415TEST(CodegenTest, ReturnAdd4) { 416 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 417 Instruction::CONST_4 | 4 << 12 | 0 << 8, 418 Instruction::ADD_INT_LIT16, 3, 419 Instruction::RETURN); 420 421 TestCode(data, true, 7); 422} 423 424TEST(CodegenTest, NonMaterializedCondition) { 425 ArenaPool pool; 426 ArenaAllocator allocator(&pool); 427 428 HGraph* graph = new (&allocator) HGraph(&allocator); 429 HBasicBlock* entry = new (&allocator) HBasicBlock(graph); 430 graph->AddBlock(entry); 431 graph->SetEntryBlock(entry); 432 entry->AddInstruction(new (&allocator) HGoto()); 433 434 HBasicBlock* first_block = new (&allocator) HBasicBlock(graph); 435 graph->AddBlock(first_block); 436 entry->AddSuccessor(first_block); 437 HIntConstant* constant0 = new (&allocator) HIntConstant(0); 438 entry->AddInstruction(constant0); 439 HIntConstant* constant1 = new (&allocator) HIntConstant(1); 440 entry->AddInstruction(constant1); 441 HEqual* equal = new (&allocator) HEqual(constant0, constant0); 442 first_block->AddInstruction(equal); 443 first_block->AddInstruction(new (&allocator) HIf(equal)); 444 445 HBasicBlock* then = new (&allocator) HBasicBlock(graph); 446 HBasicBlock* else_ = new (&allocator) HBasicBlock(graph); 447 HBasicBlock* exit = new (&allocator) HBasicBlock(graph); 448 449 graph->AddBlock(then); 450 graph->AddBlock(else_); 451 graph->AddBlock(exit); 452 first_block->AddSuccessor(then); 453 first_block->AddSuccessor(else_); 454 then->AddSuccessor(exit); 455 else_->AddSuccessor(exit); 456 457 exit->AddInstruction(new (&allocator) HExit()); 458 then->AddInstruction(new (&allocator) HReturn(constant0)); 459 else_->AddInstruction(new (&allocator) HReturn(constant1)); 460 461 ASSERT_TRUE(equal->NeedsMaterialization()); 462 graph->BuildDominatorTree(); 463 PrepareForRegisterAllocation(graph).Run(); 464 ASSERT_FALSE(equal->NeedsMaterialization()); 465 466 auto hook_before_codegen = [](HGraph* graph_in) { 467 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors().Get(0); 468 HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena()); 469 block->InsertInstructionBefore(move, block->GetLastInstruction()); 470 }; 471 472 RunCodeOptimized(graph, hook_before_codegen, true, 0); 473} 474 475#define MUL_TEST(TYPE, TEST_NAME) \ 476 TEST(CodegenTest, Return ## TEST_NAME) { \ 477 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( \ 478 Instruction::CONST_4 | 3 << 12 | 0, \ 479 Instruction::CONST_4 | 4 << 12 | 1 << 8, \ 480 Instruction::MUL_ ## TYPE, 1 << 8 | 0, \ 481 Instruction::RETURN); \ 482 \ 483 TestCode(data, true, 12); \ 484 } \ 485 \ 486 TEST(CodegenTest, Return ## TEST_NAME ## 2addr) { \ 487 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( \ 488 Instruction::CONST_4 | 3 << 12 | 0, \ 489 Instruction::CONST_4 | 4 << 12 | 1 << 8, \ 490 Instruction::MUL_ ## TYPE ## _2ADDR | 1 << 12, \ 491 Instruction::RETURN); \ 492 \ 493 TestCode(data, true, 12); \ 494 } 495 496MUL_TEST(INT, MulInt); 497MUL_TEST(LONG, MulLong); 498 499TEST(CodegenTest, ReturnMulIntLit8) { 500 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 501 Instruction::CONST_4 | 4 << 12 | 0 << 8, 502 Instruction::MUL_INT_LIT8, 3 << 8 | 0, 503 Instruction::RETURN); 504 505 TestCode(data, true, 12); 506} 507 508TEST(CodegenTest, ReturnMulIntLit16) { 509 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 510 Instruction::CONST_4 | 4 << 12 | 0 << 8, 511 Instruction::MUL_INT_LIT16, 3, 512 Instruction::RETURN); 513 514 TestCode(data, true, 12); 515} 516 517TEST(CodegenTest, MaterializedCondition1) { 518 // Check that condition are materialized correctly. A materialized condition 519 // should yield `1` if it evaluated to true, and `0` otherwise. 520 // We force the materialization of comparisons for different combinations of 521 // inputs and check the results. 522 523 int lhs[] = {1, 2, -1, 2, 0xabc}; 524 int rhs[] = {2, 1, 2, -1, 0xabc}; 525 526 for (size_t i = 0; i < arraysize(lhs); i++) { 527 ArenaPool pool; 528 ArenaAllocator allocator(&pool); 529 HGraph* graph = new (&allocator) HGraph(&allocator); 530 531 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph); 532 graph->AddBlock(entry_block); 533 graph->SetEntryBlock(entry_block); 534 entry_block->AddInstruction(new (&allocator) HGoto()); 535 HBasicBlock* code_block = new (&allocator) HBasicBlock(graph); 536 graph->AddBlock(code_block); 537 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph); 538 graph->AddBlock(exit_block); 539 exit_block->AddInstruction(new (&allocator) HExit()); 540 541 entry_block->AddSuccessor(code_block); 542 code_block->AddSuccessor(exit_block); 543 graph->SetExitBlock(exit_block); 544 545 HIntConstant cst_lhs(lhs[i]); 546 code_block->AddInstruction(&cst_lhs); 547 HIntConstant cst_rhs(rhs[i]); 548 code_block->AddInstruction(&cst_rhs); 549 HLessThan cmp_lt(&cst_lhs, &cst_rhs); 550 code_block->AddInstruction(&cmp_lt); 551 HReturn ret(&cmp_lt); 552 code_block->AddInstruction(&ret); 553 554 auto hook_before_codegen = [](HGraph* graph_in) { 555 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors().Get(0); 556 HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena()); 557 block->InsertInstructionBefore(move, block->GetLastInstruction()); 558 }; 559 560 RunCodeOptimized(graph, hook_before_codegen, true, lhs[i] < rhs[i]); 561 } 562} 563 564TEST(CodegenTest, MaterializedCondition2) { 565 // Check that HIf correctly interprets a materialized condition. 566 // We force the materialization of comparisons for different combinations of 567 // inputs. An HIf takes the materialized combination as input and returns a 568 // value that we verify. 569 570 int lhs[] = {1, 2, -1, 2, 0xabc}; 571 int rhs[] = {2, 1, 2, -1, 0xabc}; 572 573 574 for (size_t i = 0; i < arraysize(lhs); i++) { 575 ArenaPool pool; 576 ArenaAllocator allocator(&pool); 577 HGraph* graph = new (&allocator) HGraph(&allocator); 578 579 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph); 580 graph->AddBlock(entry_block); 581 graph->SetEntryBlock(entry_block); 582 entry_block->AddInstruction(new (&allocator) HGoto()); 583 584 HBasicBlock* if_block = new (&allocator) HBasicBlock(graph); 585 graph->AddBlock(if_block); 586 HBasicBlock* if_true_block = new (&allocator) HBasicBlock(graph); 587 graph->AddBlock(if_true_block); 588 HBasicBlock* if_false_block = new (&allocator) HBasicBlock(graph); 589 graph->AddBlock(if_false_block); 590 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph); 591 graph->AddBlock(exit_block); 592 exit_block->AddInstruction(new (&allocator) HExit()); 593 594 graph->SetEntryBlock(entry_block); 595 entry_block->AddSuccessor(if_block); 596 if_block->AddSuccessor(if_true_block); 597 if_block->AddSuccessor(if_false_block); 598 if_true_block->AddSuccessor(exit_block); 599 if_false_block->AddSuccessor(exit_block); 600 graph->SetExitBlock(exit_block); 601 602 HIntConstant cst_lhs(lhs[i]); 603 if_block->AddInstruction(&cst_lhs); 604 HIntConstant cst_rhs(rhs[i]); 605 if_block->AddInstruction(&cst_rhs); 606 HLessThan cmp_lt(&cst_lhs, &cst_rhs); 607 if_block->AddInstruction(&cmp_lt); 608 // We insert a temporary to separate the HIf from the HLessThan and force 609 // the materialization of the condition. 610 HTemporary force_materialization(0); 611 if_block->AddInstruction(&force_materialization); 612 HIf if_lt(&cmp_lt); 613 if_block->AddInstruction(&if_lt); 614 615 HIntConstant cst_lt(1); 616 if_true_block->AddInstruction(&cst_lt); 617 HReturn ret_lt(&cst_lt); 618 if_true_block->AddInstruction(&ret_lt); 619 HIntConstant cst_ge(0); 620 if_false_block->AddInstruction(&cst_ge); 621 HReturn ret_ge(&cst_ge); 622 if_false_block->AddInstruction(&ret_ge); 623 624 auto hook_before_codegen = [](HGraph* graph_in) { 625 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors().Get(0); 626 HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena()); 627 block->InsertInstructionBefore(move, block->GetLastInstruction()); 628 }; 629 630 RunCodeOptimized(graph, hook_before_codegen, true, lhs[i] < rhs[i]); 631 } 632} 633 634TEST(CodegenTest, ReturnDivIntLit8) { 635 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 636 Instruction::CONST_4 | 4 << 12 | 0 << 8, 637 Instruction::DIV_INT_LIT8, 3 << 8 | 0, 638 Instruction::RETURN); 639 640 TestCode(data, true, 1); 641} 642 643TEST(CodegenTest, ReturnDivInt2Addr) { 644 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 645 Instruction::CONST_4 | 4 << 12 | 0, 646 Instruction::CONST_4 | 2 << 12 | 1 << 8, 647 Instruction::DIV_INT_2ADDR | 1 << 12, 648 Instruction::RETURN); 649 650 TestCode(data, true, 2); 651} 652 653} // namespace art 654