1 /*
2  * Copyright (C) 2017 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 import java.lang.reflect.Array;
17 import java.lang.reflect.Method;
18 
19 /**
20  * Tests for SIMD related optimizations.
21  */
22 public class Main {
23 
24   /// CHECK-START: void Main.unroll(float[], float[]) loop_optimization (before)
25   /// CHECK-DAG: <<Cons:f\d+>> FloatConstant 2.5                   loop:none
26   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
27   /// CHECK-DAG: <<Get:f\d+>>  ArrayGet                            loop:<<Loop>>      outer_loop:none
28   /// CHECK-DAG: <<Mul:f\d+>>  Mul [<<Get>>,<<Cons>>]              loop:<<Loop>>      outer_loop:none
29   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Mul>>] loop:<<Loop>>      outer_loop:none
30   //
31   /// CHECK-START-ARM64: void Main.unroll(float[], float[]) loop_optimization (after)
32   /// CHECK-DAG: <<Cons:f\d+>> FloatConstant 2.5                    loop:none
33   /// CHECK-DAG: <<Incr:i\d+>> IntConstant 4                        loop:none
34   /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<Cons>>]        loop:none
35   /// CHECK-NOT:               VecReplicateScalar
36   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
37   /// CHECK-DAG: <<Get1:d\d+>> VecLoad [{{l\d+}},<<Phi>>]           loop:<<Loop>>      outer_loop:none
38   /// CHECK-DAG: <<Mul1:d\d+>> VecMul [<<Get1>>,<<Repl>>]           loop:<<Loop>>      outer_loop:none
39   /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<Mul1>>] loop:<<Loop>>      outer_loop:none
40   /// CHECK-DAG: <<Add:i\d+>>  Add [<<Phi>>,<<Incr>>]               loop:<<Loop>>      outer_loop:none
41   /// CHECK-DAG: <<Get2:d\d+>> VecLoad [{{l\d+}},<<Add>>]           loop:<<Loop>>      outer_loop:none
42   /// CHECK-DAG: <<Mul2:d\d+>> VecMul [<<Get2>>,<<Repl>>]           loop:<<Loop>>      outer_loop:none
43   /// CHECK-DAG:               VecStore [{{l\d+}},<<Add>>,<<Mul2>>] loop:<<Loop>>      outer_loop:none
44   /// CHECK-DAG:               Add [<<Add>>,<<Incr>>]               loop:<<Loop>>      outer_loop:none
unroll(float[] x, float[] y)45   private static void unroll(float[] x, float[] y) {
46     for (int i = 0; i < 100; i++) {
47       x[i] = y[i] * 2.5f;
48     }
49   }
50 
51   /// CHECK-START-ARM64: void Main.stencil(int[], int[], int) loop_optimization (after)
52   /// CHECK-DAG: <<CP1:i\d+>>   IntConstant 1                         loop:none
53   /// CHECK-DAG: <<CP2:i\d+>>   IntConstant 2                         loop:none
54   /// CHECK-DAG: <<Phi:i\d+>>   Phi                                   loop:<<Loop:B\d+>> outer_loop:none
55   /// CHECK-DAG: <<Add1:i\d+>>  Add [<<Phi>>,<<CP1>>]                 loop:<<Loop>>      outer_loop:none
56   /// CHECK-DAG: <<Get1:d\d+>>  VecLoad [{{l\d+}},<<Phi>>]            loop:<<Loop>>      outer_loop:none
57   /// CHECK-DAG: <<Get2:d\d+>>  VecLoad [{{l\d+}},<<Add1>>]           loop:<<Loop>>      outer_loop:none
58   /// CHECK-DAG: <<Add2:d\d+>>  VecAdd [<<Get1>>,<<Get2>>]            loop:<<Loop>>      outer_loop:none
59   /// CHECK-DAG: <<Add3:i\d+>>  Add [<<Phi>>,<<CP2>>]                 loop:<<Loop>>      outer_loop:none
60   /// CHECK-DAG: <<Get3:d\d+>>  VecLoad [{{l\d+}},<<Add3>>]           loop:<<Loop>>      outer_loop:none
61   /// CHECK-DAG: <<Add4:d\d+>>  VecAdd [<<Add2>>,<<Get3>>]            loop:<<Loop>>      outer_loop:none
62   /// CHECK-DAG:                VecStore [{{l\d+}},<<Add1>>,<<Add4>>] loop:<<Loop>>      outer_loop:none
stencil(int[] a, int[] b, int n)63   private static void stencil(int[] a, int[] b, int n) {
64     for (int i = 1; i < n - 1; i++) {
65       a[i] = b[i - 1] + b[i] + b[i + 1];
66     }
67   }
68 
stencilAddInt(int[] a, int[] b, int n)69   private static void stencilAddInt(int[] a, int[] b, int n) {
70     try {
71       Class<?> c = Class.forName("Smali");
72       Method m = c.getMethod("stencilAddInt",
73           Array.newInstance(int.class, 1).getClass(),
74           Array.newInstance(int.class, 1).getClass(),
75           int.class);
76       m.invoke(null, a, b, n);
77     } catch (Exception ex) {
78       throw new Error(ex);
79     }
80   }
81 
stencilSubInt(int[] a, int[] b, int n)82   private static void stencilSubInt(int[] a, int[] b, int n) {
83     try {
84       Class<?> c = Class.forName("Smali");
85       Method m = c.getMethod("stencilSubInt",
86           Array.newInstance(int.class, 1).getClass(),
87           Array.newInstance(int.class, 1).getClass(),
88           int.class);
89       m.invoke(null, a, b, n);
90     } catch (Exception ex) {
91       throw new Error(ex);
92     }
93   }
94 
95   /// CHECK-START: long Main.longInductionReduction(long[]) loop_optimization (before)
96   /// CHECK-DAG: <<L0:j\d+>>    LongConstant 0             loop:none
97   /// CHECK-DAG: <<L1:j\d+>>    LongConstant 1             loop:none
98   /// CHECK-DAG: <<I0:i\d+>>    IntConstant 0              loop:none
99   /// CHECK-DAG: <<Get:j\d+>>   ArrayGet [{{l\d+}},<<I0>>] loop:none
100   /// CHECK-DAG: <<Phi1:j\d+>>  Phi [<<L0>>,<<Add1:j\d+>>] loop:<<Loop:B\d+>> outer_loop:none
101   /// CHECK-DAG: <<Phi2:j\d+>>  Phi [<<L1>>,<<Add2:j\d+>>] loop:<<Loop>>      outer_loop:none
102   /// CHECK-DAG: <<Add2>>       Add [<<Phi2>>,<<Get>>]     loop:<<Loop>>      outer_loop:none
103   /// CHECK-DAG: <<Add1>>       Add [<<Phi1>>,<<L1>>]      loop:<<Loop>>      outer_loop:none
104   //
105   /// CHECK-START-ARM64: long Main.longInductionReduction(long[]) loop_optimization (after)
106   /// CHECK-DAG: <<L0:j\d+>>    LongConstant 0               loop:none
107   /// CHECK-DAG: <<L1:j\d+>>    LongConstant 1               loop:none
108   /// CHECK-DAG: <<L2:j\d+>>    LongConstant 2               loop:none
109   /// CHECK-DAG: <<I0:i\d+>>    IntConstant 0                loop:none
110   /// CHECK-DAG: <<Get:j\d+>>   ArrayGet [{{l\d+}},<<I0>>]   loop:none
111   /// CHECK-DAG: <<Rep:d\d+>>   VecReplicateScalar [<<Get>>] loop:none
112   /// CHECK-DAG: <<Set:d\d+>>   VecSetScalars [<<L1>>]       loop:none
113   /// CHECK-DAG: <<Phi1:j\d+>>  Phi [<<L0>>,{{j\d+}}]        loop:<<Loop:B\d+>> outer_loop:none
114   /// CHECK-DAG: <<Phi2:d\d+>>  Phi [<<Set>>,{{d\d+}}]       loop:<<Loop>>      outer_loop:none
115   /// CHECK-DAG:                VecAdd [<<Phi2>>,<<Rep>>]    loop:<<Loop>>      outer_loop:none
116   /// CHECK-DAG:                Add [<<Phi1>>,<<L2>>]        loop:<<Loop>>      outer_loop:none
longInductionReduction(long[] y)117   static long longInductionReduction(long[] y) {
118     long x = 1;
119     for (long i = 0; i < 10; i++) {
120       x += y[0];
121     }
122     return x;
123   }
124 
125   /// CHECK-START: void Main.intVectorLongInvariant(int[], long[]) loop_optimization (before)
126   /// CHECK-DAG: <<I0:i\d+>>    IntConstant 0                       loop:none
127   /// CHECK-DAG: <<I1:i\d+>>    IntConstant 1                       loop:none
128   /// CHECK-DAG: <<Get:j\d+>>   ArrayGet [{{l\d+}},<<I0>>]          loop:none
129   /// CHECK-DAG: <<Phi:i\d+>>   Phi [<<I0>>,<<Add:i\d+>>]           loop:<<Loop:B\d+>> outer_loop:none
130   /// CHECK-DAG: <<Cnv:i\d+>>   TypeConversion [<<Get>>]            loop:<<Loop>>      outer_loop:none
131   /// CHECK-DAG:                ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
132   /// CHECK-DAG: <<Add>>        Add [<<Phi>>,<<I1>>]                loop:<<Loop>>      outer_loop:none
133   //
134   /// CHECK-START-ARM64: void Main.intVectorLongInvariant(int[], long[]) loop_optimization (after)
135   /// CHECK-DAG: <<I0:i\d+>>    IntConstant 0                       loop:none
136   /// CHECK-DAG: <<I1:i\d+>>    IntConstant 1                       loop:none
137   /// CHECK-DAG: <<I4:i\d+>>    IntConstant 4                       loop:none
138   /// CHECK-DAG: <<Get:j\d+>>   ArrayGet [{{l\d+}},<<I0>>]          loop:none
139   /// CHECK-DAG: <<Cnv:i\d+>>   TypeConversion [<<Get>>]            loop:none
140   /// CHECK-DAG: <<Rep:d\d+>>   VecReplicateScalar [<<Cnv>>]        loop:none
141   /// CHECK-DAG: <<Phi:i\d+>>   Phi [<<I0>>,{{i\d+}}]               loop:<<Loop:B\d+>> outer_loop:none
142   /// CHECK-DAG:                VecStore [{{l\d+}},<<Phi>>,<<Rep>>] loop:<<Loop>>      outer_loop:none
143   /// CHECK-DAG:                Add [<<Phi>>,<<I4>>]                loop:<<Loop>>      outer_loop:none
intVectorLongInvariant(int[] x, long[] y)144   static void intVectorLongInvariant(int[] x, long[] y) {
145     for (int i = 0; i < 100; i++) {
146       x[i] = (int) y[0];
147     }
148   }
149 
150   /// CHECK-START: void Main.longCanBeDoneWithInt(int[], int[]) loop_optimization (before)
151   /// CHECK-DAG: <<I0:i\d+>>    IntConstant 0                        loop:none
152   /// CHECK-DAG: <<I1:i\d+>>    IntConstant 1                        loop:none
153   /// CHECK-DAG: <<L1:j\d+>>    LongConstant 1                       loop:none
154   /// CHECK-DAG: <<Phi:i\d+>>   Phi [<<I0>>,<<Add:i\d+>>]            loop:<<Loop:B\d+>> outer_loop:none
155   /// CHECK-DAG: <<Get:i\d+>>   ArrayGet [{{l\d+}},<<Phi>>]          loop:<<Loop>>      outer_loop:none
156   /// CHECK-DAG: <<Cnv1:j\d+>>  TypeConversion [<<Get>>]             loop:<<Loop>>      outer_loop:none
157   /// CHECK-DAG: <<AddL:j\d+>>  Add [<<Cnv1>>,<<L1>>]                loop:<<Loop>>      outer_loop:none
158   /// CHECK-DAG: <<Cnv2:i\d+>>  TypeConversion [<<AddL>>]            loop:<<Loop>>      outer_loop:none
159   /// CHECK-DAG:                ArraySet [{{l\d+}},<<Phi>>,<<Cnv2>>] loop:<<Loop>>      outer_loop:none
160   /// CHECK-DAG: <<Add>>        Add [<<Phi>>,<<I1>>]                 loop:<<Loop>>      outer_loop:none
161   //
162   /// CHECK-START-ARM64: void Main.longCanBeDoneWithInt(int[], int[]) loop_optimization (after)
163   /// CHECK-DAG: <<I0:i\d+>>    IntConstant 0                       loop:none
164   /// CHECK-DAG: <<I4:i\d+>>    IntConstant 4                       loop:none
165   /// CHECK-DAG: <<L1:j\d+>>    LongConstant 1                      loop:none
166   /// CHECK-DAG: <<Cnv:i\d+>>   TypeConversion [<<L1>>]             loop:none
167   /// CHECK-DAG: <<Rep:d\d+>>   VecReplicateScalar [<<Cnv>>]        loop:none
168   /// CHECK-DAG: <<Phi:i\d+>>   Phi [<<I0>>,{{i\d+}}]               loop:<<Loop:B\d+>> outer_loop:none
169   /// CHECK-DAG: <<Load:d\d+>>  VecLoad [{{l\d+}},<<Phi>>]          loop:<<Loop>>      outer_loop:none
170   /// CHECK-DAG: <<Add:d\d+>>   VecAdd [<<Load>>,<<Rep>>]           loop:<<Loop>>      outer_loop:none
171   /// CHECK-DAG:                VecStore [{{l\d+}},<<Phi>>,<<Add>>] loop:<<Loop>>      outer_loop:none
172   /// CHECK-DAG:                Add [<<Phi>>,<<I4>>]                loop:<<Loop>>      outer_loop:none
longCanBeDoneWithInt(int[] x, int[] y)173   static void longCanBeDoneWithInt(int[] x, int[] y) {
174     for (int i = 0; i < 100; i++) {
175       x[i] = (int) (y[i] + 1L);
176     }
177   }
178 
testUnroll()179   static void testUnroll() {
180     float[] x = new float[100];
181     float[] y = new float[100];
182     for (int i = 0; i < 100; i++) {
183       x[i] = 0.0f;
184       y[i] = 2.0f;
185     }
186     unroll(x, y);
187     for (int i = 0; i < 100; i++) {
188       expectEquals(5.0f, x[i]);
189       expectEquals(2.0f, y[i]);
190     }
191   }
192 
testStencil1()193   static void testStencil1() {
194     int[] a = new int[100];
195     int[] b = new int[100];
196     for (int i = 0; i < 100; i++) {
197       a[i] = 0;
198       b[i] = i;
199     }
200     stencil(a, b, 100);
201     for (int i = 1; i < 99; i++) {
202       int e = i + i + i;
203       expectEquals(e, a[i]);
204       expectEquals(i, b[i]);
205     }
206   }
207 
testStencil2()208   static void testStencil2() {
209     int[] a = new int[100];
210     int[] b = new int[100];
211     for (int i = 0; i < 100; i++) {
212       a[i] = 0;
213       b[i] = i;
214     }
215     stencilSubInt(a, b, 100);
216     for (int i = 1; i < 99; i++) {
217       int e = i + i + i;
218       expectEquals(e, a[i]);
219       expectEquals(i, b[i]);
220     }
221   }
222 
testStencil3()223   static void testStencil3() {
224     int[] a = new int[100];
225     int[] b = new int[100];
226     for (int i = 0; i < 100; i++) {
227       a[i] = 0;
228       b[i] = i;
229     }
230     stencilAddInt(a, b, 100);
231     for (int i = 1; i < 99; i++) {
232       int e = i + i + i;
233       expectEquals(e, a[i]);
234       expectEquals(i, b[i]);
235     }
236   }
237 
testTypes()238   static void testTypes() {
239     int[] a = new int[100];
240     int[] b = new int[100];
241     long[] l = { 3 };
242     expectEquals(31, longInductionReduction(l));
243     intVectorLongInvariant(a, l);
244     for (int i = 0; i < 100; i++) {
245       expectEquals(3, a[i]);
246     }
247     longCanBeDoneWithInt(b, a);
248     for (int i = 0; i < 100; i++) {
249       expectEquals(4, b[i]);
250     }
251   }
252 
main(String[] args)253   public static void main(String[] args) {
254     testUnroll();
255     testStencil1();
256     testStencil2();
257     testStencil3();
258     testTypes();
259     System.out.println("passed");
260   }
261 
expectEquals(int expected, int result)262   private static void expectEquals(int expected, int result) {
263     if (expected != result) {
264       throw new Error("Expected: " + expected + ", found: " + result);
265     }
266   }
267 
expectEquals(long expected, long result)268   private static void expectEquals(long expected, long result) {
269     if (expected != result) {
270       throw new Error("Expected: " + expected + ", found: " + result);
271     }
272   }
273 
expectEquals(float expected, float result)274   private static void expectEquals(float expected, float result) {
275     if (expected != result) {
276       throw new Error("Expected: " + expected + ", found: " + result);
277     }
278   }
279 }
280