1 # Copyright (C) 2015 The Android Open Source Project 2 # 3 # Licensed under the Apache License, Version 2.0 (the "License"); 4 # you may not use this file except in compliance with the License. 5 # You may obtain a copy of the License at 6 # 7 # http://www.apache.org/licenses/LICENSE-2.0 8 # 9 # Unless required by applicable law or agreed to in writing, software 10 # distributed under the License is distributed on an "AS IS" BASIS, 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 # See the License for the specific language governing permissions and 13 # limitations under the License. 14 15 .class public LIrreducibleLoop; 16 17 .super Ljava/lang/Object; 18 19 # Back-edges in the ascii-art graphs are represented with dash '-'. 20 21 # Test that we support a simple irreducible loop. 22 # 23 # entry 24 # / \ 25 # / \ 26 # loop_entry \ 27 # / \- \ 28 # exit \- \ 29 # other_loop_entry 30 # 31 ## CHECK-START: int IrreducibleLoop.simpleLoop(int) dead_code_elimination (before) 32 ## CHECK: irreducible:true 33 .method public static simpleLoop(I)I 34 .registers 2 35 const/16 v0, 42 36 if-eq v1, v0, :other_loop_entry 37 :loop_entry 38 if-ne v1, v0, :exit 39 add-int v0, v0, v0 40 :other_loop_entry 41 add-int v0, v0, v0 42 goto :loop_entry 43 :exit 44 return v0 45 .end method 46 47 # Test that lse does not wrongly optimize loads in irreducible loops. At the 48 # SSA level, since we create redundant phis for irreducible loop headers, lse 49 # does not see the relation between the dex register and the phi. 50 # 51 # entry 52 # p1 53 # / \ 54 # / \ 55 # / \ 56 # / \ 57 # loop_pre_entry \ 58 # set 42 in p1:myField \ 59 # / \ 60 # loop_entry \ 61 # get p1.myField \ 62 # / \- \ 63 # exit \- \ 64 # \- \ 65 # other_loop_entry 66 # set 30 in p1:myField 67 # 68 ## CHECK-START: int IrreducibleLoop.lse(int, Main) dead_code_elimination (after) 69 ## CHECK: irreducible:true 70 # 71 ## CHECK-START: int IrreducibleLoop.lse(int, Main) load_store_elimination (after) 72 ## CHECK: InstanceFieldGet 73 .method public static lse(ILMain;)I 74 .registers 4 75 const/16 v0, 42 76 const/16 v1, 30 77 if-eq p0, v0, :other_loop_pre_entry 78 goto: loop_pre_entry 79 :loop_pre_entry 80 iput v0, p1, LMain;->myField:I 81 :loop_entry 82 if-ne v1, v0, :exit 83 :other_loop_entry 84 iget v0, p1, LMain;->myField:I 85 if-eq v1, v0, :exit 86 goto :loop_entry 87 :exit 88 return v0 89 :other_loop_pre_entry 90 iput v1, p1, LMain;->myField:I 91 goto :other_loop_entry 92 .end method 93 94 # Check that dce does not apply for irreducible loops. 95 # 96 # entry 97 # / \ 98 # / \ 99 # loop_entry \ 100 # / \- \ 101 # exit \- \ 102 # other_loop_entry 103 # 104 ## CHECK-START: int IrreducibleLoop.dce(int) dead_code_elimination (before) 105 ## CHECK: irreducible:true 106 107 ## CHECK-START: int IrreducibleLoop.dce(int) dead_code_elimination (after) 108 ## CHECK: irreducible:true 109 .method public static dce(I)I 110 .registers 3 111 const/16 v0, 42 112 const/16 v1, 168 113 if-ne v0, v0, :other_loop_pre_entry 114 :loop_entry 115 if-ne v0, v0, :exit 116 add-int v0, v0, v0 117 :other_loop_entry 118 add-int v0, v0, v0 119 if-eq v0, v1, :exit 120 goto :loop_entry 121 :exit 122 return v0 123 :other_loop_pre_entry 124 add-int v0, v0, v0 125 goto :other_loop_entry 126 .end method 127 128 # Check that a dex register only used in the loop header remains live thanks 129 # to the (redundant) Phi created at the loop header for it. 130 # 131 # entry 132 # p0 133 # / \ 134 # / \ 135 # / \ 136 # loop_entry \ 137 # i0 = phi(p0,i1) \ 138 # / \- \ 139 # exit \- \ 140 # other_loop_entry 141 # i1 = phi(p0, i0) 142 # 143 ## CHECK-START: int IrreducibleLoop.liveness(int) liveness (after) 144 ## CHECK-DAG: <<Arg:i\d+>> ParameterValue liveness:<<ArgLiv:\d+>> ranges:{[<<ArgLiv>>,<<ArgLoopPhiUse:\d+>>)} 145 ## CHECK-DAG: <<LoopPhi:i\d+>> Phi [<<Arg>>,<<PhiInLoop:i\d+>>] liveness:<<ArgLoopPhiUse>> ranges:{[<<ArgLoopPhiUse>>,<<PhiInLoopUse:\d+>>)} 146 ## CHECK-DAG: <<PhiInLoop>> Phi [<<Arg>>,<<LoopPhi>>] liveness:<<PhiInLoopUse>> ranges:{[<<PhiInLoopUse>>,<<BackEdgeLifetimeEnd:\d+>>)} 147 ## CHECK: Return liveness:<<ReturnLiveness:\d+>> 148 ## CHECK-EVAL: <<ReturnLiveness>> == <<BackEdgeLifetimeEnd>> + 2 149 .method public static liveness(I)I 150 .registers 2 151 const/16 v0, 42 152 if-eq p0, v0, :other_loop_entry 153 :loop_entry 154 add-int v0, v0, p0 155 if-ne v1, v0, :exit 156 :other_loop_entry 157 add-int v0, v0, v0 158 goto :loop_entry 159 :exit 160 return v0 161 .end method 162 163 # Check that we don't GVN across irreducible loops: 164 # "const-class 1" in loop_entry should not be GVN with 165 # "const-class 1" in entry. 166 # 167 # entry 168 # const-class 1 169 # / \ 170 # / \ 171 # loop_entry \ 172 # const-class 1 \ 173 # / \- \ 174 # exit \- \ 175 # other_loop_entry 176 # const-class 2 177 # 178 ## CHECK-START: java.lang.Class IrreducibleLoop.gvn() GVN (before) 179 ## CHECK: LoadClass 180 ## CHECK: LoadClass 181 ## CHECK: LoadClass 182 ## CHECK-NOT: LoadClass 183 184 ## CHECK-START: java.lang.Class IrreducibleLoop.gvn() GVN (after) 185 ## CHECK: LoadClass 186 ## CHECK: LoadClass 187 ## CHECK: LoadClass 188 ## CHECK-NOT: LoadClass 189 190 .method public static gvn()Ljava/lang/Class; 191 .registers 3 192 const/4 v2, 0 193 const-class v0, LMain; 194 if-ne v0, v2, :other_loop_entry 195 :loop_entry 196 const-class v0, LMain; 197 if-ne v0, v2, :exit 198 :other_loop_entry 199 const-class v1, LIrreducibleLoop; 200 goto :loop_entry 201 :exit 202 return-object v0 203 .end method 204 205 # Check that we don't LICM across irreducible loops: 206 # "add" in loop_entry should not be LICMed. 207 # 208 # entry 209 # / \ 210 # / \ 211 # loop_entry \ 212 # add \ 213 # / \- \ 214 # exit \- \ 215 # other_loop_entry 216 # 217 ## CHECK-START: int IrreducibleLoop.licm1(int) licm (after) 218 ## CHECK: Add irreducible:true 219 .method public static licm1(I)I 220 .registers 3 221 const/4 v0, 0 222 if-ne p0, v0, :other_loop_entry 223 :loop_entry 224 add-int v0, p0, p0 225 if-ne v0, p0, :exit 226 :other_loop_entry 227 sub-int v1, p0, p0 228 goto :loop_entry 229 :exit 230 sub-int v0, v0, p0 231 return v0 232 .end method 233 234 # Check that we don't LICM across irreducible loops: 235 # "const-class" in loop_entry should not be LICMed. 236 # 237 # entry 238 # / \ 239 # / \ 240 # loop_entry \ 241 # const-class \ 242 # / \- \ 243 # exit \- \ 244 # other_loop_entry 245 # 246 ## CHECK-START: int IrreducibleLoop.licm2(int) licm (after) 247 ## CHECK: LoadClass irreducible:true 248 .method public static licm2(I)I 249 .registers 3 250 const/4 v0, 0 251 if-ne p0, v0, :other_loop_entry 252 :loop_entry 253 const-class v1, LIrreducibleLoop; 254 if-ne v0, p0, :exit 255 :other_loop_entry 256 sub-int v1, p0, p0 257 goto :loop_entry 258 :exit 259 sub-int v0, v0, p0 260 return v0 261 .end method 262 263 # Check that we don't LICM in a natural loop that contains an irreducible loop: 264 # "const-class" should not be LICMed. 265 # 266 # entry 267 # | 268 # loop_entry 269 # const-class ------------------- 270 # / \ - 271 # / \ - 272 # exit loop_body - 273 # / \ - 274 # / \ - 275 # irreducible_loop_entry \ - 276 # - \ \ - 277 # - \ \ - 278 # - irreducible_loop_other_entry 279 # - | 280 # - | 281 # ------ irreducible_loop_back_edge 282 # 283 ## CHECK-START: int IrreducibleLoop.licm3(int, int, int) licm (after) 284 ## CHECK: LoadClass loop:<<OuterLoop:B\d+>> irreducible:false 285 ## CHECK: Goto outer_loop:<<OuterLoop>> irreducible:true 286 .method public static licm3(III)I 287 .registers 4 288 :loop_entry 289 const-class v0, LIrreducibleLoop; 290 if-ne p1, p2, :exit 291 goto :loop_body 292 293 :loop_body 294 if-eq p0, p1, :irreducible_loop_entry 295 goto :irreducible_loop_other_entry 296 297 :irreducible_loop_entry 298 goto :irreducible_loop_other_entry 299 300 :irreducible_loop_other_entry 301 if-eq p0, p2, :loop_entry 302 goto :irreducible_loop_back_edge 303 304 :irreducible_loop_back_edge 305 goto :irreducible_loop_entry 306 :exit 307 return p0 308 .end method 309 310 # Check a loop within an irreducible loop 311 # 312 # entry 313 # / \ 314 # / \ 315 # irreducible_loop_entry \ 316 # / - \ irreducible_loop_pre_other_entry 317 # exit - \ / 318 # - irreducible_loop_body 319 # - | 320 # - | 321 # - loop_within_header 322 # - / \- 323 # - / \- 324 # irreducible_loop_back_edge loop_within_back_edge 325 # 326 ## CHECK-START: void IrreducibleLoop.analyze1(int) builder (after) 327 ## CHECK-DAG: Goto loop:<<OuterLoop:B\d+>> outer_loop:none irreducible:true 328 ## CHECK-DAG: Goto outer_loop:<<OuterLoop>> irreducible:false 329 .method public static analyze1(I)V 330 .registers 1 331 if-eq p0, p0, :irreducible_loop_entry 332 goto :irreducible_loop_pre_other_entry 333 334 :irreducible_loop_entry 335 if-eq p0, p0, :exit 336 goto :irreducible_loop_body 337 338 :irreducible_loop_body 339 :loop_within_header 340 if-eq p0, p0, :irreducible_loop_back_edge 341 goto :loop_within_back_edge 342 343 :loop_within_back_edge 344 goto :loop_within_header 345 346 :irreducible_loop_back_edge 347 goto :irreducible_loop_entry 348 349 :irreducible_loop_pre_other_entry 350 goto :irreducible_loop_body 351 352 :exit 353 return-void 354 .end method 355 356 # Check than a loop before an irreducible loop is not part of the 357 # irreducible loop. 358 # 359 # entry 360 # | 361 # | 362 # loop_header 363 # / \- 364 # / \- 365 # irreducible_loop_pre_entry loop_body 366 # / \ 367 # / \ 368 # irreducible_loop_entry \ 369 # / \- irreducible_loop_other_pre_entry 370 # / \- / 371 # exit \- / 372 # irreducible_loop_body 373 # 374 ## CHECK-START: void IrreducibleLoop.analyze2(int) builder (after) 375 ## CHECK-DAG: Goto outer_loop:none irreducible:false 376 ## CHECK-DAG: Goto outer_loop:none irreducible:true 377 .method public static analyze2(I)V 378 .registers 1 379 :loop_header 380 if-eq p0, p0, :irreducible_loop_pre_entry 381 goto :loop_body 382 :loop_body 383 goto :loop_header 384 385 :irreducible_loop_pre_entry 386 if-eq p0, p0, :irreducible_loop_other_pre_entry 387 goto :irreducible_loop_entry 388 389 :irreducible_loop_entry 390 if-eq p0, p0, :exit 391 goto :irreducible_loop_body 392 393 :irreducible_loop_body 394 goto :irreducible_loop_entry 395 396 :irreducible_loop_other_pre_entry 397 goto :irreducible_loop_body 398 399 :exit 400 return-void 401 .end method 402 403 # Check two irreducible loops, one within another. 404 # 405 # entry 406 # / \ 407 # / \ 408 # loop1_header loop2_header 409 # - | / - 410 # - | / - 411 # - | / - 412 # - | / - 413 # - loop2_body - 414 # - / \ - 415 # - / \ - 416 # loop1_body loop2_back_edge 417 # | 418 # | 419 # exit 420 # 421 ## CHECK-START: void IrreducibleLoop.analyze3(int) builder (after) 422 ## CHECK-DAG: Goto loop:<<OuterLoop:B\d+>> outer_loop:none irreducible:true 423 ## CHECK-DAG: Goto outer_loop:<<OuterLoop>> irreducible:true 424 .method public static analyze3(I)V 425 .registers 1 426 if-eq p0, p0, :loop2_header 427 goto :loop1_header 428 429 :loop1_header 430 goto :loop2_body 431 432 :loop2_header 433 goto :loop2_body 434 435 :loop2_body 436 if-eq p0, p0, :loop2_back_edge 437 goto :loop1_body 438 439 :loop2_back_edge 440 goto :loop2_header 441 442 :loop1_body 443 if-eq p0, p0, :exit 444 goto :loop1_header 445 446 :exit 447 return-void 448 .end method 449 450 # Check two irreducible loops, one within another. Almost identical 451 # to analyze3 except the branches of the first 'if' are swapped, to 452 # ensure the order at which we find the back edges does not matter. 453 # 454 # entry 455 # / \ 456 # / \ 457 # loop1_header loop2_header 458 # - | / - 459 # - | / - 460 # - | / - 461 # - | / - 462 # - loop2_body - 463 # - / \ - 464 # - / \ - 465 # loop1_body loop2_back_edge 466 # | 467 # | 468 # exit 469 # 470 ## CHECK-START: void IrreducibleLoop.analyze4(int) builder (after) 471 ## CHECK-DAG: Goto loop:<<OuterLoop:B\d+>> outer_loop:none irreducible:true 472 ## CHECK-DAG: Goto outer_loop:<<OuterLoop>> irreducible:true 473 .method public static analyze4(I)V 474 .registers 1 475 if-eq p0, p0, :loop1_header 476 goto :loop2_header 477 478 :loop1_header 479 goto :loop2_body 480 481 :loop2_header 482 goto :loop2_body 483 484 :loop2_body 485 if-eq p0, p0, :loop2_back_edge 486 goto :loop1_body 487 488 :loop2_back_edge 489 goto :loop2_header 490 491 :loop1_body 492 if-eq p0, p0, :exit 493 goto :loop1_header 494 495 :exit 496 return-void 497 .end method 498 499 # Check two irreducible loops, one within another. Almost identical 500 # to analyze3 and analyze4, except that the inner loop exits from the 501 # back edge, and not the body. 502 # 503 # entry 504 # / \ 505 # / \ 506 # loop1_header loop2_header 507 # - \ / - 508 # - \ / - 509 # - \ / - 510 # - \ / - 511 # - loop2_body - 512 # - | - 513 # - | - 514 # - loop2_back_edge ------ 515 # - | 516 # - | 517 # ----- loop1_body 518 # | 519 # | 520 # exit 521 # 522 ## CHECK-START: void IrreducibleLoop.analyze5(int) builder (after) 523 ## CHECK-DAG: Goto loop:<<OuterLoop:B\d+>> outer_loop:none irreducible:true 524 ## CHECK-DAG: Goto outer_loop:<<OuterLoop>> irreducible:true 525 .method public static analyze5(I)V 526 .registers 1 527 if-eq p0, p0, :loop1_header 528 goto :loop2_header 529 530 :loop1_header 531 goto :loop2_body 532 533 :loop2_header 534 goto :loop2_body 535 536 :loop2_body 537 goto :loop2_back_edge 538 539 :loop2_back_edge 540 if-eq p0, p0, :loop2_header 541 goto :loop1_body 542 543 :loop1_body 544 if-eq p0, p0, :exit 545 goto :loop1_header 546 547 :exit 548 return-void 549 .end method 550