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 LTestCase; 16.super Ljava/lang/Object; 17 18.field public static sField:I 19 20.method private static $inline$False()Z 21 .registers 1 22 const/4 v0, 0x0 23 return v0 24.end method 25 26# Test a case when one entering TryBoundary is dead but the rest of the try 27# block remains live. 28 29## CHECK-START: int TestCase.testDeadEntry(int, int, int, int) dead_code_elimination$after_inlining (before) 30## CHECK: Add 31 32## CHECK-START: int TestCase.testDeadEntry(int, int, int, int) dead_code_elimination$after_inlining (before) 33## CHECK: TryBoundary kind:entry 34## CHECK: TryBoundary kind:entry 35## CHECK-NOT: TryBoundary kind:entry 36 37## CHECK-START: int TestCase.testDeadEntry(int, int, int, int) dead_code_elimination$after_inlining (after) 38## CHECK-NOT: Add 39 40## CHECK-START: int TestCase.testDeadEntry(int, int, int, int) dead_code_elimination$after_inlining (after) 41## CHECK: TryBoundary kind:entry 42## CHECK-NOT: TryBoundary kind:entry 43 44.method public static testDeadEntry(IIII)I 45 .registers 5 46 47 invoke-static {}, LTestCase;->$inline$False()Z 48 move-result v0 49 50 if-eqz v0, :else 51 52 add-int/2addr p0, p1 53 54 :try_start 55 div-int/2addr p0, p2 56 57 :else 58 div-int/2addr p0, p3 59 :try_end 60 .catchall {:try_start .. :try_end} :catch_all 61 62 :return 63 return p0 64 65 :catch_all 66 const/4 p0, -0x1 67 goto :return 68 69.end method 70 71# Test a case when one exiting TryBoundary is dead but the rest of the try 72# block remains live. 73 74## CHECK-START: int TestCase.testDeadExit(int, int, int, int) dead_code_elimination$after_inlining (before) 75## CHECK: Add 76 77## CHECK-START: int TestCase.testDeadExit(int, int, int, int) dead_code_elimination$after_inlining (before) 78## CHECK: TryBoundary kind:exit 79## CHECK: TryBoundary kind:exit 80## CHECK-NOT: TryBoundary kind:exit 81 82## CHECK-START: int TestCase.testDeadExit(int, int, int, int) dead_code_elimination$after_inlining (after) 83## CHECK-NOT: Add 84 85## CHECK-START: int TestCase.testDeadExit(int, int, int, int) dead_code_elimination$after_inlining (after) 86## CHECK: TryBoundary kind:exit 87## CHECK-NOT: TryBoundary kind:exit 88 89.method public static testDeadExit(IIII)I 90 .registers 5 91 92 invoke-static {}, LTestCase;->$inline$False()Z 93 move-result v0 94 95 :try_start 96 div-int/2addr p0, p2 97 98 if-nez v0, :else 99 100 div-int/2addr p0, p3 101 goto :return 102 :try_end 103 .catchall {:try_start .. :try_end} :catch_all 104 105 :else 106 add-int/2addr p0, p1 107 108 :return 109 return p0 110 111 :catch_all 112 const/4 p0, -0x1 113 goto :return 114 115.end method 116 117# Test that a catch block remains live and consistent if some of try blocks 118# throwing into it are removed. 119 120## CHECK-START: int TestCase.testOneTryBlockDead(int, int, int, int) dead_code_elimination$after_inlining (before) 121## CHECK: TryBoundary kind:entry 122## CHECK: TryBoundary kind:entry 123## CHECK-NOT: TryBoundary kind:entry 124 125## CHECK-START: int TestCase.testOneTryBlockDead(int, int, int, int) dead_code_elimination$after_inlining (before) 126## CHECK: TryBoundary kind:exit 127## CHECK: TryBoundary kind:exit 128## CHECK-NOT: TryBoundary kind:exit 129 130## CHECK-START: int TestCase.testOneTryBlockDead(int, int, int, int) dead_code_elimination$after_inlining (after) 131## CHECK: TryBoundary kind:entry 132## CHECK-NOT: TryBoundary kind:entry 133 134## CHECK-START: int TestCase.testOneTryBlockDead(int, int, int, int) dead_code_elimination$after_inlining (after) 135## CHECK: TryBoundary kind:exit 136## CHECK-NOT: TryBoundary kind:exit 137 138.method public static testOneTryBlockDead(IIII)I 139 .registers 5 140 141 invoke-static {}, LTestCase;->$inline$False()Z 142 move-result v0 143 144 :try_start_1 145 div-int/2addr p0, p2 146 :try_end_1 147 .catchall {:try_start_1 .. :try_end_1} :catch_all 148 149 if-eqz v0, :return 150 151 :try_start_2 152 div-int/2addr p0, p3 153 :try_end_2 154 .catchall {:try_start_2 .. :try_end_2} :catch_all 155 156 :return 157 return p0 158 159 :catch_all 160 const/4 p0, -0x1 161 goto :return 162 163.end method 164 165# Test that try block membership is recomputed. In this test case, the try entry 166# stored with the merge block gets deleted and SSAChecker would fail if it was 167# not replaced with the try entry from the live branch. 168 169.method public static testRecomputeTryMembership(IIII)I 170 .registers 5 171 172 invoke-static {}, LTestCase;->$inline$False()Z 173 move-result v0 174 175 if-eqz v0, :else 176 177 # Dead branch 178 :try_start 179 div-int/2addr p0, p1 180 goto :merge 181 182 # Live branch 183 :else 184 div-int/2addr p0, p2 185 186 # Merge block. Make complex so it does not get merged with the live branch. 187 :merge 188 div-int/2addr p0, p3 189 if-eqz p0, :else2 190 div-int/2addr p0, p3 191 :else2 192 :try_end 193 .catchall {:try_start .. :try_end} :catch_all 194 195 :return 196 return p0 197 198 :catch_all 199 const/4 p0, -0x1 200 goto :return 201 202.end method 203 204# Test that DCE removes catch phi uses of instructions defined in dead try blocks. 205 206## CHECK-START: int TestCase.testCatchPhiInputs_DefinedInTryBlock(int, int, int, int) dead_code_elimination$after_inlining (before) 207## CHECK-DAG: <<Arg0:i\d+>> ParameterValue 208## CHECK-DAG: <<Arg1:i\d+>> ParameterValue 209## CHECK-DAG: <<Const0x0:i\d+>> IntConstant 0 210## CHECK-DAG: <<Const0xa:i\d+>> IntConstant 10 211## CHECK-DAG: <<Const0xb:i\d+>> IntConstant 11 212## CHECK-DAG: <<Const0xc:i\d+>> IntConstant 12 213## CHECK-DAG: <<Const0xd:i\d+>> IntConstant 13 214## CHECK-DAG: <<Const0xe:i\d+>> IntConstant 14 215## CHECK-DAG: <<Const0xf:i\d+>> IntConstant 15 216## CHECK-DAG: <<Const0x10:i\d+>> IntConstant 16 217## CHECK-DAG: <<Const0x11:i\d+>> IntConstant 17 218## CHECK-DAG: <<Add:i\d+>> Add [<<Arg0>>,<<Arg1>>] 219## CHECK-DAG: <<Phi:i\d+>> Phi [<<Const0x0>>,<<Const0xf>>] reg:3 is_catch_phi:false 220## CHECK-DAG: Phi [<<Const0xa>>,<<Const0xb>>,<<Const0xd>>] reg:1 is_catch_phi:true 221## CHECK-DAG: Phi [<<Add>>,<<Const0xc>>,<<Const0xe>>] reg:2 is_catch_phi:true 222## CHECK-DAG: Phi [<<Phi>>,<<Const0x10>>,<<Const0x11>>] reg:3 is_catch_phi:true 223 224## CHECK-START: int TestCase.testCatchPhiInputs_DefinedInTryBlock(int, int, int, int) dead_code_elimination$after_inlining (after) 225## CHECK-DAG: <<Const0xb:i\d+>> IntConstant 11 226## CHECK-DAG: <<Const0xc:i\d+>> IntConstant 12 227## CHECK-DAG: <<Const0xd:i\d+>> IntConstant 13 228## CHECK-DAG: <<Const0xe:i\d+>> IntConstant 14 229## CHECK-DAG: <<Const0x10:i\d+>> IntConstant 16 230## CHECK-DAG: <<Const0x11:i\d+>> IntConstant 17 231## CHECK-DAG: Phi [<<Const0xb>>,<<Const0xd>>] reg:1 is_catch_phi:true 232## CHECK-DAG: Phi [<<Const0xc>>,<<Const0xe>>] reg:2 is_catch_phi:true 233## CHECK-DAG: Phi [<<Const0x10>>,<<Const0x11>>] reg:3 is_catch_phi:true 234 235.method public static testCatchPhiInputs_DefinedInTryBlock(IIII)I 236 .registers 8 237 238 invoke-static {}, LTestCase;->$inline$False()Z 239 move-result v0 240 241 if-eqz v0, :else 242 243 shr-int/2addr p2, p3 244 245 :try_start 246 const v1, 0xa # dead catch phi input, defined in entry block (HInstruction) 247 add-int v2, p0, p1 # dead catch phi input, defined in the dead block (HInstruction) 248 move v3, v2 249 if-eqz v3, :define_phi 250 const v3, 0xf 251 :define_phi 252 # v3 = Phi [Add, 0xf] # dead catch phi input, defined in the dead block (HPhi). 253 # Note that the Add has to be equal to 0 since we do `if-eqz v3` 254 div-int/2addr p0, v2 255 256 :else 257 const v1, 0xb # live catch phi input 258 const v2, 0xc # live catch phi input 259 const v3, 0x10 # live catch phi input 260 div-int/2addr p0, p3 261 262 const v1, 0xd # live catch phi input 263 const v2, 0xe # live catch phi input 264 const v3, 0x11 # live catch phi input 265 div-int/2addr p0, p1 266 :try_end 267 .catchall {:try_start .. :try_end} :catch_all 268 269 :return 270 return p0 271 272 :catch_all 273 sub-int p0, v1, v2 # use catch phi values 274 sub-int p0, p0, v3 # use catch phi values 275 goto :return 276 277.end method 278 279# Test that DCE does not remove catch phi uses of instructions defined outside 280# dead try blocks. 281 282## CHECK-START: int TestCase.testCatchPhiInputs_DefinedOutsideTryBlock(int, int, int, int) dead_code_elimination$after_inlining (before) 283## CHECK-DAG: <<Const0xa:i\d+>> IntConstant 10 284## CHECK-DAG: <<Const0xb:i\d+>> IntConstant 11 285## CHECK-DAG: <<Const0xc:i\d+>> IntConstant 12 286## CHECK-DAG: <<Const0xd:i\d+>> IntConstant 13 287## CHECK-DAG: <<Const0xe:i\d+>> IntConstant 14 288## CHECK-DAG: <<Const0xf:i\d+>> IntConstant 15 289## CHECK-DAG: Phi [<<Const0xa>>,<<Const0xb>>,<<Const0xd>>] reg:1 is_catch_phi:true 290## CHECK-DAG: Phi [<<Const0xf>>,<<Const0xc>>,<<Const0xe>>] reg:2 is_catch_phi:true 291 292## CHECK-START: int TestCase.testCatchPhiInputs_DefinedOutsideTryBlock(int, int, int, int) dead_code_elimination$after_inlining (after) 293## CHECK-DAG: <<Const0xa:i\d+>> IntConstant 10 294## CHECK-DAG: <<Const0xb:i\d+>> IntConstant 11 295## CHECK-DAG: <<Const0xc:i\d+>> IntConstant 12 296## CHECK-DAG: <<Const0xd:i\d+>> IntConstant 13 297## CHECK-DAG: <<Const0xe:i\d+>> IntConstant 14 298## CHECK-DAG: <<Const0xf:i\d+>> IntConstant 15 299## CHECK-DAG: Phi [<<Const0xa>>,<<Const0xb>>,<<Const0xd>>] reg:1 is_catch_phi:true 300## CHECK-DAG: Phi [<<Const0xf>>,<<Const0xc>>,<<Const0xe>>] reg:2 is_catch_phi:true 301 302.method public static testCatchPhiInputs_DefinedOutsideTryBlock(IIII)I 303 .registers 7 304 305 invoke-static {}, LTestCase;->$inline$False()Z 306 move-result v0 307 308 if-eqz v0, :else 309 310 shr-int/2addr p2, p3 311 312 :try_start 313 const v1, 0xa # dead catch phi input, defined in entry block 314 const v2, 0xf # dead catch phi input, defined in entry block 315 div-int/2addr p0, v2 316 317 :else 318 const v1, 0xb # live catch phi input 319 const v2, 0xc # live catch phi input 320 div-int/2addr p0, p3 321 322 const v1, 0xd # live catch phi input 323 const v2, 0xe # live catch phi input 324 div-int/2addr p0, p1 325 :try_end 326 .catchall {:try_start .. :try_end} :catch_all 327 328 :return 329 return p0 330 331 :catch_all 332 sub-int p0, v1, v2 # use catch phi values 333 goto :return 334 335.end method 336