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  * Regression tests for loop optimizations.
19  */
20 public class Main {
21 
ensureJitCompiled(Class<?> cls, String methodName)22   private static native void ensureJitCompiled(Class<?> cls, String methodName);
23 
24   /// CHECK-START: int Main.earlyExitFirst(int) loop_optimization (before)
25   /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
26   /// CHECK-DAG: Phi loop:<<Loop>>      outer_loop:none
27   //
28   /// CHECK-START: int Main.earlyExitFirst(int) loop_optimization (after)
29   /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
30   /// CHECK-DAG: Phi loop:<<Loop>>      outer_loop:none
earlyExitFirst(int m)31   static int earlyExitFirst(int m) {
32     int k = 0;
33     for (int i = 0; i < 10; i++) {
34       if (i == m) {
35         return k;
36       }
37       k++;
38     }
39     return k;
40   }
41 
42   /// CHECK-START: int Main.earlyExitLast(int) loop_optimization (before)
43   /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
44   /// CHECK-DAG: Phi loop:<<Loop>>      outer_loop:none
45   //
46   /// CHECK-START: int Main.earlyExitLast(int) loop_optimization (after)
47   /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
48   /// CHECK-DAG: Phi loop:<<Loop>>      outer_loop:none
earlyExitLast(int m)49   static int earlyExitLast(int m) {
50     int k = 0;
51     for (int i = 0; i < 10; i++) {
52       k++;
53       if (i == m) {
54         return k;
55       }
56     }
57     return k;
58   }
59 
60   /// CHECK-START: int Main.earlyExitNested() loop_optimization (before)
61   /// CHECK-DAG: Phi loop:<<Loop1:B\d+>> outer_loop:none
62   /// CHECK-DAG: Phi loop:<<Loop1>>      outer_loop:none
63   /// CHECK-DAG: Phi loop:<<Loop2:B\d+>> outer_loop:<<Loop1>>
64   /// CHECK-DAG: Phi loop:<<Loop2>>      outer_loop:<<Loop1>>
65   //
66   /// CHECK-START: int Main.earlyExitNested() loop_optimization (after)
67   /// CHECK-DAG: Phi loop:<<Loop1:B\d+>> outer_loop:none
68   /// CHECK-DAG: Phi loop:<<Loop1>>      outer_loop:none
69   //
70   /// CHECK-START: int Main.earlyExitNested() loop_optimization (after)
71   /// CHECK-NOT: Phi loop:{{B\d+}} outer_loop:{{B\d+}}
earlyExitNested()72   static int earlyExitNested() {
73     int offset = 0;
74     for (int i = 0; i < 2; i++) {
75       int start = offset;
76       // This loop can be removed.
77       for (int j = 0; j < 2; j++) {
78         offset++;
79       }
80       if (i == 1) {
81         return start;
82       }
83     }
84     return 0;
85   }
86 
87   // Regression test for b/33774618: transfer operations involving
88   // narrowing linear induction should be done correctly.
89   //
90   /// CHECK-START: int Main.transferNarrowWrap() loop_optimization (before)
91   /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
92   /// CHECK-DAG: Phi loop:<<Loop>>      outer_loop:none
93   /// CHECK-DAG: Phi loop:<<Loop>>      outer_loop:none
94   /// CHECK-DAG: Phi loop:<<Loop>>      outer_loop:none
95   //
96   /// CHECK-START: int Main.transferNarrowWrap() loop_optimization (after)
97   /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
98   /// CHECK-DAG: Phi loop:<<Loop>>      outer_loop:none
99   /// CHECK-DAG: Phi loop:<<Loop>>      outer_loop:none
100   /// CHECK-DAG: Phi loop:<<Loop>>      outer_loop:none
transferNarrowWrap()101   static int transferNarrowWrap() {
102     short x = 0;
103     int w = 10;
104     int v = 3;
105     for (int i = 0; i < 10; i++) {
106       v = w + 1;    // transfer on wrap-around
107       w = x;   // wrap-around
108       x += 2;  // narrowing linear
109     }
110     return v;
111   }
112 
113   // Regression test for b/33774618: transfer operations involving
114   // narrowing linear induction should be done correctly
115   // (currently rejected, could be improved).
116   //
117   /// CHECK-START: int Main.polynomialShort() loop_optimization (before)
118   /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
119   /// CHECK-DAG: Phi loop:<<Loop>>      outer_loop:none
120   //
121   /// CHECK-START: int Main.polynomialShort() loop_optimization (after)
122   /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
123   /// CHECK-DAG: Phi loop:<<Loop>>      outer_loop:none
polynomialShort()124   static int polynomialShort() {
125     int x = 0;
126     for (short i = 0; i < 10; i++) {
127       x = x - i;  // polynomial on narrowing linear
128     }
129     return x;
130   }
131 
132   // Regression test for b/33774618: transfer operations involving
133   // narrowing linear induction should be done correctly
134   // (currently rejected, could be improved).
135   //
136   /// CHECK-START: int Main.polynomialIntFromLong() loop_optimization (before)
137   /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
138   /// CHECK-DAG: Phi loop:<<Loop>>      outer_loop:none
139   //
140   /// CHECK-START: int Main.polynomialIntFromLong() loop_optimization (after)
141   /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
142   /// CHECK-DAG: Phi loop:<<Loop>>      outer_loop:none
polynomialIntFromLong()143   static int polynomialIntFromLong() {
144     int x = 0;
145     for (long i = 0; i < 10; i++) {
146       x = x - (int) i;  // polynomial on narrowing linear
147     }
148     return x;
149   }
150 
151   /// CHECK-START: int Main.polynomialInt() loop_optimization (before)
152   /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
153   /// CHECK-DAG: Phi loop:<<Loop>>      outer_loop:none
154   //
155   /// CHECK-START: int Main.polynomialInt() loop_optimization (after)
156   /// CHECK-NOT: Phi
157   //
158   /// CHECK-START: int Main.polynomialInt() instruction_simplifier$after_bce (after)
159   /// CHECK-DAG: <<Int:i\d+>>  IntConstant -45  loop:none
160   /// CHECK-DAG:               Return [<<Int>>] loop:none
polynomialInt()161   static int polynomialInt() {
162     int x = 0;
163     for (int i = 0; i < 10; i++) {
164       x = x - i;
165     }
166     return x;
167   }
168 
169   // Regression test for b/34779592 (found with fuzz testing): overflow for last value
170   // of division truncates to zero, for multiplication it simply truncates.
171   //
172   /// CHECK-START: int Main.geoIntDivLastValue(int) loop_optimization (before)
173   /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
174   /// CHECK-DAG: Phi loop:<<Loop>>      outer_loop:none
175   //
176   /// CHECK-START: int Main.geoIntDivLastValue(int) loop_optimization (after)
177   /// CHECK-NOT: Phi
178   //
179   /// CHECK-START: int Main.geoIntDivLastValue(int) instruction_simplifier$after_bce (after)
180   /// CHECK-DAG: <<Int:i\d+>> IntConstant 0    loop:none
181   /// CHECK-DAG:              Return [<<Int>>] loop:none
geoIntDivLastValue(int x)182   static int geoIntDivLastValue(int x) {
183     for (int i = 0; i < 2; i++) {
184       x /= 1081788608;
185     }
186     return x;
187   }
188 
189   /// CHECK-START: int Main.geoIntMulLastValue(int) loop_optimization (before)
190   /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
191   /// CHECK-DAG: Phi loop:<<Loop>>      outer_loop:none
192   //
193   /// CHECK-START: int Main.geoIntMulLastValue(int) loop_optimization (after)
194   /// CHECK-NOT: Phi
195   //
196   /// CHECK-START: int Main.geoIntMulLastValue(int) instruction_simplifier$after_bce (after)
197   /// CHECK-DAG: <<Par:i\d+>> ParameterValue         loop:none
198   /// CHECK-DAG: <<Int:i\d+>> IntConstant -194211840 loop:none
199   /// CHECK-DAG: <<Mul:i\d+>> Mul [<<Par>>,<<Int>>]  loop:none
200   /// CHECK-DAG:              Return [<<Mul>>]       loop:none
geoIntMulLastValue(int x)201   static int geoIntMulLastValue(int x) {
202     for (int i = 0; i < 2; i++) {
203       x *= 1081788608;
204     }
205     return x;
206   }
207 
208   /// CHECK-START: long Main.geoLongDivLastValue(long) loop_optimization (before)
209   /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
210   /// CHECK-DAG: Phi loop:<<Loop>>      outer_loop:none
211   //
212   /// CHECK-START: long Main.geoLongDivLastValue(long) loop_optimization (after)
213   /// CHECK-NOT: Phi
214   //
215   /// CHECK-START: long Main.geoLongDivLastValue(long) instruction_simplifier$after_bce (after)
216   /// CHECK-DAG: <<Long:j\d+>> LongConstant 0    loop:none
217   /// CHECK-DAG:               Return [<<Long>>] loop:none
218   //
219   // Tests overflow in the divisor (while updating intermediate result).
geoLongDivLastValue(long x)220   static long geoLongDivLastValue(long x) {
221     for (int i = 0; i < 10; i++) {
222       x /= 1081788608;
223     }
224     return x;
225   }
226 
227   /// CHECK-START: long Main.geoLongDivLastValue() loop_optimization (before)
228   /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
229   /// CHECK-DAG: Phi loop:<<Loop>>      outer_loop:none
230   //
231   /// CHECK-START: long Main.geoLongDivLastValue() loop_optimization (after)
232   /// CHECK-NOT: Phi
233   //
234   /// CHECK-START: long Main.geoLongDivLastValue() instruction_simplifier$after_bce (after)
235   /// CHECK-DAG: <<Long:j\d+>> LongConstant 0    loop:none
236   /// CHECK-DAG:               Return [<<Long>>] loop:none
237   //
238   // Tests overflow in the divisor (while updating base).
geoLongDivLastValue()239   static long geoLongDivLastValue() {
240     long x = -1;
241     for (int i2 = 0; i2 < 2; i2++) {
242       x /= (Long.MAX_VALUE);
243     }
244     return x;
245   }
246 
247   /// CHECK-START: long Main.geoLongMulLastValue(long) loop_optimization (before)
248   /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
249   /// CHECK-DAG: Phi loop:<<Loop>>      outer_loop:none
250   //
251   /// CHECK-START: long Main.geoLongMulLastValue(long) loop_optimization (after)
252   /// CHECK-NOT: Phi
253   //
254   /// CHECK-START: long Main.geoLongMulLastValue(long) instruction_simplifier$after_bce (after)
255   /// CHECK-DAG: <<Par:j\d+>>  ParameterValue                    loop:none
256   /// CHECK-DAG: <<Long:j\d+>> LongConstant -8070450532247928832 loop:none
257   /// CHECK-DAG: <<Mul:j\d+>>  Mul [<<Par>>,<<Long>>]            loop:none
258   /// CHECK-DAG:               Return [<<Mul>>]                  loop:none
geoLongMulLastValue(long x)259   static long geoLongMulLastValue(long x) {
260     for (int i = 0; i < 10; i++) {
261       x *= 1081788608;
262     }
263     return x;
264   }
265 
266   // If vectorized, the narrowing subscript should not cause
267   // type inconsistencies in the synthesized code.
narrowingSubscript(float[] a)268   static void narrowingSubscript(float[] a) {
269     float val = 2.0f;
270     for (long i = 0; i < a.length; i++) {
271       a[(int) i] += val;
272     }
273   }
274 
275   // If vectorized, invariant stride should be recognized
276   // as a reduction, not a unit stride in outer loop.
reduc(int[] xx, int[] yy)277   static void reduc(int[] xx, int[] yy) {
278     for (int i0 = 0; i0 < 2; i0++) {
279       for (int i1 = 0; i1 < 469; i1++) {
280         xx[i0] -= (++yy[i1]);
281       }
282     }
283   }
284 
285   /// CHECK-START: void Main.string2Bytes(char[], java.lang.String) loop_optimization (before)
286   /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
287   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
288   //
289   /// CHECK-START-ARM: void Main.string2Bytes(char[], java.lang.String) loop_optimization (after)
290   /// CHECK-NOT: VecLoad
291   //
292   /// CHECK-START-ARM64: void Main.string2Bytes(char[], java.lang.String) loop_optimization (after)
293   /// CHECK-DAG: VecLoad  loop:<<Loop:B\d+>> outer_loop:none
294   /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
295   //
296   // NOTE: should correctly deal with compressed and uncompressed cases.
string2Bytes(char[] a, String b)297   private static void string2Bytes(char[] a, String b) {
298     int min = Math.min(a.length, b.length());
299     for (int i = 0; i < min; i++) {
300       a[i] = b.charAt(i);
301     }
302   }
303 
304   /// CHECK-START-ARM: void Main.$noinline$stringToShorts(short[], java.lang.String) loop_optimization (after)
305   /// CHECK-NOT: VecLoad
306 
307   /// CHECK-START-ARM64: void Main.$noinline$stringToShorts(short[], java.lang.String) loop_optimization (after)
308   /// CHECK-DAG: VecLoad  loop:<<Loop:B\d+>> outer_loop:none
309   /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
$noinline$stringToShorts(short[] dest, String src)310   private static void $noinline$stringToShorts(short[] dest, String src) {
311     int min = Math.min(dest.length, src.length());
312     for (int i = 0; i < min; ++i) {
313       dest[i] = (short) src.charAt(i);
314     }
315   }
316 
317   // A strange function that does not inline.
$noinline$foo(boolean x, int n)318   private static void $noinline$foo(boolean x, int n) {
319     if (n < 0)
320       throw new Error("oh no");
321     if (n > 100) {
322       $noinline$foo(!x, n - 1);
323       $noinline$foo(!x, n - 2);
324       $noinline$foo(!x, n - 3);
325       $noinline$foo(!x, n - 4);
326     }
327   }
328 
329   // A loop with environment uses of x (the terminating condition). As exposed by bug
330   // b/37247891, the loop can be unrolled, but should handle the (unlikely, but clearly
331   // not impossible) environment uses of the terminating condition in a correct manner.
envUsesInCond()332   private static void envUsesInCond() {
333     boolean x = false;
334     for (int i = 0; !(x = i >= 1); i++) {
335       $noinline$foo(true, i);
336     }
337   }
338 
339   /// CHECK-START: void Main.oneBoth(short[], char[]) loop_optimization (before)
340   /// CHECK-DAG: <<One:i\d+>>  IntConstant 1                       loop:none
341   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
342   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<One>>] loop:<<Loop>>      outer_loop:none
343   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<One>>] loop:<<Loop>>      outer_loop:none
344   //
345   /// CHECK-START-ARM: void Main.oneBoth(short[], char[]) loop_optimization (after)
346   /// CHECK-DAG: <<One:i\d+>>  IntConstant 1                             loop:none
347   /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<One>>]              loop:none
348   /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi:i\d+>>,<<Repl>>] loop:<<Loop:B\d+>> outer_loop:none
349   /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<Repl>>]      loop:<<Loop>>      outer_loop:none
350   //
351   /// CHECK-START-ARM64: void Main.oneBoth(short[], char[]) loop_optimization (after)
352   /// CHECK-DAG: <<One:i\d+>>  IntConstant 1                             loop:none
353   /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<One>>]              loop:none
354   /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi:i\d+>>,<<Repl>>] loop:<<Loop:B\d+>> outer_loop:none
355   /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<Repl>>]      loop:<<Loop>>      outer_loop:none
356   //
357   // Bug b/37764324: integral same-length packed types can be mixed freely.
oneBoth(short[] a, char[] b)358   private static void oneBoth(short[] a, char[] b) {
359     for (int i = 0; i < Math.min(a.length, b.length); i++) {
360       a[i] = 1;
361       b[i] = 1;
362     }
363   }
364 
365   // Bug b/37768917: potential dynamic BCE vs. loop optimizations
366   // case should be deal with correctly (used to DCHECK fail).
arrayInTripCount(int[] a, byte[] b, int n)367   private static void arrayInTripCount(int[] a, byte[] b, int n) {
368     for (int k = 0; k < n; k++) {
369       for (int i = 0, u = a[0]; i < u; i++) {
370         b[i] += 2;
371       }
372     }
373   }
374 
375   /// CHECK-START: void Main.typeConv(byte[], byte[]) loop_optimization (before)
376   /// CHECK-DAG: <<One:i\d+>>  IntConstant 1                       loop:none
377   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
378   /// CHECK-DAG: <<Get:b\d+>>  ArrayGet [{{l\d+}},<<Phi>>]         loop:<<Loop>>      outer_loop:none
379   /// CHECK-DAG: <<Add:i\d+>>  Add [<<Get>>,<<One>>]               loop:<<Loop>>      outer_loop:none
380   /// CHECK-DAG: <<Cnv:b\d+>>  TypeConversion [<<Add>>]            loop:<<Loop>>      outer_loop:none
381   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
382   //
383   /// CHECK-START-ARM: void Main.typeConv(byte[], byte[]) loop_optimization (after)
384   /// CHECK-DAG: <<One:i\d+>>  IntConstant 1                         loop:none
385   /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<One>>]          loop:none
386   /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1:i\d+>>]      loop:<<Loop1:B\d+>> outer_loop:none
387   /// CHECK-DAG: <<Vadd:d\d+>> VecAdd [<<Load>>,<<Repl>>]            loop:<<Loop1>>      outer_loop:none
388   /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi1>>,<<Vadd>>] loop:<<Loop1>>      outer_loop:none
389   /// CHECK-DAG: <<Get:b\d+>>  ArrayGet [{{l\d+}},<<Phi2:i\d+>>]     loop:<<Loop2:B\d+>> outer_loop:none
390   /// CHECK-DAG: <<Add:i\d+>>  Add [<<Get>>,<<One>>]                 loop:<<Loop2>>      outer_loop:none
391   /// CHECK-DAG: <<Cnv:b\d+>>  TypeConversion [<<Add>>]              loop:<<Loop2>>      outer_loop:none
392   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi2>>,<<Cnv>>]  loop:<<Loop2>>      outer_loop:none
393   //
394   /// CHECK-START-ARM64: void Main.typeConv(byte[], byte[]) loop_optimization (after)
395   /// CHECK-DAG: <<One:i\d+>>  IntConstant 1                         loop:none
396   /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<One>>]          loop:none
397   /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1:i\d+>>]      loop:<<Loop1:B\d+>> outer_loop:none
398   /// CHECK-DAG: <<Vadd:d\d+>> VecAdd [<<Load>>,<<Repl>>]            loop:<<Loop1>>      outer_loop:none
399   /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi1>>,<<Vadd>>] loop:<<Loop1>>      outer_loop:none
400   /// CHECK-DAG: <<Get:b\d+>>  ArrayGet [{{l\d+}},<<Phi2:i\d+>>]     loop:<<Loop2:B\d+>> outer_loop:none
401   /// CHECK-DAG: <<Add:i\d+>>  Add [<<Get>>,<<One>>]                 loop:<<Loop2>>      outer_loop:none
402   /// CHECK-DAG: <<Cnv:b\d+>>  TypeConversion [<<Add>>]              loop:<<Loop2>>      outer_loop:none
403   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi2>>,<<Cnv>>]  loop:<<Loop2>>      outer_loop:none
404   //
405   // Scalar code in cleanup loop uses correct byte type on array get and type conversion.
typeConv(byte[] a, byte[] b)406   private static void typeConv(byte[] a, byte[] b) {
407     int len = Math.min(a.length, b.length);
408     for (int i = 0; i < len; i++) {
409       a[i] = (byte) (b[i] + 1);
410     }
411   }
412 
413   // Environment of an instruction, removed during SimplifyInduction, should be adjusted.
414   //
415   /// CHECK-START: void Main.inductionMax(int[]) loop_optimization (before)
416   /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
417   /// CHECK-DAG: Phi loop:<<Loop>>      outer_loop:none
418   //
419   /// CHECK-START: void Main.inductionMax(int[]) loop_optimization (after)
420   /// CHECK-NOT: Phi
inductionMax(int[] a)421   private static void inductionMax(int[] a) {
422    int s = 0;
423     for (int i = 0; i < 10; i++) {
424       s = Math.max(s, 5);
425     }
426   }
427 
428   /// CHECK-START: int Main.feedsIntoDeopt(int[]) loop_optimization (before)
429   /// CHECK-DAG: Phi loop:<<Loop1:B\d+>> outer_loop:none
430   /// CHECK-DAG: Phi loop:<<Loop1>>      outer_loop:none
431   /// CHECK-DAG: Phi loop:<<Loop2:B\d+>> outer_loop:none
432   //
433   /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
434   //
435   /// CHECK-START: int Main.feedsIntoDeopt(int[]) loop_optimization (after)
436   /// CHECK-DAG: Phi loop:{{B\d+}} outer_loop:none
437   /// CHECK-NOT: Phi
feedsIntoDeopt(int[] a)438   static int feedsIntoDeopt(int[] a) {
439     // Reduction should be removed.
440     int r = 0;
441     for (int i = 0; i < 100; i++) {
442       r += 10;
443     }
444     // Even though uses feed into deopts of BCE.
445     for (int i = 1; i < 100; i++) {
446       a[i] = a[i - 1];
447     }
448     return r;
449   }
450 
absCanBeNegative(int x)451   static int absCanBeNegative(int x) {
452     int a[] = { 1, 2, 3 };
453     int y = 0;
454     for (int i = Math.abs(x); i < a.length; i++) {
455       y += a[i];
456     }
457     return y;
458   }
459 
460   // b/65478356: sum up 2-dim array.
sum(int[][] a)461   static int sum(int[][] a) {
462     int sum = 0;
463     for (int y = 0; y < a.length; y++) {
464       int[] aa = a[y];
465       for (int x = 0; x < aa.length; x++) {
466         sum += aa[x];
467       }
468     }
469     return sum;
470   }
471 
472   // Large loop body should not break unrolling computation.
largeBody(int[] x)473   static void largeBody(int[] x) {
474     for (int i = 0; i < 100; i++) {
475       x[i] = x[i] * 1 + x[i] * 2 + x[i] * 3 + x[i] * 4 + x[i] * 5 + x[i] * 6 +
476           x[i] * 7 + x[i] * 8 + x[i] * 9 + x[i] * 10 + x[i] * 11 + x[i] * 12 +
477           x[i] * 13 + x[i] * 14 + x[i] * 15 + x[i] * 1 + x[i] * 2 + x[i] * 3 + x[i] * 4 +
478           x[i] * 5 + x[i] * 6 + x[i] * 7 + x[i] * 8 + x[i] * 9 + x[i] * 10 + x[i] * 11 +
479           x[i] * 12 + x[i] * 13 + x[i] * 14 + x[i] * 15 + x[i] * 1 + x[i] * 2 + x[i] * 3 +
480           x[i] * 4 + x[i] * 5;
481     }
482   }
483 
484   // Mixed of 16-bit and 8-bit array references.
castAndNarrow(byte[] x, char[] y)485   static void castAndNarrow(byte[] x, char[] y) {
486     for (int i = 0; i < x.length; i++) {
487       x[i] = (byte) ((short) y[i] +  1);
488     }
489   }
490 
491   // Avoid bad scheduler-SIMD interaction.
doNotMoveSIMD()492   static int doNotMoveSIMD() {
493     int sum = 0;
494     for (int j = 0; j <= 8; j++) {
495       int[] a = new int[17];    // a[i] = 0;
496                                 // ConstructorFence ?
497       for (int i = 0; i < a.length; i++) {
498         a[i] += 1;              // a[i] = 1;
499       }
500       for (int i = 0; i < a.length; i++) {
501         sum += a[i];            // expect a[i] = 1;
502       }
503     }
504     return sum;
505   }
506 
507   // Ensure spilling saves full SIMD values.
reduction32Values(int[] a, int[] b, int[] c, int[] d)508   private static final int reduction32Values(int[] a, int[] b, int[] c, int[] d) {
509     int s0 = 0;
510     int s1 = 0;
511     int s2 = 0;
512     int s3 = 0;
513     int s4 = 0;
514     int s5 = 0;
515     int s6 = 0;
516     int s7 = 0;
517     int s8 = 0;
518     int s9 = 0;
519     int s10 = 0;
520     int s11 = 0;
521     int s12 = 0;
522     int s13 = 0;
523     int s14 = 0;
524     int s15 = 0;
525     int s16 = 0;
526     int s17 = 0;
527     int s18 = 0;
528     int s19 = 0;
529     int s20 = 0;
530     int s21 = 0;
531     int s22 = 0;
532     int s23 = 0;
533     int s24 = 0;
534     int s25 = 0;
535     int s26 = 0;
536     int s27 = 0;
537     int s28 = 0;
538     int s29 = 0;
539     int s30 = 0;
540     int s31 = 0;
541     for (int i = 1; i < 100; i++) {
542       s0 += a[i];
543       s1 += b[i];
544       s2 += c[i];
545       s3 += d[i];
546       s4 += a[i];
547       s5 += b[i];
548       s6 += c[i];
549       s7 += d[i];
550       s8 += a[i];
551       s9 += b[i];
552       s10 += c[i];
553       s11 += d[i];
554       s12 += a[i];
555       s13 += b[i];
556       s14 += c[i];
557       s15 += d[i];
558       s16 += a[i];
559       s17 += b[i];
560       s18 += c[i];
561       s19 += d[i];
562       s20 += a[i];
563       s21 += b[i];
564       s22 += c[i];
565       s23 += d[i];
566       s24 += a[i];
567       s25 += b[i];
568       s26 += c[i];
569       s27 += d[i];
570       s28 += a[i];
571       s29 += b[i];
572       s30 += c[i];
573       s31 += d[i];
574     }
575     return s0 + s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10 + s11 + s12 + s13 + s14 + s15 +
576            s16 + s17 + s18 + s19 + s20 + s21 + s22 + s23 +
577            s24 + s25 + s26 + s27 + s28 + s29 + s30 + s31;
578   }
579 
reductionIntoReplication()580   public static int reductionIntoReplication() {
581     int[] a = { 1, 2, 3, 4 };
582     int x = 0;
583     for (int i = 0; i < 4; i++) {
584       x += a[i];
585     }
586     for (int i = 0; i < 4; i++) {
587       a[i] = x;
588     }
589     return a[3];
590   }
591 
main(String[] args)592   public static void main(String[] args) {
593     System.loadLibrary(args[0]);
594 
595     expectEquals(10, earlyExitFirst(-1));
596     for (int i = 0; i <= 10; i++) {
597       expectEquals(i, earlyExitFirst(i));
598     }
599     expectEquals(10, earlyExitFirst(11));
600 
601     expectEquals(10, earlyExitLast(-1));
602     for (int i = 0; i < 10; i++) {
603       expectEquals(i + 1, earlyExitLast(i));
604     }
605     expectEquals(10, earlyExitLast(10));
606     expectEquals(10, earlyExitLast(11));
607 
608     expectEquals(2, earlyExitNested());
609 
610     expectEquals(17, transferNarrowWrap());
611     expectEquals(-45, polynomialShort());
612     expectEquals(-45, polynomialIntFromLong());
613     expectEquals(-45, polynomialInt());
614 
615     expectEquals(0, geoIntDivLastValue(0));
616     expectEquals(0, geoIntDivLastValue(1));
617     expectEquals(0, geoIntDivLastValue(2));
618     expectEquals(0, geoIntDivLastValue(1081788608));
619     expectEquals(0, geoIntDivLastValue(-1081788608));
620     expectEquals(0, geoIntDivLastValue(2147483647));
621     expectEquals(0, geoIntDivLastValue(-2147483648));
622 
623     expectEquals(          0, geoIntMulLastValue(0));
624     expectEquals( -194211840, geoIntMulLastValue(1));
625     expectEquals( -388423680, geoIntMulLastValue(2));
626     expectEquals(-1041498112, geoIntMulLastValue(1081788608));
627     expectEquals( 1041498112, geoIntMulLastValue(-1081788608));
628     expectEquals(  194211840, geoIntMulLastValue(2147483647));
629     expectEquals(          0, geoIntMulLastValue(-2147483648));
630 
631     expectEquals(0L, geoLongDivLastValue(0L));
632     expectEquals(0L, geoLongDivLastValue(1L));
633     expectEquals(0L, geoLongDivLastValue(2L));
634     expectEquals(0L, geoLongDivLastValue(1081788608L));
635     expectEquals(0L, geoLongDivLastValue(-1081788608L));
636     expectEquals(0L, geoLongDivLastValue(2147483647L));
637     expectEquals(0L, geoLongDivLastValue(-2147483648L));
638     expectEquals(0L, geoLongDivLastValue(9223372036854775807L));
639     expectEquals(0L, geoLongDivLastValue(-9223372036854775808L));
640 
641     expectEquals(0L, geoLongDivLastValue());
642 
643     expectEquals(                   0L, geoLongMulLastValue(0L));
644     expectEquals(-8070450532247928832L, geoLongMulLastValue(1L));
645     expectEquals( 2305843009213693952L, geoLongMulLastValue(2L));
646     expectEquals(                   0L, geoLongMulLastValue(1081788608L));
647     expectEquals(                   0L, geoLongMulLastValue(-1081788608L));
648     expectEquals( 8070450532247928832L, geoLongMulLastValue(2147483647L));
649     expectEquals(                   0L, geoLongMulLastValue(-2147483648L));
650     expectEquals( 8070450532247928832L, geoLongMulLastValue(9223372036854775807L));
651     expectEquals(                   0L, geoLongMulLastValue(-9223372036854775808L));
652 
653     float[] a = new float[16];
654     narrowingSubscript(a);
655     for (int i = 0; i < 16; i++) {
656       expectEquals(2.0f, a[i]);
657     }
658 
659     int[] xx = new int[2];
660     int[] yy = new int[469];
661     reduc(xx, yy);
662     expectEquals(-469, xx[0]);
663     expectEquals(-938, xx[1]);
664     for (int i = 0; i < 469; i++) {
665       expectEquals(2, yy[i]);
666     }
667 
668     char[] aa = new char[23];
669     String bb = "hello world how are you";
670     string2Bytes(aa, bb);
671     for (int i = 0; i < aa.length; i++) {
672       expectEquals(aa[i], bb.charAt(i));
673     }
674     String cc = "\u1010\u2020llo world how are y\u3030\u4040";
675     string2Bytes(aa, cc);
676     for (int i = 0; i < aa.length; i++) {
677       expectEquals(aa[i], cc.charAt(i));
678     }
679 
680     short[] s2s = new short[12];
681     $noinline$stringToShorts(s2s, "abcdefghijkl");
682     for (int i = 0; i < s2s.length; ++i) {
683       expectEquals((short) "abcdefghijkl".charAt(i), s2s[i]);
684     }
685 
686     envUsesInCond();
687 
688     short[] dd = new short[23];
689     oneBoth(dd, aa);
690     for (int i = 0; i < aa.length; i++) {
691       expectEquals(aa[i], 1);
692       expectEquals(dd[i], 1);
693     }
694 
695     xx[0] = 10;
696     byte[] bt = new byte[10];
697     arrayInTripCount(xx, bt, 20);
698     for (int i = 0; i < bt.length; i++) {
699       expectEquals(40, bt[i]);
700     }
701 
702     byte[] b1 = new byte[259];  // few extra iterations
703     byte[] b2 = new byte[259];
704     for (int i = 0; i < 259; i++) {
705       b1[i] = 0;
706       b2[i] = (byte) i;
707     }
708     typeConv(b1, b2);
709     for (int i = 0; i < 259; i++) {
710       expectEquals((byte)(i + 1), b1[i]);
711     }
712 
713     inductionMax(yy);
714 
715     int[] f = new int[100];
716     f[0] = 11;
717     expectEquals(1000, feedsIntoDeopt(f));
718     for (int i = 0; i < 100; i++) {
719       expectEquals(11, f[i]);
720     }
721 
722     expectEquals(0, absCanBeNegative(-3));
723     expectEquals(3, absCanBeNegative(-2));
724     expectEquals(5, absCanBeNegative(-1));
725     expectEquals(6, absCanBeNegative(0));
726     expectEquals(5, absCanBeNegative(1));
727     expectEquals(3, absCanBeNegative(2));
728     expectEquals(0, absCanBeNegative(3));
729     expectEquals(0, absCanBeNegative(Integer.MAX_VALUE));
730     // Abs(min_int) = min_int.
731     int verify = 0;
732     try {
733       absCanBeNegative(Integer.MIN_VALUE);
734       verify = 1;
735     } catch (ArrayIndexOutOfBoundsException e) {
736       verify = 2;
737     }
738     expectEquals(2, verify);
739 
740     int[][] x = new int[128][128];
741     for (int i = 0; i < 128; i++) {
742       for (int j = 0; j < 128; j++) {
743         x[i][j] = -i - j;
744       }
745     }
746     expectEquals(-2080768, sum(x));
747 
748     largeBody(f);
749     for (int i = 0; i < 100; i++) {
750       expectEquals(2805, f[i]);
751     }
752 
753     char[] cx = new char[259];
754     for (int i = 0; i < 259; i++) {
755       cx[i] = (char) (i - 100);
756     }
757     castAndNarrow(b1, cx);
758     for (int i = 0; i < 259; i++) {
759       expectEquals((byte)((short) cx[i] + 1), b1[i]);
760     }
761 
762     expectEquals(153, doNotMoveSIMD());
763 
764     // This test exposed SIMDization issues on x86 and x86_64
765     // so we make sure the test runs with JIT enabled.
766     ensureJitCompiled(Main.class, "reduction32Values");
767     {
768       int[] a1 = new int[100];
769       int[] a2 = new int[100];
770       int[] a3 = new int[100];
771       int[] a4 = new int[100];
772       for (int i = 0; i < 100; i++) {
773         a1[i] = i;
774         a2[i] = 1;
775         a3[i] = 100 - i;
776         a4[i] = i % 16;
777       }
778       expectEquals(85800, reduction32Values(a1, a2, a3, a4));
779     }
780 
781     expectEquals(10, reductionIntoReplication());
782 
783     System.out.println("passed");
784   }
785 
expectEquals(int expected, int result)786   private static void expectEquals(int expected, int result) {
787     if (expected != result) {
788       throw new Error("Expected: " + expected + ", found: " + result);
789     }
790   }
791 
expectEquals(long expected, long result)792   private static void expectEquals(long expected, long result) {
793     if (expected != result) {
794       throw new Error("Expected: " + expected + ", found: " + result);
795     }
796   }
797 
expectEquals(float expected, float result)798   private static void expectEquals(float expected, float result) {
799     if (expected != result) {
800       throw new Error("Expected: " + expected + ", found: " + result);
801     }
802   }
803 }
804