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 public class SimdSadInt {
21 
22   /// CHECK-START: int SimdSadInt.sadInt2Int(int[], int[]) loop_optimization (before)
23   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
24   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
25   /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
26   /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
27   /// CHECK-DAG: <<Get1:i\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
28   /// CHECK-DAG: <<Get2:i\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
29   /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get1>>,<<Get2>>]        loop:<<Loop>>      outer_loop:none
30   /// CHECK-DAG: <<Intrin:i\d+>> Abs [<<Sub>>]                  loop:<<Loop>>      outer_loop:none
31   /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
32   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
33   //
34   /// CHECK-START-{ARM,ARM64}: int SimdSadInt.sadInt2Int(int[], int[]) loop_optimization (after)
35   /// CHECK-DAG: <<Cons:i\d+>>   IntConstant {{2|4}}                        loop:none
36   /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [{{i\d+}}]                   loop:none
37   /// CHECK-DAG: <<Phi:d\d+>>    Phi [<<Set>>,{{d\d+}}]                     loop:<<Loop:B\d+>> outer_loop:none
38   /// CHECK-DAG: <<Ld1:d\d+>>    VecLoad [{{l\d+}},<<I:i\d+>>]              loop:<<Loop>>      outer_loop:none
39   /// CHECK-DAG: <<Ld2:d\d+>>    VecLoad [{{l\d+}},<<I>>]                   loop:<<Loop>>      outer_loop:none
40   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi>>,<<Ld1>>,<<Ld2>>] loop:<<Loop>> outer_loop:none
41   /// CHECK-DAG:                 Add [<<I>>,<<Cons>>]                       loop:<<Loop>> outer_loop:none
sadInt2Int(int[] x, int[] y)42   private static int sadInt2Int(int[] x, int[] y) {
43     int min_length = Math.min(x.length, y.length);
44     int sad = 0;
45     for (int i = 0; i < min_length; i++) {
46       sad += Math.abs(x[i] - y[i]);
47     }
48     return sad;
49   }
50 
51   /// CHECK-START: int SimdSadInt.sadInt2IntAlt(int[], int[]) loop_optimization (before)
52   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                       loop:none
53   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                       loop:none
54   /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]            loop:<<Loop:B\d+>> outer_loop:none
55   /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]            loop:<<Loop>>      outer_loop:none
56   /// CHECK-DAG: <<Get1:i\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]        loop:<<Loop>>      outer_loop:none
57   /// CHECK-DAG: <<Get2:i\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]        loop:<<Loop>>      outer_loop:none
58   /// CHECK-DAG: <<Sub1:i\d+>>   Sub [<<Get2>>,<<Get1>>]             loop:<<Loop>>      outer_loop:none
59   /// CHECK-DAG: <<Sub2:i\d+>>   Sub [<<Get1>>,<<Get2>>]             loop:<<Loop>>      outer_loop:none
60   /// CHECK-DAG: <<Select:i\d+>> Select [<<Sub2>>,<<Sub1>>,{{z\d+}}] loop:<<Loop>>      outer_loop:none
61   /// CHECK-DAG:                 Add [<<Phi2>>,<<Select>>]           loop:<<Loop>>      outer_loop:none
62   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]            loop:<<Loop>>      outer_loop:none
63   //
64   // No ABS? No SAD!
65   //
66   /// CHECK-START: int SimdSadInt.sadInt2IntAlt(int[], int[]) loop_optimization (after)
67   /// CHECK-NOT: VecSADAccumulate
sadInt2IntAlt(int[] x, int[] y)68   private static int sadInt2IntAlt(int[] x, int[] y) {
69     int min_length = Math.min(x.length, y.length);
70     int sad = 0;
71     for (int i = 0; i < min_length; i++) {
72       int s = x[i];
73       int p = y[i];
74       sad += s >= p ? s - p : p - s;
75     }
76     return sad;
77   }
78 
79   /// CHECK-START: int SimdSadInt.sadInt2IntAlt2(int[], int[]) loop_optimization (before)
80   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
81   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
82   /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
83   /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
84   /// CHECK-DAG: <<Get1:i\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
85   /// CHECK-DAG: <<Get2:i\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
86   /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Get1>>,<<Get2>>]        loop:<<Loop>>      outer_loop:none
87   /// CHECK-DAG: <<Intrin:i\d+>> Abs [<<Sub>>]                  loop:<<Loop>>      outer_loop:none
88   /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
89   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
90   //
91   /// CHECK-START-{ARM,ARM64}: int SimdSadInt.sadInt2IntAlt2(int[], int[]) loop_optimization (after)
92   /// CHECK-DAG: <<Cons:i\d+>>   IntConstant {{2|4}}                        loop:none
93   /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [{{i\d+}}]                   loop:none
94   /// CHECK-DAG: <<Phi:d\d+>>    Phi [<<Set>>,{{d\d+}}]                     loop:<<Loop:B\d+>> outer_loop:none
95   /// CHECK-DAG: <<Ld1:d\d+>>    VecLoad [{{l\d+}},<<I:i\d+>>]              loop:<<Loop>>      outer_loop:none
96   /// CHECK-DAG: <<Ld2:d\d+>>    VecLoad [{{l\d+}},<<I>>]                   loop:<<Loop>>      outer_loop:none
97   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi>>,<<Ld1>>,<<Ld2>>] loop:<<Loop>> outer_loop:none
98   /// CHECK-DAG:                 Add [<<I>>,<<Cons>>]                       loop:<<Loop>> outer_loop:none
sadInt2IntAlt2(int[] x, int[] y)99   private static int sadInt2IntAlt2(int[] x, int[] y) {
100     int min_length = Math.min(x.length, y.length);
101     int sad = 0;
102     for (int i = 0; i < min_length; i++) {
103       int s = x[i];
104       int p = y[i];
105       int m = s - p;
106       if (m < 0) m = -m;
107       sad += m;
108     }
109     return sad;
110   }
111 
112   /// CHECK-START: long SimdSadInt.sadInt2Long(int[], int[]) loop_optimization (before)
113   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
114   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
115   /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 0                 loop:none
116   /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
117   /// CHECK-DAG: <<Phi2:j\d+>>   Phi [<<ConsL>>,{{j\d+}}]       loop:<<Loop>>      outer_loop:none
118   /// CHECK-DAG: <<Get1:i\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
119   /// CHECK-DAG: <<Get2:i\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
120   /// CHECK-DAG: <<Cnv1:j\d+>>   TypeConversion [<<Get1>>]      loop:<<Loop>>      outer_loop:none
121   /// CHECK-DAG: <<Cnv2:j\d+>>   TypeConversion [<<Get2>>]      loop:<<Loop>>      outer_loop:none
122   /// CHECK-DAG: <<Sub:j\d+>>    Sub [<<Cnv1>>,<<Cnv2>>]        loop:<<Loop>>      outer_loop:none
123   /// CHECK-DAG: <<Intrin:j\d+>> Abs [<<Sub>>]                  loop:<<Loop>>      outer_loop:none
124   /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
125   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
126   //
127   /// CHECK-START-ARM64: long SimdSadInt.sadInt2Long(int[], int[]) loop_optimization (after)
128   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
129   /// CHECK-DAG: <<Cons4:i\d+>>  IntConstant 4                  loop:none
130   /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 0                 loop:none
131   /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsL>>]      loop:none
132   /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
133   /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
134   /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
135   /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
136   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
137   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons4>>]       loop:<<Loop>>      outer_loop:none
sadInt2Long(int[] x, int[] y)138   private static long sadInt2Long(int[] x, int[] y) {
139     int min_length = Math.min(x.length, y.length);
140     long sad = 0;
141     for (int i = 0; i < min_length; i++) {
142       long s = x[i];
143       long p = y[i];
144       sad += Math.abs(s - p);
145     }
146     return sad;
147   }
148 
149   /// CHECK-START: long SimdSadInt.sadInt2LongAt1(int[], int[]) loop_optimization (before)
150   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
151   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
152   /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 1                 loop:none
153   /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
154   /// CHECK-DAG: <<Phi2:j\d+>>   Phi [<<ConsL>>,{{j\d+}}]       loop:<<Loop>>      outer_loop:none
155   /// CHECK-DAG: <<Get1:i\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
156   /// CHECK-DAG: <<Get2:i\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
157   /// CHECK-DAG: <<Cnv1:j\d+>>   TypeConversion [<<Get1>>]      loop:<<Loop>>      outer_loop:none
158   /// CHECK-DAG: <<Cnv2:j\d+>>   TypeConversion [<<Get2>>]      loop:<<Loop>>      outer_loop:none
159   /// CHECK-DAG: <<Sub:j\d+>>    Sub [<<Cnv1>>,<<Cnv2>>]        loop:<<Loop>>      outer_loop:none
160   /// CHECK-DAG: <<Intrin:j\d+>> Abs [<<Sub>>]                  loop:<<Loop>>      outer_loop:none
161   /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
162   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
163   //
164   /// CHECK-START-ARM64: long SimdSadInt.sadInt2LongAt1(int[], int[]) loop_optimization (after)
165   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
166   /// CHECK-DAG: <<Cons4:i\d+>>  IntConstant 4                  loop:none
167   /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 1                 loop:none
168   /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsL>>]      loop:none
169   /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
170   /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
171   /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
172   /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
173   /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
174   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons4>>]       loop:<<Loop>>      outer_loop:none
sadInt2LongAt1(int[] x, int[] y)175   private static long sadInt2LongAt1(int[] x, int[] y) {
176     int min_length = Math.min(x.length, y.length);
177     long sad = 1;  // starts at 1
178     for (int i = 0; i < min_length; i++) {
179       long s = x[i];
180       long p = y[i];
181       sad += Math.abs(s - p);
182     }
183     return sad;
184   }
185 
main()186   public static void main() {
187     // Cross-test the two most extreme values individually.
188     int[] x = { 0, Integer.MAX_VALUE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
189     int[] y = { 0, Integer.MIN_VALUE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
190     expectEquals(1, sadInt2Int(x, y));
191     expectEquals(1, sadInt2Int(y, x));
192     expectEquals(-1, sadInt2IntAlt(x, y));
193     expectEquals(-1, sadInt2IntAlt(y, x));
194     expectEquals(1, sadInt2IntAlt2(x, y));
195     expectEquals(1, sadInt2IntAlt2(y, x));
196     expectEquals(4294967295L, sadInt2Long(x, y));
197     expectEquals(4294967295L, sadInt2Long(y, x));
198     expectEquals(4294967296L, sadInt2LongAt1(x, y));
199     expectEquals(4294967296L, sadInt2LongAt1(y, x));
200 
201     // Use cross-values for the interesting values.
202     int[] interesting = {
203       0x00000000, 0x00000001, 0x00007fff, 0x00008000, 0x00008001, 0x0000ffff,
204       0x00010000, 0x00010001, 0x00017fff, 0x00018000, 0x00018001, 0x0001ffff,
205       0x7fff0000, 0x7fff0001, 0x7fff7fff, 0x7fff8000, 0x7fff8001, 0x7fffffff,
206       0x80000000, 0x80000001, 0x80007fff, 0x80008000, 0x80008001, 0x8000ffff,
207       0x80010000, 0x80010001, 0x80017fff, 0x80018000, 0x80018001, 0x8001ffff,
208       0xffff0000, 0xffff0001, 0xffff7fff, 0xffff8000, 0xffff8001, 0xffffffff
209     };
210     int n = interesting.length;
211     int m = n * n + 1;
212     x = new int[m];
213     y = new int[m];
214     int k = 0;
215     for (int i = 0; i < n; i++) {
216       for (int j = 0; j < n; j++) {
217         x[k] = interesting[i];
218         y[k] = interesting[j];
219         k++;
220       }
221     }
222     x[k] = 10;
223     y[k] = 2;
224     expectEquals(8, sadInt2Int(x, y));
225     expectEquals(-13762600, sadInt2IntAlt(x, y));
226     expectEquals(8, sadInt2IntAlt2(x, y));
227     expectEquals(2010030931928L, sadInt2Long(x, y));
228     expectEquals(2010030931929L, sadInt2LongAt1(x, y));
229 
230     System.out.println("SimdSadInt passed");
231   }
232 
expectEquals(int expected, int result)233   private static void expectEquals(int expected, int result) {
234     if (expected != result) {
235       throw new Error("Expected: " + expected + ", found: " + result);
236     }
237   }
238 
expectEquals(long expected, long result)239   private static void expectEquals(long expected, long result) {
240     if (expected != result) {
241       throw new Error("Expected: " + expected + ", found: " + result);
242     }
243   }
244 }
245