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 */
20public class Main {
21
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
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
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+}}
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
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
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
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
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
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
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).
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).
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
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.
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.
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.
297  //
298  /// CHECK-START-MIPS64: void Main.string2Bytes(char[], java.lang.String) loop_optimization (after)
299  /// CHECK-NOT: VecLoad
300  private static void string2Bytes(char[] a, String b) {
301    int min = Math.min(a.length, b.length());
302    for (int i = 0; i < min; i++) {
303      a[i] = b.charAt(i);
304    }
305  }
306
307  // A strange function that does not inline.
308  private static void $noinline$foo(boolean x, int n) {
309    if (n < 0)
310      throw new Error("oh no");
311    if (n > 100) {
312      $noinline$foo(!x, n - 1);
313      $noinline$foo(!x, n - 2);
314      $noinline$foo(!x, n - 3);
315      $noinline$foo(!x, n - 4);
316    }
317  }
318
319  // A loop with environment uses of x (the terminating condition). As exposed by bug
320  // b/37247891, the loop can be unrolled, but should handle the (unlikely, but clearly
321  // not impossible) environment uses of the terminating condition in a correct manner.
322  private static void envUsesInCond() {
323    boolean x = false;
324    for (int i = 0; !(x = i >= 1); i++) {
325      $noinline$foo(true, i);
326    }
327  }
328
329  /// CHECK-START: void Main.oneBoth(short[], char[]) loop_optimization (before)
330  /// CHECK-DAG: <<One:i\d+>>  IntConstant 1                       loop:none
331  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
332  /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<One>>] loop:<<Loop>>      outer_loop:none
333  /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<One>>] loop:<<Loop>>      outer_loop:none
334  //
335  /// CHECK-START-ARM: void Main.oneBoth(short[], char[]) loop_optimization (after)
336  /// CHECK-DAG: <<One:i\d+>>  IntConstant 1                             loop:none
337  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<One>>]              loop:none
338  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi:i\d+>>,<<Repl>>] loop:<<Loop:B\d+>> outer_loop:none
339  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<Repl>>]      loop:<<Loop>>      outer_loop:none
340  //
341  /// CHECK-START-ARM64: void Main.oneBoth(short[], char[]) loop_optimization (after)
342  /// CHECK-DAG: <<One:i\d+>>  IntConstant 1                             loop:none
343  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<One>>]              loop:none
344  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi:i\d+>>,<<Repl>>] loop:<<Loop:B\d+>> outer_loop:none
345  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<Repl>>]      loop:<<Loop>>      outer_loop:none
346  //
347  /// CHECK-START-MIPS64: void Main.oneBoth(short[], char[]) loop_optimization (after)
348  /// CHECK-DAG: <<One:i\d+>>  IntConstant 1                             loop:none
349  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<One>>]              loop:none
350  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi:i\d+>>,<<Repl>>] loop:<<Loop:B\d+>> outer_loop:none
351  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<Repl>>]      loop:<<Loop>>      outer_loop:none
352  //
353  // Bug b/37764324: integral same-length packed types can be mixed freely.
354  private static void oneBoth(short[] a, char[] b) {
355    for (int i = 0; i < Math.min(a.length, b.length); i++) {
356      a[i] = 1;
357      b[i] = 1;
358    }
359  }
360
361  // Bug b/37768917: potential dynamic BCE vs. loop optimizations
362  // case should be deal with correctly (used to DCHECK fail).
363  private static void arrayInTripCount(int[] a, byte[] b, int n) {
364    for (int k = 0; k < n; k++) {
365      for (int i = 0, u = a[0]; i < u; i++) {
366        b[i] += 2;
367      }
368    }
369  }
370
371  /// CHECK-START: void Main.typeConv(byte[], byte[]) loop_optimization (before)
372  /// CHECK-DAG: <<One:i\d+>>  IntConstant 1                       loop:none
373  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
374  /// CHECK-DAG: <<Get:b\d+>>  ArrayGet [{{l\d+}},<<Phi>>]         loop:<<Loop>>      outer_loop:none
375  /// CHECK-DAG: <<Add:i\d+>>  Add [<<Get>>,<<One>>]               loop:<<Loop>>      outer_loop:none
376  /// CHECK-DAG: <<Cnv:b\d+>>  TypeConversion [<<Add>>]            loop:<<Loop>>      outer_loop:none
377  /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
378  //
379  /// CHECK-START-ARM: void Main.typeConv(byte[], byte[]) loop_optimization (after)
380  /// CHECK-DAG: <<One:i\d+>>  IntConstant 1                         loop:none
381  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<One>>]          loop:none
382  /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1:i\d+>>]      loop:<<Loop1:B\d+>> outer_loop:none
383  /// CHECK-DAG: <<Vadd:d\d+>> VecAdd [<<Load>>,<<Repl>>]            loop:<<Loop1>>      outer_loop:none
384  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi1>>,<<Vadd>>] loop:<<Loop1>>      outer_loop:none
385  /// CHECK-DAG: <<Get:b\d+>>  ArrayGet [{{l\d+}},<<Phi2:i\d+>>]     loop:<<Loop2:B\d+>> outer_loop:none
386  /// CHECK-DAG: <<Add:i\d+>>  Add [<<Get>>,<<One>>]                 loop:<<Loop2>>      outer_loop:none
387  /// CHECK-DAG: <<Cnv:b\d+>>  TypeConversion [<<Add>>]              loop:<<Loop2>>      outer_loop:none
388  /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi2>>,<<Cnv>>]  loop:<<Loop2>>      outer_loop:none
389  //
390  /// CHECK-START-ARM64: void Main.typeConv(byte[], byte[]) loop_optimization (after)
391  /// CHECK-DAG: <<One:i\d+>>  IntConstant 1                         loop:none
392  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<One>>]          loop:none
393  /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1:i\d+>>]      loop:<<Loop1:B\d+>> outer_loop:none
394  /// CHECK-DAG: <<Vadd:d\d+>> VecAdd [<<Load>>,<<Repl>>]            loop:<<Loop1>>      outer_loop:none
395  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi1>>,<<Vadd>>] loop:<<Loop1>>      outer_loop:none
396  /// CHECK-DAG: <<Get:b\d+>>  ArrayGet [{{l\d+}},<<Phi2:i\d+>>]     loop:<<Loop2:B\d+>> outer_loop:none
397  /// CHECK-DAG: <<Add:i\d+>>  Add [<<Get>>,<<One>>]                 loop:<<Loop2>>      outer_loop:none
398  /// CHECK-DAG: <<Cnv:b\d+>>  TypeConversion [<<Add>>]              loop:<<Loop2>>      outer_loop:none
399  /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi2>>,<<Cnv>>]  loop:<<Loop2>>      outer_loop:none
400  //
401  /// CHECK-START-MIPS64: void Main.typeConv(byte[], byte[]) loop_optimization (after)
402  /// CHECK-DAG: <<One:i\d+>>  IntConstant 1                         loop:none
403  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<One>>]          loop:none
404  /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1:i\d+>>]      loop:<<Loop1:B\d+>> outer_loop:none
405  /// CHECK-DAG: <<Vadd:d\d+>> VecAdd [<<Load>>,<<Repl>>]            loop:<<Loop1>>      outer_loop:none
406  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi1>>,<<Vadd>>] loop:<<Loop1>>      outer_loop:none
407  /// CHECK-DAG: <<Get:b\d+>>  ArrayGet [{{l\d+}},<<Phi2:i\d+>>]     loop:<<Loop2:B\d+>> outer_loop:none
408  /// CHECK-DAG: <<Add:i\d+>>  Add [<<Get>>,<<One>>]                 loop:<<Loop2>>      outer_loop:none
409  /// CHECK-DAG: <<Cnv:b\d+>>  TypeConversion [<<Add>>]              loop:<<Loop2>>      outer_loop:none
410  /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi2>>,<<Cnv>>]  loop:<<Loop2>>      outer_loop:none
411  //
412  // Scalar code in cleanup loop uses correct byte type on array get and type conversion.
413  private static void typeConv(byte[] a, byte[] b) {
414    int len = Math.min(a.length, b.length);
415    for (int i = 0; i < len; i++) {
416      a[i] = (byte) (b[i] + 1);
417    }
418  }
419
420  // Environment of an instruction, removed during SimplifyInduction, should be adjusted.
421  //
422  /// CHECK-START: void Main.inductionMax(int[]) loop_optimization (before)
423  /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
424  /// CHECK-DAG: Phi loop:<<Loop>>      outer_loop:none
425  //
426  /// CHECK-START: void Main.inductionMax(int[]) loop_optimization (after)
427  /// CHECK-NOT: Phi
428  private static void inductionMax(int[] a) {
429   int s = 0;
430    for (int i = 0; i < 10; i++) {
431      s = Math.max(s, 5);
432    }
433  }
434
435  /// CHECK-START: int Main.feedsIntoDeopt(int[]) loop_optimization (before)
436  /// CHECK-DAG: Phi loop:<<Loop1:B\d+>> outer_loop:none
437  /// CHECK-DAG: Phi loop:<<Loop1>>      outer_loop:none
438  /// CHECK-DAG: Phi loop:<<Loop2:B\d+>> outer_loop:none
439  //
440  /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
441  //
442  /// CHECK-START: int Main.feedsIntoDeopt(int[]) loop_optimization (after)
443  /// CHECK-DAG: Phi loop:{{B\d+}} outer_loop:none
444  /// CHECK-NOT: Phi
445  static int feedsIntoDeopt(int[] a) {
446    // Reduction should be removed.
447    int r = 0;
448    for (int i = 0; i < 100; i++) {
449      r += 10;
450    }
451    // Even though uses feed into deopts of BCE.
452    for (int i = 1; i < 100; i++) {
453      a[i] = a[i - 1];
454    }
455    return r;
456  }
457
458  static int absCanBeNegative(int x) {
459    int a[] = { 1, 2, 3 };
460    int y = 0;
461    for (int i = Math.abs(x); i < a.length; i++) {
462      y += a[i];
463    }
464    return y;
465  }
466
467  // b/65478356: sum up 2-dim array.
468  static int sum(int[][] a) {
469    int sum = 0;
470    for (int y = 0; y < a.length; y++) {
471      int[] aa = a[y];
472      for (int x = 0; x < aa.length; x++) {
473        sum += aa[x];
474      }
475    }
476    return sum;
477  }
478
479  // Large loop body should not break unrolling computation.
480  static void largeBody(int[] x) {
481    for (int i = 0; i < 100; i++) {
482      x[i] = x[i] * 1 + x[i] * 2 + x[i] * 3 + x[i] * 4 + x[i] * 5 + x[i] * 6 +
483          x[i] * 7 + x[i] * 8 + x[i] * 9 + x[i] * 10 + x[i] * 11 + x[i] * 12 +
484          x[i] * 13 + x[i] * 14 + x[i] * 15 + x[i] * 1 + x[i] * 2 + x[i] * 3 + x[i] * 4 +
485          x[i] * 5 + x[i] * 6 + x[i] * 7 + x[i] * 8 + x[i] * 9 + x[i] * 10 + x[i] * 11 +
486          x[i] * 12 + x[i] * 13 + x[i] * 14 + x[i] * 15 + x[i] * 1 + x[i] * 2 + x[i] * 3 +
487          x[i] * 4 + x[i] * 5;
488    }
489  }
490
491  // Mixed of 16-bit and 8-bit array references.
492  static void castAndNarrow(byte[] x, char[] y) {
493    for (int i = 0; i < x.length; i++) {
494      x[i] = (byte) ((short) y[i] +  1);
495    }
496  }
497
498  // Avoid bad scheduler-SIMD interaction.
499  static int doNotMoveSIMD() {
500    int sum = 0;
501    for (int j = 0; j <= 8; j++) {
502      int[] a = new int[17];    // a[i] = 0;
503                                // ConstructorFence ?
504      for (int i = 0; i < a.length; i++) {
505        a[i] += 1;              // a[i] = 1;
506      }
507      for (int i = 0; i < a.length; i++) {
508        sum += a[i];            // expect a[i] = 1;
509      }
510    }
511    return sum;
512  }
513
514  // Ensure spilling saves full SIMD values.
515  private static final int reduction32Values(int[] a, int[] b, int[] c, int[] d) {
516    int s0 = 0;
517    int s1 = 0;
518    int s2 = 0;
519    int s3 = 0;
520    int s4 = 0;
521    int s5 = 0;
522    int s6 = 0;
523    int s7 = 0;
524    int s8 = 0;
525    int s9 = 0;
526    int s10 = 0;
527    int s11 = 0;
528    int s12 = 0;
529    int s13 = 0;
530    int s14 = 0;
531    int s15 = 0;
532    int s16 = 0;
533    int s17 = 0;
534    int s18 = 0;
535    int s19 = 0;
536    int s20 = 0;
537    int s21 = 0;
538    int s22 = 0;
539    int s23 = 0;
540    int s24 = 0;
541    int s25 = 0;
542    int s26 = 0;
543    int s27 = 0;
544    int s28 = 0;
545    int s29 = 0;
546    int s30 = 0;
547    int s31 = 0;
548    for (int i = 1; i < 100; i++) {
549      s0 += a[i];
550      s1 += b[i];
551      s2 += c[i];
552      s3 += d[i];
553      s4 += a[i];
554      s5 += b[i];
555      s6 += c[i];
556      s7 += d[i];
557      s8 += a[i];
558      s9 += b[i];
559      s10 += c[i];
560      s11 += d[i];
561      s12 += a[i];
562      s13 += b[i];
563      s14 += c[i];
564      s15 += d[i];
565      s16 += a[i];
566      s17 += b[i];
567      s18 += c[i];
568      s19 += d[i];
569      s20 += a[i];
570      s21 += b[i];
571      s22 += c[i];
572      s23 += d[i];
573      s24 += a[i];
574      s25 += b[i];
575      s26 += c[i];
576      s27 += d[i];
577      s28 += a[i];
578      s29 += b[i];
579      s30 += c[i];
580      s31 += d[i];
581    }
582    return s0 + s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10 + s11 + s12 + s13 + s14 + s15 +
583           s16 + s17 + s18 + s19 + s20 + s21 + s22 + s23 +
584           s24 + s25 + s26 + s27 + s28 + s29 + s30 + s31;
585  }
586
587  public static int reductionIntoReplication() {
588    int[] a = { 1, 2, 3, 4 };
589    int x = 0;
590    for (int i = 0; i < 4; i++) {
591      x += a[i];
592    }
593    for (int i = 0; i < 4; i++) {
594      a[i] = x;
595    }
596    return a[3];
597  }
598
599  public static void main(String[] args) {
600    System.loadLibrary(args[0]);
601
602    expectEquals(10, earlyExitFirst(-1));
603    for (int i = 0; i <= 10; i++) {
604      expectEquals(i, earlyExitFirst(i));
605    }
606    expectEquals(10, earlyExitFirst(11));
607
608    expectEquals(10, earlyExitLast(-1));
609    for (int i = 0; i < 10; i++) {
610      expectEquals(i + 1, earlyExitLast(i));
611    }
612    expectEquals(10, earlyExitLast(10));
613    expectEquals(10, earlyExitLast(11));
614
615    expectEquals(2, earlyExitNested());
616
617    expectEquals(17, transferNarrowWrap());
618    expectEquals(-45, polynomialShort());
619    expectEquals(-45, polynomialIntFromLong());
620    expectEquals(-45, polynomialInt());
621
622    expectEquals(0, geoIntDivLastValue(0));
623    expectEquals(0, geoIntDivLastValue(1));
624    expectEquals(0, geoIntDivLastValue(2));
625    expectEquals(0, geoIntDivLastValue(1081788608));
626    expectEquals(0, geoIntDivLastValue(-1081788608));
627    expectEquals(0, geoIntDivLastValue(2147483647));
628    expectEquals(0, geoIntDivLastValue(-2147483648));
629
630    expectEquals(          0, geoIntMulLastValue(0));
631    expectEquals( -194211840, geoIntMulLastValue(1));
632    expectEquals( -388423680, geoIntMulLastValue(2));
633    expectEquals(-1041498112, geoIntMulLastValue(1081788608));
634    expectEquals( 1041498112, geoIntMulLastValue(-1081788608));
635    expectEquals(  194211840, geoIntMulLastValue(2147483647));
636    expectEquals(          0, geoIntMulLastValue(-2147483648));
637
638    expectEquals(0L, geoLongDivLastValue(0L));
639    expectEquals(0L, geoLongDivLastValue(1L));
640    expectEquals(0L, geoLongDivLastValue(2L));
641    expectEquals(0L, geoLongDivLastValue(1081788608L));
642    expectEquals(0L, geoLongDivLastValue(-1081788608L));
643    expectEquals(0L, geoLongDivLastValue(2147483647L));
644    expectEquals(0L, geoLongDivLastValue(-2147483648L));
645    expectEquals(0L, geoLongDivLastValue(9223372036854775807L));
646    expectEquals(0L, geoLongDivLastValue(-9223372036854775808L));
647
648    expectEquals(0L, geoLongDivLastValue());
649
650    expectEquals(                   0L, geoLongMulLastValue(0L));
651    expectEquals(-8070450532247928832L, geoLongMulLastValue(1L));
652    expectEquals( 2305843009213693952L, geoLongMulLastValue(2L));
653    expectEquals(                   0L, geoLongMulLastValue(1081788608L));
654    expectEquals(                   0L, geoLongMulLastValue(-1081788608L));
655    expectEquals( 8070450532247928832L, geoLongMulLastValue(2147483647L));
656    expectEquals(                   0L, geoLongMulLastValue(-2147483648L));
657    expectEquals( 8070450532247928832L, geoLongMulLastValue(9223372036854775807L));
658    expectEquals(                   0L, geoLongMulLastValue(-9223372036854775808L));
659
660    float[] a = new float[16];
661    narrowingSubscript(a);
662    for (int i = 0; i < 16; i++) {
663      expectEquals(2.0f, a[i]);
664    }
665
666    int[] xx = new int[2];
667    int[] yy = new int[469];
668    reduc(xx, yy);
669    expectEquals(-469, xx[0]);
670    expectEquals(-938, xx[1]);
671    for (int i = 0; i < 469; i++) {
672      expectEquals(2, yy[i]);
673    }
674
675    char[] aa = new char[23];
676    String bb = "hello world how are you";
677    string2Bytes(aa, bb);
678    for (int i = 0; i < aa.length; i++) {
679      expectEquals(aa[i], bb.charAt(i));
680    }
681    String cc = "\u1010\u2020llo world how are y\u3030\u4040";
682    string2Bytes(aa, cc);
683    for (int i = 0; i < aa.length; i++) {
684      expectEquals(aa[i], cc.charAt(i));
685    }
686
687    envUsesInCond();
688
689    short[] dd = new short[23];
690    oneBoth(dd, aa);
691    for (int i = 0; i < aa.length; i++) {
692      expectEquals(aa[i], 1);
693      expectEquals(dd[i], 1);
694    }
695
696    xx[0] = 10;
697    byte[] bt = new byte[10];
698    arrayInTripCount(xx, bt, 20);
699    for (int i = 0; i < bt.length; i++) {
700      expectEquals(40, bt[i]);
701    }
702
703    byte[] b1 = new byte[259];  // few extra iterations
704    byte[] b2 = new byte[259];
705    for (int i = 0; i < 259; i++) {
706      b1[i] = 0;
707      b2[i] = (byte) i;
708    }
709    typeConv(b1, b2);
710    for (int i = 0; i < 259; i++) {
711      expectEquals((byte)(i + 1), b1[i]);
712    }
713
714    inductionMax(yy);
715
716    int[] f = new int[100];
717    f[0] = 11;
718    expectEquals(1000, feedsIntoDeopt(f));
719    for (int i = 0; i < 100; i++) {
720      expectEquals(11, f[i]);
721    }
722
723    expectEquals(0, absCanBeNegative(-3));
724    expectEquals(3, absCanBeNegative(-2));
725    expectEquals(5, absCanBeNegative(-1));
726    expectEquals(6, absCanBeNegative(0));
727    expectEquals(5, absCanBeNegative(1));
728    expectEquals(3, absCanBeNegative(2));
729    expectEquals(0, absCanBeNegative(3));
730    expectEquals(0, absCanBeNegative(Integer.MAX_VALUE));
731    // Abs(min_int) = min_int.
732    int verify = 0;
733    try {
734      absCanBeNegative(Integer.MIN_VALUE);
735      verify = 1;
736    } catch (ArrayIndexOutOfBoundsException e) {
737      verify = 2;
738    }
739    expectEquals(2, verify);
740
741    int[][] x = new int[128][128];
742    for (int i = 0; i < 128; i++) {
743      for (int j = 0; j < 128; j++) {
744        x[i][j] = -i - j;
745      }
746    }
747    expectEquals(-2080768, sum(x));
748
749    largeBody(f);
750    for (int i = 0; i < 100; i++) {
751      expectEquals(2805, f[i]);
752    }
753
754    char[] cx = new char[259];
755    for (int i = 0; i < 259; i++) {
756      cx[i] = (char) (i - 100);
757    }
758    castAndNarrow(b1, cx);
759    for (int i = 0; i < 259; i++) {
760      expectEquals((byte)((short) cx[i] + 1), b1[i]);
761    }
762
763    expectEquals(153, doNotMoveSIMD());
764
765    // This test exposed SIMDization issues on x86 and x86_64
766    // so we make sure the test runs with JIT enabled.
767    ensureJitCompiled(Main.class, "reduction32Values");
768    {
769      int[] a1 = new int[100];
770      int[] a2 = new int[100];
771      int[] a3 = new int[100];
772      int[] a4 = new int[100];
773      for (int i = 0; i < 100; i++) {
774        a1[i] = i;
775        a2[i] = 1;
776        a3[i] = 100 - i;
777        a4[i] = i % 16;
778      }
779      expectEquals(85800, reduction32Values(a1, a2, a3, a4));
780    }
781
782    expectEquals(10, reductionIntoReplication());
783
784    System.out.println("passed");
785  }
786
787  private static void expectEquals(int expected, int result) {
788    if (expected != result) {
789      throw new Error("Expected: " + expected + ", found: " + result);
790    }
791  }
792
793  private static void expectEquals(long expected, long result) {
794    if (expected != result) {
795      throw new Error("Expected: " + expected + ", found: " + result);
796    }
797  }
798
799  private static void expectEquals(float expected, float result) {
800    if (expected != result) {
801      throw new Error("Expected: " + expected + ", found: " + result);
802    }
803  }
804}
805