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