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