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