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:     <<Const0xa:i\d+>>  IntConstant 10
210## CHECK-DAG:     <<Const0xb:i\d+>>  IntConstant 11
211## CHECK-DAG:     <<Const0xc:i\d+>>  IntConstant 12
212## CHECK-DAG:     <<Const0xd:i\d+>>  IntConstant 13
213## CHECK-DAG:     <<Const0xe:i\d+>>  IntConstant 14
214## CHECK-DAG:     <<Const0xf:i\d+>>  IntConstant 15
215## CHECK-DAG:     <<Const0x10:i\d+>> IntConstant 16
216## CHECK-DAG:     <<Const0x11:i\d+>> IntConstant 17
217## CHECK-DAG:     <<Add:i\d+>>       Add [<<Arg0>>,<<Arg1>>]
218## CHECK-DAG:     <<Phi:i\d+>>       Phi [<<Add>>,<<Const0xf>>] reg:3 is_catch_phi:false
219## CHECK-DAG:                        Phi [<<Const0xa>>,<<Const0xb>>,<<Const0xd>>] reg:1 is_catch_phi:true
220## CHECK-DAG:                        Phi [<<Add>>,<<Const0xc>>,<<Const0xe>>] reg:2 is_catch_phi:true
221## CHECK-DAG:                        Phi [<<Phi>>,<<Const0x10>>,<<Const0x11>>] reg:3 is_catch_phi:true
222
223## CHECK-START: int TestCase.testCatchPhiInputs_DefinedInTryBlock(int, int, int, int) dead_code_elimination$after_inlining (after)
224## CHECK-DAG:     <<Const0xb:i\d+>>  IntConstant 11
225## CHECK-DAG:     <<Const0xc:i\d+>>  IntConstant 12
226## CHECK-DAG:     <<Const0xd:i\d+>>  IntConstant 13
227## CHECK-DAG:     <<Const0xe:i\d+>>  IntConstant 14
228## CHECK-DAG:     <<Const0x10:i\d+>> IntConstant 16
229## CHECK-DAG:     <<Const0x11:i\d+>> IntConstant 17
230## CHECK-DAG:                        Phi [<<Const0xb>>,<<Const0xd>>] reg:1 is_catch_phi:true
231## CHECK-DAG:                        Phi [<<Const0xc>>,<<Const0xe>>] reg:2 is_catch_phi:true
232## CHECK-DAG:                        Phi [<<Const0x10>>,<<Const0x11>>] reg:3 is_catch_phi:true
233
234.method public static testCatchPhiInputs_DefinedInTryBlock(IIII)I
235    .registers 8
236
237    invoke-static {}, LTestCase;->$inline$False()Z
238    move-result v0
239
240    if-eqz v0, :else
241
242    shr-int/2addr p2, p3
243
244    :try_start
245    const v1, 0xa                  # dead catch phi input, defined in entry block (HInstruction)
246    add-int v2, p0, p1             # dead catch phi input, defined in the dead block (HInstruction)
247    move v3, v2
248    if-eqz v3, :define_phi
249    const v3, 0xf
250    :define_phi
251    # v3 = Phi [Add, 0xf]          # dead catch phi input, defined in the dead block (HPhi)
252    div-int/2addr p0, v2
253
254    :else
255    const v1, 0xb                  # live catch phi input
256    const v2, 0xc                  # live catch phi input
257    const v3, 0x10                 # live catch phi input
258    div-int/2addr p0, p3
259
260    const v1, 0xd                  # live catch phi input
261    const v2, 0xe                  # live catch phi input
262    const v3, 0x11                 # live catch phi input
263    div-int/2addr p0, p1
264    :try_end
265    .catchall {:try_start .. :try_end} :catch_all
266
267    :return
268    return p0
269
270    :catch_all
271    sub-int p0, v1, v2      # use catch phi values
272    sub-int p0, p0, v3      # use catch phi values
273    goto :return
274
275.end method
276
277# Test that DCE does not remove catch phi uses of instructions defined outside
278# dead try blocks.
279
280## CHECK-START: int TestCase.testCatchPhiInputs_DefinedOutsideTryBlock(int, int, int, int) dead_code_elimination$after_inlining (before)
281## CHECK-DAG:     <<Const0xa:i\d+>> IntConstant 10
282## CHECK-DAG:     <<Const0xb:i\d+>> IntConstant 11
283## CHECK-DAG:     <<Const0xc:i\d+>> IntConstant 12
284## CHECK-DAG:     <<Const0xd:i\d+>> IntConstant 13
285## CHECK-DAG:     <<Const0xe:i\d+>> IntConstant 14
286## CHECK-DAG:     <<Const0xf:i\d+>> IntConstant 15
287## CHECK-DAG:                       Phi [<<Const0xa>>,<<Const0xb>>,<<Const0xd>>] reg:1 is_catch_phi:true
288## CHECK-DAG:                       Phi [<<Const0xf>>,<<Const0xc>>,<<Const0xe>>] reg:2 is_catch_phi:true
289
290## CHECK-START: int TestCase.testCatchPhiInputs_DefinedOutsideTryBlock(int, int, int, int) dead_code_elimination$after_inlining (after)
291## CHECK-DAG:     <<Const0xa:i\d+>> IntConstant 10
292## CHECK-DAG:     <<Const0xb:i\d+>> IntConstant 11
293## CHECK-DAG:     <<Const0xc:i\d+>> IntConstant 12
294## CHECK-DAG:     <<Const0xd:i\d+>> IntConstant 13
295## CHECK-DAG:     <<Const0xe:i\d+>> IntConstant 14
296## CHECK-DAG:     <<Const0xf:i\d+>> IntConstant 15
297## CHECK-DAG:                       Phi [<<Const0xa>>,<<Const0xb>>,<<Const0xd>>] reg:1 is_catch_phi:true
298## CHECK-DAG:                       Phi [<<Const0xf>>,<<Const0xc>>,<<Const0xe>>] reg:2 is_catch_phi:true
299
300.method public static testCatchPhiInputs_DefinedOutsideTryBlock(IIII)I
301    .registers 7
302
303    invoke-static {}, LTestCase;->$inline$False()Z
304    move-result v0
305
306    if-eqz v0, :else
307
308    shr-int/2addr p2, p3
309
310    :try_start
311    const v1, 0xa           # dead catch phi input, defined in entry block
312    const v2, 0xf           # dead catch phi input, defined in entry block
313    div-int/2addr p0, v2
314
315    :else
316    const v1, 0xb           # live catch phi input
317    const v2, 0xc           # live catch phi input
318    div-int/2addr p0, p3
319
320    const v1, 0xd           # live catch phi input
321    const v2, 0xe           # live catch phi input
322    div-int/2addr p0, p1
323    :try_end
324    .catchall {:try_start .. :try_end} :catch_all
325
326    :return
327    return p0
328
329    :catch_all
330    sub-int p0, v1, v2      # use catch phi values
331    goto :return
332
333.end method
334