1 /*
2  * Copyright (C) 2015 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 import java.util.Arrays;
18 
19 //
20 // Test on array parameters with or without potential aliasing.
21 //
22 public class Main {
23 
24   //
25   // Cross-over on parameters with potential aliasing on parameters.
26   // The arrays a and b may point to the same memory, which (without
27   // further runtime tests) prevents hoisting the seemingly invariant
28   // array reference.
29   //
30 
31   /// CHECK-START: void Main.CrossOverLoop1(int[], int[]) licm (before)
32   /// CHECK-DAG: ArraySet loop:none
33   /// CHECK-DAG: ArrayGet loop:{{B\d+}}
34   /// CHECK-DAG: ArraySet loop:{{B\d+}}
35   //
36   /// CHECK-START: void Main.CrossOverLoop1(int[], int[]) licm (after)
37   /// CHECK-DAG: ArraySet loop:none
38   /// CHECK-DAG: ArrayGet loop:{{B\d+}}
39   /// CHECK-DAG: ArraySet loop:{{B\d+}}
CrossOverLoop1(int a[], int b[])40   private static void CrossOverLoop1(int a[], int b[]) {
41     b[20] = 99;
42     for (int i = 0; i < a.length; i++) {
43       a[i] = b[20] - 7;
44     }
45   }
46 
47   /// CHECK-START: void Main.CrossOverLoop2(float[], float[]) licm (before)
48   /// CHECK-DAG: ArraySet loop:none
49   /// CHECK-DAG: ArrayGet loop:{{B\d+}}
50   /// CHECK-DAG: ArraySet loop:{{B\d+}}
51   //
52   /// CHECK-START: void Main.CrossOverLoop2(float[], float[]) licm (after)
53   /// CHECK-DAG: ArraySet loop:none
54   /// CHECK-DAG: ArrayGet loop:{{B\d+}}
55   /// CHECK-DAG: ArraySet loop:{{B\d+}}
CrossOverLoop2(float a[], float b[])56   private static void CrossOverLoop2(float a[], float b[]) {
57     b[20] = 99;
58     for (int i = 0; i < a.length; i++) {
59       a[i] = b[20] - 7;
60     }
61   }
62 
63   /// CHECK-START: void Main.CrossOverLoop3(long[], long[]) licm (before)
64   /// CHECK-DAG: ArraySet loop:none
65   /// CHECK-DAG: ArrayGet loop:{{B\d+}}
66   /// CHECK-DAG: ArraySet loop:{{B\d+}}
67   //
68   /// CHECK-START: void Main.CrossOverLoop3(long[], long[]) licm (after)
69   /// CHECK-DAG: ArraySet loop:none
70   /// CHECK-DAG: ArrayGet loop:{{B\d+}}
71   /// CHECK-DAG: ArraySet loop:{{B\d+}}
CrossOverLoop3(long a[], long b[])72   private static void CrossOverLoop3(long a[], long b[]) {
73     b[20] = 99;
74     for (int i = 0; i < a.length; i++) {
75       a[i] = b[20] - 7;
76     }
77   }
78 
79   /// CHECK-START: void Main.CrossOverLoop4(double[], double[]) licm (before)
80   /// CHECK-DAG: ArraySet loop:none
81   /// CHECK-DAG: ArrayGet loop:{{B\d+}}
82   /// CHECK-DAG: ArraySet loop:{{B\d+}}
83   //
84   /// CHECK-START: void Main.CrossOverLoop4(double[], double[]) licm (after)
85   /// CHECK-DAG: ArraySet loop:none
86   /// CHECK-DAG: ArrayGet loop:{{B\d+}}
87   /// CHECK-DAG: ArraySet loop:{{B\d+}}
CrossOverLoop4(double a[], double b[])88   private static void CrossOverLoop4(double a[], double b[]) {
89     b[20] = 99;
90     for (int i = 0; i < a.length; i++) {
91       a[i] = b[20] - 7;
92     }
93   }
94 
95   //
96   // False cross-over on parameters. Parameters have same width (which used to
97   // cause a false type aliasing in an older version of the compiler), but since
98   // the types are different cannot be aliased. Thus, the invariant array
99   // reference can be hoisted.
100   //
101 
102   /// CHECK-START: void Main.FalseCrossOverLoop1(int[], float[]) licm (before)
103   /// CHECK-DAG: ArraySet loop:none
104   /// CHECK-DAG: ArrayGet loop:{{B\d+}}
105   /// CHECK-DAG: ArraySet loop:{{B\d+}}
106   //
107   /// CHECK-START: void Main.FalseCrossOverLoop1(int[], float[]) licm (after)
108   /// CHECK-DAG: ArraySet loop:none
109   /// CHECK-DAG: ArrayGet loop:none
110   /// CHECK-DAG: ArraySet loop:{{B\d+}}
FalseCrossOverLoop1(int a[], float b[])111   private static void FalseCrossOverLoop1(int a[], float b[]) {
112     b[20] = -99;
113     for (int i = 0; i < a.length; i++) {
114       a[i] = (int) b[20] - 7;
115     }
116   }
117 
118   /// CHECK-START: void Main.FalseCrossOverLoop2(float[], int[]) licm (before)
119   /// CHECK-DAG: ArraySet loop:none
120   /// CHECK-DAG: ArrayGet loop:{{B\d+}}
121   /// CHECK-DAG: ArraySet loop:{{B\d+}}
122   //
123   /// CHECK-START: void Main.FalseCrossOverLoop2(float[], int[]) licm (after)
124   /// CHECK-DAG: ArraySet loop:none
125   /// CHECK-DAG: ArrayGet loop:none
126   /// CHECK-DAG: ArraySet loop:{{B\d+}}
FalseCrossOverLoop2(float a[], int b[])127   private static void FalseCrossOverLoop2(float a[], int b[]) {
128     b[20] = -99;
129     for (int i = 0; i < a.length; i++) {
130       a[i] = b[20] - 7;
131     }
132   }
133 
134   /// CHECK-START: void Main.FalseCrossOverLoop3(long[], double[]) licm (before)
135   /// CHECK-DAG: ArraySet loop:none
136   /// CHECK-DAG: ArrayGet loop:{{B\d+}}
137   /// CHECK-DAG: ArraySet loop:{{B\d+}}
138   //
139   /// CHECK-START: void Main.FalseCrossOverLoop3(long[], double[]) licm (after)
140   /// CHECK-DAG: ArraySet loop:none
141   /// CHECK-DAG: ArrayGet loop:none
142   /// CHECK-DAG: ArraySet loop:{{B\d+}}
FalseCrossOverLoop3(long a[], double b[])143   private static void FalseCrossOverLoop3(long a[], double b[]) {
144     b[20] = -99;
145     for (int i = 0; i < a.length; i++) {
146       a[i] = (long) b[20] - 7;
147     }
148   }
149 
150   /// CHECK-START: void Main.FalseCrossOverLoop4(double[], long[]) licm (before)
151   /// CHECK-DAG: ArraySet loop:none
152   /// CHECK-DAG: ArrayGet loop:{{B\d+}}
153   /// CHECK-DAG: ArraySet loop:{{B\d+}}
154   //
155   /// CHECK-START: void Main.FalseCrossOverLoop4(double[], long[]) licm (after)
156   /// CHECK-DAG: ArraySet loop:none
157   /// CHECK-DAG: ArrayGet loop:none
158   /// CHECK-DAG: ArraySet loop:{{B\d+}}
FalseCrossOverLoop4(double a[], long b[])159   private static void FalseCrossOverLoop4(double a[], long b[]) {
160     b[20] = -99;
161     for (int i = 0; i < a.length; i++) {
162       a[i] = b[20] - 7;
163     }
164   }
165 
166   //
167   // Main driver and testers.
168   //
169 
main(String[] args)170   public static void main(String[] args) {
171     int[] aI = new int[100];
172     float[] aF = new float[100];
173     long[] aJ = new long[100];
174     double[] aD = new double[100];
175 
176     // Type I.
177     CrossOverLoop1(aI, aI);
178     for (int i = 0; i < aI.length; i++) {
179       expectEquals(i <= 20 ? 92 : 85, aI[i]);
180     }
181     // Type F.
182     CrossOverLoop2(aF, aF);
183     for (int i = 0; i < aF.length; i++) {
184       expectEquals(i <= 20 ? 92 : 85, aF[i]);
185     }
186     // Type J.
187     CrossOverLoop3(aJ, aJ);
188     for (int i = 0; i < aJ.length; i++) {
189       expectEquals(i <= 20 ? 92 : 85, aJ[i]);
190     }
191     // Type D.
192     CrossOverLoop4(aD, aD);
193     for (int i = 0; i < aD.length; i++) {
194       expectEquals(i <= 20 ? 92 : 85, aD[i]);
195     }
196 
197     // Type I vs F.
198     FalseCrossOverLoop1(aI, aF);
199     for (int i = 0; i < aI.length; i++) {
200       expectEquals(-106, aI[i]);
201     }
202     // Type F vs I.
203     FalseCrossOverLoop2(aF, aI);
204     for (int i = 0; i < aF.length; i++) {
205       expectEquals(-106, aF[i]);
206     }
207     // Type J vs D.
208     FalseCrossOverLoop3(aJ, aD);
209     for (int i = 0; i < aJ.length; i++) {
210       expectEquals(-106, aJ[i]);
211     }
212     // Type D vs J.
213     FalseCrossOverLoop4(aD, aJ);
214     for (int i = 0; i < aD.length; i++) {
215       expectEquals(-106, aD[i]);
216     }
217 
218     // Real-world example where incorrect type assignment could introduce a bug.
219     // The library sorting algorithm is heavy on array reads and writes, and
220     // assigning the wrong J/D type to one of these would introduce errors.
221     for (int i = 0; i < aD.length; i++) {
222       aD[i] = aD.length - i - 1;
223     }
224     Arrays.sort(aD);
225     for (int i = 0; i < aD.length; i++) {
226       expectEquals((double) i, aD[i]);
227     }
228 
229     System.out.println("passed");
230   }
231 
expectEquals(int expected, int result)232   private static void expectEquals(int expected, int result) {
233     if (expected != result) {
234       throw new Error("Expected: " + expected + ", found: " + result);
235     }
236   }
237 
expectEquals(long expected, long result)238   private static void expectEquals(long expected, long result) {
239     if (expected != result) {
240       throw new Error("Expected: " + expected + ", found: " + result);
241     }
242   }
243 
expectEquals(float expected, float result)244   private static void expectEquals(float expected, float result) {
245     if (expected != result) {
246       throw new Error("Expected: " + expected + ", found: " + result);
247     }
248   }
249 
expectEquals(double expected, double result)250   private static void expectEquals(double expected, double result) {
251     if (expected != result) {
252       throw new Error("Expected: " + expected + ", found: " + result);
253     }
254   }
255 }
256