• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 import java.lang.reflect.Method;
18 
19 public class Main {
20 
21   // A dummy value to defeat inlining of these routines.
22   static boolean doThrow = false;
23 
assertIntEquals(int expected, int result)24   public static void assertIntEquals(int expected, int result) {
25     if (expected != result) {
26       throw new Error("Expected: " + expected + ", found: " + result);
27     }
28   }
29 
assertLongEquals(long expected, long result)30   public static void assertLongEquals(long expected, long result) {
31     if (expected != result) {
32       throw new Error("Expected: " + expected + ", found: " + result);
33     }
34   }
35 
assertEquals(boolean expected, boolean result)36   public static void assertEquals(boolean expected, boolean result) {
37     if (expected != result) {
38       throw new Error("Expected: " + expected + ", found: " + result);
39     }
40   }
41 
$noinline$runSmaliTest(String name, Class<T> klass, T input1, T input2)42   public static <T> T $noinline$runSmaliTest(String name, Class<T> klass, T input1, T input2) {
43     if (doThrow) { throw new Error(); }
44 
45     Class<T> inputKlass = (Class<T>)input1.getClass();
46     try {
47       Class<?> c = Class.forName("SmaliTests");
48       Method m = c.getMethod(name, klass, klass);
49       return inputKlass.cast(m.invoke(null, input1, input2));
50     } catch (Exception ex) {
51       throw new Error(ex);
52     }
53   }
54 
55   /**
56    * Test transformation of Not/Not/And into Or/Not.
57    */
58 
59   // Note: before the instruction_simplifier pass, Xor's are used instead of
60   // Not's (the simplification happens during the same pass).
61   /// CHECK-START: int Main.$opt$noinline$andToOr(int, int) instruction_simplifier (before)
62   /// CHECK-DAG:       <<P1:i\d+>>          ParameterValue
63   /// CHECK-DAG:       <<P2:i\d+>>          ParameterValue
64   /// CHECK-DAG:       <<CstM1:i\d+>>       IntConstant -1
65   /// CHECK-DAG:       <<Not1:i\d+>>        Xor [<<P1>>,<<CstM1>>]
66   /// CHECK-DAG:       <<Not2:i\d+>>        Xor [<<P2>>,<<CstM1>>]
67   /// CHECK-DAG:       <<And:i\d+>>         And [<<Not1>>,<<Not2>>]
68   /// CHECK-DAG:                            Return [<<And>>]
69 
70   /// CHECK-START: int Main.$opt$noinline$andToOr(int, int) instruction_simplifier (after)
71   /// CHECK-DAG:       <<P1:i\d+>>          ParameterValue
72   /// CHECK-DAG:       <<P2:i\d+>>          ParameterValue
73   /// CHECK-DAG:       <<Or:i\d+>>          Or [<<P1>>,<<P2>>]
74   /// CHECK-DAG:       <<Not:i\d+>>         Not [<<Or>>]
75   /// CHECK-DAG:                            Return [<<Not>>]
76 
77   /// CHECK-START: int Main.$opt$noinline$andToOr(int, int) instruction_simplifier (after)
78   /// CHECK-DAG:                            Not
79   /// CHECK-NOT:                            Not
80 
81   /// CHECK-START: int Main.$opt$noinline$andToOr(int, int) instruction_simplifier (after)
82   /// CHECK-NOT:                            And
83 
$opt$noinline$andToOr(int a, int b)84   public static int $opt$noinline$andToOr(int a, int b) {
85     if (doThrow) throw new Error();
86     return ~a & ~b;
87   }
88 
89   /**
90    * Test transformation of Not/Not/And into Or/Not for boolean negations.
91    * Note that the graph before this instruction simplification pass does not
92    * contain `HBooleanNot` instructions. This is because this transformation
93    * follows the optimization of `HSelect` to `HBooleanNot` occurring in the
94    * same pass.
95    */
96 
97   /// CHECK-START: boolean Main.$opt$noinline$booleanAndToOr(boolean, boolean) instruction_simplifier$after_inlining (before)
98   /// CHECK-DAG:       <<P1:z\d+>>          ParameterValue
99   /// CHECK-DAG:       <<P2:z\d+>>          ParameterValue
100   /// CHECK-DAG:       <<Const0:i\d+>>      IntConstant 0
101   /// CHECK-DAG:       <<Const1:i\d+>>      IntConstant 1
102   /// CHECK-DAG:       <<Select1:i\d+>>     Select [<<Const1>>,<<Const0>>,<<P1>>]
103   /// CHECK-DAG:       <<Select2:i\d+>>     Select [<<Const1>>,<<Const0>>,<<P2>>]
104   /// CHECK-DAG:       <<And:i\d+>>         And [<<Select2>>,<<Select1>>]
105   /// CHECK-DAG:                            Return [<<And>>]
106 
107   /// CHECK-START: boolean Main.$opt$noinline$booleanAndToOr(boolean, boolean) instruction_simplifier$after_inlining (after)
108   /// CHECK-DAG:       <<Cond1:z\d+>>       ParameterValue
109   /// CHECK-DAG:       <<Cond2:z\d+>>       ParameterValue
110   /// CHECK-DAG:       <<Or:i\d+>>          Or [<<Cond2>>,<<Cond1>>]
111   /// CHECK-DAG:       <<BooleanNot:z\d+>>  BooleanNot [<<Or>>]
112   /// CHECK-DAG:                            Return [<<BooleanNot>>]
113 
114   /// CHECK-START: boolean Main.$opt$noinline$booleanAndToOr(boolean, boolean) instruction_simplifier$after_bce (after)
115   /// CHECK-DAG:                            BooleanNot
116   /// CHECK-NOT:                            BooleanNot
117 
118   /// CHECK-START: boolean Main.$opt$noinline$booleanAndToOr(boolean, boolean) instruction_simplifier$after_bce (after)
119   /// CHECK-NOT:                            And
120 
$opt$noinline$booleanAndToOr(boolean a, boolean b)121   public static boolean $opt$noinline$booleanAndToOr(boolean a, boolean b) {
122     if (doThrow) throw new Error();
123     return !a & !b;
124   }
125 
126   /**
127    * Test transformation of Not/Not/Or into And/Not.
128    */
129 
130   // See note above.
131   // The second Xor has its arguments reversed for no obvious reason.
132   /// CHECK-START: long Main.$opt$noinline$orToAnd(long, long) instruction_simplifier (before)
133   /// CHECK-DAG:       <<P1:j\d+>>          ParameterValue
134   /// CHECK-DAG:       <<P2:j\d+>>          ParameterValue
135   /// CHECK-DAG:       <<CstM1:j\d+>>       LongConstant -1
136   /// CHECK-DAG:       <<Not1:j\d+>>        Xor [<<P1>>,<<CstM1>>]
137   /// CHECK-DAG:       <<Not2:j\d+>>        Xor [<<CstM1>>,<<P2>>]
138   /// CHECK-DAG:       <<Or:j\d+>>          Or [<<Not1>>,<<Not2>>]
139   /// CHECK-DAG:                            Return [<<Or>>]
140 
141   /// CHECK-START: long Main.$opt$noinline$orToAnd(long, long) instruction_simplifier (after)
142   /// CHECK-DAG:       <<P1:j\d+>>          ParameterValue
143   /// CHECK-DAG:       <<P2:j\d+>>          ParameterValue
144   /// CHECK-DAG:       <<And:j\d+>>         And [<<P1>>,<<P2>>]
145   /// CHECK-DAG:       <<Not:j\d+>>         Not [<<And>>]
146   /// CHECK-DAG:                            Return [<<Not>>]
147 
148   /// CHECK-START: long Main.$opt$noinline$orToAnd(long, long) instruction_simplifier (after)
149   /// CHECK-DAG:                            Not
150   /// CHECK-NOT:                            Not
151 
152   /// CHECK-START: long Main.$opt$noinline$orToAnd(long, long) instruction_simplifier (after)
153   /// CHECK-NOT:                            Or
154 
$opt$noinline$orToAnd(long a, long b)155   public static long $opt$noinline$orToAnd(long a, long b) {
156     if (doThrow) throw new Error();
157     return ~a | ~b;
158   }
159 
160   /**
161    * Test transformation of Not/Not/Or into Or/And for boolean negations.
162    * Note that the graph before this instruction simplification pass does not
163    * contain `HBooleanNot` instructions. This is because this transformation
164    * follows the optimization of `HSelect` to `HBooleanNot` occurring in the
165    * same pass.
166    */
167 
168   /// CHECK-START: boolean Main.$opt$noinline$booleanOrToAnd(boolean, boolean) instruction_simplifier$after_inlining (before)
169   /// CHECK-DAG:       <<P1:z\d+>>          ParameterValue
170   /// CHECK-DAG:       <<P2:z\d+>>          ParameterValue
171   /// CHECK-DAG:       <<Const0:i\d+>>      IntConstant 0
172   /// CHECK-DAG:       <<Const1:i\d+>>      IntConstant 1
173   /// CHECK-DAG:       <<Select1:i\d+>>     Select [<<Const1>>,<<Const0>>,<<P1>>]
174   /// CHECK-DAG:       <<Select2:i\d+>>     Select [<<Const1>>,<<Const0>>,<<P2>>]
175   /// CHECK-DAG:       <<Or:i\d+>>          Or [<<Select2>>,<<Select1>>]
176   /// CHECK-DAG:                            Return [<<Or>>]
177 
178   /// CHECK-START: boolean Main.$opt$noinline$booleanOrToAnd(boolean, boolean) instruction_simplifier$after_inlining (after)
179   /// CHECK-DAG:       <<Cond1:z\d+>>       ParameterValue
180   /// CHECK-DAG:       <<Cond2:z\d+>>       ParameterValue
181   /// CHECK-DAG:       <<And:i\d+>>         And [<<Cond2>>,<<Cond1>>]
182   /// CHECK-DAG:       <<BooleanNot:z\d+>>  BooleanNot [<<And>>]
183   /// CHECK-DAG:                            Return [<<BooleanNot>>]
184 
185   /// CHECK-START: boolean Main.$opt$noinline$booleanOrToAnd(boolean, boolean) instruction_simplifier$after_bce (after)
186   /// CHECK-DAG:                            BooleanNot
187   /// CHECK-NOT:                            BooleanNot
188 
189   /// CHECK-START: boolean Main.$opt$noinline$booleanOrToAnd(boolean, boolean) instruction_simplifier$after_bce (after)
190   /// CHECK-NOT:                            Or
191 
$opt$noinline$booleanOrToAnd(boolean a, boolean b)192   public static boolean $opt$noinline$booleanOrToAnd(boolean a, boolean b) {
193     if (doThrow) throw new Error();
194     return !a | !b;
195   }
196 
197   /**
198    * Test that the transformation copes with inputs being separated from the
199    * bitwise operations.
200    * This is a regression test. The initial logic was inserting the new bitwise
201    * operation incorrectly.
202    */
203 
204   /// CHECK-START: int Main.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (before)
205   /// CHECK-DAG:       <<P1:i\d+>>          ParameterValue
206   /// CHECK-DAG:       <<P2:i\d+>>          ParameterValue
207   /// CHECK-DAG:       <<Cst1:i\d+>>        IntConstant 1
208   /// CHECK-DAG:       <<CstM1:i\d+>>       IntConstant -1
209   /// CHECK-DAG:       <<AddP1:i\d+>>       Add [<<P1>>,<<Cst1>>]
210   /// CHECK-DAG:       <<Not1:i\d+>>        Xor [<<AddP1>>,<<CstM1>>]
211   /// CHECK-DAG:       <<AddP2:i\d+>>       Add [<<P2>>,<<Cst1>>]
212   /// CHECK-DAG:       <<Not2:i\d+>>        Xor [<<AddP2>>,<<CstM1>>]
213   /// CHECK-DAG:       <<Or:i\d+>>          Or [<<Not1>>,<<Not2>>]
214   /// CHECK-DAG:                            Return [<<Or>>]
215 
216   /// CHECK-START: int Main.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (after)
217   /// CHECK-DAG:       <<P1:i\d+>>          ParameterValue
218   /// CHECK-DAG:       <<P2:i\d+>>          ParameterValue
219   /// CHECK-DAG:       <<Cst1:i\d+>>        IntConstant 1
220   /// CHECK-DAG:       <<AddP1:i\d+>>       Add [<<P1>>,<<Cst1>>]
221   /// CHECK-DAG:       <<AddP2:i\d+>>       Add [<<P2>>,<<Cst1>>]
222   /// CHECK-DAG:       <<And:i\d+>>         And [<<AddP1>>,<<AddP2>>]
223   /// CHECK-DAG:       <<Not:i\d+>>         Not [<<And>>]
224   /// CHECK-DAG:                            Return [<<Not>>]
225 
226   /// CHECK-START: int Main.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (after)
227   /// CHECK-DAG:                            Not
228   /// CHECK-NOT:                            Not
229 
230   /// CHECK-START: int Main.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (after)
231   /// CHECK-NOT:                            Or
232 
$opt$noinline$regressInputsAway(int a, int b)233   public static int $opt$noinline$regressInputsAway(int a, int b) {
234     if (doThrow) throw new Error();
235     int a1 = a + 1;
236     int not_a1 = ~a1;
237     int b1 = b + 1;
238     int not_b1 = ~b1;
239     return not_a1 | not_b1;
240   }
241 
242   /**
243    * Test transformation of Not/Not/Xor into Xor.
244    */
245 
246   // See first note above.
247   /// CHECK-START: int Main.$opt$noinline$notXorToXor(int, int) instruction_simplifier (before)
248   /// CHECK-DAG:       <<P1:i\d+>>          ParameterValue
249   /// CHECK-DAG:       <<P2:i\d+>>          ParameterValue
250   /// CHECK-DAG:       <<CstM1:i\d+>>       IntConstant -1
251   /// CHECK-DAG:       <<Not1:i\d+>>        Xor [<<P1>>,<<CstM1>>]
252   /// CHECK-DAG:       <<Not2:i\d+>>        Xor [<<P2>>,<<CstM1>>]
253   /// CHECK-DAG:       <<Xor:i\d+>>         Xor [<<Not1>>,<<Not2>>]
254   /// CHECK-DAG:                            Return [<<Xor>>]
255 
256   /// CHECK-START: int Main.$opt$noinline$notXorToXor(int, int) instruction_simplifier (after)
257   /// CHECK-DAG:       <<P1:i\d+>>          ParameterValue
258   /// CHECK-DAG:       <<P2:i\d+>>          ParameterValue
259   /// CHECK-DAG:       <<Xor:i\d+>>         Xor [<<P1>>,<<P2>>]
260   /// CHECK-DAG:                            Return [<<Xor>>]
261 
262   /// CHECK-START: int Main.$opt$noinline$notXorToXor(int, int) instruction_simplifier (after)
263   /// CHECK-NOT:                            Not
264 
$opt$noinline$notXorToXor(int a, int b)265   public static int $opt$noinline$notXorToXor(int a, int b) {
266     if (doThrow) throw new Error();
267     return ~a ^ ~b;
268   }
269 
270   /**
271    * Test transformation of Not/Not/Xor into Xor for boolean negations.
272    * Note that the graph before this instruction simplification pass does not
273    * contain `HBooleanNot` instructions. This is because this transformation
274    * follows the optimization of `HSelect` to `HBooleanNot` occurring in the
275    * same pass.
276    */
277 
278   /// CHECK-START: boolean Main.$opt$noinline$booleanNotXorToXor(boolean, boolean) instruction_simplifier$after_inlining (before)
279   /// CHECK-DAG:       <<P1:z\d+>>          ParameterValue
280   /// CHECK-DAG:       <<P2:z\d+>>          ParameterValue
281   /// CHECK-DAG:       <<Const0:i\d+>>      IntConstant 0
282   /// CHECK-DAG:       <<Const1:i\d+>>      IntConstant 1
283   /// CHECK-DAG:       <<Select1:i\d+>>     Select [<<Const1>>,<<Const0>>,<<P1>>]
284   /// CHECK-DAG:       <<Select2:i\d+>>     Select [<<Const1>>,<<Const0>>,<<P2>>]
285   /// CHECK-DAG:       <<Xor:i\d+>>         Xor [<<Select2>>,<<Select1>>]
286   /// CHECK-DAG:                            Return [<<Xor>>]
287 
288   /// CHECK-START: boolean Main.$opt$noinline$booleanNotXorToXor(boolean, boolean) instruction_simplifier$after_inlining (after)
289   /// CHECK-DAG:       <<Cond1:z\d+>>       ParameterValue
290   /// CHECK-DAG:       <<Cond2:z\d+>>       ParameterValue
291   /// CHECK-DAG:       <<Xor:i\d+>>         Xor [<<Cond2>>,<<Cond1>>]
292   /// CHECK-DAG:                            Return [<<Xor>>]
293 
294   /// CHECK-START: boolean Main.$opt$noinline$booleanNotXorToXor(boolean, boolean) instruction_simplifier$after_bce (after)
295   /// CHECK-NOT:                            BooleanNot
296 
$opt$noinline$booleanNotXorToXor(boolean a, boolean b)297   public static boolean $opt$noinline$booleanNotXorToXor(boolean a, boolean b) {
298     if (doThrow) throw new Error();
299     return !a ^ !b;
300   }
301 
302   /**
303    * Check that no transformation is done when one Not has multiple uses.
304    */
305 
306   /// CHECK-START: int Main.$opt$noinline$notMultipleUses(int, int) instruction_simplifier (before)
307   /// CHECK-DAG:       <<P1:i\d+>>          ParameterValue
308   /// CHECK-DAG:       <<P2:i\d+>>          ParameterValue
309   /// CHECK-DAG:       <<CstM1:i\d+>>       IntConstant -1
310   /// CHECK-DAG:       <<One:i\d+>>         IntConstant 1
311   /// CHECK-DAG:       <<Not2:i\d+>>        Xor [<<P2>>,<<CstM1>>]
312   /// CHECK-DAG:       <<And2:i\d+>>        And [<<Not2>>,<<One>>]
313   /// CHECK-DAG:       <<Not1:i\d+>>        Xor [<<P1>>,<<CstM1>>]
314   /// CHECK-DAG:       <<And1:i\d+>>        And [<<Not1>>,<<Not2>>]
315   /// CHECK-DAG:       <<Add:i\d+>>         Add [<<And2>>,<<And1>>]
316   /// CHECK-DAG:                            Return [<<Add>>]
317 
318   /// CHECK-START: int Main.$opt$noinline$notMultipleUses(int, int) instruction_simplifier (after)
319   /// CHECK-DAG:       <<P1:i\d+>>          ParameterValue
320   /// CHECK-DAG:       <<P2:i\d+>>          ParameterValue
321   /// CHECK-DAG:       <<One:i\d+>>         IntConstant 1
322   /// CHECK-DAG:       <<Not2:i\d+>>        Not [<<P2>>]
323   /// CHECK-DAG:       <<And2:i\d+>>        And [<<Not2>>,<<One>>]
324   /// CHECK-DAG:       <<Not1:i\d+>>        Not [<<P1>>]
325   /// CHECK-DAG:       <<And1:i\d+>>        And [<<Not1>>,<<Not2>>]
326   /// CHECK-DAG:       <<Add:i\d+>>         Add [<<And2>>,<<And1>>]
327   /// CHECK-DAG:                            Return [<<Add>>]
328 
329   /// CHECK-START: int Main.$opt$noinline$notMultipleUses(int, int) instruction_simplifier (after)
330   /// CHECK-NOT:                            Or
331 
$opt$noinline$notMultipleUses(int a, int b)332   public static int $opt$noinline$notMultipleUses(int a, int b) {
333     if (doThrow) throw new Error();
334     int tmp = ~b;
335     return (tmp & 0x1) + (~a & tmp);
336   }
337 
main(String[] args)338   public static void main(String[] args) {
339     assertIntEquals(~0xff, $opt$noinline$andToOr(0xf, 0xff));
340     assertIntEquals(~0xff, $noinline$runSmaliTest("$opt$noinline$andToOr", int.class, 0xf, 0xff));
341     assertEquals(true, $opt$noinline$booleanAndToOr(false, false));
342     assertEquals(true, $noinline$runSmaliTest("$opt$noinline$booleanAndToOr", boolean.class, false, false));
343     assertLongEquals(~0xf, $opt$noinline$orToAnd(0xf, 0xff));
344     assertLongEquals(~0xf, $noinline$runSmaliTest("$opt$noinline$orToAnd", long.class, 0xfL, 0xffL));
345     assertEquals(false, $opt$noinline$booleanOrToAnd(true, true));
346     assertEquals(false, $noinline$runSmaliTest("$opt$noinline$booleanOrToAnd", boolean.class, true, true));
347     assertIntEquals(-1, $opt$noinline$regressInputsAway(0xf, 0xff));
348     assertIntEquals(-1, $noinline$runSmaliTest("$opt$noinline$regressInputsAway", int.class, 0xf, 0xff));
349     assertIntEquals(0xf0, $opt$noinline$notXorToXor(0xf, 0xff));
350     assertIntEquals(0xf0, $noinline$runSmaliTest("$opt$noinline$notXorToXor", int.class, 0xf, 0xff));
351     assertEquals(true, $opt$noinline$booleanNotXorToXor(true, false));
352     assertEquals(true, $noinline$runSmaliTest("$opt$noinline$booleanNotXorToXor", boolean.class, true, false));
353     assertIntEquals(~0xff, $opt$noinline$notMultipleUses(0xf, 0xff));
354     assertIntEquals(~0xff, $noinline$runSmaliTest("$opt$noinline$notMultipleUses", int.class, 0xf, 0xff));
355   }
356 }
357