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