1 /*
  2  * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  *
 23  */
 24 
 25 /*
 26  * @test
 27  * @bug 8304042
 28  * @summary Test some examples with independent packs with cyclic dependency
 29  *          between the packs.
 30  * @requires vm.bits == 64
 31  * @requires vm.compiler2.enabled
 32  * @modules java.base/jdk.internal.misc
 33  * @library /test/lib /
 34  * @run driver compiler.loopopts.superword.TestIndependentPacksWithCyclicDependency
 35  */
 36 
 37 package compiler.loopopts.superword;
 38 
 39 import jdk.internal.misc.Unsafe;
 40 import jdk.test.lib.Asserts;
 41 import compiler.lib.ir_framework.*;
 42 
 43 public class TestIndependentPacksWithCyclicDependency {
 44     static final int RANGE = 1024;
 45     static final int ITER  = 10_000;
 46     static Unsafe unsafe = Unsafe.getUnsafe();
 47 
 48     int[]   goldI0 = new int[RANGE];
 49     float[] goldF0 = new float[RANGE];
 50     int[]   goldI1 = new int[RANGE];
 51     float[] goldF1 = new float[RANGE];
 52     int[]   goldI2 = new int[RANGE];
 53     float[] goldF2 = new float[RANGE];
 54     int[]   goldI3 = new int[RANGE];
 55     float[] goldF3 = new float[RANGE];
 56     int[]   goldI4 = new int[RANGE];
 57     float[] goldF4 = new float[RANGE];
 58     int[]   goldI5 = new int[RANGE];
 59     float[] goldF5 = new float[RANGE];
 60     int[]   goldI6 = new int[RANGE];
 61     float[] goldF6 = new float[RANGE];
 62     long[]  goldL6 = new long[RANGE];
 63     int[]   goldI7 = new int[RANGE];
 64     float[] goldF7 = new float[RANGE];
 65     long[]  goldL7 = new long[RANGE];
 66     int[]   goldI8 = new int[RANGE];
 67     float[] goldF8 = new float[RANGE];
 68     long[]  goldL8 = new long[RANGE];
 69     int[]   goldI9 = new int[RANGE];
 70     float[] goldF9 = new float[RANGE];
 71     long[]  goldL9 = new long[RANGE];
 72     int[]   goldI10 = new int[RANGE];
 73     float[] goldF10 = new float[RANGE];
 74     long[]  goldL10 = new long[RANGE];
 75 
 76     public static void main(String args[]) {
 77         TestFramework.runWithFlags("--add-modules", "java.base", "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED",
 78                                    "-XX:CompileCommand=compileonly,compiler.loopopts.superword.TestIndependentPacksWithCyclicDependency::test*",
 79                                    "-XX:CompileCommand=compileonly,compiler.loopopts.superword.TestIndependentPacksWithCyclicDependency::verify",
 80                                    "-XX:CompileCommand=compileonly,compiler.loopopts.superword.TestIndependentPacksWithCyclicDependency::init",
 81                                    "-XX:LoopUnrollLimit=1000");
 82     }
 83 
 84     TestIndependentPacksWithCyclicDependency() {
 85         // compute the gold standard in interpreter mode
 86         init(goldI0, goldF0);
 87         test0(goldI0, goldI0, goldF0, goldF0);
 88         init(goldI1, goldF1);
 89         test1(goldI1, goldI1, goldF1, goldF1);
 90         init(goldI2, goldF2);
 91         test2(goldI2, goldI2, goldF2, goldF2);
 92         init(goldI3, goldF3);
 93         test3(goldI3, goldI3, goldF3, goldF3);
 94         init(goldI4, goldF4);
 95         test4(goldI4, goldI4, goldF4, goldF4);
 96         init(goldI5, goldF5);
 97         test5(goldI5, goldI5, goldF5, goldF5);
 98         init(goldI6, goldF6, goldL6);
 99         test6(goldI6, goldI6, goldF6, goldF6, goldL6, goldL6);
100         init(goldI7, goldF7, goldL7);
101         test7(goldI7, goldI7, goldF7, goldF7, goldL7, goldL7);
102         init(goldI8, goldF8, goldL8);
103         test8(goldI8, goldI8, goldF8, goldF8, goldL8, goldL8);
104         init(goldI9, goldF9, goldL9);
105         test9(goldI9, goldI9, goldF9, goldF9, goldL9, goldL9);
106         init(goldI10, goldF10, goldL10);
107         test10(goldI10, goldI10, goldF10, goldF10, goldL10, goldL10);
108     }
109 
110     @Run(test = "test0")
111     @Warmup(100)
112     public void runTest0() {
113         int[] dataI = new int[RANGE];
114         float[] dataF = new float[RANGE];
115         init(dataI, dataF);
116         test0(dataI, dataI, dataF, dataF);
117         verify("test0", dataI, goldI0);
118         verify("test0", dataF, goldF0);
119     }
120 
121     @Test
122     @IR(counts = {IRNode.ADD_VI, "> 0", IRNode.MUL_VF, "> 0"},
123         applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
124     static void test0(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb) {
125         for (int i = 0; i < RANGE; i+=2) {
126             // Hand-unrolled 2x. Int and Float slice are completely separate.
127             dataIb[i+0] = dataIa[i+0] + 3;
128             dataIb[i+1] = dataIa[i+1] + 3;
129             dataFb[i+0] = dataFa[i+0] * 1.3f;
130             dataFb[i+1] = dataFa[i+1] * 1.3f;
131         }
132     }
133 
134     @Run(test = "test1")
135     @Warmup(100)
136     public void runTest1() {
137         int[] dataI = new int[RANGE];
138         float[] dataF = new float[RANGE];
139         init(dataI, dataF);
140         test1(dataI, dataI, dataF, dataF);
141         verify("test1", dataI, goldI1);
142         verify("test1", dataF, goldF1);
143     }
144 
145     @Test
146     @IR(counts = {IRNode.ADD_VI, "> 0", IRNode.MUL_VF, "> 0", IRNode.VECTOR_CAST_F2I, "> 0", IRNode.VECTOR_CAST_I2F, "> 0"},
147         applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"})
148     static void test1(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb) {
149         for (int i = 0; i < RANGE; i+=2) {
150             // Hand-unrolled 2x. Converst to and from. StoreF -> LoadF dependency.
151             dataFa[i+0] = dataIa[i+0] + 3;
152             dataFa[i+1] = dataIa[i+1] + 3;
153             dataIb[i+0] = (int)(dataFb[i+0] * 1.3f);
154             dataIb[i+1] = (int)(dataFb[i+1] * 1.3f);
155         }
156     }
157 
158     @Run(test = "test2")
159     public void runTest2() {
160         int[] dataI = new int[RANGE];
161         float[] dataF = new float[RANGE];
162         init(dataI, dataF);
163         test2(dataI, dataI, dataF, dataF);
164         verify("test2", dataI, goldI2);
165         verify("test2", dataF, goldF2);
166     }
167 
168     @Test
169     @IR(counts = {IRNode.ADD_VI, "> 0", IRNode.MUL_VI, "> 0"},
170         applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
171     static void test2(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb) {
172         for (int i = 0; i < RANGE; i+=2) {
173             // int and float arrays are two slices. But we pretend both are of type int.
174             unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, dataIa[i+0] + 1);
175             unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, dataIa[i+1] + 1);
176             dataIb[i+0] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0);
177             dataIb[i+1] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4);
178         }
179     }
180 
181     @Run(test = "test3")
182     @Warmup(100)
183     public void runTest3() {
184         int[] dataI = new int[RANGE];
185         float[] dataF = new float[RANGE];
186         init(dataI, dataF);
187         test3(dataI, dataI, dataF, dataF);
188         verify("test3", dataI, goldI3);
189         verify("test3", dataF, goldF3);
190     }
191 
192     @Test
193     @IR(counts = {IRNode.ADD_VI, "> 0", IRNode.MUL_VF, "> 0"},
194         applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
195     static void test3(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb) {
196         for (int i = 0; i < RANGE; i+=2) {
197             // Inversion of orders. But because we operate on separate slices, this should
198             // safely vectorize. It should detect that each line is independent, so it can
199             // reorder them.
200             dataIb[i+0] = dataIa[i+0] + 3;
201             dataFb[i+1] = dataFa[i+1] * 1.3f;
202             dataFb[i+0] = dataFa[i+0] * 1.3f;
203             dataIb[i+1] = dataIa[i+1] + 3;
204         }
205     }
206 
207     @Run(test = "test4")
208     @Warmup(100)
209     public void runTest4() {
210         int[] dataI = new int[RANGE];
211         float[] dataF = new float[RANGE];
212         init(dataI, dataF);
213         test4(dataI, dataI, dataF, dataF);
214         verify("test4", dataI, goldI4);
215         verify("test4", dataF, goldF4);
216     }
217 
218     @Test
219     static void test4(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb) {
220         for (int i = 0; i < RANGE; i+=2) {
221             // same as test1, except that reordering leads to different semantics
222             // [A,B] and [X,Y] are both packs that are internally independent
223             // But we have dependencies A -> X (StoreF -> LoadF)
224             //                      and Y -> B (StoreI -> LoadI)
225             // Hence the two packs have a cyclic dependency, we cannot schedule
226             // one before the other.
227             dataFa[i+0] = dataIa[i+0] + 3;            // A
228             dataIb[i+0] = (int)(dataFb[i+0] * 1.3f);  // X
229             dataIb[i+1] = (int)(dataFb[i+1] * 1.3f);  // Y
230             dataFa[i+1] = dataIa[i+1] + 3;            // B
231         }
232     }
233 
234     @Run(test = "test5")
235     public void runTest5() {
236         int[] dataI = new int[RANGE];
237         float[] dataF = new float[RANGE];
238         init(dataI, dataF);
239         test5(dataI, dataI, dataF, dataF);
240         verify("test5", dataI, goldI5);
241         verify("test5", dataF, goldF5);
242     }
243 
244     @Test
245     static void test5(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb) {
246         for (int i = 0; i < RANGE; i+=2) {
247             // same as test2, except that reordering leads to different semantics
248             // explanation analogue to test4
249             unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, dataIa[i+0] + 1); // A
250             dataIb[i+0] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0); // X
251             dataIb[i+1] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4); // Y
252             unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, dataIa[i+1] + 1); // B
253         }
254     }
255 
256     @Run(test = "test6")
257     public void runTest6() {
258         int[]   dataI = new int[RANGE];
259         float[] dataF = new float[RANGE];
260         long[]  dataL = new long[RANGE];
261         init(dataI, dataF, dataL);
262         test6(dataI, dataI, dataF, dataF, dataL, dataL);
263         verify("test6", dataI, goldI6);
264         verify("test6", dataF, goldF6);
265         verify("test6", dataL, goldL6);
266     }
267 
268     @Test
269     @IR(counts = {IRNode.ADD_VI, "> 0", IRNode.MUL_VI, "> 0", IRNode.ADD_VF, "> 0"},
270         applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"})
271     static void test6(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb,
272                       long[] dataLa, long[] dataLb) {
273         for (int i = 0; i < RANGE; i+=2) {
274             // Chain of parallelizable op and conversion
275             int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0) + 3;
276             int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4) + 3;
277             unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, v00);
278             unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, v01);
279             int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0) * 45;
280             int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4) * 45;
281             unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0, v10);
282             unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4, v11);
283             float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0) + 0.55f;
284             float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4) + 0.55f;
285             unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0, v20);
286             unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4, v21);
287         }
288     }
289 
290     @Run(test = "test7")
291     public void runTest7() {
292         int[]   dataI = new int[RANGE];
293         float[] dataF = new float[RANGE];
294         long[]  dataL = new long[RANGE];
295         init(dataI, dataF, dataL);
296         test7(dataI, dataI, dataF, dataF, dataL, dataL);
297         verify("test7", dataI, goldI7);
298         verify("test7", dataF, goldF7);
299         verify("test7", dataL, goldL7);
300     }
301 
302     @Test
303     static void test7(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb,
304                       long[] dataLa, long[] dataLb) {
305         for (int i = 0; i < RANGE; i+=2) {
306             // Cycle involving 3 memory slices
307             int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0) + 3;
308             unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, v00);
309             int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0) * 45;
310             int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4) * 45;
311             unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0, v10);
312             unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4, v11);
313             float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0) + 0.55f;
314             float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4) + 0.55f;
315             unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0, v20);
316             unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4, v21);
317             int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4) + 3; // moved down
318             unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, v01);
319         }
320     }
321 
322 
323     @Run(test = "test8")
324     public void runTest8() {
325         int[]   dataI = new int[RANGE];
326         float[] dataF = new float[RANGE];
327         long[]  dataL = new long[RANGE];
328         init(dataI, dataF, dataL);
329         test8(dataI, dataI, dataF, dataF, dataL, dataL);
330         verify("test8", dataI, goldI8);
331         verify("test8", dataF, goldF8);
332         verify("test8", dataL, goldL8);
333     }
334 
335     @Test
336     static void test8(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb,
337                       long[] dataLa, long[] dataLb) {
338         for (int i = 0; i < RANGE; i+=2) {
339             // 2-cycle, with more ops after
340             int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0) + 3;
341             unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, v00);
342             int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0) * 45;
343             int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4) * 45;
344             unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0, v10);
345             unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4, v11);
346             int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4) + 3;
347             unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, v01);
348             // more stuff after
349             float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0) + 0.55f;
350             float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4) + 0.55f;
351             unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0, v20);
352             unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4, v21);
353         }
354     }
355 
356     @Run(test = "test9")
357     public void runTest9() {
358         int[]   dataI = new int[RANGE];
359         float[] dataF = new float[RANGE];
360         long[]  dataL = new long[RANGE];
361         init(dataI, dataF, dataL);
362         test9(dataI, dataI, dataF, dataF, dataL, dataL);
363         verify("test9", dataI, goldI9);
364         verify("test9", dataF, goldF9);
365         verify("test9", dataL, goldL9);
366     }
367 
368     @Test
369     static void test9(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb,
370                       long[] dataLa, long[] dataLb) {
371         for (int i = 0; i < RANGE; i+=2) {
372             // 2-cycle, with more stuff before
373             float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0) + 0.55f;
374             float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4) + 0.55f;
375             unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0, v20);
376             unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4, v21);
377             // 2-cycle
378             int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0) + 3;
379             unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, v00);
380             int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0) * 45;
381             int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4) * 45;
382             unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0, v10);
383             unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4, v11);
384             int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4) + 3;
385             unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, v01);
386         }
387     }
388 
389     @Run(test = "test10")
390     public void runTest10() {
391         int[]   dataI = new int[RANGE];
392         float[] dataF = new float[RANGE];
393         long[]  dataL = new long[RANGE];
394         init(dataI, dataF, dataL);
395         test10(dataI, dataI, dataF, dataF, dataL, dataL);
396         verify("test10", dataI, goldI10);
397         verify("test10", dataF, goldF10);
398         verify("test10", dataL, goldL10);
399     }
400 
401     @Test
402     static void test10(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb,
403                       long[] dataLa, long[] dataLb) {
404         for (int i = 0; i < RANGE; i+=2) {
405             // This creates the following graph before SuperWord:
406             //
407             // A -> R -> U
408             //      S -> V -> B
409             //
410             // SuperWord analyzes the graph, and sees that [A,B] and [U,V]
411             // are adjacent, isomorphic and independent packs. However,
412             // [R,S] are not isomorphic (R mul, S add).
413             // So it vectorizes [A,B] and [U,V] this gives us this graph:
414             //
415             //        -> R
416             //  [A,B]      -> [U,V] -+
417             //    ^   -> S           |
418             //    |                  |
419             //    +------------------+
420             //
421             // The cycle thus does not only go via packs, but also scalar ops.
422             //
423             int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0) + 3; // A
424             unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, v00);
425             int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0) * 45; // R: constant mismatch
426             int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4) + 43; // S
427             unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0, v10);
428             unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4, v11);
429             float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0) + 0.55f; // U
430             float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4) + 0.55f; // V
431             unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0, v20);
432             unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4, v21);
433             int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4) + 3; // B: moved down
434             unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, v01);
435         }
436     }
437 
438     static void init(int[] dataI, float[] dataF) {
439         for (int i = 0; i < RANGE; i++) {
440             dataI[i] = i + 1;
441             dataF[i] = i + 0.1f;
442         }
443     }
444 
445     static void init(int[] dataI, float[] dataF, long[] dataL) {
446         for (int i = 0; i < RANGE; i++) {
447             dataI[i] = i + 1;
448             dataF[i] = i + 0.1f;
449             dataL[i] = i + 1;
450         }
451     }
452 
453     static void verify(String name, int[] data, int[] gold) {
454         for (int i = 0; i < RANGE; i++) {
455             if (data[i] != gold[i]) {
456                 throw new RuntimeException(" Invalid " + name + " result: dataI[" + i + "]: " + data[i] + " != " + gold[i]);
457             }
458         }
459     }
460 
461     static void verify(String name, float[] data, float[] gold) {
462         for (int i = 0; i < RANGE; i++) {
463             int datav = unsafe.getInt(data, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i);
464             int goldv = unsafe.getInt(gold, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i);
465             if (datav != goldv) {
466                 throw new RuntimeException(" Invalid " + name + " result: dataF[" + i + "]: " + datav + " != " + goldv);
467             }
468         }
469     }
470 
471     static void verify(String name, long[] data, long[] gold) {
472         for (int i = 0; i < RANGE; i++) {
473             if (data[i] != gold[i]) {
474                 throw new RuntimeException(" Invalid " + name + " result: dataL[" + i + "]: " + data[i] + " != " + gold[i]);
475             }
476         }
477     }
478 }
479