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 halving-add idiomatic vectorization.
19  */
20 public class HaddShort {
21 
22   private static final int N = 64 * 1024;
23   private static final int M = N + 31;
24 
25   static short[] sB1 = new short[M];
26   static short[] sB2 = new short[M];
27   static short[] sBo = new short[M];
28 
$inline$mone()29   private static int $inline$mone() {
30     return -1;
31   }
32 
33   /// CHECK-START: void HaddShort.halving_add_signed(short[], short[], short[]) loop_optimization (before)
34   /// CHECK-DAG: <<I1:i\d+>>   IntConstant 1                       loop:none
35   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
36   /// CHECK-DAG: <<Get1:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
37   /// CHECK-DAG: <<Get2:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
38   /// CHECK-DAG: <<Add:i\d+>>  Add [<<Get1>>,<<Get2>>]             loop:<<Loop>>      outer_loop:none
39   /// CHECK-DAG: <<Shr:i\d+>>  Shr [<<Add>>,<<I1>>]                loop:<<Loop>>      outer_loop:none
40   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
41   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
42   //
43   /// CHECK-START-{ARM,ARM64}: void HaddShort.halving_add_signed(short[], short[], short[]) loop_optimization (after)
44   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                               loop:<<Loop:B\d+>> outer_loop:none
45   /// CHECK-DAG: <<Get2:d\d+>> VecLoad                               loop:<<Loop>>      outer_loop:none
46   /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:false loop:<<Loop>> outer_loop:none
47   /// CHECK-DAG:               VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>>      outer_loop:none
halving_add_signed(short[] b1, short[] b2, short[] bo)48   private static void halving_add_signed(short[] b1, short[] b2, short[] bo) {
49     int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
50     for (int i = 0; i < min_length; i++) {
51       bo[i] = (short) ((b1[i] + b2[i]) >> 1);
52     }
53   }
54 
55   /// CHECK-START: void HaddShort.halving_add_signed_alt(short[], short[], short[]) loop_optimization (before)
56   /// CHECK-DAG: <<I1:i\d+>>   IntConstant 1                       loop:none
57   /// CHECK-DAG: <<I10:i\d+>>  IntConstant 10                      loop:none
58   /// CHECK-DAG: <<M10:i\d+>>  IntConstant -10                     loop:none
59   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
60   /// CHECK-DAG: <<Get1:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
61   /// CHECK-DAG: <<Get2:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
62   /// CHECK-DAG: <<Add1:i\d+>> Add [<<Get1>>,<<I10>>]              loop:<<Loop>>      outer_loop:none
63   /// CHECK-DAG: <<Add2:i\d+>> Add [<<Get2>>,<<M10>>]              loop:<<Loop>>      outer_loop:none
64   /// CHECK-DAG: <<Add3:i\d+>> Add [<<Add1>>,<<Add2>>]             loop:<<Loop>>      outer_loop:none
65   /// CHECK-DAG: <<Shr:i\d+>>  Shr [<<Add3>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
66   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
67   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
68   //
69   /// CHECK-START-{ARM,ARM64}: void HaddShort.halving_add_signed_alt(short[], short[], short[]) loop_optimization (after)
70   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                               loop:<<Loop:B\d+>> outer_loop:none
71   /// CHECK-DAG: <<Get2:d\d+>> VecLoad                               loop:<<Loop>>      outer_loop:none
72   /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:false loop:<<Loop>> outer_loop:none
73   /// CHECK-DAG:               VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>>      outer_loop:none
halving_add_signed_alt(short[] b1, short[] b2, short[] bo)74   private static void halving_add_signed_alt(short[] b1, short[] b2, short[] bo) {
75     int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
76     for (int i = 0; i < min_length; i++) {
77       // Cancelling constant computations do not confuse recognition.
78       bo[i] = (short) (((b1[i] + 10) + (b2[i] - 10)) >> 1);
79     }
80   }
81 
82   /// CHECK-START: void HaddShort.halving_add_unsigned(short[], short[], short[]) instruction_simplifier (before)
83   /// CHECK-DAG: <<I1:i\d+>>   IntConstant 1                       loop:none
84   /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535                   loop:none
85   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
86   /// CHECK-DAG: <<Get1:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
87   /// CHECK-DAG: <<Get2:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
88   /// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<UMAX>>]             loop:<<Loop>>      outer_loop:none
89   /// CHECK-DAG: <<And2:i\d+>> And [<<UMAX>>,<<Get2>>]             loop:<<Loop>>      outer_loop:none
90   /// CHECK-DAG: <<Add:i\d+>>  Add [<<And1>>,<<And2>>]             loop:<<Loop>>      outer_loop:none
91   /// CHECK-DAG: <<Shr:i\d+>>  Shr [<<Add>>,<<I1>>]                loop:<<Loop>>      outer_loop:none
92   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
93   /// CHECK-DAG:               ArraySet [{{l\d+}},{{i\d+}},<<Cnv>>] loop:<<Loop>>      outer_loop:none
94   //
95   /// CHECK-START: void HaddShort.halving_add_unsigned(short[], short[], short[]) loop_optimization (before)
96   /// CHECK-DAG: <<I1:i\d+>>   IntConstant 1                       loop:none
97   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
98   /// CHECK-DAG: <<Get1:c\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
99   /// CHECK-DAG: <<Get2:c\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
100   /// CHECK-DAG: <<Add:i\d+>>  Add [<<Get1>>,<<Get2>>]             loop:<<Loop>>      outer_loop:none
101   /// CHECK-DAG: <<Shr:i\d+>>  Shr [<<Add>>,<<I1>>]                loop:<<Loop>>      outer_loop:none
102   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
103   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
104   //
105   /// CHECK-START-{ARM,ARM64}: void HaddShort.halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
106   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                               loop:<<Loop:B\d+>> outer_loop:none
107   /// CHECK-DAG: <<Get2:d\d+>> VecLoad                               loop:<<Loop>>      outer_loop:none
108   /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:false loop:<<Loop>> outer_loop:none
109   /// CHECK-DAG:               VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>>      outer_loop:none
halving_add_unsigned(short[] b1, short[] b2, short[] bo)110   private static void halving_add_unsigned(short[] b1, short[] b2, short[] bo) {
111     int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
112     for (int i = 0; i < min_length; i++) {
113       int v1 = b1[i] & 0xffff;
114       int v2 = b2[i] & 0xffff;
115       bo[i] = (short) ((v1 + v2) >> 1);
116     }
117   }
118 
119   /// CHECK-START: void HaddShort.rounding_halving_add_signed(short[], short[], short[]) loop_optimization (before)
120   /// CHECK-DAG: <<I1:i\d+>>   IntConstant 1                       loop:none
121   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
122   /// CHECK-DAG: <<Get1:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
123   /// CHECK-DAG: <<Get2:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
124   /// CHECK-DAG: <<Add1:i\d+>> Add [<<Get1>>,<<Get2>>]             loop:<<Loop>>      outer_loop:none
125   /// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
126   /// CHECK-DAG: <<Shr:i\d+>>  Shr [<<Add2>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
127   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
128   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
129   //
130   /// CHECK-START-{ARM,ARM64}: void HaddShort.rounding_halving_add_signed(short[], short[], short[]) loop_optimization (after)
131   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                               loop:<<Loop:B\d+>> outer_loop:none
132   /// CHECK-DAG: <<Get2:d\d+>> VecLoad                               loop:<<Loop>>      outer_loop:none
133   /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:true loop:<<Loop>> outer_loop:none
134   /// CHECK-DAG:               VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>>      outer_loop:none
rounding_halving_add_signed(short[] b1, short[] b2, short[] bo)135   private static void rounding_halving_add_signed(short[] b1, short[] b2, short[] bo) {
136     int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
137     for (int i = 0; i < min_length; i++) {
138       bo[i] = (short) ((b1[i] + b2[i] + 1) >> 1);
139     }
140   }
141 
142   /// CHECK-START: void HaddShort.rounding_halving_add_signed_alt(short[], short[], short[]) loop_optimization (before)
143   /// CHECK-DAG: <<I1:i\d+>>   IntConstant 1                       loop:none
144   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
145   /// CHECK-DAG: <<Get1:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
146   /// CHECK-DAG: <<Get2:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
147   /// CHECK-DAG: <<Add1:i\d+>> Add [<<Get1>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
148   /// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<Get2>>]             loop:<<Loop>>      outer_loop:none
149   /// CHECK-DAG: <<Shr:i\d+>>  Shr [<<Add2>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
150   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
151   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
152   //
153   /// CHECK-START-{ARM,ARM64}: void HaddShort.rounding_halving_add_signed_alt(short[], short[], short[]) loop_optimization (after)
154   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                               loop:<<Loop:B\d+>> outer_loop:none
155   /// CHECK-DAG: <<Get2:d\d+>> VecLoad                               loop:<<Loop>>      outer_loop:none
156   /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:true loop:<<Loop>> outer_loop:none
157   /// CHECK-DAG:               VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>>      outer_loop:none
rounding_halving_add_signed_alt(short[] b1, short[] b2, short[] bo)158   private static void rounding_halving_add_signed_alt(short[] b1, short[] b2, short[] bo) {
159     int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
160     for (int i = 0; i < min_length; i++) {
161       // Slightly different order in idiom does not confuse recognition.
162       bo[i] = (short) (((1 + b1[i]) + b2[i]) >> 1);
163     }
164   }
165 
166   /// CHECK-START: void HaddShort.rounding_halving_add_signed_alt2(short[], short[], short[]) loop_optimization (before)
167   /// CHECK-DAG: <<I1:i\d+>>   IntConstant 1                       loop:none
168   /// CHECK-DAG: <<I10:i\d+>>  IntConstant 10                      loop:none
169   /// CHECK-DAG: <<M9:i\d+>>   IntConstant -9                      loop:none
170   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
171   /// CHECK-DAG: <<Get1:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
172   /// CHECK-DAG: <<Get2:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
173   /// CHECK-DAG: <<Add1:i\d+>> Add [<<Get1>>,<<I10>>]              loop:<<Loop>>      outer_loop:none
174   /// CHECK-DAG: <<Add2:i\d+>> Add [<<Get2>>,<<M9>>]               loop:<<Loop>>      outer_loop:none
175   /// CHECK-DAG: <<Add3:i\d+>> Add [<<Add1>>,<<Add2>>]             loop:<<Loop>>      outer_loop:none
176   /// CHECK-DAG: <<Shr:i\d+>>  Shr [<<Add3>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
177   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
178   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
179   //
180   /// CHECK-START-{ARM,ARM64}: void HaddShort.rounding_halving_add_signed_alt2(short[], short[], short[]) loop_optimization (after)
181   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                               loop:<<Loop:B\d+>> outer_loop:none
182   /// CHECK-DAG: <<Get2:d\d+>> VecLoad                               loop:<<Loop>>      outer_loop:none
183   /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:true loop:<<Loop>> outer_loop:none
184   /// CHECK-DAG:               VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>>      outer_loop:none
rounding_halving_add_signed_alt2(short[] b1, short[] b2, short[] bo)185   private static void rounding_halving_add_signed_alt2(short[] b1, short[] b2, short[] bo) {
186     int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
187     for (int i = 0; i < min_length; i++) {
188       // Computations that cancel to adding 1 also do not confuse recognition.
189       bo[i] = (short) (((b1[i] + 10) + (b2[i] - 9)) >> 1);
190     }
191   }
192 
193   /// CHECK-START: void HaddShort.rounding_halving_add_signed_alt3(short[], short[], short[]) loop_optimization (before)
194   /// CHECK-DAG: <<I1:i\d+>>   IntConstant 1                       loop:none
195   /// CHECK-DAG: <<M1:i\d+>>   IntConstant -1                      loop:none
196   /// CHECK-DAG: <<I9:i\d+>>   IntConstant 9                       loop:none
197   /// CHECK-DAG: <<M9:i\d+>>   IntConstant -9                      loop:none
198   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
199   /// CHECK-DAG: <<Get1:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
200   /// CHECK-DAG: <<Get2:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
201   /// CHECK-DAG: <<Add1:i\d+>> Add [<<Get1>>,<<I9>>]               loop:<<Loop>>      outer_loop:none
202   /// CHECK-DAG: <<Add2:i\d+>> Add [<<Get2>>,<<M9>>]               loop:<<Loop>>      outer_loop:none
203   /// CHECK-DAG: <<Add3:i\d+>> Add [<<Add1>>,<<Add2>>]             loop:<<Loop>>      outer_loop:none
204   /// CHECK-DAG: <<Sub:i\d+>>  Sub [<<Add3>>,<<M1>>]               loop:<<Loop>>      outer_loop:none
205   /// CHECK-DAG: <<Shr:i\d+>>  Shr [<<Sub>>,<<I1>>]                loop:<<Loop>>      outer_loop:none
206   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
207   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
208   //
209   /// CHECK-START-{ARM,ARM64}: void HaddShort.rounding_halving_add_signed_alt3(short[], short[], short[]) loop_optimization (after)
210   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                               loop:<<Loop:B\d+>> outer_loop:none
211   /// CHECK-DAG: <<Get2:d\d+>> VecLoad                               loop:<<Loop>>      outer_loop:none
212   /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:true loop:<<Loop>> outer_loop:none
213   /// CHECK-DAG:               VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>>      outer_loop:none
rounding_halving_add_signed_alt3(short[] b1, short[] b2, short[] bo)214   private static void rounding_halving_add_signed_alt3(short[] b1, short[] b2, short[] bo) {
215     int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
216     for (int i = 0; i < min_length; i++) {
217       // Computations that cancel to adding 1 also do not confuse recognition.
218       bo[i] = (short) (((b1[i] + 9) + (b2[i] - 9) - $inline$mone()) >> 1);
219     }
220   }
221 
222   /// CHECK-START: void HaddShort.rounding_halving_add_unsigned(short[], short[], short[]) instruction_simplifier (before)
223   /// CHECK-DAG: <<I1:i\d+>>   IntConstant 1                       loop:none
224   /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535                   loop:none
225   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
226   /// CHECK-DAG: <<Get1:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
227   /// CHECK-DAG: <<Get2:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
228   /// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<UMAX>>]             loop:<<Loop>>      outer_loop:none
229   /// CHECK-DAG: <<And2:i\d+>> And [<<UMAX>>,<<Get2>>]             loop:<<Loop>>      outer_loop:none
230   /// CHECK-DAG: <<Add1:i\d+>> Add [<<And1>>,<<And2>>]             loop:<<Loop>>      outer_loop:none
231   /// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
232   /// CHECK-DAG: <<Shr:i\d+>>  Shr [<<Add2>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
233   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
234   /// CHECK-DAG:               ArraySet [{{l\d+}},{{i\d+}},<<Cnv>>] loop:<<Loop>>      outer_loop:none
235   //
236   /// CHECK-START: void HaddShort.rounding_halving_add_unsigned(short[], short[], short[]) loop_optimization (before)
237   /// CHECK-DAG: <<I1:i\d+>>   IntConstant 1                       loop:none
238   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
239   /// CHECK-DAG: <<Get1:c\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
240   /// CHECK-DAG: <<Get2:c\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
241   /// CHECK-DAG: <<Add1:i\d+>> Add [<<Get1>>,<<Get2>>]             loop:<<Loop>>      outer_loop:none
242   /// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
243   /// CHECK-DAG: <<Shr:i\d+>>  Shr [<<Add2>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
244   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
245   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
246   //
247   /// CHECK-START-{ARM,ARM64}: void HaddShort.rounding_halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
248   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                               loop:<<Loop:B\d+>> outer_loop:none
249   /// CHECK-DAG: <<Get2:d\d+>> VecLoad                               loop:<<Loop>>      outer_loop:none
250   /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:true loop:<<Loop>> outer_loop:none
251   /// CHECK-DAG:               VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>>      outer_loop:none
rounding_halving_add_unsigned(short[] b1, short[] b2, short[] bo)252   private static void rounding_halving_add_unsigned(short[] b1, short[] b2, short[] bo) {
253     int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
254     for (int i = 0; i < min_length; i++) {
255       int v1 = b1[i] & 0xffff;
256       int v2 = b2[i] & 0xffff;
257       bo[i] = (short) ((v1 + v2 + 1) >> 1);
258     }
259   }
260 
261   /// CHECK-START: void HaddShort.rounding_halving_add_unsigned_alt(short[], short[], short[]) instruction_simplifier (before)
262   /// CHECK-DAG: <<I1:i\d+>>   IntConstant 1                       loop:none
263   /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535                   loop:none
264   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
265   /// CHECK-DAG: <<Get1:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
266   /// CHECK-DAG: <<Get2:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
267   /// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<UMAX>>]             loop:<<Loop>>      outer_loop:none
268   /// CHECK-DAG: <<And2:i\d+>> And [<<UMAX>>,<<Get2>>]             loop:<<Loop>>      outer_loop:none
269   /// CHECK-DAG: <<Add1:i\d+>> Add [<<And2>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
270   /// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<And1>>]             loop:<<Loop>>      outer_loop:none
271   /// CHECK-DAG: <<Shr:i\d+>>  Shr [<<Add2>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
272   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
273   /// CHECK-DAG:               ArraySet [{{l\d+}},{{i\d+}},<<Cnv>>] loop:<<Loop>>      outer_loop:none
274   //
275   /// CHECK-START: void HaddShort.rounding_halving_add_unsigned_alt(short[], short[], short[]) loop_optimization (before)
276   /// CHECK-DAG: <<I1:i\d+>>   IntConstant 1                       loop:none
277   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
278   /// CHECK-DAG: <<Get1:c\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
279   /// CHECK-DAG: <<Get2:c\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
280   /// CHECK-DAG: <<Add1:i\d+>> Add [<<Get2>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
281   /// CHECK-DAG: <<Add2:i\d+>> Add [<<Get1>>,<<Add1>>]             loop:<<Loop>>      outer_loop:none
282   /// CHECK-DAG: <<Shr:i\d+>>  Shr [<<Add2>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
283   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
284   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
285   //
286   /// CHECK-START-{ARM,ARM64}: void HaddShort.rounding_halving_add_unsigned_alt(short[], short[], short[]) loop_optimization (after)
287   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                               loop:<<Loop:B\d+>> outer_loop:none
288   /// CHECK-DAG: <<Get2:d\d+>> VecLoad                               loop:<<Loop>>      outer_loop:none
289   /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:true loop:<<Loop>> outer_loop:none
290   /// CHECK-DAG:               VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>>      outer_loop:none
rounding_halving_add_unsigned_alt(short[] b1, short[] b2, short[] bo)291   private static void rounding_halving_add_unsigned_alt(short[] b1, short[] b2, short[] bo) {
292     int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
293     for (int i = 0; i < min_length; i++) {
294       // Slightly different order in idiom does not confuse recognition.
295       int v1 = b1[i] & 0xffff;
296       int v2 = b2[i] & 0xffff;
297       bo[i] = (short) (v1 + (v2 + 1) >> 1);
298     }
299   }
300 
301   /// CHECK-START: void HaddShort.halving_add_signed_constant(short[], short[]) loop_optimization (before)
302   /// CHECK-DAG: <<I1:i\d+>>   IntConstant 1                       loop:none
303   /// CHECK-DAG: <<SMAX:i\d+>> IntConstant 32767                   loop:none
304   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
305   /// CHECK-DAG: <<Get:s\d+>>  ArrayGet                            loop:<<Loop>>      outer_loop:none
306   /// CHECK-DAG: <<Add:i\d+>>  Add [<<Get>>,<<SMAX>>]              loop:<<Loop>>      outer_loop:none
307   /// CHECK-DAG: <<Shr:i\d+>>  Shr [<<Add>>,<<I1>>]                loop:<<Loop>>      outer_loop:none
308   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
309   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
310   //
311   /// CHECK-START-{ARM,ARM64}: void HaddShort.halving_add_signed_constant(short[], short[]) loop_optimization (after)
312   /// CHECK-DAG: <<SMAX:i\d+>> IntConstant 32767                     loop:none
313   /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<SMAX>>]         loop:none
314   /// CHECK-DAG: <<Get:d\d+>>  VecLoad                               loop:<<Loop:B\d+>> outer_loop:none
315   /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] packed_type:Int16 rounded:false loop:<<Loop>> outer_loop:none
316   /// CHECK-DAG:               VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>>      outer_loop:none
halving_add_signed_constant(short[] b1, short[] bo)317   private static void halving_add_signed_constant(short[] b1, short[] bo) {
318     int min_length = Math.min(bo.length, b1.length);
319     for (int i = 0; i < min_length; i++) {
320       bo[i] = (short) ((b1[i] + 0x7fff) >> 1);
321     }
322   }
323 
324   /// CHECK-START: void HaddShort.halving_add_unsigned_constant(short[], short[]) instruction_simplifier (before)
325   /// CHECK-DAG: <<I1:i\d+>>   IntConstant 1                       loop:none
326   /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535                   loop:none
327   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
328   /// CHECK-DAG: <<Get:s\d+>>  ArrayGet                            loop:<<Loop>>      outer_loop:none
329   /// CHECK-DAG: <<And:i\d+>>  And [<<Get>>,<<UMAX>>]              loop:<<Loop>>      outer_loop:none
330   /// CHECK-DAG: <<Add:i\d+>>  Add [<<And>>,<<UMAX>>]              loop:<<Loop>>      outer_loop:none
331   /// CHECK-DAG: <<Shr:i\d+>>  Shr [<<Add>>,<<I1>>]                loop:<<Loop>>      outer_loop:none
332   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
333   /// CHECK-DAG:               ArraySet [{{l\d+}},{{i\d+}},<<Cnv>>] loop:<<Loop>>      outer_loop:none
334   //
335   /// CHECK-START: void HaddShort.halving_add_unsigned_constant(short[], short[]) loop_optimization (before)
336   /// CHECK-DAG: <<I1:i\d+>>   IntConstant 1                       loop:none
337   /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535                   loop:none
338   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
339   /// CHECK-DAG: <<Get:c\d+>>  ArrayGet                            loop:<<Loop>>      outer_loop:none
340   /// CHECK-DAG: <<Add:i\d+>>  Add [<<Get>>,<<UMAX>>]              loop:<<Loop>>      outer_loop:none
341   /// CHECK-DAG: <<Shr:i\d+>>  Shr [<<Add>>,<<I1>>]                loop:<<Loop>>      outer_loop:none
342   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
343   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
344   //
345   /// CHECK-START-{ARM,ARM64}: void HaddShort.halving_add_unsigned_constant(short[], short[]) loop_optimization (after)
346   /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535                     loop:none
347   /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<UMAX>>]         loop:none
348   /// CHECK-DAG: <<Get:d\d+>>  VecLoad                               loop:<<Loop:B\d+>> outer_loop:none
349   /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] packed_type:Uint16 rounded:false loop:<<Loop>> outer_loop:none
350   /// CHECK-DAG:               VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>>      outer_loop:none
halving_add_unsigned_constant(short[] b1, short[] bo)351   private static void halving_add_unsigned_constant(short[] b1, short[] bo) {
352     int min_length = Math.min(bo.length, b1.length);
353     for (int i = 0; i < min_length; i++) {
354       bo[i] = (short) (((b1[i] & 0xffff) + 0xffff) >> 1);
355     }
356   }
357 
main()358   public static void main() {
359     // Some interesting values.
360     short[] interesting = {
361       (short) 0x0000,
362       (short) 0x0001,
363       (short) 0x0002,
364       (short) 0x1234,
365       (short) 0x8000,
366       (short) 0x8001,
367       (short) 0x7fff,
368       (short) 0xffff
369     };
370     // Initialize cross-values to test all cases, and also
371     // set up some extra values to exercise the cleanup loop.
372     for (int i = 0; i < M; i++) {
373       sB1[i] = (short) i;
374       sB2[i] = interesting[i & 7];
375     }
376 
377     // Test halving add idioms.
378     halving_add_signed(sB1, sB2, sBo);
379     for (int i = 0; i < M; i++) {
380       short e = (short) ((sB1[i] + sB2[i]) >> 1);
381       expectEquals(e, sBo[i]);
382     }
383     halving_add_signed_alt(sB1, sB2, sBo);
384     for (int i = 0; i < M; i++) {
385       short e = (short) ((sB1[i] + sB2[i]) >> 1);
386       expectEquals(e, sBo[i]);
387     }
388     halving_add_unsigned(sB1, sB2, sBo);
389     for (int i = 0; i < M; i++) {
390       short e = (short) (((sB1[i] & 0xffff) + (sB2[i] & 0xffff)) >> 1);
391       expectEquals(e, sBo[i]);
392     }
393     rounding_halving_add_signed(sB1, sB2, sBo);
394     for (int i = 0; i < M; i++) {
395       short e = (short) ((sB1[i] + sB2[i] + 1) >> 1);
396       expectEquals(e, sBo[i]);
397     }
398     rounding_halving_add_signed_alt(sB1, sB2, sBo);
399     for (int i = 0; i < M; i++) {
400       short e = (short) ((sB1[i] + sB2[i] + 1) >> 1);
401       expectEquals(e, sBo[i]);
402     }
403     rounding_halving_add_signed_alt2(sB1, sB2, sBo);
404     for (int i = 0; i < M; i++) {
405       short e = (short) ((sB1[i] + sB2[i] + 1) >> 1);
406       expectEquals(e, sBo[i]);
407     }
408     rounding_halving_add_signed_alt3(sB1, sB2, sBo);
409     for (int i = 0; i < M; i++) {
410       short e = (short) ((sB1[i] + sB2[i] + 1) >> 1);
411       expectEquals(e, sBo[i]);
412     }
413     rounding_halving_add_unsigned(sB1, sB2, sBo);
414     for (int i = 0; i < M; i++) {
415       short e = (short) (((sB1[i] & 0xffff) + (sB2[i] & 0xffff) + 1) >> 1);
416       expectEquals(e, sBo[i]);
417     }
418     rounding_halving_add_unsigned_alt(sB1, sB2, sBo);
419     for (int i = 0; i < M; i++) {
420       short e = (short) (((sB1[i] & 0xffff) + (sB2[i] & 0xffff) + 1) >> 1);
421       expectEquals(e, sBo[i]);
422     }
423     halving_add_signed_constant(sB1, sBo);
424     for (int i = 0; i < M; i++) {
425       short e = (short) ((sB1[i] + 0x7fff) >> 1);
426       expectEquals(e, sBo[i]);
427     }
428     halving_add_unsigned_constant(sB1, sBo);
429     for (int i = 0; i < M; i++) {
430       short e = (short) (((sB1[i] & 0xffff) + 0xffff) >> 1);
431       expectEquals(e, sBo[i]);
432     }
433 
434     System.out.println("HaddShort passed");
435   }
436 
expectEquals(int expected, int result)437   private static void expectEquals(int expected, int result) {
438     if (expected != result) {
439       throw new Error("Expected: " + expected + ", found: " + result);
440     }
441   }
442 }
443