1# Copyright (C) 2017 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 LSmaliTests;
16.super Ljava/lang/Object;
17
18#
19# Test transformation of Not/Not/And into Or/Not.
20#
21
22## CHECK-START: int SmaliTests.$opt$noinline$andToOr(int, int) instruction_simplifier (before)
23## CHECK-DAG:       <<P1:i\d+>>          ParameterValue
24## CHECK-DAG:       <<P2:i\d+>>          ParameterValue
25## CHECK-DAG:       <<Not1:i\d+>>        Not [<<P1>>]
26## CHECK-DAG:       <<Not2:i\d+>>        Not [<<P2>>]
27## CHECK-DAG:       <<And:i\d+>>         And [<<Not1>>,<<Not2>>]
28## CHECK-DAG:                            Return [<<And>>]
29
30## CHECK-START: int SmaliTests.$opt$noinline$andToOr(int, int) instruction_simplifier (after)
31## CHECK-DAG:       <<P1:i\d+>>          ParameterValue
32## CHECK-DAG:       <<P2:i\d+>>          ParameterValue
33## CHECK-DAG:       <<Or:i\d+>>          Or [<<P1>>,<<P2>>]
34## CHECK-DAG:       <<Not:i\d+>>         Not [<<Or>>]
35## CHECK-DAG:                            Return [<<Not>>]
36
37## CHECK-START: int SmaliTests.$opt$noinline$andToOr(int, int) instruction_simplifier (after)
38## CHECK-DAG:                            Not
39## CHECK-NOT:                            Not
40
41## CHECK-START: int SmaliTests.$opt$noinline$andToOr(int, int) instruction_simplifier (after)
42## CHECK-NOT:                            And
43.method public static $opt$noinline$andToOr(II)I
44    .registers 4
45    .param p0, "a"    # I
46    .param p1, "b"    # I
47
48    .prologue
49    sget-boolean v0, LSmaliTests;->doThrow:Z
50    if-eqz v0, :cond_a
51    new-instance v0, Ljava/lang/Error;
52    invoke-direct {v0}, Ljava/lang/Error;-><init>()V
53    throw v0
54
55  :cond_a
56    # return ~a & ~b;
57    not-int v0, p0
58    not-int v1, p1
59    and-int/2addr v0, v1
60
61    return v0
62.end method
63
64# Test transformation of Not/Not/And into Or/Not for boolean negations.
65# Note that the graph before this instruction simplification pass does not
66# contain `HBooleanNot` instructions. This is because this transformation
67# follows the optimization of `HSelect` to `HBooleanNot` occurring in the
68# same pass.
69
70## CHECK-START: boolean SmaliTests.$opt$noinline$booleanAndToOr(boolean, boolean) instruction_simplifier (before)
71## CHECK-DAG:       <<P1:z\d+>>          ParameterValue
72## CHECK-DAG:       <<P2:z\d+>>          ParameterValue
73## CHECK-DAG:       <<Const1:i\d+>>      IntConstant 1
74## CHECK-DAG:       <<NotP1:i\d+>>       Xor [<<P1>>,<<Const1>>]
75## CHECK-DAG:       <<NotP2:i\d+>>       Xor [<<P2>>,<<Const1>>]
76## CHECK-DAG:       <<And:i\d+>>         And [<<NotP1>>,<<NotP2>>]
77## CHECK-DAG:                            Return [<<And>>]
78
79## CHECK-START: boolean SmaliTests.$opt$noinline$booleanAndToOr(boolean, boolean) instruction_simplifier (after)
80## CHECK-DAG:       <<Cond1:z\d+>>       ParameterValue
81## CHECK-DAG:       <<Cond2:z\d+>>       ParameterValue
82## CHECK-DAG:       <<Or:i\d+>>          Or [<<Cond1>>,<<Cond2>>]
83## CHECK-DAG:       <<BooleanNot:z\d+>>  BooleanNot [<<Or>>]
84## CHECK-DAG:                            Return [<<BooleanNot>>]
85
86## CHECK-START: boolean SmaliTests.$opt$noinline$booleanAndToOr(boolean, boolean) instruction_simplifier$after_bce (after)
87## CHECK-DAG:                            BooleanNot
88## CHECK-NOT:                            BooleanNot
89
90## CHECK-START: boolean SmaliTests.$opt$noinline$booleanAndToOr(boolean, boolean) instruction_simplifier$after_bce (after)
91## CHECK-NOT:                            And
92.method public static $opt$noinline$booleanAndToOr(ZZ)Z
93    .registers 4
94    .param p0, "a"    # Z
95    .param p1, "b"    # Z
96
97    .prologue
98    sget-boolean v0, LSmaliTests;->doThrow:Z
99    if-eqz v0, :cond_a
100    new-instance v0, Ljava/lang/Error;
101    invoke-direct {v0}, Ljava/lang/Error;-><init>()V
102    throw v0
103
104  :cond_a
105    # return !a & !b;
106    xor-int/lit8 v0, p0, 0x1
107    xor-int/lit8 v1, p1, 0x1
108    and-int/2addr v0, v1
109    return v0
110.end method
111
112# Test transformation of Not/Not/Or into And/Not.
113
114## CHECK-START: long SmaliTests.$opt$noinline$orToAnd(long, long) instruction_simplifier (before)
115## CHECK-DAG:       <<P1:j\d+>>          ParameterValue
116## CHECK-DAG:       <<P2:j\d+>>          ParameterValue
117## CHECK-DAG:       <<Not1:j\d+>>        Not [<<P1>>]
118## CHECK-DAG:       <<Not2:j\d+>>        Not [<<P2>>]
119## CHECK-DAG:       <<Or:j\d+>>          Or [<<Not1>>,<<Not2>>]
120## CHECK-DAG:                            Return [<<Or>>]
121
122## CHECK-START: long SmaliTests.$opt$noinline$orToAnd(long, long) instruction_simplifier (after)
123## CHECK-DAG:       <<P1:j\d+>>          ParameterValue
124## CHECK-DAG:       <<P2:j\d+>>          ParameterValue
125## CHECK-DAG:       <<And:j\d+>>         And [<<P1>>,<<P2>>]
126## CHECK-DAG:       <<Not:j\d+>>         Not [<<And>>]
127## CHECK-DAG:                            Return [<<Not>>]
128
129## CHECK-START: long SmaliTests.$opt$noinline$orToAnd(long, long) instruction_simplifier (after)
130## CHECK-DAG:                            Not
131## CHECK-NOT:                            Not
132
133## CHECK-START: long SmaliTests.$opt$noinline$orToAnd(long, long) instruction_simplifier (after)
134## CHECK-NOT:                            Or
135.method public static $opt$noinline$orToAnd(JJ)J
136    .registers 8
137    .param p0, "a"    # J
138    .param p2, "b"    # J
139
140    .prologue
141    sget-boolean v0, LSmaliTests;->doThrow:Z
142    if-eqz v0, :cond_a
143    new-instance v0, Ljava/lang/Error;
144    invoke-direct {v0}, Ljava/lang/Error;-><init>()V
145    throw v0
146
147  :cond_a
148    # return ~a | ~b;
149    not-long v0, p0
150    not-long v2, p2
151    or-long/2addr v0, v2
152    return-wide v0
153.end method
154
155# Test transformation of Not/Not/Or into Or/And for boolean negations.
156# Note that the graph before this instruction simplification pass does not
157# contain `HBooleanNot` instructions. This is because this transformation
158# follows the optimization of `HSelect` to `HBooleanNot` occurring in the
159# same pass.
160
161## CHECK-START: boolean SmaliTests.$opt$noinline$booleanOrToAnd(boolean, boolean) instruction_simplifier (before)
162## CHECK-DAG:       <<P1:z\d+>>          ParameterValue
163## CHECK-DAG:       <<P2:z\d+>>          ParameterValue
164## CHECK-DAG:       <<Const1:i\d+>>      IntConstant 1
165## CHECK-DAG:       <<NotP1:i\d+>>       Xor [<<P1>>,<<Const1>>]
166## CHECK-DAG:       <<NotP2:i\d+>>       Xor [<<P2>>,<<Const1>>]
167## CHECK-DAG:       <<Or:i\d+>>          Or [<<NotP1>>,<<NotP2>>]
168## CHECK-DAG:                            Return [<<Or>>]
169
170## CHECK-START: boolean SmaliTests.$opt$noinline$booleanOrToAnd(boolean, boolean) instruction_simplifier (after)
171## CHECK-DAG:       <<Cond1:z\d+>>       ParameterValue
172## CHECK-DAG:       <<Cond2:z\d+>>       ParameterValue
173## CHECK-DAG:       <<And:i\d+>>         And [<<Cond1>>,<<Cond2>>]
174## CHECK-DAG:       <<BooleanNot:z\d+>>  BooleanNot [<<And>>]
175## CHECK-DAG:                            Return [<<BooleanNot>>]
176
177## CHECK-START: boolean SmaliTests.$opt$noinline$booleanOrToAnd(boolean, boolean) instruction_simplifier$after_bce (after)
178## CHECK-DAG:                            BooleanNot
179## CHECK-NOT:                            BooleanNot
180
181## CHECK-START: boolean SmaliTests.$opt$noinline$booleanOrToAnd(boolean, boolean) instruction_simplifier$after_bce (after)
182## CHECK-NOT:                            Or
183.method public static $opt$noinline$booleanOrToAnd(ZZ)Z
184    .registers 4
185    .param p0, "a"    # Z
186    .param p1, "b"    # Z
187
188    .prologue
189    sget-boolean v0, LSmaliTests;->doThrow:Z
190    if-eqz v0, :cond_a
191    new-instance v0, Ljava/lang/Error;
192    invoke-direct {v0}, Ljava/lang/Error;-><init>()V
193    throw v0
194
195  :cond_a
196    # return !a | !b;
197    xor-int/lit8 v0, p0, 0x1
198    xor-int/lit8 v1, p1, 0x1
199    or-int/2addr v0, v1
200    return v0
201.end method
202
203# Test that the transformation copes with inputs being separated from the
204# bitwise operations.
205# This is a regression test. The initial logic was inserting the new bitwise
206# operation incorrectly.
207
208## CHECK-START: int SmaliTests.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (before)
209## CHECK-DAG:       <<P1:i\d+>>          ParameterValue
210## CHECK-DAG:       <<P2:i\d+>>          ParameterValue
211## CHECK-DAG:       <<Cst1:i\d+>>        IntConstant 1
212## CHECK-DAG:       <<AddP1:i\d+>>       Add [<<P1>>,<<Cst1>>]
213## CHECK-DAG:       <<Not1:i\d+>>        Not [<<AddP1>>]
214## CHECK-DAG:       <<AddP2:i\d+>>       Add [<<P2>>,<<Cst1>>]
215## CHECK-DAG:       <<Not2:i\d+>>        Not [<<AddP2>>]
216## CHECK-DAG:       <<Or:i\d+>>          Or [<<Not1>>,<<Not2>>]
217## CHECK-DAG:                            Return [<<Or>>]
218
219## CHECK-START: int SmaliTests.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (after)
220## CHECK-DAG:       <<P1:i\d+>>          ParameterValue
221## CHECK-DAG:       <<P2:i\d+>>          ParameterValue
222## CHECK-DAG:       <<Cst1:i\d+>>        IntConstant 1
223## CHECK-DAG:       <<AddP1:i\d+>>       Add [<<P1>>,<<Cst1>>]
224## CHECK-DAG:       <<AddP2:i\d+>>       Add [<<P2>>,<<Cst1>>]
225## CHECK-DAG:       <<And:i\d+>>         And [<<AddP1>>,<<AddP2>>]
226## CHECK-DAG:       <<Not:i\d+>>         Not [<<And>>]
227## CHECK-DAG:                            Return [<<Not>>]
228
229## CHECK-START: int SmaliTests.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (after)
230## CHECK-DAG:                            Not
231## CHECK-NOT:                            Not
232
233## CHECK-START: int SmaliTests.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (after)
234## CHECK-NOT:                            Or
235.method public static $opt$noinline$regressInputsAway(II)I
236    .registers 7
237    .param p0, "a"    # I
238    .param p1, "b"    # I
239
240    .prologue
241    sget-boolean v4, LSmaliTests;->doThrow:Z
242    if-eqz v4, :cond_a
243    new-instance v4, Ljava/lang/Error;
244    invoke-direct {v4}, Ljava/lang/Error;-><init>()V
245    throw v4
246
247  :cond_a
248    # int a1 = a + 1;
249    add-int/lit8 v0, p0, 0x1
250    # int not_a1 = ~a1;
251    not-int v2, v0
252    # int b1 = b + 1;
253    add-int/lit8 v1, p1, 0x1
254    # int not_b1 = ~b1;
255    not-int v3, v1
256
257    # return not_a1 | not_b1
258    or-int v4, v2, v3
259    return v4
260.end method
261
262# Test transformation of Not/Not/Xor into Xor.
263
264# See first note above.
265## CHECK-START: int SmaliTests.$opt$noinline$notXorToXor(int, int) instruction_simplifier (before)
266## CHECK-DAG:       <<P1:i\d+>>          ParameterValue
267## CHECK-DAG:       <<P2:i\d+>>          ParameterValue
268## CHECK-DAG:       <<Not1:i\d+>>        Not [<<P1>>]
269## CHECK-DAG:       <<Not2:i\d+>>        Not [<<P2>>]
270## CHECK-DAG:       <<Xor:i\d+>>         Xor [<<Not1>>,<<Not2>>]
271## CHECK-DAG:                            Return [<<Xor>>]
272
273## CHECK-START: int SmaliTests.$opt$noinline$notXorToXor(int, int) instruction_simplifier (after)
274## CHECK-DAG:       <<P1:i\d+>>          ParameterValue
275## CHECK-DAG:       <<P2:i\d+>>          ParameterValue
276## CHECK-DAG:       <<Xor:i\d+>>         Xor [<<P1>>,<<P2>>]
277## CHECK-DAG:                            Return [<<Xor>>]
278
279## CHECK-START: int SmaliTests.$opt$noinline$notXorToXor(int, int) instruction_simplifier (after)
280## CHECK-NOT:                            Not
281.method public static $opt$noinline$notXorToXor(II)I
282    .registers 4
283    .param p0, "a"    # I
284    .param p1, "b"    # I
285
286    .prologue
287    sget-boolean v0, LSmaliTests;->doThrow:Z
288    if-eqz v0, :cond_a
289    new-instance v0, Ljava/lang/Error;
290    invoke-direct {v0}, Ljava/lang/Error;-><init>()V
291    throw v0
292
293  :cond_a
294    # return ~a ^ ~b;
295    not-int v0, p0
296    not-int v1, p1
297    xor-int/2addr v0, v1
298    return v0
299.end method
300
301# Test transformation of Not/Not/Xor into Xor for boolean negations.
302# Note that the graph before this instruction simplification pass does not
303# contain `HBooleanNot` instructions. This is because this transformation
304# follows the optimization of `HSelect` to `HBooleanNot` occurring in the
305# same pass.
306
307## CHECK-START: boolean SmaliTests.$opt$noinline$booleanNotXorToXor(boolean, boolean) instruction_simplifier (before)
308## CHECK-DAG:       <<P1:z\d+>>          ParameterValue
309## CHECK-DAG:       <<P2:z\d+>>          ParameterValue
310## CHECK-DAG:       <<Const1:i\d+>>      IntConstant 1
311## CHECK-DAG:       <<NotP1:i\d+>>       Xor [<<P1>>,<<Const1>>]
312## CHECK-DAG:       <<NotP2:i\d+>>       Xor [<<P2>>,<<Const1>>]
313## CHECK-DAG:       <<Xor:i\d+>>         Xor [<<NotP1>>,<<NotP2>>]
314## CHECK-DAG:                            Return [<<Xor>>]
315
316## CHECK-START: boolean SmaliTests.$opt$noinline$booleanNotXorToXor(boolean, boolean) instruction_simplifier (after)
317## CHECK-DAG:       <<Cond1:z\d+>>       ParameterValue
318## CHECK-DAG:       <<Cond2:z\d+>>       ParameterValue
319## CHECK-DAG:       <<Xor:i\d+>>         Xor [<<Cond1>>,<<Cond2>>]
320## CHECK-DAG:                            Return [<<Xor>>]
321
322## CHECK-START: boolean SmaliTests.$opt$noinline$booleanNotXorToXor(boolean, boolean) instruction_simplifier$after_bce (after)
323## CHECK-NOT:                            BooleanNot
324.method public static $opt$noinline$booleanNotXorToXor(ZZ)Z
325    .registers 4
326    .param p0, "a"    # Z
327    .param p1, "b"    # Z
328
329    .prologue
330    sget-boolean v0, LSmaliTests;->doThrow:Z
331    if-eqz v0, :cond_a
332    new-instance v0, Ljava/lang/Error;
333    invoke-direct {v0}, Ljava/lang/Error;-><init>()V
334    throw v0
335
336  :cond_a
337    # return !a ^ !b;
338    xor-int/lit8 v0, p0, 0x1
339    xor-int/lit8 v1, p1, 0x1
340    xor-int/2addr v0, v1
341    return v0
342.end method
343
344# Check that no transformation is done when one Not has multiple uses.
345
346## CHECK-START: int SmaliTests.$opt$noinline$notMultipleUses(int, int) instruction_simplifier (before)
347## CHECK-DAG:       <<P1:i\d+>>          ParameterValue
348## CHECK-DAG:       <<P2:i\d+>>          ParameterValue
349## CHECK-DAG:       <<One:i\d+>>         IntConstant 1
350## CHECK-DAG:       <<Not2:i\d+>>        Not [<<P2>>]
351## CHECK-DAG:       <<And2:i\d+>>        And [<<Not2>>,<<One>>]
352## CHECK-DAG:       <<Not1:i\d+>>        Not [<<P1>>]
353## CHECK-DAG:       <<And1:i\d+>>        And [<<Not1>>,<<Not2>>]
354## CHECK-DAG:       <<Add:i\d+>>         Add [<<And2>>,<<And1>>]
355## CHECK-DAG:                            Return [<<Add>>]
356
357## CHECK-START: int SmaliTests.$opt$noinline$notMultipleUses(int, int) instruction_simplifier (after)
358## CHECK-DAG:       <<P1:i\d+>>          ParameterValue
359## CHECK-DAG:       <<P2:i\d+>>          ParameterValue
360## CHECK-DAG:       <<One:i\d+>>         IntConstant 1
361## CHECK-DAG:       <<Not2:i\d+>>        Not [<<P2>>]
362## CHECK-DAG:       <<And2:i\d+>>        And [<<Not2>>,<<One>>]
363## CHECK-DAG:       <<Not1:i\d+>>        Not [<<P1>>]
364## CHECK-DAG:       <<And1:i\d+>>        And [<<Not1>>,<<Not2>>]
365## CHECK-DAG:       <<Add:i\d+>>         Add [<<And2>>,<<And1>>]
366## CHECK-DAG:                            Return [<<Add>>]
367
368## CHECK-START: int SmaliTests.$opt$noinline$notMultipleUses(int, int) instruction_simplifier (after)
369## CHECK-NOT:                            Or
370.method public static $opt$noinline$notMultipleUses(II)I
371    .registers 5
372    .param p0, "a"    # I
373    .param p1, "b"    # I
374
375    .prologue
376    sget-boolean v1, LSmaliTests;->doThrow:Z
377    if-eqz v1, :cond_a
378    new-instance v1, Ljava/lang/Error;
379    invoke-direct {v1}, Ljava/lang/Error;-><init>()V
380    throw v1
381
382  :cond_a
383    # int tmp = ~b;
384    not-int v0, p1
385    # return (tmp & 0x1) + (~a & tmp);
386    and-int/lit8 v1, v0, 0x1
387    not-int v2, p0
388    and-int/2addr v2, v0
389    add-int/2addr v1, v2
390    return v1
391.end method
392
393# static fields
394.field static doThrow:Z # boolean
395
396# direct methods
397.method static constructor <clinit>()V
398    .registers 1
399
400    .prologue
401    # doThrow = false
402    const/4 v0, 0x0
403    sput-boolean v0, LSmaliTests;->doThrow:Z
404    return-void
405.end method
406
407
408# Test transformation of Not/Not/And into Or/Not.
409
410# Note: before the instruction_simplifier pass, Xor's are used instead of
411# Not's (the simplification happens during the same pass).
412## CHECK-START: int SmaliTests.$opt$noinline$andToOrV2(int, int) instruction_simplifier (before)
413## CHECK-DAG:       <<P1:i\d+>>          ParameterValue
414## CHECK-DAG:       <<P2:i\d+>>          ParameterValue
415## CHECK-DAG:       <<CstM1:i\d+>>       IntConstant -1
416## CHECK-DAG:       <<Not1:i\d+>>        Xor [<<P1>>,<<CstM1>>]
417## CHECK-DAG:       <<Not2:i\d+>>        Xor [<<P2>>,<<CstM1>>]
418## CHECK-DAG:       <<And:i\d+>>         And [<<Not1>>,<<Not2>>]
419## CHECK-DAG:                            Return [<<And>>]
420
421## CHECK-START: int SmaliTests.$opt$noinline$andToOrV2(int, int) instruction_simplifier (after)
422## CHECK-DAG:       <<P1:i\d+>>          ParameterValue
423## CHECK-DAG:       <<P2:i\d+>>          ParameterValue
424## CHECK-DAG:       <<Or:i\d+>>          Or [<<P1>>,<<P2>>]
425## CHECK-DAG:       <<Not:i\d+>>         Not [<<Or>>]
426## CHECK-DAG:                            Return [<<Not>>]
427
428## CHECK-START: int SmaliTests.$opt$noinline$andToOrV2(int, int) instruction_simplifier (after)
429## CHECK-DAG:                            Not
430## CHECK-NOT:                            Not
431
432## CHECK-START: int SmaliTests.$opt$noinline$andToOrV2(int, int) instruction_simplifier (after)
433## CHECK-NOT:                            And
434
435# Original java source:
436#
437#     public static int $opt$noinline$andToOr(int a, int b) {
438#       if (doThrow) throw new Error();
439#       return ~a & ~b;
440#     }
441
442.method public static $opt$noinline$andToOrV2(II)I
443    .registers 4
444    .param p0, "a"    # I
445    .param p1, "b"    # I
446
447    .prologue
448    .line 85
449    sget-boolean v0, LMain;->doThrow:Z
450
451    if-eqz v0, :cond_a
452
453    new-instance v0, Ljava/lang/Error;
454
455    invoke-direct {v0}, Ljava/lang/Error;-><init>()V
456
457    throw v0
458
459    .line 86
460    :cond_a
461    xor-int/lit8 v0, p0, -0x1
462
463    xor-int/lit8 v1, p1, -0x1
464
465    and-int/2addr v0, v1
466
467    return v0
468.end method
469
470
471# Test transformation of Not/Not/And into Or/Not for boolean negations.
472# Note that the graph before this instruction simplification pass does not
473# contain `HBooleanNot` instructions. This is because this transformation
474# follows the optimization of `HSelect` to `HBooleanNot` occurring in the
475# same pass.
476
477## CHECK-START: boolean SmaliTests.$opt$noinline$booleanAndToOrV2(boolean, boolean) instruction_simplifier$after_gvn (before)
478## CHECK-DAG:       <<P1:z\d+>>          ParameterValue
479## CHECK-DAG:       <<P2:z\d+>>          ParameterValue
480## CHECK-DAG:       <<Const0:i\d+>>      IntConstant 0
481## CHECK-DAG:       <<Const1:i\d+>>      IntConstant 1
482## CHECK-DAG:       <<Select1:i\d+>>     Select [<<Const1>>,<<Const0>>,<<P1>>]
483## CHECK-DAG:       <<Select2:i\d+>>     Select [<<Const1>>,<<Const0>>,<<P2>>]
484## CHECK-DAG:       <<And:i\d+>>         And [<<Select1>>,<<Select2>>]
485## CHECK-DAG:                            Return [<<And>>]
486
487## CHECK-START: boolean SmaliTests.$opt$noinline$booleanAndToOrV2(boolean, boolean) instruction_simplifier$after_gvn (after)
488## CHECK-DAG:       <<Cond1:z\d+>>       ParameterValue
489## CHECK-DAG:       <<Cond2:z\d+>>       ParameterValue
490## CHECK-DAG:       <<Or:i\d+>>          Or [<<Cond1>>,<<Cond2>>]
491## CHECK-DAG:       <<BooleanNot:z\d+>>  BooleanNot [<<Or>>]
492## CHECK-DAG:                            Return [<<BooleanNot>>]
493
494## CHECK-START: boolean SmaliTests.$opt$noinline$booleanAndToOrV2(boolean, boolean) instruction_simplifier$after_bce (after)
495## CHECK-DAG:                            BooleanNot
496## CHECK-NOT:                            BooleanNot
497
498## CHECK-START: boolean SmaliTests.$opt$noinline$booleanAndToOrV2(boolean, boolean) instruction_simplifier$after_bce (after)
499## CHECK-NOT:                            And
500
501# Original java source:
502#
503#     public static boolean $opt$noinline$booleanAndToOr(boolean a, boolean b) {
504#       if (doThrow) throw new Error();
505#       return !a & !b;
506#     }
507
508.method public static $opt$noinline$booleanAndToOrV2(ZZ)Z
509    .registers 5
510    .param p0, "a"    # Z
511    .param p1, "b"    # Z
512
513    .prologue
514    const/4 v0, 0x1
515
516    const/4 v1, 0x0
517
518    .line 122
519    sget-boolean v2, LMain;->doThrow:Z
520
521    if-eqz v2, :cond_c
522
523    new-instance v0, Ljava/lang/Error;
524
525    invoke-direct {v0}, Ljava/lang/Error;-><init>()V
526
527    throw v0
528
529    .line 123
530    :cond_c
531    if-nez p0, :cond_13
532
533    move v2, v0
534
535    :goto_f
536    if-nez p1, :cond_15
537
538    :goto_11
539    and-int/2addr v0, v2
540
541    return v0
542
543    :cond_13
544    move v2, v1
545
546    goto :goto_f
547
548    :cond_15
549    move v0, v1
550
551    goto :goto_11
552.end method
553
554
555# Test transformation of Not/Not/Or into And/Not.
556
557# See note above.
558# The second Xor has its arguments reversed for no obvious reason.
559## CHECK-START: long SmaliTests.$opt$noinline$orToAndV2(long, long) instruction_simplifier (before)
560## CHECK-DAG:       <<P1:j\d+>>          ParameterValue
561## CHECK-DAG:       <<P2:j\d+>>          ParameterValue
562## CHECK-DAG:       <<CstM1:j\d+>>       LongConstant -1
563## CHECK-DAG:       <<Not1:j\d+>>        Xor [<<P1>>,<<CstM1>>]
564## CHECK-DAG:       <<Not2:j\d+>>        Xor [<<CstM1>>,<<P2>>]
565## CHECK-DAG:       <<Or:j\d+>>          Or [<<Not1>>,<<Not2>>]
566## CHECK-DAG:                            Return [<<Or>>]
567
568## CHECK-START: long SmaliTests.$opt$noinline$orToAndV2(long, long) instruction_simplifier (after)
569## CHECK-DAG:       <<P1:j\d+>>          ParameterValue
570## CHECK-DAG:       <<P2:j\d+>>          ParameterValue
571## CHECK-DAG:       <<And:j\d+>>         And [<<P1>>,<<P2>>]
572## CHECK-DAG:       <<Not:j\d+>>         Not [<<And>>]
573## CHECK-DAG:                            Return [<<Not>>]
574
575## CHECK-START: long SmaliTests.$opt$noinline$orToAndV2(long, long) instruction_simplifier (after)
576## CHECK-DAG:                            Not
577## CHECK-NOT:                            Not
578
579## CHECK-START: long SmaliTests.$opt$noinline$orToAndV2(long, long) instruction_simplifier (after)
580## CHECK-NOT:                            Or
581
582# Original java source:
583#
584#     public static long $opt$noinline$orToAnd(long a, long b) {
585#       if (doThrow) throw new Error();
586#       return ~a | ~b;
587#     }
588
589.method public static $opt$noinline$orToAndV2(JJ)J
590    .registers 8
591    .param p0, "a"    # J
592    .param p2, "b"    # J
593
594    .prologue
595    const-wide/16 v2, -0x1
596
597    .line 156
598    sget-boolean v0, LMain;->doThrow:Z
599
600    if-eqz v0, :cond_c
601
602    new-instance v0, Ljava/lang/Error;
603
604    invoke-direct {v0}, Ljava/lang/Error;-><init>()V
605
606    throw v0
607
608    .line 157
609    :cond_c
610    xor-long v0, p0, v2
611
612    xor-long/2addr v2, p2
613
614    or-long/2addr v0, v2
615
616    return-wide v0
617.end method
618
619# Test transformation of Not/Not/Or into Or/And for boolean negations.
620# Note that the graph before this instruction simplification pass does not
621# contain `HBooleanNot` instructions. This is because this transformation
622# follows the optimization of `HSelect` to `HBooleanNot` occurring in the
623# same pass.
624
625## CHECK-START: boolean SmaliTests.$opt$noinline$booleanOrToAndV2(boolean, boolean) instruction_simplifier$after_gvn (before)
626## CHECK-DAG:       <<P1:z\d+>>          ParameterValue
627## CHECK-DAG:       <<P2:z\d+>>          ParameterValue
628## CHECK-DAG:       <<Const0:i\d+>>      IntConstant 0
629## CHECK-DAG:       <<Const1:i\d+>>      IntConstant 1
630## CHECK-DAG:       <<Select1:i\d+>>     Select [<<Const1>>,<<Const0>>,<<P1>>]
631## CHECK-DAG:       <<Select2:i\d+>>     Select [<<Const1>>,<<Const0>>,<<P2>>]
632## CHECK-DAG:       <<Or:i\d+>>          Or [<<Select1>>,<<Select2>>]
633## CHECK-DAG:                            Return [<<Or>>]
634
635## CHECK-START: boolean SmaliTests.$opt$noinline$booleanOrToAndV2(boolean, boolean) instruction_simplifier$after_gvn (after)
636## CHECK-DAG:       <<Cond1:z\d+>>       ParameterValue
637## CHECK-DAG:       <<Cond2:z\d+>>       ParameterValue
638## CHECK-DAG:       <<And:i\d+>>         And [<<Cond1>>,<<Cond2>>]
639## CHECK-DAG:       <<BooleanNot:z\d+>>  BooleanNot [<<And>>]
640## CHECK-DAG:                            Return [<<BooleanNot>>]
641
642## CHECK-START: boolean SmaliTests.$opt$noinline$booleanOrToAndV2(boolean, boolean) instruction_simplifier$after_bce (after)
643## CHECK-DAG:                            BooleanNot
644## CHECK-NOT:                            BooleanNot
645
646## CHECK-START: boolean SmaliTests.$opt$noinline$booleanOrToAndV2(boolean, boolean) instruction_simplifier$after_bce (after)
647## CHECK-NOT:                            Or
648
649# Original java source:
650#
651#     public static boolean $opt$noinline$booleanOrToAnd(boolean a, boolean b) {
652#       if (doThrow) throw new Error();
653#       return !a | !b;
654#     }
655
656.method public static $opt$noinline$booleanOrToAndV2(ZZ)Z
657    .registers 5
658    .param p0, "a"    # Z
659    .param p1, "b"    # Z
660
661    .prologue
662    const/4 v0, 0x1
663
664    const/4 v1, 0x0
665
666    .line 193
667    sget-boolean v2, LMain;->doThrow:Z
668
669    if-eqz v2, :cond_c
670
671    new-instance v0, Ljava/lang/Error;
672
673    invoke-direct {v0}, Ljava/lang/Error;-><init>()V
674
675    throw v0
676
677    .line 194
678    :cond_c
679    if-nez p0, :cond_13
680
681    move v2, v0
682
683    :goto_f
684    if-nez p1, :cond_15
685
686    :goto_11
687    or-int/2addr v0, v2
688
689    return v0
690
691    :cond_13
692    move v2, v1
693
694    goto :goto_f
695
696    :cond_15
697    move v0, v1
698
699    goto :goto_11
700.end method
701
702
703# Test that the transformation copes with inputs being separated from the
704# bitwise operations.
705# This is a regression test. The initial logic was inserting the new bitwise
706# operation incorrectly.
707
708## CHECK-START: int SmaliTests.$opt$noinline$regressInputsAwayV2(int, int) instruction_simplifier (before)
709## CHECK-DAG:       <<P1:i\d+>>          ParameterValue
710## CHECK-DAG:       <<P2:i\d+>>          ParameterValue
711## CHECK-DAG:       <<Cst1:i\d+>>        IntConstant 1
712## CHECK-DAG:       <<CstM1:i\d+>>       IntConstant -1
713## CHECK-DAG:       <<AddP1:i\d+>>       Add [<<P1>>,<<Cst1>>]
714## CHECK-DAG:       <<Not1:i\d+>>        Xor [<<AddP1>>,<<CstM1>>]
715## CHECK-DAG:       <<AddP2:i\d+>>       Add [<<P2>>,<<Cst1>>]
716## CHECK-DAG:       <<Not2:i\d+>>        Xor [<<AddP2>>,<<CstM1>>]
717## CHECK-DAG:       <<Or:i\d+>>          Or [<<Not1>>,<<Not2>>]
718## CHECK-DAG:                            Return [<<Or>>]
719
720## CHECK-START: int SmaliTests.$opt$noinline$regressInputsAwayV2(int, int) instruction_simplifier (after)
721## CHECK-DAG:       <<P1:i\d+>>          ParameterValue
722## CHECK-DAG:       <<P2:i\d+>>          ParameterValue
723## CHECK-DAG:       <<Cst1:i\d+>>        IntConstant 1
724## CHECK-DAG:       <<AddP1:i\d+>>       Add [<<P1>>,<<Cst1>>]
725## CHECK-DAG:       <<AddP2:i\d+>>       Add [<<P2>>,<<Cst1>>]
726## CHECK-DAG:       <<And:i\d+>>         And [<<AddP1>>,<<AddP2>>]
727## CHECK-DAG:       <<Not:i\d+>>         Not [<<And>>]
728## CHECK-DAG:                            Return [<<Not>>]
729
730## CHECK-START: int SmaliTests.$opt$noinline$regressInputsAwayV2(int, int) instruction_simplifier (after)
731## CHECK-DAG:                            Not
732## CHECK-NOT:                            Not
733
734## CHECK-START: int SmaliTests.$opt$noinline$regressInputsAwayV2(int, int) instruction_simplifier (after)
735## CHECK-NOT:                            Or
736
737# Original java source:
738#
739#     public static int $opt$noinline$regressInputsAway(int a, int b) {
740#       if (doThrow) throw new Error();
741#       int a1 = a + 1;
742#       int not_a1 = ~a1;
743#       int b1 = b + 1;
744#       int not_b1 = ~b1;
745#       return not_a1 | not_b1;
746#     }
747
748.method public static $opt$noinline$regressInputsAwayV2(II)I
749    .registers 7
750    .param p0, "a"    # I
751    .param p1, "b"    # I
752
753    .prologue
754    .line 234
755    sget-boolean v4, LMain;->doThrow:Z
756
757    if-eqz v4, :cond_a
758
759    new-instance v4, Ljava/lang/Error;
760
761    invoke-direct {v4}, Ljava/lang/Error;-><init>()V
762
763    throw v4
764
765    .line 235
766    :cond_a
767    add-int/lit8 v0, p0, 0x1
768
769    .line 236
770    .local v0, "a1":I
771    xor-int/lit8 v2, v0, -0x1
772
773    .line 237
774    .local v2, "not_a1":I
775    add-int/lit8 v1, p1, 0x1
776
777    .line 238
778    .local v1, "b1":I
779    xor-int/lit8 v3, v1, -0x1
780
781    .line 239
782    .local v3, "not_b1":I
783    or-int v4, v2, v3
784
785    return v4
786.end method
787
788
789# Test transformation of Not/Not/Xor into Xor.
790
791# See first note above.
792## CHECK-START: int SmaliTests.$opt$noinline$notXorToXorV2(int, int) instruction_simplifier (before)
793## CHECK-DAG:       <<P1:i\d+>>          ParameterValue
794## CHECK-DAG:       <<P2:i\d+>>          ParameterValue
795## CHECK-DAG:       <<CstM1:i\d+>>       IntConstant -1
796## CHECK-DAG:       <<Not1:i\d+>>        Xor [<<P1>>,<<CstM1>>]
797## CHECK-DAG:       <<Not2:i\d+>>        Xor [<<P2>>,<<CstM1>>]
798## CHECK-DAG:       <<Xor:i\d+>>         Xor [<<Not1>>,<<Not2>>]
799## CHECK-DAG:                            Return [<<Xor>>]
800
801## CHECK-START: int SmaliTests.$opt$noinline$notXorToXorV2(int, int) instruction_simplifier (after)
802## CHECK-DAG:       <<P1:i\d+>>          ParameterValue
803## CHECK-DAG:       <<P2:i\d+>>          ParameterValue
804## CHECK-DAG:       <<Xor:i\d+>>         Xor [<<P1>>,<<P2>>]
805## CHECK-DAG:                            Return [<<Xor>>]
806
807## CHECK-START: int SmaliTests.$opt$noinline$notXorToXorV2(int, int) instruction_simplifier (after)
808## CHECK-NOT:                            Not
809
810# Original java source:
811#
812#     public static int $opt$noinline$notXorToXor(int a, int b) {
813#       if (doThrow) throw new Error();
814#       return ~a ^ ~b;
815#     }
816
817.method public static $opt$noinline$notXorToXorV2(II)I
818    .registers 4
819    .param p0, "a"    # I
820    .param p1, "b"    # I
821
822    .prologue
823    .line 266
824    sget-boolean v0, LMain;->doThrow:Z
825
826    if-eqz v0, :cond_a
827
828    new-instance v0, Ljava/lang/Error;
829
830    invoke-direct {v0}, Ljava/lang/Error;-><init>()V
831
832    throw v0
833
834    .line 267
835    :cond_a
836    xor-int/lit8 v0, p0, -0x1
837
838    xor-int/lit8 v1, p1, -0x1
839
840    xor-int/2addr v0, v1
841
842    return v0
843.end method
844
845
846# Test transformation of Not/Not/Xor into Xor for boolean negations.
847# Note that the graph before this instruction simplification pass does not
848# contain `HBooleanNot` instructions. This is because this transformation
849# follows the optimization of `HSelect` to `HBooleanNot` occurring in the
850# same pass.
851
852## CHECK-START: boolean SmaliTests.$opt$noinline$booleanNotXorToXorV2(boolean, boolean) instruction_simplifier$after_gvn (before)
853## CHECK-DAG:       <<P1:z\d+>>          ParameterValue
854## CHECK-DAG:       <<P2:z\d+>>          ParameterValue
855## CHECK-DAG:       <<Const0:i\d+>>      IntConstant 0
856## CHECK-DAG:       <<Const1:i\d+>>      IntConstant 1
857## CHECK-DAG:       <<Select1:i\d+>>     Select [<<Const1>>,<<Const0>>,<<P1>>]
858## CHECK-DAG:       <<Select2:i\d+>>     Select [<<Const1>>,<<Const0>>,<<P2>>]
859## CHECK-DAG:       <<Xor:i\d+>>         Xor [<<Select1>>,<<Select2>>]
860## CHECK-DAG:                            Return [<<Xor>>]
861
862## CHECK-START: boolean SmaliTests.$opt$noinline$booleanNotXorToXorV2(boolean, boolean) instruction_simplifier$after_gvn (after)
863## CHECK-DAG:       <<Cond1:z\d+>>       ParameterValue
864## CHECK-DAG:       <<Cond2:z\d+>>       ParameterValue
865## CHECK-DAG:       <<Xor:i\d+>>         Xor [<<Cond1>>,<<Cond2>>]
866## CHECK-DAG:                            Return [<<Xor>>]
867
868## CHECK-START: boolean SmaliTests.$opt$noinline$booleanNotXorToXorV2(boolean, boolean) instruction_simplifier$after_bce (after)
869## CHECK-NOT:                            BooleanNot
870
871# Original java source:
872#
873#     public static boolean $opt$noinline$booleanNotXorToXor(boolean a, boolean b) {
874#       if (doThrow) throw new Error();
875#       return !a ^ !b;
876#     }
877
878.method public static $opt$noinline$booleanNotXorToXorV2(ZZ)Z
879    .registers 5
880    .param p0, "a"    # Z
881    .param p1, "b"    # Z
882
883    .prologue
884    const/4 v0, 0x1
885
886    const/4 v1, 0x0
887
888    .line 298
889    sget-boolean v2, LMain;->doThrow:Z
890
891    if-eqz v2, :cond_c
892
893    new-instance v0, Ljava/lang/Error;
894
895    invoke-direct {v0}, Ljava/lang/Error;-><init>()V
896
897    throw v0
898
899    .line 299
900    :cond_c
901    if-nez p0, :cond_13
902
903    move v2, v0
904
905    :goto_f
906    if-nez p1, :cond_15
907
908    :goto_11
909    xor-int/2addr v0, v2
910
911    return v0
912
913    :cond_13
914    move v2, v1
915
916    goto :goto_f
917
918    :cond_15
919    move v0, v1
920
921    goto :goto_11
922.end method
923
924
925# Check that no transformation is done when one Not has multiple uses.
926
927## CHECK-START: int SmaliTests.$opt$noinline$notMultipleUsesV2(int, int) instruction_simplifier (before)
928## CHECK-DAG:       <<P1:i\d+>>          ParameterValue
929## CHECK-DAG:       <<P2:i\d+>>          ParameterValue
930## CHECK-DAG:       <<CstM1:i\d+>>       IntConstant -1
931## CHECK-DAG:       <<One:i\d+>>         IntConstant 1
932## CHECK-DAG:       <<Not2:i\d+>>        Xor [<<P2>>,<<CstM1>>]
933## CHECK-DAG:       <<And2:i\d+>>        And [<<Not2>>,<<One>>]
934## CHECK-DAG:       <<Not1:i\d+>>        Xor [<<P1>>,<<CstM1>>]
935## CHECK-DAG:       <<And1:i\d+>>        And [<<Not1>>,<<Not2>>]
936## CHECK-DAG:       <<Add:i\d+>>         Add [<<And2>>,<<And1>>]
937## CHECK-DAG:                            Return [<<Add>>]
938
939## CHECK-START: int SmaliTests.$opt$noinline$notMultipleUsesV2(int, int) instruction_simplifier (after)
940## CHECK-DAG:       <<P1:i\d+>>          ParameterValue
941## CHECK-DAG:       <<P2:i\d+>>          ParameterValue
942## CHECK-DAG:       <<One:i\d+>>         IntConstant 1
943## CHECK-DAG:       <<Not2:i\d+>>        Not [<<P2>>]
944## CHECK-DAG:       <<And2:i\d+>>        And [<<Not2>>,<<One>>]
945## CHECK-DAG:       <<Not1:i\d+>>        Not [<<P1>>]
946## CHECK-DAG:       <<And1:i\d+>>        And [<<Not1>>,<<Not2>>]
947## CHECK-DAG:       <<Add:i\d+>>         Add [<<And2>>,<<And1>>]
948## CHECK-DAG:                            Return [<<Add>>]
949
950## CHECK-START: int SmaliTests.$opt$noinline$notMultipleUsesV2(int, int) instruction_simplifier (after)
951## CHECK-NOT:                            Or
952
953# Original java source:
954#
955#     public static int $opt$noinline$notMultipleUses(int a, int b) {
956#       if (doThrow) throw new Error();
957#       int tmp = ~b;
958#       return (tmp & 0x1) + (~a & tmp);
959#     }
960
961.method public static $opt$noinline$notMultipleUsesV2(II)I
962    .registers 5
963    .param p0, "a"    # I
964    .param p1, "b"    # I
965
966    .prologue
967    .line 333
968    sget-boolean v1, LMain;->doThrow:Z
969
970    if-eqz v1, :cond_a
971
972    new-instance v1, Ljava/lang/Error;
973
974    invoke-direct {v1}, Ljava/lang/Error;-><init>()V
975
976    throw v1
977
978    .line 334
979    :cond_a
980    xor-int/lit8 v0, p1, -0x1
981
982    .line 335
983    .local v0, "tmp":I
984    and-int/lit8 v1, v0, 0x1
985
986    xor-int/lit8 v2, p0, -0x1
987
988    and-int/2addr v2, v0
989
990    add-int/2addr v1, v2
991
992    return v1
993.end method
994