1 /*
2  * Copyright (C) 2023 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  * Tests for autovectorization of loops with control flow.
19  */
20 public class Main {
21 
22   public static final int ARRAY_LENGTH = 128;
23   public static final int USED_ARRAY_LENGTH = ARRAY_LENGTH - 1;
24 
25   public static boolean[] booleanArray = new boolean[ARRAY_LENGTH];
26   public static boolean[] booleanArray2 = new boolean[ARRAY_LENGTH];
27   public static byte[] byteArray = new byte[ARRAY_LENGTH];
28   public static short[] shortArray = new short[ARRAY_LENGTH];
29   public static char[] charArray = new char[ARRAY_LENGTH];
30   public static int[] intArray = new int[ARRAY_LENGTH];
31   public static long[] longArray = new long[ARRAY_LENGTH];
32   public static float[] floatArray = new float[ARRAY_LENGTH];
33   public static double[] doubleArray = new double[ARRAY_LENGTH];
34 
35   public static final int MAGIC_VALUE_A = 2;
36   public static final int MAGIC_VALUE_B = 10;
37   public static final int MAGIC_VALUE_C = 100;
38 
39   public static final int MAGIC_ADD_CONST = 99;
40 
41   public static final float MAGIC_FLOAT_VALUE_A = 2.0f;
42   public static final float MAGIC_FLOAT_VALUE_B = 10.0f;
43   public static final float MAGIC_FLOAT_VALUE_C = 100.0f;
44 
45   public static final float MAGIC_FLOAT_ADD_CONST = 99.0f;
46 
47   /// CHECK-START-ARM64: int Main.$compile$noinline$FullDiamond(int[]) loop_optimization (after)
48   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
49   //
50   ///     CHECK-DAG: <<C0:i\d+>>      IntConstant 0                                         loop:none
51   ///     CHECK-DAG: <<C4:i\d+>>      IntConstant 4                                         loop:none
52   ///     CHECK-DAG: <<C99:i\d+>>     IntConstant 99                                        loop:none
53   ///     CHECK-DAG: <<C100:i\d+>>    IntConstant 100                                       loop:none
54   ///     CHECK-DAG: <<Vec4:d\d+>>    VecReplicateScalar [<<C4>>,{{j\d+}}]                  loop:none
55   ///     CHECK-DAG: <<Vec99:d\d+>>   VecReplicateScalar [<<C99>>,{{j\d+}}]                 loop:none
56   ///     CHECK-DAG: <<Vec100:d\d+>>  VecReplicateScalar [<<C100>>,{{j\d+}}]                loop:none
57   //
58   ///     CHECK-DAG: <<Phi:i\d+>>     Phi [<<C0>>,{{i\d+}}]                                 loop:<<Loop:B\d+>> outer_loop:none
59   ///     CHECK-DAG: <<LoopP:j\d+>>   VecPredWhile [<<Phi>>,{{i\d+}}]                       loop:<<Loop>>      outer_loop:none
60   //
61   ///     CHECK-DAG: <<Load1:d\d+>>   VecLoad [<<Arr:l\d+>>,<<Phi>>,<<LoopP>>]              loop:<<Loop>>      outer_loop:none
62   ///     CHECK-DAG: <<Cond:j\d+>>    VecCondition [<<Load1>>,<<Vec100>>,<<LoopP>>]         loop:<<Loop>>      outer_loop:none
63   ///     CHECK-DAG: <<CondR:j\d+>>   VecPredNot [<<Cond>>,<<LoopP>>]                       loop:<<Loop>>      outer_loop:none
64   ///     CHECK-DAG: <<AddT:d\d+>>    VecAdd [<<Load1>>,<<Vec99>>,<<CondR>>]                loop:<<Loop>>      outer_loop:none
65   ///     CHECK-DAG: <<StT:d\d+>>     VecStore [<<Arr>>,<<Phi>>,<<AddT>>,<<CondR>>]         loop:<<Loop>>      outer_loop:none
66   ///     CHECK-DAG: <<StF:d\d+>>     VecStore [<<Arr>>,<<Phi>>,{{d\d+}},<<Cond>>]          loop:<<Loop>>      outer_loop:none
67   ///     CHECK-DAG: <<Ld2:d\d+>>     VecLoad [<<Arr>>,<<Phi>>,<<LoopP>>]                   loop:<<Loop>>      outer_loop:none
68   ///     CHECK-DAG: <<Add2:d\d+>>    VecAdd [<<Ld2>>,<<Vec4>>,<<LoopP>>]                   loop:<<Loop>>      outer_loop:none
69   ///     CHECK-DAG: <<St21:d\d+>>    VecStore [<<Arr>>,<<Phi>>,<<Add2>>,<<LoopP>>]         loop:<<Loop>>      outer_loop:none
70   //
71   /// CHECK-ELSE:
72   //
73   ///     CHECK-NOT:                      VecLoad
74   //
75   /// CHECK-FI:
$compile$noinline$FullDiamond(int[] x)76   public static int $compile$noinline$FullDiamond(int[] x) {
77     int i = 0;
78     for (; i < USED_ARRAY_LENGTH; i++) {
79       int val = x[i];
80       if (val != MAGIC_VALUE_C) {
81         x[i] += MAGIC_ADD_CONST;
82       } else {
83         x[i] += 3;
84       }
85       x[i] += 4;
86     }
87     return i;
88   }
89 
90   //
91   // Test various types.
92   //
93 
94   /// CHECK-START-ARM64: void Main.$compile$noinline$SimpleBoolean(boolean[], boolean[]) loop_optimization (after)
95   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
96   //
97   ///     CHECK-NOT: VecLoad
98   //
99   /// CHECK-FI:
100   //
101   // TODO: Support extra condition types and boolean comparisons.
$compile$noinline$SimpleBoolean(boolean[] x, boolean[] y)102   public static void $compile$noinline$SimpleBoolean(boolean[] x, boolean[] y) {
103     for (int i = 0; i < USED_ARRAY_LENGTH; i++) {
104       boolean val = x[i];
105       if (val != y[i]) {
106         x[i] |= y[i];
107       }
108     }
109   }
110 
111   /// CHECK-START-ARM64: void Main.$compile$noinline$SimpleByte(byte[]) loop_optimization (after)
112   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
113   //
114   ///     CHECK-DAG: VecLoad
115   //
116   /// CHECK-FI:
$compile$noinline$SimpleByte(byte[] x)117   public static void $compile$noinline$SimpleByte(byte[] x) {
118     for (int i = 0; i < USED_ARRAY_LENGTH; i++) {
119       byte val = x[i];
120       if (val != MAGIC_VALUE_C) {
121         x[i] += MAGIC_ADD_CONST;
122       }
123     }
124   }
125 
126   /// CHECK-START-ARM64: void Main.$compile$noinline$SimpleUByte(byte[]) loop_optimization (after)
127   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
128   //
129   ///     CHECK-DAG: VecLoad
130   //
131   /// CHECK-FI:
$compile$noinline$SimpleUByte(byte[] x)132   public static void $compile$noinline$SimpleUByte(byte[] x) {
133     for (int i = 0; i < USED_ARRAY_LENGTH; i++) {
134       if ((x[i] & 0xFF) != MAGIC_VALUE_C) {
135         x[i] += MAGIC_ADD_CONST;
136       }
137     }
138   }
139 
140   /// CHECK-START-ARM64: void Main.$compile$noinline$SimpleShort(short[]) loop_optimization (after)
141   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
142   //
143   ///     CHECK-DAG: VecLoad
144   //
145   /// CHECK-FI:
$compile$noinline$SimpleShort(short[] x)146   public static void $compile$noinline$SimpleShort(short[] x) {
147     for (int i = 0; i < USED_ARRAY_LENGTH; i++) {
148       short val = x[i];
149       if (val != MAGIC_VALUE_C) {
150         x[i] += MAGIC_ADD_CONST;
151       }
152     }
153   }
154 
155   /// CHECK-START-ARM64: void Main.$compile$noinline$SimpleChar(char[]) loop_optimization (after)
156   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
157   //
158   ///     CHECK-DAG: VecLoad
159   //
160   /// CHECK-FI:
$compile$noinline$SimpleChar(char[] x)161   public static void $compile$noinline$SimpleChar(char[] x) {
162     for (int i = 0; i < USED_ARRAY_LENGTH; i++) {
163       char val = x[i];
164       if (val != MAGIC_VALUE_C) {
165         x[i] += MAGIC_ADD_CONST;
166       }
167     }
168   }
169 
170   /// CHECK-START-ARM64: void Main.$compile$noinline$SimpleInt(int[]) loop_optimization (after)
171   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
172   //
173   ///     CHECK-DAG: VecLoad
174   //
175   /// CHECK-FI:
$compile$noinline$SimpleInt(int[] x)176   public static void $compile$noinline$SimpleInt(int[] x) {
177     for (int i = 0; i < USED_ARRAY_LENGTH; i++) {
178       int val = x[i];
179       if (val != MAGIC_VALUE_C) {
180         x[i] += MAGIC_ADD_CONST;
181       }
182     }
183   }
184 
185   /// CHECK-START-ARM64: void Main.$compile$noinline$SimpleLong(long[]) loop_optimization (after)
186   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
187   //
188   ///     CHECK-NOT: VecLoad
189   //
190   /// CHECK-FI:
191   //
192   // TODO: Support long comparisons.
$compile$noinline$SimpleLong(long[] x)193   public static void $compile$noinline$SimpleLong(long[] x) {
194     for (int i = 0; i < USED_ARRAY_LENGTH; i++) {
195       long val = x[i];
196       if (val != MAGIC_VALUE_C) {
197         x[i] += MAGIC_ADD_CONST;
198       }
199     }
200   }
201 
202   /// CHECK-START-ARM64: void Main.$compile$noinline$SimpleFloat(float[]) loop_optimization (after)
203   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
204   //
205   ///     CHECK-NOT: VecLoad
206   //
207   /// CHECK-FI:
208   //
209   // TODO: Support FP comparisons.
$compile$noinline$SimpleFloat(float[] x)210   public static void $compile$noinline$SimpleFloat(float[] x) {
211     for (int i = 0; i < USED_ARRAY_LENGTH; i++) {
212       float val = x[i];
213       if (val > 10.0f) {
214         x[i] += 99.1f;
215       }
216     }
217   }
218 
219   /// CHECK-START-ARM64: void Main.$compile$noinline$SimpleDouble(double[]) loop_optimization (after)
220   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
221   //
222   ///     CHECK-NOT: VecLoad
223   //
224   /// CHECK-FI:
225   //
226   // TODO: Support FP comparisons.
$compile$noinline$SimpleDouble(double[] x)227   public static void $compile$noinline$SimpleDouble(double[] x) {
228     for (int i = 0; i < USED_ARRAY_LENGTH; i++) {
229       double val = x[i];
230       if (val != 10.0) {
231         x[i] += 99.1;
232       }
233     }
234   }
235 
236   //
237   // Narrowing types.
238   //
239 
240   /// CHECK-START-ARM64: void Main.$compile$noinline$ByteConv(byte[], byte[]) loop_optimization (after)
241   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
242   //
243   ///     CHECK-DAG: VecLoad
244   //
245   /// CHECK-FI:
$compile$noinline$ByteConv(byte[] x, byte[] y)246   public static void $compile$noinline$ByteConv(byte[] x, byte[] y) {
247     for (int i = 0; i < USED_ARRAY_LENGTH; i++) {
248       byte val = (byte)(x[i] + 1);
249       if (val != y[i]) {
250         x[i] += MAGIC_ADD_CONST;
251       }
252     }
253   }
254 
255   /// CHECK-START-ARM64: void Main.$compile$noinline$UByteAndWrongConst(byte[]) loop_optimization (after)
256   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
257   //
258   ///     CHECK-NOT: VecLoad
259   //
260   /// CHECK-FI:
261   //
262   // 'NarrowerOperands' not met: the constant is not a ubyte one.
$compile$noinline$UByteAndWrongConst(byte[] x)263   public static void $compile$noinline$UByteAndWrongConst(byte[] x) {
264     for (int i = 0; i < USED_ARRAY_LENGTH; i++) {
265       if ((x[i] & 0xFF) != (MAGIC_VALUE_C | 0x100)) {
266         x[i] += MAGIC_ADD_CONST;
267       }
268     }
269   }
270 
271   /// CHECK-START-ARM64: void Main.$compile$noinline$ByteNoHiBits(byte[], byte[]) loop_optimization (after)
272   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
273   //
274   ///     CHECK-NOT: VecLoad
275   //
276   /// CHECK-FI:
277   //
278   // Check kNoHiBits case when "wider" operations cannot bring in higher order bits.
$compile$noinline$ByteNoHiBits(byte[] x, byte[] y)279   public static void $compile$noinline$ByteNoHiBits(byte[] x, byte[] y) {
280     for (int i = 0; i < USED_ARRAY_LENGTH; i++) {
281       byte val = x[i];
282       if ((val >>> 3) != y[i]) {
283         x[i] += MAGIC_ADD_CONST;
284       }
285     }
286   }
287 
288   //
289   // Test condition types.
290   //
291 
292   /// CHECK-START-ARM64: void Main.$compile$noinline$SimpleBelow(int[]) loop_optimization (after)
293   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
294   //
295   ///     CHECK-NOT: VecLoad
296   //
297   /// CHECK-FI:
298   //
299   // TODO: Support other conditions.
$compile$noinline$SimpleBelow(int[] x)300   public static void $compile$noinline$SimpleBelow(int[] x) {
301     for (int i = 0; i < USED_ARRAY_LENGTH; i++) {
302       int val = x[i];
303       if (val < MAGIC_VALUE_C) {
304         x[i] += MAGIC_ADD_CONST;
305       }
306     }
307   }
308 
309   //
310   // Test vectorization idioms.
311   //
312 
313   /// CHECK-START-ARM64: void Main.$compile$noinline$Select(int[]) loop_optimization (after)
314   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
315   //
316   ///     CHECK-NOT: VecLoad
317   //
318   /// CHECK-FI:
319   //
320   // TODO: vectorize loops with select in the body.
$compile$noinline$Select(int[] x)321   public static void $compile$noinline$Select(int[] x) {
322     for (int i = 0; i < USED_ARRAY_LENGTH; i++) {
323       int val = x[i];
324       if (val != MAGIC_VALUE_C) {
325         val += MAGIC_ADD_CONST;
326       }
327       x[i] = val;
328     }
329   }
330 
331   /// CHECK-START-ARM64: void Main.$compile$noinline$Phi(int[]) loop_optimization (after)
332   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
333   //
334   ///     CHECK-NOT: VecLoad
335   //
336   /// CHECK-FI:
337   //
338   // TODO: vectorize loops with phis in the body.
$compile$noinline$Phi(int[] x)339   public static void $compile$noinline$Phi(int[] x) {
340     for (int i = 0; i < USED_ARRAY_LENGTH; i++) {
341       int val = x[i];
342       if (val != MAGIC_VALUE_C) {
343         val += MAGIC_ADD_CONST;
344         x[i] += val;
345       }
346       x[i] += val;
347     }
348   }
349 
350   // TODO: when Phis are supported, test dotprod and sad idioms.
351 
352   /// CHECK-START-ARM64: int Main.$compile$noinline$Reduction(int[]) loop_optimization (after)
353   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
354   //
355   ///     CHECK-NOT: VecLoad
356   //
357   /// CHECK-FI:
358   //
359   // TODO: vectorize loops with phis and reductions in the body.
$compile$noinline$Reduction(int[] x)360   private static int $compile$noinline$Reduction(int[] x) {
361     int sum = 0;
362     for (int i = 0; i < ARRAY_LENGTH; i++) {
363       int val = x[i];
364       if (val != MAGIC_VALUE_C) {
365         sum += val + x[i];
366       }
367     }
368     return sum;
369   }
370 
371   /// CHECK-START-ARM64: int Main.$compile$noinline$ReductionBackEdge(int[]) loop_optimization (after)
372   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
373   //
374   ///     CHECK-DAG: VecLoad
375   //
376   /// CHECK-FI:
377   //
378   // Reduction in the back edge block, non-CF-dependent.
$compile$noinline$ReductionBackEdge(int[] x)379   public static int $compile$noinline$ReductionBackEdge(int[] x) {
380     int sum = 0;
381     for (int i = 0; i < USED_ARRAY_LENGTH; i++) {
382       int val = x[i];
383       if (val != MAGIC_VALUE_C) {
384         x[i] += MAGIC_ADD_CONST;
385       }
386       sum += x[i];
387     }
388     return sum;
389   }
390 
391   //
392   // Negative compile tests.
393   //
394 
395   public static final int STENCIL_ARRAY_SIZE = 130;
396 
397   /// CHECK-START-ARM64: void Main.$compile$noinline$stencilAlike(int[], int[]) loop_optimization (after)
398   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
399   //
400   ///     CHECK-NOT: VecLoad
401   //
402   /// CHECK-FI:
403   //
404   // This loop needs a runtime test for array references disambiguation and a scalar cleanup loop.
405   // Currently we can't generate a scalar clean up loop with control flow.
$compile$noinline$stencilAlike(int[] a, int[] b)406   private static void $compile$noinline$stencilAlike(int[] a, int[] b) {
407     for (int i = 1; i < STENCIL_ARRAY_SIZE - 1; i++) {
408       int val0 = b[i - 1];
409       int val1 = b[i];
410       int val2 = b[i + 1];
411       int un = a[i];
412       if (val1 != MAGIC_VALUE_C) {
413         a[i] = val0 + val1 + val2;
414       }
415     }
416   }
417 
418   /// CHECK-START-ARM64: void Main.$compile$noinline$NotDiamondCf(int[]) loop_optimization (after)
419   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
420   //
421   ///     CHECK-NOT: VecLoad
422   //
423   /// CHECK-FI:
424   //
425   // Loops with complex CF are not supported.
$compile$noinline$NotDiamondCf(int[] x)426   public static void $compile$noinline$NotDiamondCf(int[] x) {
427     for (int i = 0; i < USED_ARRAY_LENGTH; i++) {
428       int val = x[i];
429       if (val != MAGIC_VALUE_C) {
430         if (val != 1234) {
431           x[i] += MAGIC_ADD_CONST;
432         }
433       }
434     }
435   }
436 
437   /// CHECK-START-ARM64: void Main.$compile$noinline$BrokenInduction(int[]) loop_optimization (after)
438   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
439   //
440   ///     CHECK-NOT: VecLoad
441   //
442   /// CHECK-FI:
$compile$noinline$BrokenInduction(int[] x)443   public static void $compile$noinline$BrokenInduction(int[] x) {
444     for (int i = 0; i < USED_ARRAY_LENGTH; i++) {
445       int val = x[i];
446       if (val != MAGIC_VALUE_C) {
447         x[i] += MAGIC_ADD_CONST;
448         i++;
449       }
450     }
451   }
452 
453   //
454   // Main driver.
455   //
456 
main(String[] args)457   public static void main(String[] args) {
458     initIntArray(intArray);
459     int final_ind_value = $compile$noinline$FullDiamond(intArray);
460     expectIntEquals(23755, IntArraySum(intArray));
461     expectIntEquals(USED_ARRAY_LENGTH, final_ind_value);
462 
463     // Types.
464     initBooleanArray(booleanArray);
465     booleanArray2[12] = true;
466     $compile$noinline$SimpleBoolean(booleanArray, booleanArray2);
467     expectIntEquals(86, BooleanArraySum(booleanArray));
468 
469     initByteArray(byteArray);
470     $compile$noinline$SimpleByte(byteArray);
471     expectIntEquals(-64, ByteArraySum(byteArray));
472 
473     initByteArray(byteArray);
474     $compile$noinline$SimpleUByte(byteArray);
475     expectIntEquals(-64, ByteArraySum(byteArray));
476 
477     initShortArray(shortArray);
478     $compile$noinline$SimpleShort(shortArray);
479     expectIntEquals(23121, ShortArraySum(shortArray));
480 
481     initCharArray(charArray);
482     $compile$noinline$SimpleChar(charArray);
483     expectIntEquals(23121, CharArraySum(charArray));
484 
485     initIntArray(intArray);
486     $compile$noinline$SimpleInt(intArray);
487     expectIntEquals(23121, IntArraySum(intArray));
488 
489     initLongArray(longArray);
490     $compile$noinline$SimpleLong(longArray);
491     expectLongEquals(23121, LongArraySum(longArray));
492 
493     initFloatArray(floatArray);
494     $compile$noinline$SimpleFloat(floatArray);
495     expectFloatEquals(18868.2f, FloatArraySum(floatArray));
496 
497     initDoubleArray(doubleArray);
498     $compile$noinline$SimpleDouble(doubleArray);
499     expectDoubleEquals(23129.5, DoubleArraySum(doubleArray));
500 
501     // Narrowing types.
502     initByteArray(byteArray);
503     $compile$noinline$ByteConv(byteArray, byteArray);
504     expectIntEquals(-2, ByteArraySum(byteArray));
505 
506     initByteArray(byteArray);
507     $compile$noinline$UByteAndWrongConst(byteArray);
508     expectIntEquals(-2, ByteArraySum(byteArray));
509 
510     initByteArray(byteArray);
511     $compile$noinline$ByteNoHiBits(byteArray, byteArray);
512     expectIntEquals(-2, ByteArraySum(byteArray));
513 
514     // Conditions.
515     initIntArray(intArray);
516     $compile$noinline$SimpleBelow(intArray);
517     expectIntEquals(23121, IntArraySum(intArray));
518 
519     // Idioms.
520     initIntArray(intArray);
521     $compile$noinline$Select(intArray);
522     expectIntEquals(23121, IntArraySum(intArray));
523 
524     initIntArray(intArray);
525     $compile$noinline$Phi(intArray);
526     expectIntEquals(36748, IntArraySum(intArray));
527 
528     int reduction_result = 0;
529 
530     initIntArray(intArray);
531     reduction_result = $compile$noinline$Reduction(intArray);
532     expectIntEquals(14706, IntArraySum(intArray));
533     expectIntEquals(21012, reduction_result);
534 
535     initIntArray(intArray);
536     reduction_result = $compile$noinline$ReductionBackEdge(intArray);
537     expectIntEquals(23121, IntArraySum(intArray));
538     expectIntEquals(13121, reduction_result);
539 
540     int[] stencilArrayA = new int[STENCIL_ARRAY_SIZE];
541     int[] stencilArrayB = new int[STENCIL_ARRAY_SIZE];
542     initIntArray(stencilArrayA);
543     initIntArray(stencilArrayB);
544     $compile$noinline$stencilAlike(stencilArrayA, stencilArrayB);
545     expectIntEquals(43602, IntArraySum(stencilArrayA));
546 
547     initIntArray(intArray);
548     $compile$noinline$NotDiamondCf(intArray);
549     expectIntEquals(23121, IntArraySum(intArray));
550 
551     initIntArray(intArray);
552     $compile$noinline$BrokenInduction(intArray);
553     expectIntEquals(18963, IntArraySum(intArray));
554 
555     System.out.println("passed");
556   }
557 
initBooleanArray(boolean[] a)558   public static void initBooleanArray(boolean[] a) {
559     for (int i = 0; i < ARRAY_LENGTH; i++) {
560       if (i % 3 != 0) {
561         a[i] = true;
562       }
563     }
564   }
565 
initByteArray(byte[] a)566   public static void initByteArray(byte[] a) {
567     for (int i = 0; i < ARRAY_LENGTH; i++) {
568       if (i % 3 == 0) {
569         a[i] = (byte)MAGIC_VALUE_A;
570       } else if (i % 3 == 1) {
571         a[i] = (byte)MAGIC_VALUE_B;
572       } else {
573         a[i] = (byte)MAGIC_VALUE_C;
574       }
575     }
576     a[USED_ARRAY_LENGTH] = 127;
577   }
578 
initShortArray(short[] a)579   public static void initShortArray(short[] a) {
580     for (int i = 0; i < ARRAY_LENGTH; i++) {
581       if (i % 3 == 0) {
582         a[i] = (short)MAGIC_VALUE_A;
583       } else if (i % 3 == 1) {
584         a[i] = (short)MAGIC_VALUE_B;
585       } else {
586         a[i] = (short)MAGIC_VALUE_C;
587       }
588     }
589     a[USED_ARRAY_LENGTH] = 10000;
590   }
591 
initCharArray(char[] a)592   public static void initCharArray(char[] a) {
593     for (int i = 0; i < ARRAY_LENGTH; i++) {
594       if (i % 3 == 0) {
595         a[i] = (char)MAGIC_VALUE_A;
596       } else if (i % 3 == 1) {
597         a[i] = (char)MAGIC_VALUE_B;
598       } else {
599         a[i] = (char)MAGIC_VALUE_C;
600       }
601     }
602     a[USED_ARRAY_LENGTH] = 10000;
603   }
604 
initIntArray(int[] a)605   public static void initIntArray(int[] a) {
606     for (int i = 0; i < ARRAY_LENGTH; i++) {
607       if (i % 3 == 0) {
608         a[i] = MAGIC_VALUE_A;
609       } else if (i % 3 == 1) {
610         a[i] = MAGIC_VALUE_B;
611       } else {
612         a[i] = MAGIC_VALUE_C;
613       }
614     }
615     a[USED_ARRAY_LENGTH] = 10000;
616   }
617 
initLongArray(long[] a)618   public static void initLongArray(long[] a) {
619     for (int i = 0; i < ARRAY_LENGTH; i++) {
620       if (i % 3 == 0) {
621         a[i] = MAGIC_VALUE_A;
622       } else if (i % 3 == 1) {
623         a[i] = MAGIC_VALUE_B;
624       } else {
625         a[i] = MAGIC_VALUE_C;
626       }
627     }
628     a[USED_ARRAY_LENGTH] = 10000;
629   }
630 
initFloatArray(float[] a)631   public static void initFloatArray(float[] a) {
632     for (int i = 0; i < ARRAY_LENGTH; i++) {
633       if (i % 3 == 0) {
634         a[i] = MAGIC_FLOAT_VALUE_A;
635       } else if (i % 3 == 1) {
636         a[i] = MAGIC_FLOAT_VALUE_B;
637       } else {
638         a[i] = MAGIC_FLOAT_VALUE_C;
639       }
640     }
641     a[USED_ARRAY_LENGTH] = 10000.0f;
642   }
643 
initDoubleArray(double[] a)644   public static void initDoubleArray(double[] a) {
645     for (int i = 0; i < ARRAY_LENGTH; i++) {
646       if (i % 3 == 0) {
647         a[i] = MAGIC_FLOAT_VALUE_A;
648       } else if (i % 3 == 1) {
649         a[i] = MAGIC_FLOAT_VALUE_B;
650       } else {
651         a[i] = MAGIC_FLOAT_VALUE_C;
652       }
653     }
654     a[USED_ARRAY_LENGTH] = 10000.0f;
655   }
656 
BooleanArraySum(boolean[] a)657   public static byte BooleanArraySum(boolean[] a) {
658     byte sum = 0;
659     for (int i = 0; i < a.length; i++) {
660       sum += a[i] ? 1 : 0;
661     }
662     return sum;
663   }
664 
ByteArraySum(byte[] a)665   public static byte ByteArraySum(byte[] a) {
666     byte sum = 0;
667     for (int i = 0; i < a.length; i++) {
668       sum += a[i];
669     }
670     return sum;
671   }
672 
ShortArraySum(short[] a)673   public static short ShortArraySum(short[] a) {
674     short sum = 0;
675     for (int i = 0; i < a.length; i++) {
676       sum += a[i];
677     }
678     return sum;
679   }
680 
CharArraySum(char[] a)681   public static char CharArraySum(char[] a) {
682     char sum = 0;
683     for (int i = 0; i < a.length; i++) {
684       sum += a[i];
685     }
686     return sum;
687   }
688 
IntArraySum(int[] a)689   public static int IntArraySum(int[] a) {
690     int sum = 0;
691     for (int i = 0; i < a.length; i++) {
692       sum += a[i];
693     }
694     return sum;
695   }
696 
LongArraySum(long[] a)697   public static long LongArraySum(long[] a) {
698     long sum = 0;
699     for (int i = 0; i < a.length; i++) {
700       sum += a[i];
701     }
702     return sum;
703   }
704 
FloatArraySum(float[] a)705   public static float FloatArraySum(float[] a) {
706     float sum = 0.0f;
707     for (int i = 0; i < a.length; i++) {
708       sum += a[i];
709     }
710     return sum;
711   }
712 
DoubleArraySum(double[] a)713   public static double DoubleArraySum(double[] a) {
714     double sum = 0.0;
715     for (int i = 0; i < a.length; i++) {
716       sum += a[i];
717     }
718     return sum;
719   }
720 
expectIntEquals(int expected, int result)721   private static void expectIntEquals(int expected, int result) {
722     if (expected != result) {
723       throw new Error("Expected: " + expected + ", found: " + result);
724     }
725   }
726 
expectLongEquals(long expected, long result)727   private static void expectLongEquals(long expected, long result) {
728     if (expected != result) {
729       throw new Error("Expected: " + expected + ", found: " + result);
730     }
731   }
732 
expectFloatEquals(float expected, float result)733   private static void expectFloatEquals(float expected, float result) {
734     final float THRESHOLD = .1f;
735     if (Math.abs(expected - result) >= THRESHOLD) {
736       throw new Error("Expected: " + expected + ", found: " + result);
737     }
738   }
739 
expectDoubleEquals(double expected, double result)740   private static void expectDoubleEquals(double expected, double result) {
741     final double THRESHOLD = .1;
742     if (Math.abs(expected - result) >= THRESHOLD) {
743       throw new Error("Expected: " + expected + ", found: " + result);
744     }
745   }
746 }
747