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 
17 /**
18  * Tests for SAD (sum of absolute differences).
19  *
20  * Special case, char array that is first cast to short, forcing sign extension.
21  */
22 public class SimdSadShort2 {
23 
24   // TODO: lower precision still coming, b/64091002
25 
sadCastChar2Short(char[] s1, char[] s2)26   private static short sadCastChar2Short(char[] s1, char[] s2) {
27       int min_length = Math.min(s1.length, s2.length);
28       short sad = 0;
29       for (int i = 0; i < min_length; i++) {
30           sad += Math.abs(((short) s1[i]) - ((short) s2[i]));
31       }
32       return sad;
33   }
34 
sadCastChar2ShortAlt(char[] s1, char[] s2)35   private static short sadCastChar2ShortAlt(char[] s1, char[] s2) {
36       int min_length = Math.min(s1.length, s2.length);
37       short sad = 0;
38       for (int i = 0; i < min_length; i++) {
39           short s = (short) s1[i];
40           short p = (short) s2[i];
41           sad += s >= p ? s - p : p - s;
42       }
43       return sad;
44   }
45 
sadCastChar2ShortAlt2(char[] s1, char[] s2)46   private static short sadCastChar2ShortAlt2(char[] s1, char[] s2) {
47       int min_length = Math.min(s1.length, s2.length);
48       short sad = 0;
49       for (int i = 0; i < min_length; i++) {
50           short s = (short) s1[i];
51           short p = (short) s2[i];
52           int x = s - p;
53           if (x < 0)
54               x = -x;
55           sad += x;
56       }
57       return sad;
58   }
59 
60   /// CHECK-START: int SimdSadShort2.sadCastChar2Int(char[], char[]) instruction_simplifier (before)
61   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
62   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
63   /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
64   /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
65   /// CHECK-DAG: <<BC1:i\d+>>    BoundsCheck [<<Phi1>>,{{i\d+}}] loop:<<Loop>>     outer_loop:none
66   /// CHECK-DAG: <<BC2:i\d+>>    BoundsCheck [<<Phi1>>,{{i\d+}}] loop:<<Loop>>     outer_loop:none
67   /// CHECK-DAG: <<Get1:c\d+>>   ArrayGet [{{l\d+}},<<BC1>>]    loop:<<Loop>>      outer_loop:none
68   /// CHECK-DAG: <<Get2:c\d+>>   ArrayGet [{{l\d+}},<<BC2>>]    loop:<<Loop>>      outer_loop:none
69   /// CHECK-DAG: <<Cnv1:s\d+>>   TypeConversion [<<Get1>>]      loop:<<Loop>>      outer_loop:none
70   /// CHECK-DAG: <<Cnv2:s\d+>>   TypeConversion [<<Get2>>]      loop:<<Loop>>      outer_loop:none
71   /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Cnv1>>,<<Cnv2>>]        loop:<<Loop>>      outer_loop:none
72   /// CHECK-DAG: <<Abs:i\d+>>    Abs [<<Sub>>]                  loop:<<Loop>>      outer_loop:none
73   /// CHECK-DAG:                 Add [<<Phi2>>,<<Abs>>]         loop:<<Loop>>      outer_loop:none
74   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
75   //
76   /// CHECK-START: int SimdSadShort2.sadCastChar2Int(char[], char[]) loop_optimization (before)
77   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
78   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
79   /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
80   /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
81   /// CHECK-DAG: <<Get1:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
82   /// CHECK-DAG: <<Get2:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
83   /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get1>>,<<Get2>>]        loop:<<Loop>>      outer_loop:none
84   /// CHECK-DAG: <<Abs:i\d+>>    Abs [<<Sub>>]                  loop:<<Loop>>      outer_loop:none
85   /// CHECK-DAG:                 Add [<<Phi2>>,<<Abs>>]         loop:<<Loop>>      outer_loop:none
86   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
87   //
88   /// CHECK-START-ARM64: int SimdSadShort2.sadCastChar2Int(char[], char[]) loop_optimization (after)
89   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
90   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
91   //
92   //      SAD idiom is not supported for SVE.
93   ///     CHECK-NOT: VecSADAccumulate
94   //
95   /// CHECK-ELSE:
96   //
97   ///     CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
98   ///     CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
99   ///     CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
100   ///     CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
101   ///     CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
102   ///     CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
103   ///     CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
104   ///     CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
105   //
106   /// CHECK-FI:
sadCastChar2Int(char[] s1, char[] s2)107   private static int sadCastChar2Int(char[] s1, char[] s2) {
108       int min_length = Math.min(s1.length, s2.length);
109       int sad = 0;
110       for (int i = 0; i < min_length; i++) {
111           sad += Math.abs(((short) s1[i]) - ((short) s2[i]));
112       }
113       return sad;
114   }
115 
116   /// CHECK-START: int SimdSadShort2.sadCastChar2IntAlt(char[], char[]) instruction_simplifier (before)
117   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
118   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
119   /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
120   /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
121   /// CHECK-DAG: <<BC1:i\d+>>    BoundsCheck [<<Phi1>>,{{i\d+}}] loop:<<Loop>>      outer_loop:none
122   /// CHECK-DAG: <<BC2:i\d+>>    BoundsCheck [<<Phi1>>,{{i\d+}}] loop:<<Loop>>      outer_loop:none
123   /// CHECK-DAG: <<Get1:c\d+>>   ArrayGet [{{l\d+}},<<BC1>>]    loop:<<Loop>>      outer_loop:none
124   /// CHECK-DAG: <<Get2:c\d+>>   ArrayGet [{{l\d+}},<<BC2>>]    loop:<<Loop>>      outer_loop:none
125   /// CHECK-DAG: <<Cnv1:s\d+>>   TypeConversion [<<Get1>>]      loop:<<Loop>>      outer_loop:none
126   /// CHECK-DAG: <<Cnv2:s\d+>>   TypeConversion [<<Get2>>]      loop:<<Loop>>      outer_loop:none
127   /// CHECK-DAG: <<Sub1:i\d+>>   Sub [<<Cnv2>>,<<Cnv1>>]        loop:<<Loop>>      outer_loop:none
128   /// CHECK-DAG: <<Sub2:i\d+>>   Sub [<<Cnv1>>,<<Cnv2>>]        loop:<<Loop>>      outer_loop:none
129   /// CHECK-DAG: <<Phi3:i\d+>>   Phi [<<Sub2>>,<<Sub1>>]        loop:<<Loop>>      outer_loop:none
130   /// CHECK-DAG:                 Add [<<Phi2>>,<<Phi3>>]        loop:<<Loop>>      outer_loop:none
131   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
132   //
133   /// CHECK-START: int SimdSadShort2.sadCastChar2IntAlt(char[], char[]) loop_optimization (before)
134   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
135   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
136   /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
137   /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
138   /// CHECK-DAG: <<Get1:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
139   /// CHECK-DAG: <<Get2:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
140   /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get2>>,<<Get1>>]        loop:<<Loop>>      outer_loop:none
141   /// CHECK-DAG: <<Intrin:i\d+>> Abs [<<Sub>>]                  loop:<<Loop>>      outer_loop:none
142   /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
143   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
144   //
145   /// CHECK-START-ARM64: int SimdSadShort2.sadCastChar2IntAlt(char[], char[]) loop_optimization (after)
146   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
147   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
148   //
149   //      SAD idiom is not supported for SVE.
150   ///     CHECK-NOT: VecSADAccumulate
151   //
152   /// CHECK-ELSE:
153   //
154   ///     CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
155   ///     CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
156   ///     CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
157   ///     CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
158   ///     CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
159   ///     CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
160   ///     CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load2>>,<<Load1>>] loop:<<Loop>> outer_loop:none
161   ///     CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
162   //
163   /// CHECK-FI:
sadCastChar2IntAlt(char[] s1, char[] s2)164   private static int sadCastChar2IntAlt(char[] s1, char[] s2) {
165       int min_length = Math.min(s1.length, s2.length);
166       int sad = 0;
167       for (int i = 0; i < min_length; i++) {
168           short s = (short) s1[i];
169           short p = (short) s2[i];
170           sad += s >= p ? s - p : p - s;
171       }
172       return sad;
173   }
174 
175   /// CHECK-START: int SimdSadShort2.sadCastChar2IntAlt2(char[], char[]) instruction_simplifier (before)
176   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
177   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
178   /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
179   /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
180   /// CHECK-DAG: <<BC1:i\d+>>    BoundsCheck [<<Phi1>>,{{i\d+}}] loop:<<Loop>>      outer_loop:none
181   /// CHECK-DAG: <<BC2:i\d+>>    BoundsCheck [<<Phi1>>,{{i\d+}}] loop:<<Loop>>      outer_loop:none
182   /// CHECK-DAG: <<Get1:c\d+>>   ArrayGet [{{l\d+}},<<BC1>>]    loop:<<Loop>>      outer_loop:none
183   /// CHECK-DAG: <<Get2:c\d+>>   ArrayGet [{{l\d+}},<<BC2>>]    loop:<<Loop>>      outer_loop:none
184   /// CHECK-DAG: <<Cnv1:s\d+>>   TypeConversion [<<Get1>>]      loop:<<Loop>>      outer_loop:none
185   /// CHECK-DAG: <<Cnv2:s\d+>>   TypeConversion [<<Get2>>]      loop:<<Loop>>      outer_loop:none
186   /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Cnv1>>,<<Cnv2>>]        loop:<<Loop>>      outer_loop:none
187   /// CHECK-DAG: <<Neg:i\d+>>    Neg [<<Sub>>]                  loop:<<Loop>>      outer_loop:none
188   /// CHECK-DAG: <<Phi3:i\d+>>   Phi [<<Sub>>,<<Neg>>]          loop:<<Loop>>      outer_loop:none
189   /// CHECK-DAG:                 Add [<<Phi2>>,<<Phi3>>]        loop:<<Loop>>      outer_loop:none
190   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
191   //
192   /// CHECK-START: int SimdSadShort2.sadCastChar2IntAlt2(char[], char[]) loop_optimization (before)
193   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
194   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
195   /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
196   /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
197   /// CHECK-DAG: <<Get1:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
198   /// CHECK-DAG: <<Get2:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
199   /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get1>>,<<Get2>>]        loop:<<Loop>>      outer_loop:none
200   /// CHECK-DAG: <<Intrin:i\d+>> Abs [<<Sub>>]                  loop:<<Loop>>      outer_loop:none
201   /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
202   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
203   //
204   /// CHECK-START-ARM64: int SimdSadShort2.sadCastChar2IntAlt2(char[], char[]) loop_optimization (after)
205   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
206   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
207   //
208   //      SAD idiom is not supported for SVE.
209   ///     CHECK-NOT: VecSADAccumulate
210   //
211   /// CHECK-ELSE:
212   //
213   ///     CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
214   ///     CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
215   ///     CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
216   ///     CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
217   ///     CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
218   ///     CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
219   ///     CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
220   ///     CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
221   //
222   /// CHECK-FI:
sadCastChar2IntAlt2(char[] s1, char[] s2)223   private static int sadCastChar2IntAlt2(char[] s1, char[] s2) {
224       int min_length = Math.min(s1.length, s2.length);
225       int sad = 0;
226       for (int i = 0; i < min_length; i++) {
227           short s = (short) s1[i];
228           short p = (short) s2[i];
229           int x = s - p;
230           if (x < 0)
231               x = -x;
232           sad += x;
233       }
234       return sad;
235   }
236 
237   /// CHECK-START: long SimdSadShort2.sadCastChar2Long(char[], char[]) instruction_simplifier (before)
238   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
239   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
240   /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 0                 loop:none
241   /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
242   /// CHECK-DAG: <<Phi2:j\d+>>   Phi [<<ConsL>>,{{j\d+}}]       loop:<<Loop>>      outer_loop:none
243   /// CHECK-DAG: <<BC1:i\d+>>    BoundsCheck [<<Phi1>>,{{i\d+}}] loop:<<Loop>>     outer_loop:none
244   /// CHECK-DAG: <<BC2:i\d+>>    BoundsCheck [<<Phi1>>,{{i\d+}}] loop:<<Loop>>     outer_loop:none
245   /// CHECK-DAG: <<Get1:c\d+>>   ArrayGet [{{l\d+}},<<BC1>>]    loop:<<Loop>>      outer_loop:none
246   /// CHECK-DAG: <<Get2:c\d+>>   ArrayGet [{{l\d+}},<<BC2>>]    loop:<<Loop>>      outer_loop:none
247   /// CHECK-DAG: <<Cnv1:s\d+>>   TypeConversion [<<Get1>>]      loop:<<Loop>>      outer_loop:none
248   /// CHECK-DAG: <<Cnv2:s\d+>>   TypeConversion [<<Get2>>]      loop:<<Loop>>      outer_loop:none
249   /// CHECK-DAG: <<Cnv3:j\d+>>   TypeConversion [<<Cnv1>>]      loop:<<Loop>>      outer_loop:none
250   /// CHECK-DAG: <<Cnv4:j\d+>>   TypeConversion [<<Cnv2>>]      loop:<<Loop>>      outer_loop:none
251   /// CHECK-DAG: <<Sub:j\d+>>    Sub [<<Cnv3>>,<<Cnv4>>]        loop:<<Loop>>      outer_loop:none
252   /// CHECK-DAG: <<Abs:j\d+>>    Abs [<<Sub>>]                  loop:<<Loop>> outer_loop:none
253   /// CHECK-DAG:                 Add [<<Phi2>>,<<Abs>>]         loop:<<Loop>>      outer_loop:none
254   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
255   //
256   /// CHECK-START: long SimdSadShort2.sadCastChar2Long(char[], char[]) loop_optimization (before)
257   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
258   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
259   /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 0                 loop:none
260   /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
261   /// CHECK-DAG: <<Phi2:j\d+>>   Phi [<<ConsL>>,{{j\d+}}]       loop:<<Loop>>      outer_loop:none
262   /// CHECK-DAG: <<Get1:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
263   /// CHECK-DAG: <<Get2:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
264   /// CHECK-DAG: <<Cnv1:j\d+>>   TypeConversion [<<Get1>>]      loop:<<Loop>>      outer_loop:none
265   /// CHECK-DAG: <<Cnv2:j\d+>>   TypeConversion [<<Get2>>]      loop:<<Loop>>      outer_loop:none
266   /// CHECK-DAG: <<Sub:j\d+>>    Sub [<<Cnv1>>,<<Cnv2>>]        loop:<<Loop>>      outer_loop:none
267   /// CHECK-DAG: <<Abs:j\d+>>    Abs [<<Sub>>]                  loop:<<Loop>>      outer_loop:none
268   /// CHECK-DAG:                 Add [<<Phi2>>,<<Abs>>]         loop:<<Loop>>      outer_loop:none
269   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
270   //
271   /// CHECK-START-ARM64: long SimdSadShort2.sadCastChar2Long(char[], char[]) loop_optimization (after)
272   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
273   /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 0                 loop:none
274   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
275   //
276   //      SAD idiom is not supported for SVE.
277   ///     CHECK-NOT: VecSADAccumulate
278   //
279   /// CHECK-ELSE:
280   //
281   ///     CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
282   ///     CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsL>>]      loop:none
283   ///     CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
284   ///     CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
285   ///     CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
286   ///     CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
287   ///     CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
288   ///     CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
289   //
290   /// CHECK-FI:
sadCastChar2Long(char[] s1, char[] s2)291   private static long sadCastChar2Long(char[] s1, char[] s2) {
292       int min_length = Math.min(s1.length, s2.length);
293       long sad = 0;
294       for (int i = 0; i < min_length; i++) {
295           long x = (short) s1[i];
296           long y = (short) s2[i];
297           sad += Math.abs(x - y);
298       }
299       return sad;
300   }
301 
302   /// CHECK-START: long SimdSadShort2.sadCastChar2LongAt1(char[], char[]) instruction_simplifier (before)
303   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
304   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
305   /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 1                 loop:none
306   /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
307   /// CHECK-DAG: <<Phi2:j\d+>>   Phi [<<ConsL>>,{{j\d+}}]       loop:<<Loop>>      outer_loop:none
308   /// CHECK-DAG: <<BC1:i\d+>>    BoundsCheck [<<Phi1>>,{{i\d+}}] loop:<<Loop>>     outer_loop:none
309   /// CHECK-DAG: <<BC2:i\d+>>    BoundsCheck [<<Phi1>>,{{i\d+}}] loop:<<Loop>>     outer_loop:none
310   /// CHECK-DAG: <<Get1:c\d+>>   ArrayGet [{{l\d+}},<<BC1>>]    loop:<<Loop>>      outer_loop:none
311   /// CHECK-DAG: <<Get2:c\d+>>   ArrayGet [{{l\d+}},<<BC2>>]    loop:<<Loop>>      outer_loop:none
312   /// CHECK-DAG: <<Cnv1:s\d+>>   TypeConversion [<<Get1>>]      loop:<<Loop>>      outer_loop:none
313   /// CHECK-DAG: <<Cnv2:s\d+>>   TypeConversion [<<Get2>>]      loop:<<Loop>>      outer_loop:none
314   /// CHECK-DAG: <<Cnv3:j\d+>>   TypeConversion [<<Cnv1>>]      loop:<<Loop>>      outer_loop:none
315   /// CHECK-DAG: <<Cnv4:j\d+>>   TypeConversion [<<Cnv2>>]      loop:<<Loop>>      outer_loop:none
316   /// CHECK-DAG: <<Sub:j\d+>>    Sub [<<Cnv3>>,<<Cnv4>>]        loop:<<Loop>>      outer_loop:none
317   /// CHECK-DAG: <<Abs:j\d+>>    Abs [<<Sub>>]                  loop:<<Loop>> outer_loop:none
318   /// CHECK-DAG:                 Add [<<Phi2>>,<<Abs>>]         loop:<<Loop>>      outer_loop:none
319   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
320   //
321   /// CHECK-START: long SimdSadShort2.sadCastChar2LongAt1(char[], char[]) loop_optimization (before)
322   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
323   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
324   /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 1                 loop:none
325   /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
326   /// CHECK-DAG: <<Phi2:j\d+>>   Phi [<<ConsL>>,{{j\d+}}]       loop:<<Loop>>      outer_loop:none
327   /// CHECK-DAG: <<Get1:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
328   /// CHECK-DAG: <<Get2:s\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
329   /// CHECK-DAG: <<Cnv1:j\d+>>   TypeConversion [<<Get1>>]      loop:<<Loop>>      outer_loop:none
330   /// CHECK-DAG: <<Cnv2:j\d+>>   TypeConversion [<<Get2>>]      loop:<<Loop>>      outer_loop:none
331   /// CHECK-DAG: <<Sub:j\d+>>    Sub [<<Cnv1>>,<<Cnv2>>]        loop:<<Loop>>      outer_loop:none
332   /// CHECK-DAG: <<Abs:j\d+>>    Abs [<<Sub>>]                  loop:<<Loop>>      outer_loop:none
333   /// CHECK-DAG:                 Add [<<Phi2>>,<<Abs>>]         loop:<<Loop>>      outer_loop:none
334   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
335   //
336   /// CHECK-START-ARM64: long SimdSadShort2.sadCastChar2LongAt1(char[], char[]) loop_optimization (after)
337   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
338   /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 1                 loop:none
339   /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
340   //
341   //      SAD idiom is not supported for SVE.
342   ///     CHECK-NOT: VecSADAccumulate
343   //
344   /// CHECK-ELSE:
345   //
346   ///     CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
347   ///     CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsL>>]      loop:none
348   ///     CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
349   ///     CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
350   ///     CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
351   ///     CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
352   ///     CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
353   ///     CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
354   //
355   /// CHECK-FI:
sadCastChar2LongAt1(char[] s1, char[] s2)356   private static long sadCastChar2LongAt1(char[] s1, char[] s2) {
357       int min_length = Math.min(s1.length, s2.length);
358       long sad = 1; // starts at 1
359       for (int i = 0; i < min_length; i++) {
360           long x = (short) s1[i];
361           long y = (short) s2[i];
362           sad += Math.abs(x - y);
363       }
364       return sad;
365   }
366 
main()367   public static void main() {
368     // Cross-test the two most extreme values individually.
369     char[] s1 = { 0, 0x8000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
370     char[] s2 = { 0, 0x7fff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
371     expectEquals(-1, sadCastChar2Short(s1, s2));
372     expectEquals(-1, sadCastChar2Short(s2, s1));
373     expectEquals(-1, sadCastChar2ShortAlt(s1, s2));
374     expectEquals(-1, sadCastChar2ShortAlt(s2, s1));
375     expectEquals(-1, sadCastChar2ShortAlt2(s1, s2));
376     expectEquals(-1, sadCastChar2ShortAlt2(s2, s1));
377     expectEquals(65535, sadCastChar2Int(s1, s2));
378     expectEquals(65535, sadCastChar2Int(s2, s1));
379     expectEquals(65535, sadCastChar2IntAlt(s1, s2));
380     expectEquals(65535, sadCastChar2IntAlt(s2, s1));
381     expectEquals(65535, sadCastChar2IntAlt2(s1, s2));
382     expectEquals(65535, sadCastChar2IntAlt2(s2, s1));
383     expectEquals(65535L, sadCastChar2Long(s1, s2));
384     expectEquals(65535L, sadCastChar2Long(s2, s1));
385     expectEquals(65536L, sadCastChar2LongAt1(s1, s2));
386     expectEquals(65536L, sadCastChar2LongAt1(s2, s1));
387 
388     // Use cross-values to test all cases.
389     char[] interesting = {
390       (char) 0x0000,
391       (char) 0x0001,
392       (char) 0x0002,
393       (char) 0x1234,
394       (char) 0x8000,
395       (char) 0x8001,
396       (char) 0x7fff,
397       (char) 0xffff
398     };
399     int n = interesting.length;
400     int m = n * n + 1;
401     s1 = new char[m];
402     s2 = new char[m];
403     int k = 0;
404     for (int i = 0; i < n; i++) {
405       for (int j = 0; j < n; j++) {
406         s1[k] = interesting[i];
407         s2[k] = interesting[j];
408         k++;
409       }
410     }
411     s1[k] = 10;
412     s2[k] = 2;
413     expectEquals(-18932, sadCastChar2Short(s1, s2));
414     expectEquals(-18932, sadCastChar2ShortAlt(s1, s2));
415     expectEquals(-18932, sadCastChar2ShortAlt2(s1, s2));
416     expectEquals(1291788, sadCastChar2Int(s1, s2));
417     expectEquals(1291788, sadCastChar2IntAlt(s1, s2));
418     expectEquals(1291788, sadCastChar2IntAlt2(s1, s2));
419     expectEquals(1291788L, sadCastChar2Long(s1, s2));
420     expectEquals(1291789L, sadCastChar2LongAt1(s1, s2));
421 
422     System.out.println("SimdSadShort2 passed");
423   }
424 
expectEquals(int expected, int result)425   private static void expectEquals(int expected, int result) {
426     if (expected != result) {
427       throw new Error("Expected: " + expected + ", found: " + result);
428     }
429   }
430 
expectEquals(long expected, long result)431   private static void expectEquals(long expected, long result) {
432     if (expected != result) {
433       throw new Error("Expected: " + expected + ", found: " + result);
434     }
435   }
436 }
437