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 //
18 // Test on loop optimizations, in particular around geometric induction.
19 //
20 public class Main {
21 
22   /// CHECK-START: int Main.geo1(int) loop_optimization (before)
23   /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
24   /// CHECK-DAG: Mul loop:<<Loop>>
25   //
26   /// CHECK-START: int Main.geo1(int) loop_optimization (after)
27   /// CHECK-DAG: <<Par:i\d+>> ParameterValue         loop:none
28   /// CHECK-DAG: <<Zer:i\d+>> IntConstant 0          loop:none
29   /// CHECK-DAG: <<Int:i\d+>> IntConstant 1410065408 loop:none
30   /// CHECK-DAG: <<Mul:i\d+>> Mul [<<Par>>,<<Int>>]  loop:none
31   /// CHECK-DAG: <<Add:i\d+>> Add [<<Mul>>,<<Zer>>]  loop:none
32   /// CHECK-DAG:              Return [<<Add>>]       loop:none
33   //
34   /// CHECK-START: int Main.geo1(int) loop_optimization (after)
35   /// CHECK-NOT: Phi
geo1(int a)36   public static int geo1(int a) {
37     for (int i = 0; i < 10; i++) {
38       a *= 10;
39     }
40     return a;
41   }
42 
43   /// CHECK-START: int Main.geo2(int) loop_optimization (before)
44   /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
45   /// CHECK-DAG: Shl loop:<<Loop>>
46   //
47   /// CHECK-START: int Main.geo2(int) loop_optimization (after)
48   /// CHECK-DAG: <<Par:i\d+>> ParameterValue        loop:none
49   /// CHECK-DAG: <<Zer:i\d+>> IntConstant 0         loop:none
50   /// CHECK-DAG: <<Int:i\d+>> IntConstant 1024      loop:none
51   /// CHECK-DAG: <<Mul:i\d+>> Mul [<<Par>>,<<Int>>] loop:none
52   /// CHECK-DAG: <<Add:i\d+>> Add [<<Mul>>,<<Zer>>] loop:none
53   /// CHECK-DAG:              Return [<<Add>>]      loop:none
54   //
55   /// CHECK-START: int Main.geo2(int) loop_optimization (after)
56   /// CHECK-NOT: Phi
geo2(int a)57   public static int geo2(int a) {
58     for (int i = 0; i < 10; i++) {
59       a <<= 1;
60     }
61     return a;
62   }
63 
64   /// CHECK-START: int Main.geo3(int) loop_optimization (before)
65   /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
66   /// CHECK-DAG: Div loop:<<Loop>>
67   //
68   /// CHECK-START: int Main.geo3(int) loop_optimization (after)
69   /// CHECK-DAG: <<Par:i\d+>> ParameterValue        loop:none
70   /// CHECK-DAG: <<Zer:i\d+>> IntConstant 0         loop:none
71   /// CHECK-DAG: <<Int:i\d+>> IntConstant 59049     loop:none
72   /// CHECK-DAG: <<Div:i\d+>> Div [<<Par>>,<<Int>>] loop:none
73   /// CHECK-DAG: <<Add:i\d+>> Add [<<Div>>,<<Zer>>] loop:none
74   /// CHECK-DAG:              Return [<<Add>>]      loop:none
75   //
76   /// CHECK-START: int Main.geo3(int) loop_optimization (after)
77   /// CHECK-NOT: Phi
geo3(int a)78   public static int geo3(int a) {
79     for (int i = 0; i < 10; i++) {
80       a /= 3;
81     }
82     return a;
83   }
84 
85   /// CHECK-START: int Main.geo4(int) loop_optimization (before)
86   /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
87   /// CHECK-DAG: Rem loop:<<Loop>>
88   //
89   /// CHECK-START: int Main.geo4(int) loop_optimization (after)
90   /// CHECK-DAG: <<Par:i\d+>> ParameterValue        loop:none
91   /// CHECK-DAG: <<Int:i\d+>> IntConstant 7         loop:none
92   /// CHECK-DAG: <<Rem:i\d+>> Rem [<<Par>>,<<Int>>] loop:none
93   /// CHECK-DAG:              Return [<<Rem>>]      loop:none
94   //
95   /// CHECK-START: int Main.geo4(int) loop_optimization (after)
96   /// CHECK-NOT: Phi
geo4(int a)97   public static int geo4(int a) {
98     for (int i = 0; i < 10; i++) {
99       a %= 7;  // a wrap-around induction
100     }
101     return a;
102   }
103 
104   /// CHECK-START: int Main.geo5() loop_optimization (before)
105   /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
106   /// CHECK-DAG: Shr loop:<<Loop>>
107   //
108   /// CHECK-START: int Main.geo5() loop_optimization (after)
109   /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0          loop:none
110   /// CHECK-DAG: <<Int1:i\d+>> IntConstant 2147483647 loop:none
111   /// CHECK-DAG: <<Int2:i\d+>> IntConstant 1024       loop:none
112   /// CHECK-DAG: <<Div:i\d+>>  Div [<<Int1>>,<<Int2>>] loop:none
113   /// CHECK-DAG: <<Add:i\d+>>  Add [<<Div>>,<<Zero>>]  loop:none
114   /// CHECK-DAG:               Return [<<Add>>]        loop:none
115   //
116   /// CHECK-START: int Main.geo5() loop_optimization (after)
117   /// CHECK-NOT: Phi
geo5()118   public static int geo5() {
119     int a = 0x7fffffff;
120     for (int i = 0; i < 10; i++) {
121       a >>= 1;
122     }
123     return a;
124   }
125 
126   // TODO: someday?
127   //
128   /// CHECK-START: int Main.geo1BCE() BCE (before)
129   /// CHECK-DAG: BoundsCheck loop:none
130   /// CHECK-DAG: BoundsCheck loop:{{B\d+}}
131   //
132   /// CHECK-START: int Main.geo1BCE() BCE (after)
133   /// CHECK-DAG: BoundsCheck loop:{{B\d+}}
134   //
135   /// CHECK-START: int Main.geo1BCE() BCE (after)
136   /// CHECK-NOT: BoundsCheck loop:none
137   /// CHECK-NOT: Deoptimize
geo1BCE()138   public static int geo1BCE() {
139     int[] x = {  1,  2,  3,  4,  5,  6,  7,  8,  9, 10,
140                 11, 12, 13, 14, 15, 16, 17, 19, 19, 20,
141                 21, 22, 23, 24, 25, 26 };
142     int a = 1;
143     int r = 0;
144     for (int i = 0; i < 3; i++) {
145       r += x[a];
146       a *= 5;
147     }
148     return r;
149   }
150 
151   // TODO: someday?
152   //
153   /// CHECK-START: int Main.geo2BCE() BCE (before)
154   /// CHECK-DAG: BoundsCheck loop:none
155   /// CHECK-DAG: BoundsCheck loop:{{B\d+}}
156   //
157   /// CHECK-START: int Main.geo2BCE() BCE (after)
158   /// CHECK-DAG: BoundsCheck loop:{{B\d+}}
159   //
160   /// CHECK-START: int Main.geo2BCE() BCE (after)
161   /// CHECK-NOT: BoundsCheck loop:none
162   /// CHECK-NOT: Deoptimize
geo2BCE()163   public static int geo2BCE() {
164     int[] x = {  1,  2,  3,  4,  5,  6,  7,  8,  9, 10,
165                 11, 12, 13, 14, 15, 16, 17, 19, 19, 20,
166                 21, 22, 23, 24, 25, 26 };
167     int a = 1;
168     int r = 0;
169     for (int i = 0; i < 5; i++) {
170       r += x[a];
171       a <<= 1;
172     }
173     return r;
174   }
175 
176   /// CHECK-START: int Main.geo3BCE() BCE (before)
177   /// CHECK-DAG: BoundsCheck loop:none
178   /// CHECK-DAG: BoundsCheck loop:{{B\d+}}
179   //
180   /// CHECK-START: int Main.geo3BCE() BCE (after)
181   /// CHECK-NOT: BoundsCheck
182   /// CHECK-NOT: Deoptimize
geo3BCE()183   public static int geo3BCE() {
184     int[] x = {  1,  2,  3,  4,  5,  6,  7,  8,  9, 10,
185                 11, 12, 13, 14, 15, 16, 17, 19, 19, 20,
186                 21, 22, 23, 24, 25, 26 };
187     int a = 25;
188     int r = 0;
189     for (int i = 0; i < 100; i++) {  // a converges to 0
190       r += x[a];
191       a /= 5;
192     }
193     return r;
194   }
195 
196   /// CHECK-START: int Main.geo4BCE() BCE (before)
197   /// CHECK-DAG: BoundsCheck loop:none
198   /// CHECK-DAG: BoundsCheck loop:{{B\d+}}
199   //
200   /// CHECK-START: int Main.geo4BCE() BCE (after)
201   /// CHECK-NOT: BoundsCheck
202   /// CHECK-NOT: Deoptimize
geo4BCE()203   public static int geo4BCE() {
204     int[] x = {  1,  2,  3,  4,  5,  6,  7,  8,  9, 10,
205                 11, 12, 13, 14, 15, 16, 17, 19, 19, 20,
206                 21, 22, 23, 24, 25, 26 };
207     int a = 25;
208     int r = 0;
209     for (int i = 0; i < 100; i++) {  // a converges to 0
210       r += x[a];
211       a %= 5;  // a wrap-around induction
212     }
213     return r;
214   }
215 
216   /// CHECK-START: int Main.geoMulBlackHole(int) loop_optimization (before)
217   /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
218   /// CHECK-DAG: Mul loop:<<Loop>>
219   //
220   /// CHECK-START: int Main.geoMulBlackHole(int) loop_optimization (after)
221   /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0
222   /// CHECK-DAG:               Return [<<Zero>>]
223   //
224   /// CHECK-START: int Main.geoMulBlackHole(int) loop_optimization (after)
225   /// CHECK-NOT: Phi
226   /// CHECK-NOT: Mul
geoMulBlackHole(int a)227   public static int geoMulBlackHole(int a) {
228     for (int i = 0; i < 100; i++) {
229       a *= 10;
230     }
231     return a;
232   }
233 
234   /// CHECK-START: int Main.geoShlBlackHole(int) loop_optimization (before)
235   /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
236   /// CHECK-DAG: Shl loop:<<Loop>>
237   //
238   /// CHECK-START: int Main.geoShlBlackHole(int) loop_optimization (after)
239   /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0
240   /// CHECK-DAG:               Return [<<Zero>>]
241   //
242   /// CHECK-START: int Main.geoShlBlackHole(int) loop_optimization (after)
243   /// CHECK-NOT: Phi
244   /// CHECK-NOT: Shl
geoShlBlackHole(int a)245   public static int geoShlBlackHole(int a) {
246     for (int i = 0; i < 100; i++) {
247       a <<= 1;
248     }
249     return a;
250   }
251 
252   /// CHECK-START: int Main.geoDivBlackHole(int) loop_optimization (before)
253   /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
254   /// CHECK-DAG: Div loop:<<Loop>>
255   //
256   /// CHECK-START: int Main.geoDivBlackHole(int) loop_optimization (after)
257   /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0
258   /// CHECK-DAG:               Return [<<Zero>>]
259   //
260   /// CHECK-START: int Main.geoDivBlackHole(int) loop_optimization (after)
261   /// CHECK-NOT: Phi
262   /// CHECK-NOT: Div
geoDivBlackHole(int a)263   public static int geoDivBlackHole(int a) {
264     for (int i = 0; i < 100; i++) {
265       a /= 10;
266     }
267     return a;
268   }
269 
270   // Even though Rem is already optimized away by the time induction analysis
271   // and the loop optimizer run, the loop is optimized with a trivial
272   // wrap-around induction just as the wrap-around for REM would.
273   //
274   /// CHECK-START: int Main.geoRemBlackHole(int) loop_optimization (before)
275   /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
276   /// CHECK-DAG: Phi loop:<<Loop>>
277   //
278   /// CHECK-START: int Main.geoRemBlackHole(int) loop_optimization (after)
279   /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0
280   /// CHECK-DAG:               Return [<<Zero>>]
281   //
282   /// CHECK-START: int Main.geoRemBlackHole(int) loop_optimization (after)
283   /// CHECK-NOT: Phi
geoRemBlackHole(int a)284   public static int geoRemBlackHole(int a) {
285     for (int i = 0; i < 100; i++) {
286       a %= 1;
287     }
288     return a;
289   }
290 
291   //
292   // Verifier.
293   //
294 
main(String[] args)295   public static void main(String[] args) {
296     int m = 1410065408;
297     for (int i = -100; i <= 100; i++) {
298       expectEquals(m * i, geo1(i));
299     }
300     for (int i = 1; i <= 1000000000; i *= 10) {
301       expectEquals( m * i, geo1( i));
302       expectEquals(-m * i, geo1(-i));
303     }
304 
305     for (int i = -100; i <= 100; i++) {
306       expectEquals(i << 10, geo2(i));
307     }
308     for (int i = 0; i < 22; i++) {
309       expectEquals(1 << (i + 10), geo2(1 << i));
310     }
311     expectEquals(0x80000400, geo2(0x00200001));
312     expectEquals(0x00000000, geo2(0x00400000));
313     expectEquals(0x00000400, geo2(0x00400001));
314 
315     int d = 59049;
316     for (int i = -100; i <= 100; i++) {
317       expectEquals(0, geo3(i));
318     }
319     for (int i = 1; i <= 100; i++) {
320       expectEquals( i, geo3( i * d));
321       expectEquals( i, geo3( i * d + 1));
322       expectEquals(-i, geo3(-i * d));
323       expectEquals(-i, geo3(-i * d - 1));
324     }
325 
326     for (int i = -100; i <= 100; i++) {
327       expectEquals(i % 7, geo4(i));
328     }
329 
330     expectEquals(0x1fffff, geo5());
331 
332     expectEquals(34,  geo1BCE());
333     expectEquals(36,  geo2BCE());
334     expectEquals(131, geo3BCE());
335     expectEquals(125, geo4BCE());
336 
337     // Nothing escapes!
338     expectEquals(0, geoMulBlackHole(0));
339     expectEquals(0, geoShlBlackHole(0));
340     expectEquals(0, geoDivBlackHole(0));
341     expectEquals(0, geoRemBlackHole(0));
342     for (int i = -100; i <= 100; i++) {
343       expectEquals(0, geoMulBlackHole(i));
344       expectEquals(0, geoShlBlackHole(i));
345       expectEquals(0, geoDivBlackHole(i));
346       expectEquals(0, geoRemBlackHole(i));
347     }
348     for (int i = 0; i < 31; i++) {
349       expectEquals(0, geoMulBlackHole(1 << i));
350       expectEquals(0, geoShlBlackHole(1 << i));
351       expectEquals(0, geoDivBlackHole(1 << i));
352       expectEquals(0, geoRemBlackHole(1 << i));
353     }
354     expectEquals(0, geoMulBlackHole(0x7fffffff));
355     expectEquals(0, geoShlBlackHole(0x7fffffff));
356     expectEquals(0, geoDivBlackHole(0x7fffffff));
357     expectEquals(0, geoRemBlackHole(0x7fffffff));
358     expectEquals(0, geoMulBlackHole(0x80000000));
359     expectEquals(0, geoShlBlackHole(0x80000000));
360     expectEquals(0, geoDivBlackHole(0x80000000));
361     expectEquals(0, geoRemBlackHole(0x80000000));
362 
363     System.out.println("passed");
364   }
365 
expectEquals(int expected, int result)366   private static void expectEquals(int expected, int result) {
367     if (expected != result) {
368       throw new Error("Expected: " + expected + ", found: " + result);
369     }
370   }
371 }
372