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/x86/instruction_set_features_x86.h" 20 #include "code_generator_x86.h" 21 #include "constant_folding.h" 22 #include "dead_code_elimination.h" 23 #include "driver/compiler_options.h" 24 #include "graph_checker.h" 25 #include "optimizing_unit_test.h" 26 #include "pretty_printer.h" 27 28 #include "gtest/gtest.h" 29 30 namespace art { 31 32 /** 33 * Fixture class for the constant folding and dce tests. 34 */ 35 class ConstantFoldingTest : public CommonCompilerTest { 36 public: 37 ConstantFoldingTest() : pool_(), allocator_(&pool_) { 38 graph_ = CreateGraph(&allocator_); 39 } 40 41 void TestCode(const uint16_t* data, 42 const std::string& expected_before, 43 const std::string& expected_after_cf, 44 const std::string& expected_after_dce, 45 std::function<void(HGraph*)> check_after_cf, 46 Primitive::Type return_type = Primitive::kPrimInt) { 47 graph_ = CreateCFG(&allocator_, data, return_type); 48 TestCodeOnReadyGraph(expected_before, 49 expected_after_cf, 50 expected_after_dce, 51 check_after_cf); 52 } 53 54 void TestCodeOnReadyGraph(const std::string& expected_before, 55 const std::string& expected_after_cf, 56 const std::string& expected_after_dce, 57 std::function<void(HGraph*)> check_after_cf) { 58 ASSERT_NE(graph_, nullptr); 59 60 StringPrettyPrinter printer_before(graph_); 61 printer_before.VisitInsertionOrder(); 62 std::string actual_before = printer_before.str(); 63 EXPECT_EQ(expected_before, actual_before); 64 65 std::unique_ptr<const X86InstructionSetFeatures> features_x86( 66 X86InstructionSetFeatures::FromCppDefines()); 67 x86::CodeGeneratorX86 codegenX86(graph_, *features_x86.get(), CompilerOptions()); 68 HConstantFolding(graph_).Run(); 69 GraphChecker graph_checker_cf(graph_); 70 graph_checker_cf.Run(); 71 ASSERT_TRUE(graph_checker_cf.IsValid()); 72 73 StringPrettyPrinter printer_after_cf(graph_); 74 printer_after_cf.VisitInsertionOrder(); 75 std::string actual_after_cf = printer_after_cf.str(); 76 EXPECT_EQ(expected_after_cf, actual_after_cf); 77 78 check_after_cf(graph_); 79 80 HDeadCodeElimination(graph_).Run(); 81 GraphChecker graph_checker_dce(graph_); 82 graph_checker_dce.Run(); 83 ASSERT_TRUE(graph_checker_dce.IsValid()); 84 85 StringPrettyPrinter printer_after_dce(graph_); 86 printer_after_dce.VisitInsertionOrder(); 87 std::string actual_after_dce = printer_after_dce.str(); 88 EXPECT_EQ(expected_after_dce, actual_after_dce); 89 } 90 91 ArenaPool pool_; 92 ArenaAllocator allocator_; 93 HGraph* graph_; 94 }; 95 96 /** 97 * Tiny three-register program exercising int constant folding on negation. 98 * 99 * 16-bit 100 * offset 101 * ------ 102 * v0 <- 1 0. const/4 v0, #+1 103 * v1 <- -v0 1. neg-int v1, v0 104 * return v1 2. return v1 105 */ 106 TEST_F(ConstantFoldingTest, IntConstantFoldingNegation) { 107 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 108 Instruction::CONST_4 | 0 << 8 | 1 << 12, 109 Instruction::NEG_INT | 1 << 8 | 0 << 12, 110 Instruction::RETURN | 1 << 8); 111 112 std::string expected_before = 113 "BasicBlock 0, succ: 1\n" 114 " 2: IntConstant [3]\n" 115 " 0: SuspendCheck\n" 116 " 1: Goto 1\n" 117 "BasicBlock 1, pred: 0, succ: 2\n" 118 " 3: Neg(2) [4]\n" 119 " 4: Return(3)\n" 120 "BasicBlock 2, pred: 1\n" 121 " 5: Exit\n"; 122 123 // Expected difference after constant folding. 124 diff_t expected_cf_diff = { 125 { " 2: IntConstant [3]\n", " 2: IntConstant\n" 126 " 6: IntConstant [4]\n" }, 127 { " 3: Neg(2) [4]\n", removed }, 128 { " 4: Return(3)\n", " 4: Return(6)\n" } 129 }; 130 std::string expected_after_cf = Patch(expected_before, expected_cf_diff); 131 132 // Check the value of the computed constant. 133 auto check_after_cf = [](HGraph* graph) { 134 HInstruction* inst = graph->GetBlocks()[1]->GetFirstInstruction()->InputAt(0); 135 ASSERT_TRUE(inst->IsIntConstant()); 136 ASSERT_EQ(inst->AsIntConstant()->GetValue(), -1); 137 }; 138 139 // Expected difference after dead code elimination. 140 diff_t expected_dce_diff = { 141 { " 2: IntConstant\n", removed }, 142 }; 143 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff); 144 145 TestCode(data, 146 expected_before, 147 expected_after_cf, 148 expected_after_dce, 149 check_after_cf); 150 } 151 152 /** 153 * Tiny three-register program exercising long constant folding on negation. 154 * 155 * 16-bit 156 * offset 157 * ------ 158 * (v0, v1) <- 4294967296 0. const-wide v0 #+4294967296 159 * (v2, v3) <- -(v0, v1) 1. neg-long v2, v0 160 * return (v2, v3) 2. return-wide v2 161 */ 162 TEST_F(ConstantFoldingTest, LongConstantFoldingNegation) { 163 const int64_t input = INT64_C(4294967296); // 2^32 164 const uint16_t word0 = Low16Bits(Low32Bits(input)); // LSW. 165 const uint16_t word1 = High16Bits(Low32Bits(input)); 166 const uint16_t word2 = Low16Bits(High32Bits(input)); 167 const uint16_t word3 = High16Bits(High32Bits(input)); // MSW. 168 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM( 169 Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3, 170 Instruction::NEG_LONG | 2 << 8 | 0 << 12, 171 Instruction::RETURN_WIDE | 2 << 8); 172 173 std::string expected_before = 174 "BasicBlock 0, succ: 1\n" 175 " 2: LongConstant [3]\n" 176 " 0: SuspendCheck\n" 177 " 1: Goto 1\n" 178 "BasicBlock 1, pred: 0, succ: 2\n" 179 " 3: Neg(2) [4]\n" 180 " 4: Return(3)\n" 181 "BasicBlock 2, pred: 1\n" 182 " 5: Exit\n"; 183 184 // Expected difference after constant folding. 185 diff_t expected_cf_diff = { 186 { " 2: LongConstant [3]\n", " 2: LongConstant\n" 187 " 6: LongConstant [4]\n" }, 188 { " 3: Neg(2) [4]\n", removed }, 189 { " 4: Return(3)\n", " 4: Return(6)\n" } 190 }; 191 std::string expected_after_cf = Patch(expected_before, expected_cf_diff); 192 193 // Check the value of the computed constant. 194 auto check_after_cf = [](HGraph* graph) { 195 HInstruction* inst = graph->GetBlocks()[1]->GetFirstInstruction()->InputAt(0); 196 ASSERT_TRUE(inst->IsLongConstant()); 197 ASSERT_EQ(inst->AsLongConstant()->GetValue(), INT64_C(-4294967296)); 198 }; 199 200 // Expected difference after dead code elimination. 201 diff_t expected_dce_diff = { 202 { " 2: LongConstant\n", removed }, 203 }; 204 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff); 205 206 TestCode(data, 207 expected_before, 208 expected_after_cf, 209 expected_after_dce, 210 check_after_cf, 211 Primitive::kPrimLong); 212 } 213 214 /** 215 * Tiny three-register program exercising int constant folding on addition. 216 * 217 * 16-bit 218 * offset 219 * ------ 220 * v0 <- 1 0. const/4 v0, #+1 221 * v1 <- 2 1. const/4 v1, #+2 222 * v2 <- v0 + v1 2. add-int v2, v0, v1 223 * return v2 4. return v2 224 */ 225 TEST_F(ConstantFoldingTest, IntConstantFoldingOnAddition1) { 226 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM( 227 Instruction::CONST_4 | 0 << 8 | 1 << 12, 228 Instruction::CONST_4 | 1 << 8 | 2 << 12, 229 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8, 230 Instruction::RETURN | 2 << 8); 231 232 std::string expected_before = 233 "BasicBlock 0, succ: 1\n" 234 " 2: IntConstant [4]\n" 235 " 3: IntConstant [4]\n" 236 " 0: SuspendCheck\n" 237 " 1: Goto 1\n" 238 "BasicBlock 1, pred: 0, succ: 2\n" 239 " 4: Add(2, 3) [5]\n" 240 " 5: Return(4)\n" 241 "BasicBlock 2, pred: 1\n" 242 " 6: Exit\n"; 243 244 // Expected difference after constant folding. 245 diff_t expected_cf_diff = { 246 { " 2: IntConstant [4]\n", " 2: IntConstant\n" }, 247 { " 3: IntConstant [4]\n", " 3: IntConstant\n" 248 " 7: IntConstant [5]\n" }, 249 { " 4: Add(2, 3) [5]\n", removed }, 250 { " 5: Return(4)\n", " 5: Return(7)\n" } 251 }; 252 std::string expected_after_cf = Patch(expected_before, expected_cf_diff); 253 254 // Check the value of the computed constant. 255 auto check_after_cf = [](HGraph* graph) { 256 HInstruction* inst = graph->GetBlocks()[1]->GetFirstInstruction()->InputAt(0); 257 ASSERT_TRUE(inst->IsIntConstant()); 258 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 3); 259 }; 260 261 // Expected difference after dead code elimination. 262 diff_t expected_dce_diff = { 263 { " 2: IntConstant\n", removed }, 264 { " 3: IntConstant\n", removed } 265 }; 266 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff); 267 268 TestCode(data, 269 expected_before, 270 expected_after_cf, 271 expected_after_dce, 272 check_after_cf); 273 } 274 275 /** 276 * Small three-register program exercising int constant folding on addition. 277 * 278 * 16-bit 279 * offset 280 * ------ 281 * v0 <- 1 0. const/4 v0, #+1 282 * v1 <- 2 1. const/4 v1, #+2 283 * v0 <- v0 + v1 2. add-int/2addr v0, v1 284 * v1 <- 4 3. const/4 v1, #+4 285 * v2 <- 5 4. const/4 v2, #+5 286 * v1 <- v1 + v2 5. add-int/2addr v1, v2 287 * v2 <- v0 + v1 6. add-int v2, v0, v1 288 * return v2 8. return v2 289 */ 290 TEST_F(ConstantFoldingTest, IntConstantFoldingOnAddition2) { 291 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM( 292 Instruction::CONST_4 | 0 << 8 | 1 << 12, 293 Instruction::CONST_4 | 1 << 8 | 2 << 12, 294 Instruction::ADD_INT_2ADDR | 0 << 8 | 1 << 12, 295 Instruction::CONST_4 | 1 << 8 | 4 << 12, 296 Instruction::CONST_4 | 2 << 8 | 5 << 12, 297 Instruction::ADD_INT_2ADDR | 1 << 8 | 2 << 12, 298 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8, 299 Instruction::RETURN | 2 << 8); 300 301 std::string expected_before = 302 "BasicBlock 0, succ: 1\n" 303 " 2: IntConstant [4]\n" 304 " 3: IntConstant [4]\n" 305 " 5: IntConstant [7]\n" 306 " 6: IntConstant [7]\n" 307 " 0: SuspendCheck\n" 308 " 1: Goto 1\n" 309 "BasicBlock 1, pred: 0, succ: 2\n" 310 " 4: Add(2, 3) [8]\n" 311 " 7: Add(5, 6) [8]\n" 312 " 8: Add(4, 7) [9]\n" 313 " 9: Return(8)\n" 314 "BasicBlock 2, pred: 1\n" 315 " 10: Exit\n"; 316 317 // Expected difference after constant folding. 318 diff_t expected_cf_diff = { 319 { " 2: IntConstant [4]\n", " 2: IntConstant\n" }, 320 { " 3: IntConstant [4]\n", " 3: IntConstant\n" }, 321 { " 5: IntConstant [7]\n", " 5: IntConstant\n" }, 322 { " 6: IntConstant [7]\n", " 6: IntConstant\n" 323 " 11: IntConstant\n" 324 " 12: IntConstant\n" 325 " 13: IntConstant [9]\n" }, 326 { " 4: Add(2, 3) [8]\n", removed }, 327 { " 7: Add(5, 6) [8]\n", removed }, 328 { " 8: Add(4, 7) [9]\n", removed }, 329 { " 9: Return(8)\n", " 9: Return(13)\n" } 330 }; 331 std::string expected_after_cf = Patch(expected_before, expected_cf_diff); 332 333 // Check the values of the computed constants. 334 auto check_after_cf = [](HGraph* graph) { 335 HInstruction* inst1 = graph->GetBlocks()[1]->GetFirstInstruction()->InputAt(0); 336 ASSERT_TRUE(inst1->IsIntConstant()); 337 ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 12); 338 HInstruction* inst2 = inst1->GetPrevious(); 339 ASSERT_TRUE(inst2->IsIntConstant()); 340 ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 9); 341 HInstruction* inst3 = inst2->GetPrevious(); 342 ASSERT_TRUE(inst3->IsIntConstant()); 343 ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 3); 344 }; 345 346 // Expected difference after dead code elimination. 347 diff_t expected_dce_diff = { 348 { " 2: IntConstant\n", removed }, 349 { " 3: IntConstant\n", removed }, 350 { " 5: IntConstant\n", removed }, 351 { " 6: IntConstant\n", removed }, 352 { " 11: IntConstant\n", removed }, 353 { " 12: IntConstant\n", removed } 354 }; 355 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff); 356 357 TestCode(data, 358 expected_before, 359 expected_after_cf, 360 expected_after_dce, 361 check_after_cf); 362 } 363 364 /** 365 * Tiny three-register program exercising int constant folding on subtraction. 366 * 367 * 16-bit 368 * offset 369 * ------ 370 * v0 <- 3 0. const/4 v0, #+3 371 * v1 <- 2 1. const/4 v1, #+2 372 * v2 <- v0 - v1 2. sub-int v2, v0, v1 373 * return v2 4. return v2 374 */ 375 TEST_F(ConstantFoldingTest, IntConstantFoldingOnSubtraction) { 376 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM( 377 Instruction::CONST_4 | 0 << 8 | 3 << 12, 378 Instruction::CONST_4 | 1 << 8 | 2 << 12, 379 Instruction::SUB_INT | 2 << 8, 0 | 1 << 8, 380 Instruction::RETURN | 2 << 8); 381 382 std::string expected_before = 383 "BasicBlock 0, succ: 1\n" 384 " 2: IntConstant [4]\n" 385 " 3: IntConstant [4]\n" 386 " 0: SuspendCheck\n" 387 " 1: Goto 1\n" 388 "BasicBlock 1, pred: 0, succ: 2\n" 389 " 4: Sub(2, 3) [5]\n" 390 " 5: Return(4)\n" 391 "BasicBlock 2, pred: 1\n" 392 " 6: Exit\n"; 393 394 // Expected difference after constant folding. 395 diff_t expected_cf_diff = { 396 { " 2: IntConstant [4]\n", " 2: IntConstant\n" }, 397 { " 3: IntConstant [4]\n", " 3: IntConstant\n" 398 " 7: IntConstant [5]\n" }, 399 { " 4: Sub(2, 3) [5]\n", removed }, 400 { " 5: Return(4)\n", " 5: Return(7)\n" } 401 }; 402 std::string expected_after_cf = Patch(expected_before, expected_cf_diff); 403 404 // Check the value of the computed constant. 405 auto check_after_cf = [](HGraph* graph) { 406 HInstruction* inst = graph->GetBlocks()[1]->GetFirstInstruction()->InputAt(0); 407 ASSERT_TRUE(inst->IsIntConstant()); 408 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1); 409 }; 410 411 // Expected difference after dead code elimination. 412 diff_t expected_dce_diff = { 413 { " 2: IntConstant\n", removed }, 414 { " 3: IntConstant\n", removed } 415 }; 416 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff); 417 418 TestCode(data, 419 expected_before, 420 expected_after_cf, 421 expected_after_dce, 422 check_after_cf); 423 } 424 425 /** 426 * Tiny three-register-pair program exercising long constant folding 427 * on addition. 428 * 429 * 16-bit 430 * offset 431 * ------ 432 * (v0, v1) <- 1 0. const-wide/16 v0, #+1 433 * (v2, v3) <- 2 2. const-wide/16 v2, #+2 434 * (v4, v5) <- 435 * (v0, v1) + (v1, v2) 4. add-long v4, v0, v2 436 * return (v4, v5) 6. return-wide v4 437 */ 438 TEST_F(ConstantFoldingTest, LongConstantFoldingOnAddition) { 439 const uint16_t data[] = SIX_REGISTERS_CODE_ITEM( 440 Instruction::CONST_WIDE_16 | 0 << 8, 1, 441 Instruction::CONST_WIDE_16 | 2 << 8, 2, 442 Instruction::ADD_LONG | 4 << 8, 0 | 2 << 8, 443 Instruction::RETURN_WIDE | 4 << 8); 444 445 std::string expected_before = 446 "BasicBlock 0, succ: 1\n" 447 " 2: LongConstant [4]\n" 448 " 3: LongConstant [4]\n" 449 " 0: SuspendCheck\n" 450 " 1: Goto 1\n" 451 "BasicBlock 1, pred: 0, succ: 2\n" 452 " 4: Add(2, 3) [5]\n" 453 " 5: Return(4)\n" 454 "BasicBlock 2, pred: 1\n" 455 " 6: Exit\n"; 456 457 // Expected difference after constant folding. 458 diff_t expected_cf_diff = { 459 { " 2: LongConstant [4]\n", " 2: LongConstant\n" }, 460 { " 3: LongConstant [4]\n", " 3: LongConstant\n" 461 " 7: LongConstant [5]\n" }, 462 { " 4: Add(2, 3) [5]\n", removed }, 463 { " 5: Return(4)\n", " 5: Return(7)\n" } 464 }; 465 std::string expected_after_cf = Patch(expected_before, expected_cf_diff); 466 467 // Check the value of the computed constant. 468 auto check_after_cf = [](HGraph* graph) { 469 HInstruction* inst = graph->GetBlocks()[1]->GetFirstInstruction()->InputAt(0); 470 ASSERT_TRUE(inst->IsLongConstant()); 471 ASSERT_EQ(inst->AsLongConstant()->GetValue(), 3); 472 }; 473 474 // Expected difference after dead code elimination. 475 diff_t expected_dce_diff = { 476 { " 2: LongConstant\n", removed }, 477 { " 3: LongConstant\n", removed } 478 }; 479 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff); 480 481 TestCode(data, 482 expected_before, 483 expected_after_cf, 484 expected_after_dce, 485 check_after_cf, 486 Primitive::kPrimLong); 487 } 488 489 /** 490 * Tiny three-register-pair program exercising long constant folding 491 * on subtraction. 492 * 493 * 16-bit 494 * offset 495 * ------ 496 * (v0, v1) <- 3 0. const-wide/16 v0, #+3 497 * (v2, v3) <- 2 2. const-wide/16 v2, #+2 498 * (v4, v5) <- 499 * (v0, v1) - (v1, v2) 4. sub-long v4, v0, v2 500 * return (v4, v5) 6. return-wide v4 501 */ 502 TEST_F(ConstantFoldingTest, LongConstantFoldingOnSubtraction) { 503 const uint16_t data[] = SIX_REGISTERS_CODE_ITEM( 504 Instruction::CONST_WIDE_16 | 0 << 8, 3, 505 Instruction::CONST_WIDE_16 | 2 << 8, 2, 506 Instruction::SUB_LONG | 4 << 8, 0 | 2 << 8, 507 Instruction::RETURN_WIDE | 4 << 8); 508 509 std::string expected_before = 510 "BasicBlock 0, succ: 1\n" 511 " 2: LongConstant [4]\n" 512 " 3: LongConstant [4]\n" 513 " 0: SuspendCheck\n" 514 " 1: Goto 1\n" 515 "BasicBlock 1, pred: 0, succ: 2\n" 516 " 4: Sub(2, 3) [5]\n" 517 " 5: Return(4)\n" 518 "BasicBlock 2, pred: 1\n" 519 " 6: Exit\n"; 520 521 // Expected difference after constant folding. 522 diff_t expected_cf_diff = { 523 { " 2: LongConstant [4]\n", " 2: LongConstant\n" }, 524 { " 3: LongConstant [4]\n", " 3: LongConstant\n" 525 " 7: LongConstant [5]\n" }, 526 { " 4: Sub(2, 3) [5]\n", removed }, 527 { " 5: Return(4)\n", " 5: Return(7)\n" } 528 }; 529 std::string expected_after_cf = Patch(expected_before, expected_cf_diff); 530 531 // Check the value of the computed constant. 532 auto check_after_cf = [](HGraph* graph) { 533 HInstruction* inst = graph->GetBlocks()[1]->GetFirstInstruction()->InputAt(0); 534 ASSERT_TRUE(inst->IsLongConstant()); 535 ASSERT_EQ(inst->AsLongConstant()->GetValue(), 1); 536 }; 537 538 // Expected difference after dead code elimination. 539 diff_t expected_dce_diff = { 540 { " 2: LongConstant\n", removed }, 541 { " 3: LongConstant\n", removed } 542 }; 543 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff); 544 545 TestCode(data, 546 expected_before, 547 expected_after_cf, 548 expected_after_dce, 549 check_after_cf, 550 Primitive::kPrimLong); 551 } 552 553 /** 554 * Three-register program with jumps leading to the creation of many 555 * blocks. 556 * 557 * The intent of this test is to ensure that all constant expressions 558 * are actually evaluated at compile-time, thanks to the reverse 559 * (forward) post-order traversal of the the dominator tree. 560 * 561 * 16-bit 562 * offset 563 * ------ 564 * v0 <- 1 0. const/4 v0, #+1 565 * v1 <- 2 1. const/4 v1, #+2 566 * v2 <- v0 + v1 2. add-int v2, v0, v1 567 * goto L2 4. goto +4 568 * L1: v1 <- v0 + 5 5. add-int/lit16 v1, v0, #+5 569 * goto L3 7. goto +4 570 * L2: v0 <- v2 + 4 8. add-int/lit16 v0, v2, #+4 571 * goto L1 10. goto +(-5) 572 * L3: v2 <- v1 + 8 11. add-int/lit16 v2, v1, #+8 573 * return v2 13. return v2 574 */ 575 TEST_F(ConstantFoldingTest, IntConstantFoldingAndJumps) { 576 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM( 577 Instruction::CONST_4 | 0 << 8 | 1 << 12, 578 Instruction::CONST_4 | 1 << 8 | 2 << 12, 579 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8, 580 Instruction::GOTO | 4 << 8, 581 Instruction::ADD_INT_LIT16 | 1 << 8 | 0 << 12, 5, 582 Instruction::GOTO | 4 << 8, 583 Instruction::ADD_INT_LIT16 | 0 << 8 | 2 << 12, 4, 584 static_cast<uint16_t>(Instruction::GOTO | 0xFFFFFFFB << 8), 585 Instruction::ADD_INT_LIT16 | 2 << 8 | 1 << 12, 8, 586 Instruction::RETURN | 2 << 8); 587 588 std::string expected_before = 589 "BasicBlock 0, succ: 1\n" 590 " 2: IntConstant [4]\n" // v0 <- 1 591 " 3: IntConstant [4]\n" // v1 <- 2 592 " 6: IntConstant [7]\n" // const 5 593 " 9: IntConstant [10]\n" // const 4 594 " 12: IntConstant [13]\n" // const 8 595 " 0: SuspendCheck\n" 596 " 1: Goto 1\n" 597 "BasicBlock 1, pred: 0, succ: 3\n" 598 " 4: Add(2, 3) [7]\n" // v2 <- v0 + v1 = 1 + 2 = 3 599 " 5: Goto 3\n" // goto L2 600 "BasicBlock 2, pred: 3, succ: 4\n" // L1: 601 " 10: Add(7, 9) [13]\n" // v1 <- v0 + 3 = 7 + 5 = 12 602 " 11: Goto 4\n" // goto L3 603 "BasicBlock 3, pred: 1, succ: 2\n" // L2: 604 " 7: Add(4, 6) [10]\n" // v0 <- v2 + 2 = 3 + 4 = 7 605 " 8: Goto 2\n" // goto L1 606 "BasicBlock 4, pred: 2, succ: 5\n" // L3: 607 " 13: Add(10, 12) [14]\n" // v2 <- v1 + 4 = 12 + 8 = 20 608 " 14: Return(13)\n" // return v2 609 "BasicBlock 5, pred: 4\n" 610 " 15: Exit\n"; 611 612 // Expected difference after constant folding. 613 diff_t expected_cf_diff = { 614 { " 2: IntConstant [4]\n", " 2: IntConstant\n" }, 615 { " 3: IntConstant [4]\n", " 3: IntConstant\n" }, 616 { " 6: IntConstant [7]\n", " 6: IntConstant\n" }, 617 { " 9: IntConstant [10]\n", " 9: IntConstant\n" }, 618 { " 12: IntConstant [13]\n", " 12: IntConstant\n" 619 " 16: IntConstant\n" 620 " 17: IntConstant\n" 621 " 18: IntConstant\n" 622 " 19: IntConstant [14]\n" }, 623 { " 4: Add(2, 3) [7]\n", removed }, 624 { " 10: Add(7, 9) [13]\n", removed }, 625 { " 7: Add(4, 6) [10]\n", removed }, 626 { " 13: Add(10, 12) [14]\n", removed }, 627 { " 14: Return(13)\n", " 14: Return(19)\n"} 628 }; 629 std::string expected_after_cf = Patch(expected_before, expected_cf_diff); 630 631 // Check the values of the computed constants. 632 auto check_after_cf = [](HGraph* graph) { 633 HInstruction* inst1 = graph->GetBlocks()[4]->GetFirstInstruction()->InputAt(0); 634 ASSERT_TRUE(inst1->IsIntConstant()); 635 ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 20); 636 HInstruction* inst2 = inst1->GetPrevious(); 637 ASSERT_TRUE(inst2->IsIntConstant()); 638 ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 12); 639 HInstruction* inst3 = inst2->GetPrevious(); 640 ASSERT_TRUE(inst3->IsIntConstant()); 641 ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 7); 642 HInstruction* inst4 = inst3->GetPrevious(); 643 ASSERT_TRUE(inst4->IsIntConstant()); 644 ASSERT_EQ(inst4->AsIntConstant()->GetValue(), 3); 645 }; 646 647 // Expected difference after dead code elimination. 648 std::string expected_after_dce = 649 "BasicBlock 0, succ: 1\n" 650 " 19: IntConstant [14]\n" 651 " 0: SuspendCheck\n" 652 " 1: Goto 1\n" 653 "BasicBlock 1, pred: 0, succ: 5\n" 654 " 14: Return(19)\n" 655 "BasicBlock 5, pred: 1\n" 656 " 15: Exit\n"; 657 658 TestCode(data, 659 expected_before, 660 expected_after_cf, 661 expected_after_dce, 662 check_after_cf); 663 } 664 665 /** 666 * Three-register program with a constant (static) condition. 667 * 668 * 16-bit 669 * offset 670 * ------ 671 * v1 <- 1 0. const/4 v1, #+1 672 * v0 <- 0 1. const/4 v0, #+0 673 * if v1 >= 0 goto L1 2. if-gez v1, +3 674 * v0 <- v1 4. move v0, v1 675 * L1: v2 <- v0 + v1 5. add-int v2, v0, v1 676 * return-void 7. return 677 */ 678 TEST_F(ConstantFoldingTest, ConstantCondition) { 679 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM( 680 Instruction::CONST_4 | 1 << 8 | 1 << 12, 681 Instruction::CONST_4 | 0 << 8 | 0 << 12, 682 Instruction::IF_GEZ | 1 << 8, 3, 683 Instruction::MOVE | 0 << 8 | 1 << 12, 684 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8, 685 Instruction::RETURN_VOID); 686 687 std::string expected_before = 688 "BasicBlock 0, succ: 1\n" 689 " 3: IntConstant [9, 8, 5]\n" 690 " 4: IntConstant [8, 5]\n" 691 " 1: SuspendCheck\n" 692 " 2: Goto 1\n" 693 "BasicBlock 1, pred: 0, succ: 5, 2\n" 694 " 5: GreaterThanOrEqual(3, 4) [6]\n" 695 " 6: If(5)\n" 696 "BasicBlock 2, pred: 1, succ: 3\n" 697 " 7: Goto 3\n" 698 "BasicBlock 3, pred: 5, 2, succ: 4\n" 699 " 8: Phi(4, 3) [9]\n" 700 " 9: Add(8, 3)\n" 701 " 10: ReturnVoid\n" 702 "BasicBlock 4, pred: 3\n" 703 " 11: Exit\n" 704 "BasicBlock 5, pred: 1, succ: 3\n" 705 " 0: Goto 3\n"; 706 707 // Expected difference after constant folding. 708 diff_t expected_cf_diff = { 709 { " 3: IntConstant [9, 8, 5]\n", " 3: IntConstant [6, 9, 8]\n" }, 710 { " 4: IntConstant [8, 5]\n", " 4: IntConstant [8]\n" }, 711 { " 5: GreaterThanOrEqual(3, 4) [6]\n", removed }, 712 { " 6: If(5)\n", " 6: If(3)\n" } 713 }; 714 std::string expected_after_cf = Patch(expected_before, expected_cf_diff); 715 716 // Check the values of the computed constants. 717 auto check_after_cf = [](HGraph* graph) { 718 HInstruction* inst = graph->GetBlocks()[1]->GetFirstInstruction()->InputAt(0); 719 ASSERT_TRUE(inst->IsIntConstant()); 720 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1); 721 }; 722 723 // Expected graph after dead code elimination. 724 std::string expected_after_dce = 725 "BasicBlock 0, succ: 1\n" 726 " 1: SuspendCheck\n" 727 " 2: Goto 1\n" 728 "BasicBlock 1, pred: 0, succ: 4\n" 729 " 10: ReturnVoid\n" 730 "BasicBlock 4, pred: 1\n" 731 " 11: Exit\n"; 732 733 TestCode(data, 734 expected_before, 735 expected_after_cf, 736 expected_after_dce, 737 check_after_cf); 738 } 739 740 /** 741 * Unsigned comparisons with zero. Since these instructions are not present 742 * in the bytecode, we need to set up the graph explicitly. 743 */ 744 TEST_F(ConstantFoldingTest, UnsignedComparisonsWithZero) { 745 graph_ = CreateGraph(&allocator_); 746 HBasicBlock* entry_block = new (&allocator_) HBasicBlock(graph_); 747 graph_->AddBlock(entry_block); 748 graph_->SetEntryBlock(entry_block); 749 HBasicBlock* block = new (&allocator_) HBasicBlock(graph_); 750 graph_->AddBlock(block); 751 HBasicBlock* exit_block = new (&allocator_) HBasicBlock(graph_); 752 graph_->AddBlock(exit_block); 753 graph_->SetExitBlock(exit_block); 754 entry_block->AddSuccessor(block); 755 block->AddSuccessor(exit_block); 756 757 // Make various unsigned comparisons with zero against a parameter. 758 HInstruction* parameter = new (&allocator_) HParameterValue( 759 graph_->GetDexFile(), 0, 0, Primitive::kPrimInt, true); 760 entry_block->AddInstruction(parameter); 761 entry_block->AddInstruction(new (&allocator_) HGoto()); 762 763 HInstruction* zero = graph_->GetIntConstant(0); 764 765 HInstruction* last; 766 block->AddInstruction(last = new (&allocator_) HAbove(zero, parameter)); 767 block->AddInstruction(new (&allocator_) HSelect(last, parameter, parameter, 0)); 768 block->AddInstruction(last = new (&allocator_) HAbove(parameter, zero)); 769 block->AddInstruction(new (&allocator_) HSelect(last, parameter, parameter, 0)); 770 block->AddInstruction(last = new (&allocator_) HAboveOrEqual(zero, parameter)); 771 block->AddInstruction(new (&allocator_) HSelect(last, parameter, parameter, 0)); 772 block->AddInstruction(last = new (&allocator_) HAboveOrEqual(parameter, zero)); 773 block->AddInstruction(new (&allocator_) HSelect(last, parameter, parameter, 0)); 774 block->AddInstruction(last = new (&allocator_) HBelow(zero, parameter)); 775 block->AddInstruction(new (&allocator_) HSelect(last, parameter, parameter, 0)); 776 block->AddInstruction(last = new (&allocator_) HBelow(parameter, zero)); 777 block->AddInstruction(new (&allocator_) HSelect(last, parameter, parameter, 0)); 778 block->AddInstruction(last = new (&allocator_) HBelowOrEqual(zero, parameter)); 779 block->AddInstruction(new (&allocator_) HSelect(last, parameter, parameter, 0)); 780 block->AddInstruction(last = new (&allocator_) HBelowOrEqual(parameter, zero)); 781 block->AddInstruction(new (&allocator_) HSelect(last, parameter, parameter, 0)); 782 block->AddInstruction(new (&allocator_) HReturn(zero)); 783 784 exit_block->AddInstruction(new (&allocator_) HExit()); 785 786 graph_->BuildDominatorTree(); 787 788 const std::string expected_before = 789 "BasicBlock 0, succ: 1\n" 790 " 0: ParameterValue [18, 18, 17, 16, 16, 15, 14, 14, 13, 12, 12, 11, 10, 10, 9, " 791 "8, 8, 7, 6, 6, 5, 4, 4, 3]\n" 792 " 2: IntConstant [19, 17, 15, 13, 11, 9, 7, 5, 3]\n" 793 " 1: Goto 1\n" 794 "BasicBlock 1, pred: 0, succ: 2\n" 795 " 3: Above(2, 0) [4]\n" 796 " 4: Select(0, 0, 3)\n" 797 " 5: Above(0, 2) [6]\n" 798 " 6: Select(0, 0, 5)\n" 799 " 7: AboveOrEqual(2, 0) [8]\n" 800 " 8: Select(0, 0, 7)\n" 801 " 9: AboveOrEqual(0, 2) [10]\n" 802 " 10: Select(0, 0, 9)\n" 803 " 11: Below(2, 0) [12]\n" 804 " 12: Select(0, 0, 11)\n" 805 " 13: Below(0, 2) [14]\n" 806 " 14: Select(0, 0, 13)\n" 807 " 15: BelowOrEqual(2, 0) [16]\n" 808 " 16: Select(0, 0, 15)\n" 809 " 17: BelowOrEqual(0, 2) [18]\n" 810 " 18: Select(0, 0, 17)\n" 811 " 19: Return(2)\n" 812 "BasicBlock 2, pred: 1\n" 813 " 20: Exit\n"; 814 815 const std::string expected_after_cf = 816 "BasicBlock 0, succ: 1\n" 817 " 0: ParameterValue [18, 18, 17, 16, 16, 14, 14, 12, 12, 11, 10, 10, " 818 "8, 8, 7, 6, 6, 5, 4, 4]\n" 819 " 2: IntConstant [14, 4, 19, 17, 11, 7, 5]\n" 820 " 21: IntConstant [16, 10]\n" 821 " 1: Goto 1\n" 822 "BasicBlock 1, pred: 0, succ: 2\n" 823 " 4: Select(0, 0, 2)\n" 824 " 5: Above(0, 2) [6]\n" 825 " 6: Select(0, 0, 5)\n" 826 " 7: AboveOrEqual(2, 0) [8]\n" 827 " 8: Select(0, 0, 7)\n" 828 " 10: Select(0, 0, 21)\n" 829 " 11: Below(2, 0) [12]\n" 830 " 12: Select(0, 0, 11)\n" 831 " 14: Select(0, 0, 2)\n" 832 " 16: Select(0, 0, 21)\n" 833 " 17: BelowOrEqual(0, 2) [18]\n" 834 " 18: Select(0, 0, 17)\n" 835 " 19: Return(2)\n" 836 "BasicBlock 2, pred: 1\n" 837 " 20: Exit\n"; 838 839 const std::string expected_after_dce = 840 "BasicBlock 0, succ: 1\n" 841 " 0: ParameterValue\n" 842 " 2: IntConstant [19]\n" 843 " 1: Goto 1\n" 844 "BasicBlock 1, pred: 0, succ: 2\n" 845 " 19: Return(2)\n" 846 "BasicBlock 2, pred: 1\n" 847 " 20: Exit\n"; 848 849 auto check_after_cf = [](HGraph* graph) { 850 CHECK(graph != nullptr); 851 }; 852 853 TestCodeOnReadyGraph(expected_before, 854 expected_after_cf, 855 expected_after_dce, 856 check_after_cf); 857 } 858 859 } // namespace art 860