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 "android-base/stringprintf.h" 18 19 #include "base/arena_allocator.h" 20 #include "builder.h" 21 #include "dex_file.h" 22 #include "dex_instruction.h" 23 #include "nodes.h" 24 #include "optimizing_unit_test.h" 25 #include "pretty_printer.h" 26 #include "ssa_builder.h" 27 28 #include "gtest/gtest.h" 29 30 namespace art { 31 32 class SsaTest : public CommonCompilerTest {}; 33 34 class SsaPrettyPrinter : public HPrettyPrinter { 35 public: 36 explicit SsaPrettyPrinter(HGraph* graph) : HPrettyPrinter(graph), str_("") {} 37 38 void PrintInt(int value) OVERRIDE { 39 str_ += android::base::StringPrintf("%d", value); 40 } 41 42 void PrintString(const char* value) OVERRIDE { 43 str_ += value; 44 } 45 46 void PrintNewLine() OVERRIDE { 47 str_ += '\n'; 48 } 49 50 void Clear() { str_.clear(); } 51 52 std::string str() const { return str_; } 53 54 void VisitIntConstant(HIntConstant* constant) OVERRIDE { 55 PrintPreInstruction(constant); 56 str_ += constant->DebugName(); 57 str_ += " "; 58 PrintInt(constant->GetValue()); 59 PrintPostInstruction(constant); 60 } 61 62 private: 63 std::string str_; 64 65 DISALLOW_COPY_AND_ASSIGN(SsaPrettyPrinter); 66 }; 67 68 static void ReNumberInstructions(HGraph* graph) { 69 int id = 0; 70 for (HBasicBlock* block : graph->GetBlocks()) { 71 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) { 72 it.Current()->SetId(id++); 73 } 74 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { 75 it.Current()->SetId(id++); 76 } 77 } 78 } 79 80 static void TestCode(const uint16_t* data, const char* expected) { 81 ArenaPool pool; 82 ArenaAllocator allocator(&pool); 83 HGraph* graph = CreateCFG(&allocator, data); 84 // Suspend checks implementation may change in the future, and this test relies 85 // on how instructions are ordered. 86 RemoveSuspendChecks(graph); 87 ReNumberInstructions(graph); 88 89 // Test that phis had their type set. 90 for (HBasicBlock* block : graph->GetBlocks()) { 91 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) { 92 ASSERT_NE(it.Current()->GetType(), Primitive::kPrimVoid); 93 } 94 } 95 96 SsaPrettyPrinter printer(graph); 97 printer.VisitInsertionOrder(); 98 99 ASSERT_STREQ(expected, printer.str().c_str()); 100 } 101 102 TEST_F(SsaTest, CFG1) { 103 // Test that we get rid of loads and stores. 104 const char* expected = 105 "BasicBlock 0, succ: 1\n" 106 " 0: IntConstant 0 [2, 2]\n" 107 " 1: Goto\n" 108 "BasicBlock 1, pred: 0, succ: 5, 2\n" 109 " 2: Equal(0, 0) [3]\n" 110 " 3: If(2)\n" 111 "BasicBlock 2, pred: 1, succ: 3\n" 112 " 4: Goto\n" 113 "BasicBlock 3, pred: 5, 2, succ: 4\n" 114 " 5: ReturnVoid\n" 115 "BasicBlock 4, pred: 3\n" 116 " 6: Exit\n" 117 // Synthesized block to avoid critical edge. 118 "BasicBlock 5, pred: 1, succ: 3\n" 119 " 7: Goto\n"; 120 121 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 122 Instruction::CONST_4 | 0 | 0, 123 Instruction::IF_EQ, 3, 124 Instruction::GOTO | 0x100, 125 Instruction::RETURN_VOID); 126 127 TestCode(data, expected); 128 } 129 130 TEST_F(SsaTest, CFG2) { 131 // Test that we create a phi for the join block of an if control flow instruction 132 // when there is only code in the else branch. 133 const char* expected = 134 "BasicBlock 0, succ: 1\n" 135 " 0: IntConstant 0 [6, 3, 3]\n" 136 " 1: IntConstant 4 [6]\n" 137 " 2: Goto\n" 138 "BasicBlock 1, pred: 0, succ: 5, 2\n" 139 " 3: Equal(0, 0) [4]\n" 140 " 4: If(3)\n" 141 "BasicBlock 2, pred: 1, succ: 3\n" 142 " 5: Goto\n" 143 "BasicBlock 3, pred: 5, 2, succ: 4\n" 144 " 6: Phi(0, 1) [7]\n" 145 " 7: Return(6)\n" 146 "BasicBlock 4, pred: 3\n" 147 " 8: Exit\n" 148 // Synthesized block to avoid critical edge. 149 "BasicBlock 5, pred: 1, succ: 3\n" 150 " 9: Goto\n"; 151 152 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 153 Instruction::CONST_4 | 0 | 0, 154 Instruction::IF_EQ, 3, 155 Instruction::CONST_4 | 4 << 12 | 0, 156 Instruction::RETURN | 0 << 8); 157 158 TestCode(data, expected); 159 } 160 161 TEST_F(SsaTest, CFG3) { 162 // Test that we create a phi for the join block of an if control flow instruction 163 // when both branches update a local. 164 const char* expected = 165 "BasicBlock 0, succ: 1\n" 166 " 0: IntConstant 0 [4, 4]\n" 167 " 1: IntConstant 5 [8]\n" 168 " 2: IntConstant 4 [8]\n" 169 " 3: Goto\n" 170 "BasicBlock 1, pred: 0, succ: 3, 2\n" 171 " 4: Equal(0, 0) [5]\n" 172 " 5: If(4)\n" 173 "BasicBlock 2, pred: 1, succ: 4\n" 174 " 6: Goto\n" 175 "BasicBlock 3, pred: 1, succ: 4\n" 176 " 7: Goto\n" 177 "BasicBlock 4, pred: 2, 3, succ: 5\n" 178 " 8: Phi(2, 1) [9]\n" 179 " 9: Return(8)\n" 180 "BasicBlock 5, pred: 4\n" 181 " 10: Exit\n"; 182 183 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 184 Instruction::CONST_4 | 0 | 0, 185 Instruction::IF_EQ, 4, 186 Instruction::CONST_4 | 4 << 12 | 0, 187 Instruction::GOTO | 0x200, 188 Instruction::CONST_4 | 5 << 12 | 0, 189 Instruction::RETURN | 0 << 8); 190 191 TestCode(data, expected); 192 } 193 194 TEST_F(SsaTest, Loop1) { 195 // Test that we create a phi for an initialized local at entry of a loop. 196 const char* expected = 197 "BasicBlock 0, succ: 1\n" 198 " 0: IntConstant 0 [6, 3, 3]\n" 199 " 1: IntConstant 4 [6]\n" 200 " 2: Goto\n" 201 "BasicBlock 1, pred: 0, succ: 4, 2\n" 202 " 3: Equal(0, 0) [4]\n" 203 " 4: If(3)\n" 204 "BasicBlock 2, pred: 1, succ: 3\n" 205 " 5: Goto\n" 206 "BasicBlock 3, pred: 2, 4, succ: 5\n" 207 " 6: Phi(1, 0) [9]\n" 208 " 7: Goto\n" 209 "BasicBlock 4, pred: 1, succ: 3\n" 210 " 8: Goto\n" 211 "BasicBlock 5, pred: 3, succ: 6\n" 212 " 9: Return(6)\n" 213 "BasicBlock 6, pred: 5\n" 214 " 10: Exit\n"; 215 216 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 217 Instruction::CONST_4 | 0 | 0, 218 Instruction::IF_EQ, 4, 219 Instruction::CONST_4 | 4 << 12 | 0, 220 Instruction::GOTO | 0x200, 221 Instruction::GOTO | 0xFF00, 222 Instruction::RETURN | 0 << 8); 223 224 TestCode(data, expected); 225 } 226 227 TEST_F(SsaTest, Loop2) { 228 // Simple loop with one preheader and one back edge. 229 const char* expected = 230 "BasicBlock 0, succ: 1\n" 231 " 0: IntConstant 0 [4]\n" 232 " 1: IntConstant 4 [4]\n" 233 " 2: Goto\n" 234 "BasicBlock 1, pred: 0, succ: 2\n" 235 " 3: Goto\n" 236 "BasicBlock 2, pred: 1, 3, succ: 4, 3\n" 237 " 4: Phi(0, 1) [5, 5]\n" 238 " 5: Equal(4, 4) [6]\n" 239 " 6: If(5)\n" 240 "BasicBlock 3, pred: 2, succ: 2\n" 241 " 7: Goto\n" 242 "BasicBlock 4, pred: 2, succ: 5\n" 243 " 8: ReturnVoid\n" 244 "BasicBlock 5, pred: 4\n" 245 " 9: Exit\n"; 246 247 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 248 Instruction::CONST_4 | 0 | 0, 249 Instruction::IF_EQ, 4, 250 Instruction::CONST_4 | 4 << 12 | 0, 251 Instruction::GOTO | 0xFD00, 252 Instruction::RETURN_VOID); 253 254 TestCode(data, expected); 255 } 256 257 TEST_F(SsaTest, Loop3) { 258 // Test that a local not yet defined at the entry of a loop is handled properly. 259 const char* expected = 260 "BasicBlock 0, succ: 1\n" 261 " 0: IntConstant 0 [5]\n" 262 " 1: IntConstant 5 [9]\n" 263 " 2: IntConstant 4 [5]\n" 264 " 3: Goto\n" 265 "BasicBlock 1, pred: 0, succ: 2\n" 266 " 4: Goto\n" 267 "BasicBlock 2, pred: 1, 3, succ: 4, 3\n" 268 " 5: Phi(0, 2) [6, 6]\n" 269 " 6: Equal(5, 5) [7]\n" 270 " 7: If(6)\n" 271 "BasicBlock 3, pred: 2, succ: 2\n" 272 " 8: Goto\n" 273 "BasicBlock 4, pred: 2, succ: 5\n" 274 " 9: Return(1)\n" 275 "BasicBlock 5, pred: 4\n" 276 " 10: Exit\n"; 277 278 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 279 Instruction::CONST_4 | 0 | 0, 280 Instruction::IF_EQ, 4, 281 Instruction::CONST_4 | 4 << 12 | 0, 282 Instruction::GOTO | 0xFD00, 283 Instruction::CONST_4 | 5 << 12 | 1 << 8, 284 Instruction::RETURN | 1 << 8); 285 286 TestCode(data, expected); 287 } 288 289 TEST_F(SsaTest, Loop4) { 290 // Make sure we support a preheader of a loop not being the first predecessor 291 // in the predecessor list of the header. 292 const char* expected = 293 "BasicBlock 0, succ: 1\n" 294 " 0: IntConstant 0 [4]\n" 295 " 1: IntConstant 4 [4]\n" 296 " 2: Goto\n" 297 "BasicBlock 1, pred: 0, succ: 4\n" 298 " 3: Goto\n" 299 "BasicBlock 2, pred: 4, 3, succ: 5, 3\n" 300 " 4: Phi(0, 1) [9, 5, 5]\n" 301 " 5: Equal(4, 4) [6]\n" 302 " 6: If(5)\n" 303 "BasicBlock 3, pred: 2, succ: 2\n" 304 " 7: Goto\n" 305 "BasicBlock 4, pred: 1, succ: 2\n" 306 " 8: Goto\n" 307 "BasicBlock 5, pred: 2, succ: 6\n" 308 " 9: Return(4)\n" 309 "BasicBlock 6, pred: 5\n" 310 " 10: Exit\n"; 311 312 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 313 Instruction::CONST_4 | 0 | 0, 314 Instruction::GOTO | 0x500, 315 Instruction::IF_EQ, 5, 316 Instruction::CONST_4 | 4 << 12 | 0, 317 Instruction::GOTO | 0xFD00, 318 Instruction::GOTO | 0xFC00, 319 Instruction::RETURN | 0 << 8); 320 321 TestCode(data, expected); 322 } 323 324 TEST_F(SsaTest, Loop5) { 325 // Make sure we create a preheader of a loop when a header originally has two 326 // incoming blocks and one back edge. 327 const char* expected = 328 "BasicBlock 0, succ: 1\n" 329 " 0: IntConstant 0 [4, 4]\n" 330 " 1: IntConstant 5 [13]\n" 331 " 2: IntConstant 4 [13]\n" 332 " 3: Goto\n" 333 "BasicBlock 1, pred: 0, succ: 3, 2\n" 334 " 4: Equal(0, 0) [5]\n" 335 " 5: If(4)\n" 336 "BasicBlock 2, pred: 1, succ: 8\n" 337 " 6: Goto\n" 338 "BasicBlock 3, pred: 1, succ: 8\n" 339 " 7: Goto\n" 340 "BasicBlock 4, pred: 8, 5, succ: 6, 5\n" 341 " 8: Equal(13, 13) [9]\n" 342 " 9: If(8)\n" 343 "BasicBlock 5, pred: 4, succ: 4\n" 344 " 10: Goto\n" 345 "BasicBlock 6, pred: 4, succ: 7\n" 346 " 11: Return(13)\n" 347 "BasicBlock 7, pred: 6\n" 348 " 12: Exit\n" 349 "BasicBlock 8, pred: 2, 3, succ: 4\n" 350 " 13: Phi(2, 1) [11, 8, 8]\n" 351 " 14: Goto\n"; 352 353 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 354 Instruction::CONST_4 | 0 | 0, 355 Instruction::IF_EQ, 4, 356 Instruction::CONST_4 | 4 << 12 | 0, 357 Instruction::GOTO | 0x200, 358 Instruction::CONST_4 | 5 << 12 | 0, 359 Instruction::IF_EQ, 3, 360 Instruction::GOTO | 0xFE00, 361 Instruction::RETURN | 0 << 8); 362 363 TestCode(data, expected); 364 } 365 366 TEST_F(SsaTest, Loop6) { 367 // Test a loop with one preheader and two back edges (e.g. continue). 368 const char* expected = 369 "BasicBlock 0, succ: 1\n" 370 " 0: IntConstant 0 [5]\n" 371 " 1: IntConstant 4 [5, 8, 8]\n" 372 " 2: IntConstant 5 [5]\n" 373 " 3: Goto\n" 374 "BasicBlock 1, pred: 0, succ: 2\n" 375 " 4: Goto\n" 376 "BasicBlock 2, pred: 1, 4, 5, succ: 6, 3\n" 377 " 5: Phi(0, 2, 1) [12, 6, 6]\n" 378 " 6: Equal(5, 5) [7]\n" 379 " 7: If(6)\n" 380 "BasicBlock 3, pred: 2, succ: 5, 4\n" 381 " 8: Equal(1, 1) [9]\n" 382 " 9: If(8)\n" 383 "BasicBlock 4, pred: 3, succ: 2\n" 384 " 10: Goto\n" 385 "BasicBlock 5, pred: 3, succ: 2\n" 386 " 11: Goto\n" 387 "BasicBlock 6, pred: 2, succ: 7\n" 388 " 12: Return(5)\n" 389 "BasicBlock 7, pred: 6\n" 390 " 13: Exit\n"; 391 392 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 393 Instruction::CONST_4 | 0 | 0, 394 Instruction::IF_EQ, 8, 395 Instruction::CONST_4 | 4 << 12 | 0, 396 Instruction::IF_EQ, 4, 397 Instruction::CONST_4 | 5 << 12 | 0, 398 Instruction::GOTO | 0xFA00, 399 Instruction::GOTO | 0xF900, 400 Instruction::RETURN | 0 << 8); 401 402 TestCode(data, expected); 403 } 404 405 TEST_F(SsaTest, Loop7) { 406 // Test a loop with one preheader, one back edge, and two exit edges (e.g. break). 407 const char* expected = 408 "BasicBlock 0, succ: 1\n" 409 " 0: IntConstant 0 [5]\n" 410 " 1: IntConstant 4 [5, 8, 8]\n" 411 " 2: IntConstant 5 [12]\n" 412 " 3: Goto\n" 413 "BasicBlock 1, pred: 0, succ: 2\n" 414 " 4: Goto\n" 415 "BasicBlock 2, pred: 1, 5, succ: 8, 3\n" 416 " 5: Phi(0, 1) [12, 6, 6]\n" 417 " 6: Equal(5, 5) [7]\n" 418 " 7: If(6)\n" 419 "BasicBlock 3, pred: 2, succ: 5, 4\n" 420 " 8: Equal(1, 1) [9]\n" 421 " 9: If(8)\n" 422 "BasicBlock 4, pred: 3, succ: 6\n" 423 " 10: Goto\n" 424 "BasicBlock 5, pred: 3, succ: 2\n" 425 " 11: Goto\n" 426 "BasicBlock 6, pred: 8, 4, succ: 7\n" 427 " 12: Phi(5, 2) [13]\n" 428 " 13: Return(12)\n" 429 "BasicBlock 7, pred: 6\n" 430 " 14: Exit\n" 431 "BasicBlock 8, pred: 2, succ: 6\n" 432 " 15: Goto\n"; 433 434 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 435 Instruction::CONST_4 | 0 | 0, 436 Instruction::IF_EQ, 8, 437 Instruction::CONST_4 | 4 << 12 | 0, 438 Instruction::IF_EQ, 4, 439 Instruction::CONST_4 | 5 << 12 | 0, 440 Instruction::GOTO | 0x0200, 441 Instruction::GOTO | 0xF900, 442 Instruction::RETURN | 0 << 8); 443 444 TestCode(data, expected); 445 } 446 447 TEST_F(SsaTest, DeadLocal) { 448 // Test that we correctly handle a local not being used. 449 const char* expected = 450 "BasicBlock 0, succ: 1\n" 451 " 0: IntConstant 0\n" 452 " 1: Goto\n" 453 "BasicBlock 1, pred: 0, succ: 2\n" 454 " 2: ReturnVoid\n" 455 "BasicBlock 2, pred: 1\n" 456 " 3: Exit\n"; 457 458 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 459 Instruction::CONST_4 | 0 | 0, 460 Instruction::RETURN_VOID); 461 462 TestCode(data, expected); 463 } 464 465 TEST_F(SsaTest, LocalInIf) { 466 // Test that we do not create a phi in the join block when one predecessor 467 // does not update the local. 468 const char* expected = 469 "BasicBlock 0, succ: 1\n" 470 " 0: IntConstant 0 [3, 3]\n" 471 " 1: IntConstant 4\n" 472 " 2: Goto\n" 473 "BasicBlock 1, pred: 0, succ: 5, 2\n" 474 " 3: Equal(0, 0) [4]\n" 475 " 4: If(3)\n" 476 "BasicBlock 2, pred: 1, succ: 3\n" 477 " 5: Goto\n" 478 "BasicBlock 3, pred: 5, 2, succ: 4\n" 479 " 6: ReturnVoid\n" 480 "BasicBlock 4, pred: 3\n" 481 " 7: Exit\n" 482 // Synthesized block to avoid critical edge. 483 "BasicBlock 5, pred: 1, succ: 3\n" 484 " 8: Goto\n"; 485 486 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 487 Instruction::CONST_4 | 0 | 0, 488 Instruction::IF_EQ, 3, 489 Instruction::CONST_4 | 4 << 12 | 1 << 8, 490 Instruction::RETURN_VOID); 491 492 TestCode(data, expected); 493 } 494 495 TEST_F(SsaTest, MultiplePredecessors) { 496 // Test that we do not create a phi when one predecessor 497 // does not update the local. 498 const char* expected = 499 "BasicBlock 0, succ: 1\n" 500 " 0: IntConstant 0 [4, 4, 8, 8, 6, 6, 2, 2]\n" 501 " 1: Goto\n" 502 "BasicBlock 1, pred: 0, succ: 3, 2\n" 503 " 2: Equal(0, 0) [3]\n" 504 " 3: If(2)\n" 505 "BasicBlock 2, pred: 1, succ: 5\n" 506 " 4: Add(0, 0)\n" 507 " 5: Goto\n" 508 "BasicBlock 3, pred: 1, succ: 7, 4\n" 509 " 6: Equal(0, 0) [7]\n" 510 " 7: If(6)\n" 511 "BasicBlock 4, pred: 3, succ: 5\n" 512 " 8: Add(0, 0)\n" 513 " 9: Goto\n" 514 // This block should not get a phi for local 1. 515 "BasicBlock 5, pred: 2, 7, 4, succ: 6\n" 516 " 10: ReturnVoid\n" 517 "BasicBlock 6, pred: 5\n" 518 " 11: Exit\n" 519 "BasicBlock 7, pred: 3, succ: 5\n" 520 " 12: Goto\n"; 521 522 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 523 Instruction::CONST_4 | 0 | 0, 524 Instruction::IF_EQ, 5, 525 Instruction::ADD_INT_LIT8 | 1 << 8, 0 << 8, 526 Instruction::GOTO | 0x0500, 527 Instruction::IF_EQ, 4, 528 Instruction::ADD_INT_LIT8 | 1 << 8, 0 << 8, 529 Instruction::RETURN_VOID); 530 531 TestCode(data, expected); 532 } 533 534 } // namespace art 535