1 /*
2  * Copyright (C) 2019 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 public class Main {
18   // Based on Linpack.matgen
19   // Load-store elimination did not work when a function had SIMD code.
20   // In the test below loop B is vectorized.
21   // Check that a redundant ArrayGet is eliminated in loop A.
22 
23   /// CHECK-START: double Main.$noinline$vecgen(double[], double[], int) load_store_elimination (before)
24   /// CHECK:      Rem
25   /// CHECK-NEXT: TypeConversion
26   /// CHECK-NEXT: Sub
27   /// CHECK-NEXT: Mul
28   /// CHECK-NEXT: ArraySet
29   /// CHECK-NEXT: ArrayGet
30   /// CHECK-NEXT: LessThanOrEqual
31   /// CHECK-NEXT: Select
32   /// CHECK-NEXT: Add
33   /// CHECK-NEXT: Goto loop:{{B\d+}}
34 
35   /// CHECK-START: double Main.$noinline$vecgen(double[], double[], int) load_store_elimination (after)
36   /// CHECK:      Rem
37   /// CHECK-NEXT: TypeConversion
38   /// CHECK-NEXT: Sub
39   /// CHECK-NEXT: Mul
40   /// CHECK-NEXT: ArraySet
41   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
42   //
43   ///     CHECK-NEXT: ArrayGet
44   //
45   /// CHECK-FI:
46   /// CHECK-NEXT: LessThanOrEqual
47   /// CHECK-NEXT: Select
48   /// CHECK-NEXT: Add
49   /// CHECK-NEXT: Goto loop:{{B\d+}}
50   //
51   // TODO: reenable LSE for graphs with Predicated SIMD.
$noinline$vecgen(double a[], double b[], int n)52   static double $noinline$vecgen(double a[], double b[], int n) {
53     double norma = 0.0;
54     int init = 1325;
55     // Loop A
56     for (int i = 0; i < n; ++i) {
57       init = 3125*init % 65536;
58       a[i] = (init - 32768.0)/16384.0;
59       norma = (a[i] > norma) ? a[i] : norma; // ArrayGet should be removed by LSE.
60     }
61 
62     // Loop B
63     for (int i = 0; i < n; ++i) {
64       b[i] += a[i];
65     }
66 
67     return norma;
68   }
69 
70 
test01()71   static void test01() {
72     double a[] = new double[1024];
73     double norma = $noinline$vecgen(a, a, a.length);
74     System.out.println((int)norma);
75     System.out.println((int)a[1023]);
76   }
77 
78   // Check LSE works when a function has SIMD code.
79   //
80   /// CHECK-START: double Main.$noinline$test02(double[], int) load_store_elimination (before)
81   /// CHECK:      BoundsCheck loop:none
82   /// CHECK-NEXT: ArrayGet
83   /// CHECK-NEXT: Mul
84   /// CHECK-NEXT: ArraySet
85   /// CHECK-NEXT: ArrayGet
86   /// CHECK-NEXT: ArrayLength
87   /// CHECK-NEXT: BelowOrEqual
88   //
89   /// CHECK:      ArrayGet loop:none
90   /// CHECK-NEXT: Return
91 
92   /// CHECK-START: double Main.$noinline$test02(double[], int) load_store_elimination (after)
93   /// CHECK:      BoundsCheck loop:none
94   /// CHECK-NEXT: ArrayGet
95   /// CHECK-NEXT: Mul
96   /// CHECK-NEXT: ArraySet
97   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
98   //
99   ///     CHECK-NEXT: ArrayGet
100   //
101   /// CHECK-FI:
102   /// CHECK-NEXT: ArrayLength
103   /// CHECK-NEXT: BelowOrEqual
104   //
105   /// CHECK:      Return
106   //
107   // TODO: reenable LSE for graphs with Predicated SIMD.
$noinline$test02(double a[], int n)108   static double $noinline$test02(double a[], int n) {
109     double b[] = new double[n];
110     a[0] = a[0] / 2;
111 
112     double norma = a[0]; // ArrayGet should be removed by LSE.
113 
114     // The following loop is vectorized.
115     for (int i = 0; i < 128; ++i) {
116       b[i] += a[i];
117     }
118 
119     norma = a[0]; // ArrayGet should be removed by LSE.
120     return norma;
121   }
122 
test02()123   static void test02() {
124     double a[] = new double[128];
125     java.util.Arrays.fill(a, 2.0);
126     double norma = $noinline$test02(a, a.length);
127     System.out.println((int)norma);
128   }
129 
130   // Check LSE works when a function has SIMD code.
131   //
132   /// CHECK-START: double Main.$noinline$test03(int) load_store_elimination (before)
133   /// CHECK:      ArrayGet loop:none
134   /// CHECK-NEXT: Return
135 
136   /// CHECK-START: double Main.$noinline$test03(int) load_store_elimination (after)
137   /// CHECK-IF:     not (hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true')
138   //
139   ///     CHECK-NOT:  ArrayGet loop:none
140   //
141   /// CHECK-FI:
142   //
143   // TODO: reenable LSE for graphs with Predicated SIMD.
$noinline$test03(int n)144   static double $noinline$test03(int n) {
145     double a[] = new double[n];
146     double b[] = new double[n];
147 
148     a[0] = 2.0;
149 
150     // The following loop is vectorized.
151     for (int i = 0; i < 128; ++i) {
152       b[i] += a[i];
153     }
154 
155     a[0] = 2.0;
156     return a[0]; // ArrayGet should be removed by LSE.
157   }
158 
test03()159   static void test03() {
160     double norma = $noinline$test03(128);
161     System.out.println((int)norma);
162   }
163 
164   // Check LSE eliminates VecLoad.
165   //
166   /// CHECK-START-ARM64: double[] Main.$noinline$test04(int) load_store_elimination (before)
167   /// CHECK:        VecStore
168   /// CHECK:        VecLoad
169   /// CHECK:        VecAdd
170   /// CHECK:        VecStore
171   /// CHECK:        Add
172   /// CHECK:        Goto loop:{{B\d+}}
173 
174   /// CHECK-START-ARM64: double[] Main.$noinline$test04(int) load_store_elimination (after)
175   /// CHECK-IF:     not (hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true')
176   //
177   //      In NEON case there is a post-loop which prevents the store to be removed.
178   ///     CHECK:        VecStore
179   //
180   /// CHECK-FI:
181   //
182   /// CHECK:        VecAdd
183   /// CHECK:        VecStore
184   /// CHECK:        Add
185   /// CHECK:        Goto loop:{{B\d+}}
186   //
187 
188   /// CHECK-IF:     not (hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true')
189   //
190   ///     CHECK-NOT:    VecStore
191   //
192   /// CHECK-FI:
193   //
194   // TODO: reenable LSE for graphs with Predicated SIMD.
$noinline$test04(int n)195   static double[] $noinline$test04(int n) {
196     double a[] = new double[n];
197     double b[] = new double[n];
198 
199     // The following loop is vectorized.
200     for (int i = 0; i < n; ++i) {
201       a[i] = 1;
202       b[i] = a[i] + a[i]; // VecLoad should be removed by LSE.
203     }
204 
205     return b;
206   }
207 
test04()208   static void test04() {
209     double norma = $noinline$test04(128)[0];
210     System.out.println((int)norma);
211   }
212 
213   // Check LSE eliminates VecLoad.
214   //
215   /// CHECK-START-ARM64: double[] Main.$noinline$test05(int) load_store_elimination (before)
216   /// CHECK:        VecStore
217   /// CHECK:        VecLoad
218   /// CHECK:        VecStore
219   /// CHECK:        VecStore
220   /// CHECK:        Add
221   /// CHECK:        Goto loop:{{B\d+}}
222 
223   /// CHECK-START-ARM64: double[] Main.$noinline$test05(int) load_store_elimination (after)
224   /// CHECK:        VecStore
225   /// CHECK:        VecStore
226   /// CHECK:        Add
227   /// CHECK:        Goto loop:{{B\d+}}
228   //
229   /// CHECK-NOT:    VecStore
230   //
231   // TODO: reenable LSE for graphs with Predicated SIMD.
$noinline$test05(int n)232   static double[] $noinline$test05(int n) {
233     double a[] = new double[n];
234     double b[] = new double[n];
235 
236     // The following loop is vectorized.
237     for (int i = 0; i < n; ++i) {
238       a[i] = 1;
239       b[i] = a[i];
240       a[i] = 1;
241     }
242 
243     return b;
244   }
245 
test05()246   static void test05() {
247     double norma = $noinline$test05(128)[0];
248     System.out.println((int)norma);
249   }
250 
251   // Check LSE eliminates VecLoad and ArrayGet in case of singletons and default values.
252   //
253   /// CHECK-START-ARM64: double[] Main.$noinline$test06(int) load_store_elimination (before)
254   /// CHECK:        BoundsCheck loop:none
255   /// CHECK:        ArrayGet
256   /// CHECK:        Add
257   //
258   /// CHECK:        VecLoad loop:{{B\d+}}
259   /// CHECK:        VecStore
260   /// CHECK:        VecLoad
261   /// CHECK:        VecLoad
262   /// CHECK:        VecAdd
263   /// CHECK:        VecAdd
264   /// CHECK:        VecStore
265 
266   /// CHECK-START-ARM64: double[] Main.$noinline$test06(int) load_store_elimination (after)
267   /// CHECK:        BoundsCheck loop:none
268   /// CHECK:        Add
269   //
270   /// CHECK:        VecLoad loop:{{B\d+}}
271   /// CHECK:        VecAdd
272   /// CHECK:        VecAdd
273   /// CHECK:        VecStore
274   //
275   /// CHECK-IF:     not (hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true')
276   //
277   ///     CHECK-NOT:    VecStore
278   //
279   /// CHECK-FI:
280   //
281   // TODO: reenable LSE for graphs with Predicated SIMD.
$noinline$test06(int n)282   static double[] $noinline$test06(int n) {
283     double a[] = new double[n];
284     double b[] = new double[n];
285 
286     double r = a[0] + 1.0; // ArrayGet:a[0] is eliminated and default 0.0 is used.
287     // The following loop is vectorized.
288     for (int i = 0; i < n; ++i) {
289       b[i] = a[i]; // VecLoad:a[i] is not eliminated.
290       b[i] += a[i] + r; // VecLoad:a[i] and VecLoad:b[i] are eliminated.
291     }
292 
293     return b;
294   }
295 
test06()296   static void test06() {
297     double norma = $noinline$test06(128)[0];
298     System.out.println((int)norma);
299   }
300 
main(String[] args)301   public static void main(String[] args) {
302     test01();
303     test02();
304     test03();
305     test04();
306     test05();
307     test06();
308   }
309 }
310 
311