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