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 */
20public class Main {
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
29  /// CHECK-START: void Main.halving_add_signed(short[], short[], short[]) loop_optimization (before)
30  /// CHECK-DAG: <<I1:i\d+>>   IntConstant 1                       loop:none
31  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
32  /// CHECK-DAG: <<Get1:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
33  /// CHECK-DAG: <<Get2:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
34  /// CHECK-DAG: <<Add:i\d+>>  Add [<<Get1>>,<<Get2>>]             loop:<<Loop>>      outer_loop:none
35  /// CHECK-DAG: <<Shr:i\d+>>  Shr [<<Add>>,<<I1>>]                loop:<<Loop>>      outer_loop:none
36  /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
37  /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
38  //
39  /// CHECK-START-ARM64: void Main.halving_add_signed(short[], short[], short[]) loop_optimization (after)
40  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
41  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
42  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
43  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
44  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
45  private static void halving_add_signed(short[] b1, short[] b2, short[] bo) {
46    int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
47    for (int i = 0; i < min_length; i++) {
48      bo[i] = (short) ((b1[i] + b2[i]) >> 1);
49    }
50  }
51
52  /// CHECK-START: void Main.halving_add_unsigned(short[], short[], short[]) loop_optimization (before)
53  /// CHECK-DAG: <<I1:i\d+>>   IntConstant 1                       loop:none
54  /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535                   loop:none
55  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
56  /// CHECK-DAG: <<Get1:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
57  /// CHECK-DAG: <<Get2:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
58  /// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<UMAX>>]             loop:<<Loop>>      outer_loop:none
59  /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<UMAX>>]             loop:<<Loop>>      outer_loop:none
60  /// CHECK-DAG: <<Add:i\d+>>  Add [<<And1>>,<<And2>>]             loop:<<Loop>>      outer_loop:none
61  /// CHECK-DAG: <<Shr:i\d+>>  Shr [<<Add>>,<<I1>>]                loop:<<Loop>>      outer_loop:none
62  /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
63  /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
64  //
65  /// CHECK-START-ARM64: void Main.halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
66  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
67  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
68  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
69  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
70  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
71  private static void halving_add_unsigned(short[] b1, short[] b2, short[] bo) {
72    int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
73    for (int i = 0; i < min_length; i++) {
74      bo[i] = (short) (((b1[i] & 0xffff) + (b2[i] & 0xffff)) >> 1);
75    }
76  }
77
78  /// CHECK-START: void Main.rounding_halving_add_signed(short[], short[], short[]) loop_optimization (before)
79  /// CHECK-DAG: <<I1:i\d+>>   IntConstant 1                       loop:none
80  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
81  /// CHECK-DAG: <<Get1:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
82  /// CHECK-DAG: <<Get2:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
83  /// CHECK-DAG: <<Add1:i\d+>> Add [<<Get1>>,<<Get2>>]             loop:<<Loop>>      outer_loop:none
84  /// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
85  /// CHECK-DAG: <<Shr:i\d+>>  Shr [<<Add2>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
86  /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
87  /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
88  //
89  /// CHECK-START-ARM64: void Main.rounding_halving_add_signed(short[], short[], short[]) loop_optimization (after)
90  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
91  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
92  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
93  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:true loop:<<Loop>> outer_loop:none
94  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
95  private static void rounding_halving_add_signed(short[] b1, short[] b2, short[] bo) {
96    int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
97    for (int i = 0; i < min_length; i++) {
98      bo[i] = (short) ((b1[i] + b2[i] + 1) >> 1);
99    }
100  }
101
102  /// CHECK-START: void Main.rounding_halving_add_unsigned(short[], short[], short[]) loop_optimization (before)
103  /// CHECK-DAG: <<I1:i\d+>>   IntConstant 1                       loop:none
104  /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535                   loop:none
105  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
106  /// CHECK-DAG: <<Get1:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
107  /// CHECK-DAG: <<Get2:s\d+>> ArrayGet                            loop:<<Loop>>      outer_loop:none
108  /// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<UMAX>>]             loop:<<Loop>>      outer_loop:none
109  /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<UMAX>>]             loop:<<Loop>>      outer_loop:none
110  /// CHECK-DAG: <<Add1:i\d+>> Add [<<And1>>,<<And2>>]             loop:<<Loop>>      outer_loop:none
111  /// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
112  /// CHECK-DAG: <<Shr:i\d+>>  Shr [<<Add2>>,<<I1>>]               loop:<<Loop>>      outer_loop:none
113  /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
114  /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
115  //
116  /// CHECK-START-ARM64: void Main.rounding_halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
117  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
118  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
119  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
120  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none
121  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
122  private static void rounding_halving_add_unsigned(short[] b1, short[] b2, short[] bo) {
123    int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
124    for (int i = 0; i < min_length; i++) {
125      bo[i] = (short) (((b1[i] & 0xffff) + (b2[i] & 0xffff) + 1) >> 1);
126    }
127  }
128
129  /// CHECK-START: void Main.halving_add_signed_constant(short[], short[]) loop_optimization (before)
130  /// CHECK-DAG: <<I1:i\d+>>   IntConstant 1                       loop:none
131  /// CHECK-DAG: <<SMAX:i\d+>> IntConstant 32767                   loop:none
132  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
133  /// CHECK-DAG: <<Get:s\d+>>  ArrayGet                            loop:<<Loop>>      outer_loop:none
134  /// CHECK-DAG: <<Add:i\d+>>  Add [<<Get>>,<<SMAX>>]              loop:<<Loop>>      outer_loop:none
135  /// CHECK-DAG: <<Shr:i\d+>>  Shr [<<Add>>,<<I1>>]                loop:<<Loop>>      outer_loop:none
136  /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
137  /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
138  //
139  /// CHECK-START-ARM64: void Main.halving_add_signed_constant(short[], short[]) loop_optimization (after)
140  /// CHECK-DAG: <<SMAX:i\d+>> IntConstant 32767                    loop:none
141  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<SMAX>>]        loop:none
142  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
143  /// CHECK-DAG: <<Get:d\d+>>  VecLoad                              loop:<<Loop>>      outer_loop:none
144  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
145  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
146  private static void halving_add_signed_constant(short[] b1, short[] bo) {
147    int min_length = Math.min(bo.length, b1.length);
148    for (int i = 0; i < min_length; i++) {
149      bo[i] = (short) ((b1[i] + 0x7fff) >> 1);
150    }
151  }
152
153  /// CHECK-START: void Main.halving_add_unsigned_constant(short[], short[]) loop_optimization (before)
154  /// CHECK-DAG: <<I1:i\d+>>   IntConstant 1                       loop:none
155  /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535                   loop:none
156  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
157  /// CHECK-DAG: <<Get:s\d+>>  ArrayGet                            loop:<<Loop>>      outer_loop:none
158  /// CHECK-DAG: <<And:i\d+>>  And [<<Get>>,<<UMAX>>]              loop:<<Loop>>      outer_loop:none
159  /// CHECK-DAG: <<Add:i\d+>>  Add [<<And>>,<<UMAX>>]              loop:<<Loop>>      outer_loop:none
160  /// CHECK-DAG: <<Shr:i\d+>>  Shr [<<Add>>,<<I1>>]                loop:<<Loop>>      outer_loop:none
161  /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
162  /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
163  //
164  /// CHECK-START-ARM64: void Main.halving_add_unsigned_constant(short[], short[]) loop_optimization (after)
165  /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535                    loop:none
166  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<UMAX>>]        loop:none
167  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
168  /// CHECK-DAG: <<Get:d\d+>>  VecLoad                              loop:<<Loop>>      outer_loop:none
169  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
170  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
171  private static void halving_add_unsigned_constant(short[] b1, short[] bo) {
172    int min_length = Math.min(bo.length, b1.length);
173    for (int i = 0; i < min_length; i++) {
174      bo[i] = (short) (((b1[i] & 0xffff) + 0xffff) >> 1);
175    }
176  }
177
178  public static void main(String[] args) {
179    // Some interesting values.
180    short[] interesting = {
181      (short) 0x0000,
182      (short) 0x0001,
183      (short) 0x0002,
184      (short) 0x1234,
185      (short) 0x8000,
186      (short) 0x8001,
187      (short) 0x7fff,
188      (short) 0xffff
189    };
190    // Initialize cross-values to test all cases, and also
191    // set up some extra values to exercise the cleanup loop.
192    for (int i = 0; i < M; i++) {
193      sB1[i] = (short) i;
194      sB2[i] = interesting[i & 7];
195    }
196
197    // Test halving add idioms.
198    halving_add_signed(sB1, sB2, sBo);
199    for (int i = 0; i < M; i++) {
200      short e = (short) ((sB1[i] + sB2[i]) >> 1);
201      expectEquals(e, sBo[i]);
202    }
203    halving_add_unsigned(sB1, sB2, sBo);
204    for (int i = 0; i < M; i++) {
205      short e = (short) (((sB1[i] & 0xffff) + (sB2[i] & 0xffff)) >> 1);
206      expectEquals(e, sBo[i]);
207    }
208    rounding_halving_add_signed(sB1, sB2, sBo);
209    for (int i = 0; i < M; i++) {
210      short e = (short) ((sB1[i] + sB2[i] + 1) >> 1);
211      expectEquals(e, sBo[i]);
212    }
213    rounding_halving_add_unsigned(sB1, sB2, sBo);
214    for (int i = 0; i < M; i++) {
215      short e = (short) (((sB1[i] & 0xffff) + (sB2[i] & 0xffff) + 1) >> 1);
216      expectEquals(e, sBo[i]);
217    }
218    halving_add_signed_constant(sB1, sBo);
219    for (int i = 0; i < M; i++) {
220      short e = (short) ((sB1[i] + 0x7fff) >> 1);
221      expectEquals(e, sBo[i]);
222    }
223    halving_add_unsigned_constant(sB1, sBo);
224    for (int i = 0; i < M; i++) {
225      short e = (short) (((sB1[i] & 0xffff) + 0xffff) >> 1);
226      expectEquals(e, sBo[i]);
227    }
228
229    System.out.println("passed");
230  }
231
232  private static void expectEquals(int expected, int result) {
233    if (expected != result) {
234      throw new Error("Expected: " + expected + ", found: " + result);
235    }
236  }
237}
238