1/*
2 * Copyright (c) 2018, 2020, 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 * @test
26 * @modules jdk.incubator.vector
27 * @run testng/othervm -ea -esa -Xbatch $vectorteststype$
28 */
29
30#warn This file is preprocessed before being compiled
31
32import jdk.incubator.vector.VectorShape;
33import jdk.incubator.vector.VectorSpecies;
34import jdk.incubator.vector.VectorShuffle;
35import jdk.incubator.vector.VectorMask;
36import jdk.incubator.vector.VectorOperators;
37import jdk.incubator.vector.Vector;
38
39#if[Byte]
40import jdk.incubator.vector.ByteVector;
41#end[Byte]
42#if[Float]
43import jdk.incubator.vector.FloatVector;
44#end[Float]
45#if[Int]
46import jdk.incubator.vector.IntVector;
47#end[Int]
48#if[Double]
49import jdk.incubator.vector.DoubleVector;
50#end[Double]
51#if[Short]
52import jdk.incubator.vector.ShortVector;
53#end[Short]
54#if[Long]
55import jdk.incubator.vector.LongVector;
56#end[Long]
57
58import org.testng.Assert;
59import org.testng.annotations.DataProvider;
60import org.testng.annotations.Test;
61
62import java.lang.Integer;
63import java.util.List;
64import java.util.Arrays;
65import java.util.function.BiFunction;
66import java.util.function.IntFunction;
67import java.util.Objects;
68import java.util.stream.Collectors;
69import java.util.stream.Stream;
70
71@Test
72public class $vectorteststype$ extends AbstractVectorTest {
73
74#if[MaxBit]
75    static final VectorSpecies<$Wideboxtype$> SPECIES =
76                $Type$Vector.SPECIES_MAX;
77#else[MaxBit]
78    static final VectorSpecies<$Wideboxtype$> SPECIES =
79                $Type$Vector.SPECIES_$bits$;
80#end[MaxBit]
81
82    static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100);
83
84#if[MaxBit]
85    static VectorShape getMaxBit() {
86        return VectorShape.S_Max_BIT;
87    }
88
89    private static final int Max = 256;  // juts so we can do N/$bits$
90#end[MaxBit]
91
92    static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / $bits$);
93
94    static final int BUFFER_SIZE = Integer.getInteger("jdk.incubator.vector.test.buffer-size", BUFFER_REPS * ($bits$ / 8));
95
96    interface FUnOp {
97        $type$ apply($type$ a);
98    }
99
100    static void assertArraysEquals($type$[] a, $type$[] r, FUnOp f) {
101        int i = 0;
102        try {
103            for (; i < a.length; i++) {
104                Assert.assertEquals(r[i], f.apply(a[i]));
105            }
106        } catch (AssertionError e) {
107            Assert.assertEquals(r[i], f.apply(a[i]), "at index #" + i + ", input = " + a[i]);
108        }
109    }
110
111    interface FUnArrayOp {
112        $type$[] apply($type$ a);
113    }
114
115    static void assertArraysEquals($type$[] a, $type$[] r, FUnArrayOp f) {
116        int i = 0;
117        try {
118            for (; i < a.length; i += SPECIES.length()) {
119                Assert.assertEquals(Arrays.copyOfRange(r, i, i+SPECIES.length()),
120                  f.apply(a[i]));
121            }
122        } catch (AssertionError e) {
123            $type$[] ref = f.apply(a[i]);
124            $type$[] res = Arrays.copyOfRange(r, i, i+SPECIES.length());
125            Assert.assertEquals(ref, res, "(ref: " + Arrays.toString(ref)
126              + ", res: " + Arrays.toString(res)
127              + "), at index #" + i);
128        }
129    }
130
131    static void assertArraysEquals($type$[] a, $type$[] r, boolean[] mask, FUnOp f) {
132        int i = 0;
133        try {
134            for (; i < a.length; i++) {
135                Assert.assertEquals(r[i], mask[i % SPECIES.length()] ? f.apply(a[i]) : a[i]);
136            }
137        } catch (AssertionError e) {
138            Assert.assertEquals(r[i], mask[i % SPECIES.length()] ? f.apply(a[i]) : a[i], "at index #" + i + ", input = " + a[i] + ", mask = " + mask[i % SPECIES.length()]);
139        }
140    }
141
142    interface FReductionOp {
143        $type$ apply($type$[] a, int idx);
144    }
145
146    interface FReductionAllOp {
147        $type$ apply($type$[] a);
148    }
149
150    static void assertReductionArraysEquals($type$[] a, $type$[] b, $type$ c,
151                                            FReductionOp f, FReductionAllOp fa) {
152        int i = 0;
153        try {
154            Assert.assertEquals(c, fa.apply(a));
155            for (; i < a.length; i += SPECIES.length()) {
156                Assert.assertEquals(b[i], f.apply(a, i));
157            }
158        } catch (AssertionError e) {
159            Assert.assertEquals(c, fa.apply(a), "Final result is incorrect!");
160            Assert.assertEquals(b[i], f.apply(a, i), "at index #" + i);
161        }
162    }
163
164    interface FReductionMaskedOp {
165        $type$ apply($type$[] a, int idx, boolean[] mask);
166    }
167
168    interface FReductionAllMaskedOp {
169        $type$ apply($type$[] a, boolean[] mask);
170    }
171
172    static void assertReductionArraysEqualsMasked($type$[] a, $type$[] b, $type$ c, boolean[] mask,
173                                            FReductionMaskedOp f, FReductionAllMaskedOp fa) {
174        int i = 0;
175        try {
176            Assert.assertEquals(c, fa.apply(a, mask));
177            for (; i < a.length; i += SPECIES.length()) {
178                Assert.assertEquals(b[i], f.apply(a, i, mask));
179            }
180        } catch (AssertionError e) {
181            Assert.assertEquals(c, fa.apply(a, mask), "Final result is incorrect!");
182            Assert.assertEquals(b[i], f.apply(a, i, mask), "at index #" + i);
183        }
184    }
185
186#if[!Long]
187    interface FReductionOpLong {
188        long apply($type$[] a, int idx);
189    }
190
191    interface FReductionAllOpLong {
192        long apply($type$[] a);
193    }
194
195    static void assertReductionLongArraysEquals($type$[] a, long[] b, long c,
196                                            FReductionOpLong f, FReductionAllOpLong fa) {
197        int i = 0;
198        try {
199            Assert.assertEquals(c, fa.apply(a));
200            for (; i < a.length; i += SPECIES.length()) {
201                Assert.assertEquals(b[i], f.apply(a, i));
202            }
203        } catch (AssertionError e) {
204            Assert.assertEquals(c, fa.apply(a), "Final result is incorrect!");
205            Assert.assertEquals(b[i], f.apply(a, i), "at index #" + i);
206        }
207    }
208
209    interface FReductionMaskedOpLong {
210        long apply($type$[] a, int idx, boolean[] mask);
211    }
212
213    interface FReductionAllMaskedOpLong {
214        long apply($type$[] a, boolean[] mask);
215    }
216
217    static void assertReductionLongArraysEqualsMasked($type$[] a, long[] b, long c, boolean[] mask,
218                                            FReductionMaskedOpLong f, FReductionAllMaskedOpLong fa) {
219        int i = 0;
220        try {
221            Assert.assertEquals(c, fa.apply(a, mask));
222            for (; i < a.length; i += SPECIES.length()) {
223                Assert.assertEquals(b[i], f.apply(a, i, mask));
224            }
225        } catch (AssertionError e) {
226            Assert.assertEquals(c, fa.apply(a, mask), "Final result is incorrect!");
227            Assert.assertEquals(b[i], f.apply(a, i, mask), "at index #" + i);
228        }
229    }
230#end[!Long]
231
232    interface FBoolReductionOp {
233        boolean apply(boolean[] a, int idx);
234    }
235
236    static void assertReductionBoolArraysEquals(boolean[] a, boolean[] b, FBoolReductionOp f) {
237        int i = 0;
238        try {
239            for (; i < a.length; i += SPECIES.length()) {
240                Assert.assertEquals(b[i], f.apply(a, i));
241            }
242        } catch (AssertionError e) {
243            Assert.assertEquals(b[i], f.apply(a, i), "at index #" + i);
244        }
245    }
246
247    static void assertInsertArraysEquals($type$[] a, $type$[] b, $type$ element, int index) {
248        int i = 0;
249        try {
250            for (; i < a.length; i += 1) {
251                if(i%SPECIES.length() == index) {
252                    Assert.assertEquals(b[i], element);
253                } else {
254                    Assert.assertEquals(b[i], a[i]);
255                }
256            }
257        } catch (AssertionError e) {
258            if (i%SPECIES.length() == index) {
259                Assert.assertEquals(b[i], element, "at index #" + i);
260            } else {
261                Assert.assertEquals(b[i], a[i], "at index #" + i);
262            }
263        }
264    }
265
266    static void assertRearrangeArraysEquals($type$[] a, $type$[] r, int[] order, int vector_len) {
267        int i = 0, j = 0;
268        try {
269            for (; i < a.length; i += vector_len) {
270                for (j = 0; j < vector_len; j++) {
271                    Assert.assertEquals(r[i+j], a[i+order[i+j]]);
272                }
273            }
274        } catch (AssertionError e) {
275            int idx = i + j;
276            Assert.assertEquals(r[i+j], a[i+order[i+j]], "at index #" + idx + ", input = " + a[i+order[i+j]]);
277        }
278    }
279
280    static void assertSelectFromArraysEquals($type$[] a, $type$[] r, $type$[] order, int vector_len) {
281        int i = 0, j = 0;
282        try {
283            for (; i < a.length; i += vector_len) {
284                for (j = 0; j < vector_len; j++) {
285                    Assert.assertEquals(r[i+j], a[i+(int)order[i+j]]);
286                }
287            }
288        } catch (AssertionError e) {
289            int idx = i + j;
290            Assert.assertEquals(r[i+j], a[i+(int)order[i+j]], "at index #" + idx + ", input = " + a[i+(int)order[i+j]]);
291        }
292    }
293
294    static void assertRearrangeArraysEquals($type$[] a, $type$[] r, int[] order, boolean[] mask, int vector_len) {
295        int i = 0, j = 0;
296        try {
297            for (; i < a.length; i += vector_len) {
298                for (j = 0; j < vector_len; j++) {
299                    if (mask[j % SPECIES.length()])
300                         Assert.assertEquals(r[i+j], a[i+order[i+j]]);
301                    else
302                         Assert.assertEquals(r[i+j], ($type$)0);
303                }
304            }
305        } catch (AssertionError e) {
306            int idx = i + j;
307            if (mask[j % SPECIES.length()])
308                Assert.assertEquals(r[i+j], a[i+order[i+j]], "at index #" + idx + ", input = " + a[i+order[i+j]] + ", mask = " + mask[j % SPECIES.length()]);
309            else
310                Assert.assertEquals(r[i+j], ($type$)0, "at index #" + idx + ", input = " + a[i+order[i+j]] + ", mask = " + mask[j % SPECIES.length()]);
311        }
312    }
313
314    static void assertSelectFromArraysEquals($type$[] a, $type$[] r, $type$[] order, boolean[] mask, int vector_len) {
315        int i = 0, j = 0;
316        try {
317            for (; i < a.length; i += vector_len) {
318                for (j = 0; j < vector_len; j++) {
319                    if (mask[j % SPECIES.length()])
320                         Assert.assertEquals(r[i+j], a[i+(int)order[i+j]]);
321                    else
322                         Assert.assertEquals(r[i+j], ($type$)0);
323                }
324            }
325        } catch (AssertionError e) {
326            int idx = i + j;
327            if (mask[j % SPECIES.length()])
328                Assert.assertEquals(r[i+j], a[i+(int)order[i+j]], "at index #" + idx + ", input = " + a[i+(int)order[i+j]] + ", mask = " + mask[j % SPECIES.length()]);
329            else
330                Assert.assertEquals(r[i+j], ($type$)0, "at index #" + idx + ", input = " + a[i+(int)order[i+j]] + ", mask = " + mask[j % SPECIES.length()]);
331        }
332    }
333
334    static void assertBroadcastArraysEquals($type$[]a, $type$[]r) {
335        int i = 0;
336        for (; i < a.length; i += SPECIES.length()) {
337            int idx = i;
338            for (int j = idx; j < (idx + SPECIES.length()); j++)
339                a[j]=a[idx];
340        }
341
342        try {
343            for (i = 0; i < a.length; i++) {
344                Assert.assertEquals(r[i], a[i]);
345            }
346        } catch (AssertionError e) {
347            Assert.assertEquals(r[i], a[i], "at index #" + i + ", input = " + a[i]);
348        }
349    }
350
351    interface FBinOp {
352        $type$ apply($type$ a, $type$ b);
353    }
354
355    interface FBinMaskOp {
356        $type$ apply($type$ a, $type$ b, boolean m);
357
358        static FBinMaskOp lift(FBinOp f) {
359            return (a, b, m) -> m ? f.apply(a, b) : a;
360        }
361    }
362
363    static void assertArraysEquals($type$[] a, $type$[] b, $type$[] r, FBinOp f) {
364        int i = 0;
365        try {
366            for (; i < a.length; i++) {
367                Assert.assertEquals(r[i], f.apply(a[i], b[i]));
368            }
369        } catch (AssertionError e) {
370            Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i);
371        }
372    }
373
374    static void assertBroadcastArraysEquals($type$[] a, $type$[] b, $type$[] r, FBinOp f) {
375        int i = 0;
376        try {
377            for (; i < a.length; i++) {
378                Assert.assertEquals(r[i], f.apply(a[i], b[(i / SPECIES.length()) * SPECIES.length()]));
379            }
380        } catch (AssertionError e) {
381            Assert.assertEquals(r[i], f.apply(a[i], b[(i / SPECIES.length()) * SPECIES.length()]),
382                                "(" + a[i] + ", " + b[(i / SPECIES.length()) * SPECIES.length()] + ") at index #" + i);
383        }
384    }
385
386    static void assertBroadcastLongArraysEquals($type$[] a, $type$[] b, $type$[] r, FBinOp f) {
387        int i = 0;
388        try {
389            for (; i < a.length; i++) {
390                Assert.assertEquals(r[i], f.apply(a[i], ($type$)((long)b[(i / SPECIES.length()) * SPECIES.length()])));
391            }
392        } catch (AssertionError e) {
393            Assert.assertEquals(r[i], f.apply(a[i], ($type$)((long)b[(i / SPECIES.length()) * SPECIES.length()])),
394                                "(" + a[i] + ", " + b[(i / SPECIES.length()) * SPECIES.length()] + ") at index #" + i);
395        }
396    }
397
398    static void assertArraysEquals($type$[] a, $type$[] b, $type$[] r, boolean[] mask, FBinOp f) {
399        assertArraysEquals(a, b, r, mask, FBinMaskOp.lift(f));
400    }
401
402    static void assertArraysEquals($type$[] a, $type$[] b, $type$[] r, boolean[] mask, FBinMaskOp f) {
403        int i = 0;
404        try {
405            for (; i < a.length; i++) {
406                Assert.assertEquals(r[i], f.apply(a[i], b[i], mask[i % SPECIES.length()]));
407            }
408        } catch (AssertionError err) {
409            Assert.assertEquals(r[i], f.apply(a[i], b[i], mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b[i] + ", mask = " + mask[i % SPECIES.length()]);
410        }
411    }
412
413    static void assertBroadcastArraysEquals($type$[] a, $type$[] b, $type$[] r, boolean[] mask, FBinOp f) {
414        assertBroadcastArraysEquals(a, b, r, mask, FBinMaskOp.lift(f));
415    }
416
417    static void assertBroadcastArraysEquals($type$[] a, $type$[] b, $type$[] r, boolean[] mask, FBinMaskOp f) {
418        int i = 0;
419        try {
420            for (; i < a.length; i++) {
421                Assert.assertEquals(r[i], f.apply(a[i], b[(i / SPECIES.length()) * SPECIES.length()], mask[i % SPECIES.length()]));
422            }
423        } catch (AssertionError err) {
424            Assert.assertEquals(r[i], f.apply(a[i], b[(i / SPECIES.length()) * SPECIES.length()],
425                                mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] +
426                                ", input2 = " + b[(i / SPECIES.length()) * SPECIES.length()] + ", mask = " +
427                                mask[i % SPECIES.length()]);
428        }
429    }
430
431    static void assertBroadcastLongArraysEquals($type$[] a, $type$[] b, $type$[] r, boolean[] mask, FBinOp f) {
432        assertBroadcastLongArraysEquals(a, b, r, mask, FBinMaskOp.lift(f));
433    }
434
435    static void assertBroadcastLongArraysEquals($type$[] a, $type$[] b, $type$[] r, boolean[] mask, FBinMaskOp f) {
436        int i = 0;
437        try {
438            for (; i < a.length; i++) {
439                Assert.assertEquals(r[i], f.apply(a[i], ($type$)((long)b[(i / SPECIES.length()) * SPECIES.length()]), mask[i % SPECIES.length()]));
440            }
441        } catch (AssertionError err) {
442            Assert.assertEquals(r[i], f.apply(a[i], ($type$)((long)b[(i / SPECIES.length()) * SPECIES.length()]),
443                                mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] +
444                                ", input2 = " + b[(i / SPECIES.length()) * SPECIES.length()] + ", mask = " +
445                                mask[i % SPECIES.length()]);
446        }
447    }
448
449    static void assertShiftArraysEquals($type$[] a, $type$[] b, $type$[] r, FBinOp f) {
450        int i = 0;
451        int j = 0;
452        try {
453            for (; j < a.length; j += SPECIES.length()) {
454                for (i = 0; i < SPECIES.length(); i++) {
455                    Assert.assertEquals(r[i+j], f.apply(a[i+j], b[j]));
456                }
457            }
458        } catch (AssertionError e) {
459            Assert.assertEquals(r[i+j], f.apply(a[i+j], b[j]), "at index #" + i + ", " + j);
460        }
461    }
462
463    static void assertShiftArraysEquals($type$[] a, $type$[] b, $type$[] r, boolean[] mask, FBinOp f) {
464        assertShiftArraysEquals(a, b, r, mask, FBinMaskOp.lift(f));
465    }
466
467    static void assertShiftArraysEquals($type$[] a, $type$[] b, $type$[] r, boolean[] mask, FBinMaskOp f) {
468        int i = 0;
469        int j = 0;
470        try {
471            for (; j < a.length; j += SPECIES.length()) {
472                for (i = 0; i < SPECIES.length(); i++) {
473                    Assert.assertEquals(r[i+j], f.apply(a[i+j], b[j], mask[i]));
474                }
475            }
476        } catch (AssertionError err) {
477            Assert.assertEquals(r[i+j], f.apply(a[i+j], b[j], mask[i]), "at index #" + i + ", input1 = " + a[i+j] + ", input2 = " + b[j] + ", mask = " + mask[i]);
478        }
479    }
480
481    interface FTernOp {
482        $type$ apply($type$ a, $type$ b, $type$ c);
483    }
484
485    interface FTernMaskOp {
486        $type$ apply($type$ a, $type$ b, $type$ c, boolean m);
487
488        static FTernMaskOp lift(FTernOp f) {
489            return (a, b, c, m) -> m ? f.apply(a, b, c) : a;
490        }
491    }
492
493    static void assertArraysEquals($type$[] a, $type$[] b, $type$[] c, $type$[] r, FTernOp f) {
494        int i = 0;
495        try {
496            for (; i < a.length; i++) {
497                Assert.assertEquals(r[i], f.apply(a[i], b[i], c[i]));
498            }
499        } catch (AssertionError e) {
500            Assert.assertEquals(r[i], f.apply(a[i], b[i], c[i]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b[i] + ", input3 = " + c[i]);
501        }
502    }
503
504    static void assertArraysEquals($type$[] a, $type$[] b, $type$[] c, $type$[] r, boolean[] mask, FTernOp f) {
505        assertArraysEquals(a, b, c, r, mask, FTernMaskOp.lift(f));
506    }
507
508    static void assertArraysEquals($type$[] a, $type$[] b, $type$[] c, $type$[] r, boolean[] mask, FTernMaskOp f) {
509        int i = 0;
510        try {
511            for (; i < a.length; i++) {
512                Assert.assertEquals(r[i], f.apply(a[i], b[i], c[i], mask[i % SPECIES.length()]));
513            }
514        } catch (AssertionError err) {
515            Assert.assertEquals(r[i], f.apply(a[i], b[i], c[i], mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = "
516              + b[i] + ", input3 = " + c[i] + ", mask = " + mask[i % SPECIES.length()]);
517        }
518    }
519
520    static void assertBroadcastArraysEquals($type$[] a, $type$[] b, $type$[] c, $type$[] r, FTernOp f) {
521        int i = 0;
522        try {
523            for (; i < a.length; i++) {
524                Assert.assertEquals(r[i], f.apply(a[i], b[i], c[(i / SPECIES.length()) * SPECIES.length()]));
525            }
526        } catch (AssertionError e) {
527            Assert.assertEquals(r[i], f.apply(a[i], b[i], c[(i / SPECIES.length()) * SPECIES.length()]), "at index #" +
528                                i + ", input1 = " + a[i] + ", input2 = " + b[i] + ", input3 = " +
529                                c[(i / SPECIES.length()) * SPECIES.length()]);
530        }
531    }
532
533    static void assertAltBroadcastArraysEquals($type$[] a, $type$[] b, $type$[] c, $type$[] r, FTernOp f) {
534        int i = 0;
535        try {
536            for (; i < a.length; i++) {
537                Assert.assertEquals(r[i], f.apply(a[i], b[(i / SPECIES.length()) * SPECIES.length()], c[i]));
538            }
539        } catch (AssertionError e) {
540            Assert.assertEquals(r[i], f.apply(a[i], b[(i / SPECIES.length()) * SPECIES.length()], c[i]), "at index #" +
541                                i + ", input1 = " + a[i] + ", input2 = " +
542                                b[(i / SPECIES.length()) * SPECIES.length()] + ",  input3 = " + c[i]);
543        }
544    }
545
546    static void assertBroadcastArraysEquals($type$[] a, $type$[] b, $type$[] c, $type$[] r, boolean[] mask,
547                                            FTernOp f) {
548        assertBroadcastArraysEquals(a, b, c, r, mask, FTernMaskOp.lift(f));
549    }
550
551    static void assertBroadcastArraysEquals($type$[] a, $type$[] b, $type$[] c, $type$[] r, boolean[] mask,
552                                            FTernMaskOp f) {
553        int i = 0;
554        try {
555            for (; i < a.length; i++) {
556                Assert.assertEquals(r[i], f.apply(a[i], b[i], c[(i / SPECIES.length()) * SPECIES.length()],
557                                    mask[i % SPECIES.length()]));
558            }
559        } catch (AssertionError err) {
560            Assert.assertEquals(r[i], f.apply(a[i], b[i], c[(i / SPECIES.length()) * SPECIES.length()],
561                                mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " +
562                                b[i] + ", input3 = " + c[(i / SPECIES.length()) * SPECIES.length()] + ", mask = " +
563                                mask[i % SPECIES.length()]);
564        }
565    }
566
567    static void assertAltBroadcastArraysEquals($type$[] a, $type$[] b, $type$[] c, $type$[] r, boolean[] mask,
568                                            FTernOp f) {
569        assertAltBroadcastArraysEquals(a, b, c, r, mask, FTernMaskOp.lift(f));
570    }
571
572    static void assertAltBroadcastArraysEquals($type$[] a, $type$[] b, $type$[] c, $type$[] r, boolean[] mask,
573                                            FTernMaskOp f) {
574        int i = 0;
575        try {
576            for (; i < a.length; i++) {
577                Assert.assertEquals(r[i], f.apply(a[i], b[(i / SPECIES.length()) * SPECIES.length()], c[i],
578                                    mask[i % SPECIES.length()]));
579            }
580        } catch (AssertionError err) {
581            Assert.assertEquals(r[i], f.apply(a[i], b[(i / SPECIES.length()) * SPECIES.length()], c[i],
582                                mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] +
583                                ", input2 = " + b[(i / SPECIES.length()) * SPECIES.length()] +
584                                ", input3 = " + c[i] + ", mask = " + mask[i % SPECIES.length()]);
585        }
586    }
587
588    static void assertDoubleBroadcastArraysEquals($type$[] a, $type$[] b, $type$[] c, $type$[] r, FTernOp f) {
589        int i = 0;
590        try {
591            for (; i < a.length; i++) {
592                Assert.assertEquals(r[i], f.apply(a[i], b[(i / SPECIES.length()) * SPECIES.length()],
593                                    c[(i / SPECIES.length()) * SPECIES.length()]));
594            }
595        } catch (AssertionError e) {
596            Assert.assertEquals(r[i], f.apply(a[i], b[(i / SPECIES.length()) * SPECIES.length()],
597                                c[(i / SPECIES.length()) * SPECIES.length()]), "at index #" + i + ", input1 = " + a[i]
598                                + ", input2 = " + b[(i / SPECIES.length()) * SPECIES.length()] + ", input3 = " +
599                                c[(i / SPECIES.length()) * SPECIES.length()]);
600        }
601    }
602
603    static void assertDoubleBroadcastArraysEquals($type$[] a, $type$[] b, $type$[] c, $type$[] r, boolean[] mask,
604                                                  FTernOp f) {
605        assertDoubleBroadcastArraysEquals(a, b, c, r, mask, FTernMaskOp.lift(f));
606    }
607
608    static void assertDoubleBroadcastArraysEquals($type$[] a, $type$[] b, $type$[] c, $type$[] r, boolean[] mask,
609                                                  FTernMaskOp f) {
610        int i = 0;
611        try {
612            for (; i < a.length; i++) {
613                Assert.assertEquals(r[i], f.apply(a[i], b[(i / SPECIES.length()) * SPECIES.length()],
614                                    c[(i / SPECIES.length()) * SPECIES.length()], mask[i % SPECIES.length()]));
615            }
616        } catch (AssertionError err) {
617            Assert.assertEquals(r[i], f.apply(a[i], b[(i / SPECIES.length()) * SPECIES.length()],
618                                c[(i / SPECIES.length()) * SPECIES.length()], mask[i % SPECIES.length()]), "at index #"
619                                + i + ", input1 = " + a[i] + ", input2 = " + b[(i / SPECIES.length()) * SPECIES.length()] +
620                                ", input3 = " + c[(i / SPECIES.length()) * SPECIES.length()] + ", mask = " +
621                                mask[i % SPECIES.length()]);
622        }
623    }
624
625
626#if[FP]
627    static boolean isWithin1Ulp($type$ actual, $type$ expected) {
628        if ($Type$.isNaN(expected) && !$Type$.isNaN(actual)) {
629            return false;
630        } else if (!$Type$.isNaN(expected) && $Type$.isNaN(actual)) {
631            return false;
632        }
633
634        $type$ low = Math.nextDown(expected);
635        $type$ high = Math.nextUp(expected);
636
637        if ($Type$.compare(low, expected) > 0) {
638            return false;
639        }
640
641        if ($Type$.compare(high, expected) < 0) {
642            return false;
643        }
644
645        return true;
646    }
647
648    static void assertArraysEqualsWithinOneUlp($type$[] a, $type$[] r, FUnOp mathf, FUnOp strictmathf) {
649        int i = 0;
650        try {
651            // Check that result is within 1 ulp of strict math or equivalent to math implementation.
652            for (; i < a.length; i++) {
653                Assert.assertTrue($Type$.compare(r[i], mathf.apply(a[i])) == 0 ||
654                                    isWithin1Ulp(r[i], strictmathf.apply(a[i])));
655            }
656        } catch (AssertionError e) {
657            Assert.assertTrue($Type$.compare(r[i], mathf.apply(a[i])) == 0, "at index #" + i + ", input = " + a[i] + ", actual = " + r[i] + ", expected = " + mathf.apply(a[i]));
658            Assert.assertTrue(isWithin1Ulp(r[i], strictmathf.apply(a[i])), "at index #" + i + ", input = " + a[i] + ", actual = " + r[i] + ", expected (within 1 ulp) = " + strictmathf.apply(a[i]));
659        }
660    }
661
662    static void assertArraysEqualsWithinOneUlp($type$[] a, $type$[] b, $type$[] r, FBinOp mathf, FBinOp strictmathf) {
663        int i = 0;
664        try {
665            // Check that result is within 1 ulp of strict math or equivalent to math implementation.
666            for (; i < a.length; i++) {
667                Assert.assertTrue($Type$.compare(r[i], mathf.apply(a[i], b[i])) == 0 ||
668                                    isWithin1Ulp(r[i], strictmathf.apply(a[i], b[i])));
669            }
670        } catch (AssertionError e) {
671            Assert.assertTrue($Type$.compare(r[i], mathf.apply(a[i], b[i])) == 0, "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b[i] + ", actual = " + r[i] + ", expected = " + mathf.apply(a[i], b[i]));
672            Assert.assertTrue(isWithin1Ulp(r[i], strictmathf.apply(a[i], b[i])), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b[i] + ", actual = " + r[i] + ", expected (within 1 ulp) = " + strictmathf.apply(a[i], b[i]));
673        }
674    }
675
676    static void assertBroadcastArraysEqualsWithinOneUlp($type$[] a, $type$[] b, $type$[] r,
677                                                        FBinOp mathf, FBinOp strictmathf) {
678        int i = 0;
679        try {
680            // Check that result is within 1 ulp of strict math or equivalent to math implementation.
681            for (; i < a.length; i++) {
682                Assert.assertTrue($Type$.compare(r[i],
683                                  mathf.apply(a[i], b[(i / SPECIES.length()) * SPECIES.length()])) == 0 ||
684                                  isWithin1Ulp(r[i],
685                                  strictmathf.apply(a[i], b[(i / SPECIES.length()) * SPECIES.length()])));
686            }
687        } catch (AssertionError e) {
688            Assert.assertTrue($Type$.compare(r[i],
689                              mathf.apply(a[i], b[(i / SPECIES.length()) * SPECIES.length()])) == 0,
690                              "at index #" + i + ", input1 = " + a[i] + ", input2 = " +
691                              b[(i / SPECIES.length()) * SPECIES.length()] + ", actual = " + r[i] +
692                              ", expected = " + mathf.apply(a[i], b[(i / SPECIES.length()) * SPECIES.length()]));
693            Assert.assertTrue(isWithin1Ulp(r[i],
694                              strictmathf.apply(a[i], b[(i / SPECIES.length()) * SPECIES.length()])),
695                             "at index #" + i + ", input1 = " + a[i] + ", input2 = " +
696                             b[(i / SPECIES.length()) * SPECIES.length()] + ", actual = " + r[i] +
697                             ", expected (within 1 ulp) = " + strictmathf.apply(a[i],
698                             b[(i / SPECIES.length()) * SPECIES.length()]));
699        }
700    }
701#end[FP]
702
703    interface FBinArrayOp {
704        $type$ apply($type$[] a, int b);
705    }
706
707    static void assertArraysEquals($type$[] a, $type$[] r, FBinArrayOp f) {
708        int i = 0;
709        try {
710            for (; i < a.length; i++) {
711                Assert.assertEquals(r[i], f.apply(a, i));
712            }
713        } catch (AssertionError e) {
714            Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i);
715        }
716    }
717
718    interface FGatherScatterOp {
719        $type$[] apply($type$[] a, int ix, int[] b, int iy);
720    }
721
722    static void assertArraysEquals($type$[] a, int[] b, $type$[] r, FGatherScatterOp f) {
723        int i = 0;
724        try {
725            for (; i < a.length; i += SPECIES.length()) {
726                Assert.assertEquals(Arrays.copyOfRange(r, i, i+SPECIES.length()),
727                  f.apply(a, i, b, i));
728            }
729        } catch (AssertionError e) {
730            $type$[] ref = f.apply(a, i, b, i);
731            $type$[] res = Arrays.copyOfRange(r, i, i+SPECIES.length());
732            Assert.assertEquals(res, ref,
733              "(ref: " + Arrays.toString(ref) + ", res: " + Arrays.toString(res) + ", a: "
734              + Arrays.toString(Arrays.copyOfRange(a, i, i+SPECIES.length()))
735              + ", b: "
736              + Arrays.toString(Arrays.copyOfRange(b, i, i+SPECIES.length()))
737              + " at index #" + i);
738        }
739    }
740
741    interface FGatherMaskedOp {
742        $type$[] apply($type$[] a, int ix, boolean[] mask, int[] b, int iy);
743    }
744
745    interface FScatterMaskedOp {
746        $type$[] apply($type$[] r, $type$[] a, int ix, boolean[] mask, int[] b, int iy);
747    }
748
749    static void assertArraysEquals($type$[] a, int[] b, $type$[] r, boolean[] mask, FGatherMaskedOp f) {
750        int i = 0;
751        try {
752            for (; i < a.length; i += SPECIES.length()) {
753                Assert.assertEquals(Arrays.copyOfRange(r, i, i+SPECIES.length()),
754                  f.apply(a, i, mask, b, i));
755            }
756        } catch (AssertionError e) {
757            $type$[] ref = f.apply(a, i, mask, b, i);
758            $type$[] res = Arrays.copyOfRange(r, i, i+SPECIES.length());
759            Assert.assertEquals(ref, res,
760              "(ref: " + Arrays.toString(ref) + ", res: " + Arrays.toString(res) + ", a: "
761              + Arrays.toString(Arrays.copyOfRange(a, i, i+SPECIES.length()))
762              + ", b: "
763              + Arrays.toString(Arrays.copyOfRange(b, i, i+SPECIES.length()))
764              + ", mask: "
765              + Arrays.toString(mask)
766              + " at index #" + i);
767        }
768    }
769
770    static void assertArraysEquals($type$[] a, int[] b, $type$[] r, boolean[] mask, FScatterMaskedOp f) {
771        int i = 0;
772        try {
773            for (; i < a.length; i += SPECIES.length()) {
774                Assert.assertEquals(Arrays.copyOfRange(r, i, i+SPECIES.length()),
775                  f.apply(r, a, i, mask, b, i));
776            }
777        } catch (AssertionError e) {
778            $type$[] ref = f.apply(r, a, i, mask, b, i);
779            $type$[] res = Arrays.copyOfRange(r, i, i+SPECIES.length());
780            Assert.assertEquals(ref, res,
781              "(ref: " + Arrays.toString(ref) + ", res: " + Arrays.toString(res) + ", a: "
782              + Arrays.toString(Arrays.copyOfRange(a, i, i+SPECIES.length()))
783              + ", b: "
784              + Arrays.toString(Arrays.copyOfRange(b, i, i+SPECIES.length()))
785              + ", r: "
786              + Arrays.toString(Arrays.copyOfRange(r, i, i+SPECIES.length()))
787              + ", mask: "
788              + Arrays.toString(mask)
789              + " at index #" + i);
790        }
791    }
792
793    interface FLaneOp {
794        $type$[] apply($type$[] a, int origin, int idx);
795    }
796
797    static void assertArraysEquals($type$[] a, $type$[] r, int origin, FLaneOp f) {
798        int i = 0;
799        try {
800            for (; i < a.length; i += SPECIES.length()) {
801                Assert.assertEquals(Arrays.copyOfRange(r, i, i+SPECIES.length()),
802                  f.apply(a, origin, i));
803            }
804        } catch (AssertionError e) {
805            $type$[] ref = f.apply(a, origin, i);
806            $type$[] res = Arrays.copyOfRange(r, i, i+SPECIES.length());
807            Assert.assertEquals(ref, res, "(ref: " + Arrays.toString(ref)
808              + ", res: " + Arrays.toString(res)
809              + "), at index #" + i);
810        }
811    }
812
813    interface FLaneBop {
814        $type$[] apply($type$[] a, $type$[] b, int origin, int idx);
815    }
816
817    static void assertArraysEquals($type$[] a, $type$[] b, $type$[] r, int origin, FLaneBop f) {
818        int i = 0;
819        try {
820            for (; i < a.length; i += SPECIES.length()) {
821                Assert.assertEquals(Arrays.copyOfRange(r, i, i+SPECIES.length()),
822                  f.apply(a, b, origin, i));
823            }
824        } catch (AssertionError e) {
825            $type$[] ref = f.apply(a, b, origin, i);
826            $type$[] res = Arrays.copyOfRange(r, i, i+SPECIES.length());
827            Assert.assertEquals(ref, res, "(ref: " + Arrays.toString(ref)
828              + ", res: " + Arrays.toString(res)
829              + "), at index #" + i
830              + ", at origin #" + origin);
831        }
832    }
833
834    interface FLaneMaskedBop {
835        $type$[] apply($type$[] a, $type$[] b, int origin, boolean[] mask, int idx);
836    }
837
838    static void assertArraysEquals($type$[] a, $type$[] b, $type$[] r, int origin, boolean[] mask, FLaneMaskedBop f) {
839        int i = 0;
840        try {
841            for (; i < a.length; i += SPECIES.length()) {
842                Assert.assertEquals(Arrays.copyOfRange(r, i, i+SPECIES.length()),
843                  f.apply(a, b, origin, mask, i));
844            }
845        } catch (AssertionError e) {
846            $type$[] ref = f.apply(a, b, origin, mask, i);
847            $type$[] res = Arrays.copyOfRange(r, i, i+SPECIES.length());
848            Assert.assertEquals(ref, res, "(ref: " + Arrays.toString(ref)
849              + ", res: " + Arrays.toString(res)
850              + "), at index #" + i
851              + ", at origin #" + origin);
852        }
853    }
854
855    interface FLanePartBop {
856        $type$[] apply($type$[] a, $type$[] b, int origin, int part, int idx);
857    }
858
859    static void assertArraysEquals($type$[] a, $type$[] b, $type$[] r, int origin, int part, FLanePartBop f) {
860        int i = 0;
861        try {
862            for (; i < a.length; i += SPECIES.length()) {
863                Assert.assertEquals(Arrays.copyOfRange(r, i, i+SPECIES.length()),
864                  f.apply(a, b, origin, part, i));
865            }
866        } catch (AssertionError e) {
867            $type$[] ref = f.apply(a, b, origin, part, i);
868            $type$[] res = Arrays.copyOfRange(r, i, i+SPECIES.length());
869            Assert.assertEquals(ref, res, "(ref: " + Arrays.toString(ref)
870              + ", res: " + Arrays.toString(res)
871              + "), at index #" + i
872              + ", at origin #" + origin
873              + ", with part #" + part);
874        }
875    }
876
877    interface FLanePartMaskedBop {
878        $type$[] apply($type$[] a, $type$[] b, int origin, int part, boolean[] mask, int idx);
879    }
880
881    static void assertArraysEquals($type$[] a, $type$[] b, $type$[] r, int origin, int part, boolean[] mask, FLanePartMaskedBop f) {
882        int i = 0;
883        try {
884            for (; i < a.length; i += SPECIES.length()) {
885                Assert.assertEquals(Arrays.copyOfRange(r, i, i+SPECIES.length()),
886                  f.apply(a, b, origin, part, mask, i));
887            }
888        } catch (AssertionError e) {
889            $type$[] ref = f.apply(a, b, origin, part, mask, i);
890            $type$[] res = Arrays.copyOfRange(r, i, i+SPECIES.length());
891            Assert.assertEquals(ref, res, "(ref: " + Arrays.toString(ref)
892              + ", res: " + Arrays.toString(res)
893              + "), at index #" + i
894              + ", at origin #" + origin
895              + ", with part #" + part);
896        }
897    }
898
899#if[!Int]
900#if[!byteOrShort]
901    static int intCornerCaseValue(int i) {
902        switch(i % 5) {
903            case 0:
904                return Integer.MAX_VALUE;
905            case 1:
906                return Integer.MIN_VALUE;
907            case 2:
908                return Integer.MIN_VALUE;
909            case 3:
910                return Integer.MAX_VALUE;
911            default:
912                return (int)0;
913        }
914    }
915
916    static final List<IntFunction<$type$[]>> INT_$TYPE$_GENERATORS = List.of(
917            withToString("$type$[-i * 5]", (int s) -> {
918                return fill(s * BUFFER_REPS,
919                            i -> ($type$)(-i * 5));
920            }),
921            withToString("$type$[i * 5]", (int s) -> {
922                return fill(s * BUFFER_REPS,
923                            i -> ($type$)(i * 5));
924            }),
925            withToString("$type$[i + 1]", (int s) -> {
926                return fill(s * BUFFER_REPS,
927                            i -> ((($type$)(i + 1) == 0) ? 1 : ($type$)(i + 1)));
928            }),
929            withToString("$type$[intCornerCaseValue(i)]", (int s) -> {
930                return fill(s * BUFFER_REPS,
931                            i -> ($type$)intCornerCaseValue(i));
932            })
933    );
934#end[!byteOrShort]
935#end[!Int]
936
937    static void assertArraysEquals($type$[] a, int[] r, int offs) {
938        int i = 0;
939        try {
940            for (; i < r.length; i++) {
941                Assert.assertEquals(r[i], (int)(a[i+offs]));
942            }
943        } catch (AssertionError e) {
944            Assert.assertEquals(r[i], (int)(a[i+offs]), "at index #" + i + ", input = " + a[i+offs]);
945        }
946    }
947
948#if[!Long]
949#if[FP]
950    static long longCornerCaseValue(int i) {
951        switch(i % 5) {
952            case 0:
953                return Long.MAX_VALUE;
954            case 1:
955                return Long.MIN_VALUE;
956            case 2:
957                return Long.MIN_VALUE;
958            case 3:
959                return Long.MAX_VALUE;
960            default:
961                return (long)0;
962        }
963    }
964
965    static final List<IntFunction<$type$[]>> LONG_$TYPE$_GENERATORS = List.of(
966            withToString("$type$[-i * 5]", (int s) -> {
967                return fill(s * BUFFER_REPS,
968                            i -> ($type$)(-i * 5));
969            }),
970            withToString("$type$[i * 5]", (int s) -> {
971                return fill(s * BUFFER_REPS,
972                            i -> ($type$)(i * 5));
973            }),
974            withToString("$type$[i + 1]", (int s) -> {
975                return fill(s * BUFFER_REPS,
976                            i -> ((($type$)(i + 1) == 0) ? 1 : ($type$)(i + 1)));
977            }),
978            withToString("$type$[cornerCaseValue(i)]", (int s) -> {
979                return fill(s * BUFFER_REPS,
980                            i -> ($type$)longCornerCaseValue(i));
981            })
982    );
983#end[FP]
984#end[!Long]
985
986#if[byte]
987    static void assertArraysEquals($type$[] a, $type$[] r, int offs) {
988        int i = 0;
989        try {
990            for (; i < r.length; i++) {
991                Assert.assertEquals(r[i], (long)(a[i+offs]));
992            }
993        } catch (AssertionError e) {
994            Assert.assertEquals(r[i], (long)(a[i+offs]), "at index #" + i + ", input = " + a[i+offs]);
995        }
996    }
997#end[byte]
998
999    static void assertArraysEquals($type$[] a, long[] r, int offs) {
1000        int i = 0;
1001        try {
1002            for (; i < r.length; i++) {
1003                Assert.assertEquals(r[i], (long)(a[i+offs]));
1004            }
1005        } catch (AssertionError e) {
1006            Assert.assertEquals(r[i], (long)(a[i+offs]), "at index #" + i + ", input = " + a[i+offs]);
1007        }
1008    }
1009
1010#if[!Double]
1011    static void assertArraysEquals($type$[] a, double[] r, int offs) {
1012        int i = 0;
1013        try {
1014            for (; i < r.length; i++) {
1015                Assert.assertEquals(r[i], (double)(a[i+offs]));
1016            }
1017        } catch (AssertionError e) {
1018            Assert.assertEquals(r[i], (double)(a[i+offs]), "at index #" + i + ", input = " + a[i+offs]);
1019        }
1020    }
1021#end[!Double]
1022
1023
1024    static $bitstype$ bits($type$ e) {
1025        return {#if[FP]? $Type$.$type$To$Bitstype$Bits(e): e};
1026    }
1027
1028    static final List<IntFunction<$type$[]>> $TYPE$_GENERATORS = List.of(
1029            withToString("$type$[-i * 5]", (int s) -> {
1030                return fill(s * BUFFER_REPS,
1031                            i -> ($type$)(-i * 5));
1032            }),
1033            withToString("$type$[i * 5]", (int s) -> {
1034                return fill(s * BUFFER_REPS,
1035                            i -> ($type$)(i * 5));
1036            }),
1037            withToString("$type$[i + 1]", (int s) -> {
1038                return fill(s * BUFFER_REPS,
1039                            i -> ((($type$)(i + 1) == 0) ? 1 : ($type$)(i + 1)));
1040            }),
1041            withToString("$type$[cornerCaseValue(i)]", (int s) -> {
1042                return fill(s * BUFFER_REPS,
1043                            i -> cornerCaseValue(i));
1044            })
1045    );
1046
1047    // Create combinations of pairs
1048    // @@@ Might be sensitive to order e.g. div by 0
1049    static final List<List<IntFunction<$type$[]>>> $TYPE$_GENERATOR_PAIRS =
1050        Stream.of($TYPE$_GENERATORS.get(0)).
1051                flatMap(fa -> $TYPE$_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))).
1052                collect(Collectors.toList());
1053
1054    @DataProvider
1055    public Object[][] boolUnaryOpProvider() {
1056        return BOOL_ARRAY_GENERATORS.stream().
1057                map(f -> new Object[]{f}).
1058                toArray(Object[][]::new);
1059    }
1060
1061    static final List<List<IntFunction<$type$[]>>> $TYPE$_GENERATOR_TRIPLES =
1062        $TYPE$_GENERATOR_PAIRS.stream().
1063                flatMap(pair -> $TYPE$_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))).
1064                collect(Collectors.toList());
1065
1066    @DataProvider
1067    public Object[][] $type$BinaryOpProvider() {
1068        return $TYPE$_GENERATOR_PAIRS.stream().map(List::toArray).
1069                toArray(Object[][]::new);
1070    }
1071
1072    @DataProvider
1073    public Object[][] $type$IndexedOpProvider() {
1074        return $TYPE$_GENERATOR_PAIRS.stream().map(List::toArray).
1075                toArray(Object[][]::new);
1076    }
1077
1078    @DataProvider
1079    public Object[][] $type$BinaryOpMaskProvider() {
1080        return BOOLEAN_MASK_GENERATORS.stream().
1081                flatMap(fm -> $TYPE$_GENERATOR_PAIRS.stream().map(lfa -> {
1082                    return Stream.concat(lfa.stream(), Stream.of(fm)).toArray();
1083                })).
1084                toArray(Object[][]::new);
1085    }
1086
1087    @DataProvider
1088    public Object[][] $type$TernaryOpProvider() {
1089        return $TYPE$_GENERATOR_TRIPLES.stream().map(List::toArray).
1090                toArray(Object[][]::new);
1091    }
1092
1093    @DataProvider
1094    public Object[][] $type$TernaryOpMaskProvider() {
1095        return BOOLEAN_MASK_GENERATORS.stream().
1096                flatMap(fm -> $TYPE$_GENERATOR_TRIPLES.stream().map(lfa -> {
1097                    return Stream.concat(lfa.stream(), Stream.of(fm)).toArray();
1098                })).
1099                toArray(Object[][]::new);
1100    }
1101
1102    @DataProvider
1103    public Object[][] $type$UnaryOpProvider() {
1104        return $TYPE$_GENERATORS.stream().
1105                map(f -> new Object[]{f}).
1106                toArray(Object[][]::new);
1107    }
1108
1109    @DataProvider
1110    public Object[][] $type$UnaryOpMaskProvider() {
1111        return BOOLEAN_MASK_GENERATORS.stream().
1112                flatMap(fm -> $TYPE$_GENERATORS.stream().map(fa -> {
1113                    return new Object[] {fa, fm};
1114                })).
1115                toArray(Object[][]::new);
1116    }
1117
1118#if[!Int]
1119#if[!byteOrShort]
1120    @DataProvider
1121    public Object[][] $type$toIntUnaryOpProvider() {
1122        return INT_$TYPE$_GENERATORS.stream().
1123                map(f -> new Object[]{f}).
1124                toArray(Object[][]::new);
1125    }
1126#end[!byteOrShort]
1127#end[!Int]
1128
1129#if[FP]
1130    @DataProvider
1131    public Object[][] $type$toLongUnaryOpProvider() {
1132        return LONG_$TYPE$_GENERATORS.stream().
1133                map(f -> new Object[]{f}).
1134                toArray(Object[][]::new);
1135    }
1136#end[FP]
1137
1138    @DataProvider
1139    public Object[][] maskProvider() {
1140        return BOOLEAN_MASK_GENERATORS.stream().
1141                map(f -> new Object[]{f}).
1142                toArray(Object[][]::new);
1143    }
1144
1145    @DataProvider
1146    public Object[][] maskCompareOpProvider() {
1147        return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray).
1148                toArray(Object[][]::new);
1149    }
1150
1151    @DataProvider
1152    public Object[][] shuffleProvider() {
1153        return INT_SHUFFLE_GENERATORS.stream().
1154                map(f -> new Object[]{f}).
1155                toArray(Object[][]::new);
1156    }
1157
1158    @DataProvider
1159    public Object[][] shuffleCompareOpProvider() {
1160        return INT_SHUFFLE_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray).
1161                toArray(Object[][]::new);
1162    }
1163
1164    @DataProvider
1165    public Object[][] $type$UnaryOpShuffleProvider() {
1166        return INT_SHUFFLE_GENERATORS.stream().
1167                flatMap(fs -> $TYPE$_GENERATORS.stream().map(fa -> {
1168                    return new Object[] {fa, fs};
1169                })).
1170                toArray(Object[][]::new);
1171    }
1172
1173    @DataProvider
1174    public Object[][] $type$UnaryOpShuffleMaskProvider() {
1175        return BOOLEAN_MASK_GENERATORS.stream().
1176                flatMap(fm -> INT_SHUFFLE_GENERATORS.stream().
1177                    flatMap(fs -> $TYPE$_GENERATORS.stream().map(fa -> {
1178                        return new Object[] {fa, fs, fm};
1179                }))).
1180                toArray(Object[][]::new);
1181    }
1182
1183#if[!Int]
1184    static final List<BiFunction<Integer,Integer,$type$[]>> $TYPE$_SHUFFLE_GENERATORS = List.of(
1185            withToStringBi("shuffle[random]", (Integer l, Integer m) -> {
1186                $type$[] a = new $type$[l];
1187                for (int i = 0; i < 1; i++) {
1188                    a[i] = ($type$)RAND.nextInt(m);
1189                }
1190                return a;
1191            })
1192    );
1193
1194    @DataProvider
1195    public Object[][] $type$UnaryOpSelectFromProvider() {
1196        return $TYPE$_SHUFFLE_GENERATORS.stream().
1197                flatMap(fs -> $TYPE$_GENERATORS.stream().map(fa -> {
1198                    return new Object[] {fa, fs};
1199                })).
1200                toArray(Object[][]::new);
1201    }
1202
1203    @DataProvider
1204    public Object[][] $type$UnaryOpSelectFromMaskProvider() {
1205        return BOOLEAN_MASK_GENERATORS.stream().
1206                flatMap(fm -> $TYPE$_SHUFFLE_GENERATORS.stream().
1207                    flatMap(fs -> $TYPE$_GENERATORS.stream().map(fa -> {
1208                        return new Object[] {fa, fs, fm};
1209                }))).
1210                toArray(Object[][]::new);
1211    }
1212
1213#end[!Int]
1214
1215    @DataProvider
1216    public Object[][] $type$UnaryOpIndexProvider() {
1217        return INT_INDEX_GENERATORS.stream().
1218                flatMap(fs -> $TYPE$_GENERATORS.stream().map(fa -> {
1219                    return new Object[] {fa, fs};
1220                })).
1221                toArray(Object[][]::new);
1222    }
1223
1224    @DataProvider
1225    public Object[][] $type$UnaryMaskedOpIndexProvider() {
1226        return BOOLEAN_MASK_GENERATORS.stream().
1227          flatMap(fs -> INT_INDEX_GENERATORS.stream().flatMap(fm ->
1228            $TYPE$_GENERATORS.stream().map(fa -> {
1229                    return new Object[] {fa, fm, fs};
1230            }))).
1231            toArray(Object[][]::new);
1232    }
1233
1234    @DataProvider
1235    public Object[][] scatterMaskedOpIndexProvider() {
1236        return BOOLEAN_MASK_GENERATORS.stream().
1237          flatMap(fs -> INT_INDEX_GENERATORS.stream().flatMap(fm ->
1238            $TYPE$_GENERATORS.stream().flatMap(fn ->
1239              $TYPE$_GENERATORS.stream().map(fa -> {
1240                    return new Object[] {fa, fn, fm, fs};
1241            })))).
1242            toArray(Object[][]::new);
1243    }
1244
1245    static final List<IntFunction<$type$[]>> $TYPE$_COMPARE_GENERATORS = List.of(
1246            withToString("$type$[i]", (int s) -> {
1247                return fill(s * BUFFER_REPS,
1248                            i -> ($type$)i);
1249            }),
1250            withToString("$type$[i + 1]", (int s) -> {
1251                return fill(s * BUFFER_REPS,
1252                            i -> ($type$)(i + 1));
1253            }),
1254            withToString("$type$[i - 2]", (int s) -> {
1255                return fill(s * BUFFER_REPS,
1256                            i -> ($type$)(i - 2));
1257            }),
1258            withToString("$type$[zigZag(i)]", (int s) -> {
1259                return fill(s * BUFFER_REPS,
1260                            i -> i%3 == 0 ? ($type$)i : (i%3 == 1 ? ($type$)(i + 1) : ($type$)(i - 2)));
1261            }),
1262            withToString("$type$[cornerCaseValue(i)]", (int s) -> {
1263                return fill(s * BUFFER_REPS,
1264                            i -> cornerCaseValue(i));
1265            })
1266    );
1267
1268    static final List<List<IntFunction<$type$[]>>> $TYPE$_TEST_GENERATOR_ARGS =
1269        $TYPE$_COMPARE_GENERATORS.stream().
1270                map(fa -> List.of(fa)).
1271                collect(Collectors.toList());
1272
1273    @DataProvider
1274    public Object[][] $type$TestOpProvider() {
1275        return $TYPE$_TEST_GENERATOR_ARGS.stream().map(List::toArray).
1276                toArray(Object[][]::new);
1277    }
1278
1279    @DataProvider
1280    public Object[][] $type$TestOpMaskProvider() {
1281        return BOOLEAN_MASK_GENERATORS.stream().
1282                flatMap(fm -> $TYPE$_TEST_GENERATOR_ARGS.stream().map(lfa -> {
1283                    return Stream.concat(lfa.stream(), Stream.of(fm)).toArray();
1284                })).
1285                toArray(Object[][]::new);
1286    }
1287
1288    static final List<List<IntFunction<$type$[]>>> $TYPE$_COMPARE_GENERATOR_PAIRS =
1289        $TYPE$_COMPARE_GENERATORS.stream().
1290                flatMap(fa -> $TYPE$_COMPARE_GENERATORS.stream().map(fb -> List.of(fa, fb))).
1291                collect(Collectors.toList());
1292
1293    @DataProvider
1294    public Object[][] $type$CompareOpProvider() {
1295        return $TYPE$_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray).
1296                toArray(Object[][]::new);
1297    }
1298
1299    @DataProvider
1300    public Object[][] $type$CompareOpMaskProvider() {
1301        return BOOLEAN_MASK_GENERATORS.stream().
1302                flatMap(fm -> $TYPE$_COMPARE_GENERATOR_PAIRS.stream().map(lfa -> {
1303                    return Stream.concat(lfa.stream(), Stream.of(fm)).toArray();
1304                })).
1305                toArray(Object[][]::new);
1306    }
1307
1308    interface To$Type$F {
1309        $type$ apply(int i);
1310    }
1311
1312    static $type$[] fill(int s , To$Type$F f) {
1313        return fill(new $type$[s], f);
1314    }
1315
1316    static $type$[] fill($type$[] a, To$Type$F f) {
1317        for (int i = 0; i < a.length; i++) {
1318            a[i] = f.apply(i);
1319        }
1320        return a;
1321    }
1322
1323    static $type$ cornerCaseValue(int i) {
1324#if[FP]
1325        switch(i % 7) {
1326            case 0:
1327                return $Wideboxtype$.MAX_VALUE;
1328            case 1:
1329                return $Wideboxtype$.MIN_VALUE;
1330            case 2:
1331                return $Wideboxtype$.NEGATIVE_INFINITY;
1332            case 3:
1333                return $Wideboxtype$.POSITIVE_INFINITY;
1334            case 4:
1335                return $Wideboxtype$.NaN;
1336            case 5:
1337                return ($type$)0.0;
1338            default:
1339                return ($type$)-0.0;
1340        }
1341#else[FP]
1342        switch(i % 5) {
1343            case 0:
1344                return $Wideboxtype$.MAX_VALUE;
1345            case 1:
1346                return $Wideboxtype$.MIN_VALUE;
1347            case 2:
1348                return $Wideboxtype$.MIN_VALUE;
1349            case 3:
1350                return $Wideboxtype$.MAX_VALUE;
1351            default:
1352                return ($type$)0;
1353        }
1354#end[FP]
1355    }
1356
1357    static $type$ get($type$[] a, int i) {
1358        return ($type$) a[i];
1359    }
1360
1361    static final IntFunction<$type$[]> fr = (vl) -> {
1362        int length = BUFFER_REPS * vl;
1363        return new $type$[length];
1364    };
1365
1366    static final IntFunction<boolean[]> fmr = (vl) -> {
1367        int length = BUFFER_REPS * vl;
1368        return new boolean[length];
1369    };
1370
1371#if[!Long]
1372    static final IntFunction<long[]> lfr = (vl) -> {
1373        int length = BUFFER_REPS * vl;
1374        return new long[length];
1375    };
1376#end[!Long]
1377
1378#if[BITWISE]
1379    static void replaceZero($type$[] a, $type$ v) {
1380        for (int i = 0; i < a.length; i++) {
1381            if (a[i] == 0) {
1382                a[i] = v;
1383            }
1384        }
1385    }
1386
1387    static void replaceZero($type$[] a, boolean[] mask, $type$ v) {
1388        for (int i = 0; i < a.length; i++) {
1389            if (mask[i % mask.length] && a[i] == 0) {
1390                a[i] = v;
1391            }
1392        }
1393    }
1394#end[BITWISE]
1395
1396    @Test
1397    static void smokeTest1() {
1398        $abstractvectortype$ three = $abstractvectortype$.broadcast(SPECIES, (byte)-3);
1399        $abstractvectortype$ three2 = ($abstractvectortype$) SPECIES.broadcast(-3);
1400        assert(three.eq(three2).allTrue());
1401        $abstractvectortype$ three3 = three2.broadcast(1).broadcast(-3);
1402        assert(three.eq(three3).allTrue());
1403        int scale = 2;
1404        Class<?> ETYPE = $type$.class;
1405        if (ETYPE == double.class || ETYPE == long.class)
1406            scale = 1000000;
1407        else if (ETYPE == byte.class && SPECIES.length() >= 64)
1408            scale = 1;
1409        $abstractvectortype$ higher = three.addIndex(scale);
1410        VectorMask<$Boxtype$> m = three.compare(VectorOperators.LE, higher);
1411        assert(m.allTrue());
1412        m = higher.min(($type$)-1).test(VectorOperators.IS_NEGATIVE);
1413        assert(m.allTrue());
1414#if[FP]
1415        m = higher.test(VectorOperators.IS_FINITE);
1416        assert(m.allTrue());
1417#end[FP]
1418        $type$ max = higher.reduceLanes(VectorOperators.MAX);
1419        assert(max == -3 + scale * (SPECIES.length()-1));
1420    }
1421
1422    private static $type$[]
1423    bothToArray($abstractvectortype$ a, $abstractvectortype$ b) {
1424        $type$[] r = new $type$[a.length() + b.length()];
1425        a.intoArray(r, 0);
1426        b.intoArray(r, a.length());
1427        return r;
1428    }
1429
1430    @Test
1431    static void smokeTest2() {
1432        // Do some zipping and shuffling.
1433        $abstractvectortype$ io = ($abstractvectortype$) SPECIES.broadcast(0).addIndex(1);
1434        $abstractvectortype$ io2 = ($abstractvectortype$) VectorShuffle.iota(SPECIES,0,1,false).toVector();
1435        Assert.assertEquals(io, io2);
1436        $abstractvectortype$ a = io.add(($type$)1); //[1,2]
1437        $abstractvectortype$ b = a.neg();  //[-1,-2]
1438        $type$[] abValues = bothToArray(a,b); //[1,2,-1,-2]
1439        VectorShuffle<$Boxtype$> zip0 = VectorShuffle.makeZip(SPECIES, 0);
1440        VectorShuffle<$Boxtype$> zip1 = VectorShuffle.makeZip(SPECIES, 1);
1441        $abstractvectortype$ zab0 = a.rearrange(zip0,b); //[1,-1]
1442        $abstractvectortype$ zab1 = a.rearrange(zip1,b); //[2,-2]
1443        $type$[] zabValues = bothToArray(zab0, zab1); //[1,-1,2,-2]
1444        // manually zip
1445        $type$[] manual = new $type$[zabValues.length];
1446        for (int i = 0; i < manual.length; i += 2) {
1447            manual[i+0] = abValues[i/2];
1448            manual[i+1] = abValues[a.length() + i/2];
1449        }
1450        Assert.assertEquals(Arrays.toString(zabValues), Arrays.toString(manual));
1451        VectorShuffle<$Boxtype$> unz0 = VectorShuffle.makeUnzip(SPECIES, 0);
1452        VectorShuffle<$Boxtype$> unz1 = VectorShuffle.makeUnzip(SPECIES, 1);
1453        $abstractvectortype$ uab0 = zab0.rearrange(unz0,zab1);
1454        $abstractvectortype$ uab1 = zab0.rearrange(unz1,zab1);
1455        $type$[] abValues1 = bothToArray(uab0, uab1);
1456        Assert.assertEquals(Arrays.toString(abValues), Arrays.toString(abValues1));
1457    }
1458
1459    static void iotaShuffle() {
1460        $abstractvectortype$ io = ($abstractvectortype$) SPECIES.broadcast(0).addIndex(1);
1461        $abstractvectortype$ io2 = ($abstractvectortype$) VectorShuffle.iota(SPECIES, 0 , 1, false).toVector();
1462        Assert.assertEquals(io, io2);
1463    }
1464
1465    @Test
1466    // Test all shuffle related operations.
1467    static void shuffleTest() {
1468        // To test backend instructions, make sure that C2 is used.
1469        for (int loop = 0; loop < INVOC_COUNT * INVOC_COUNT; loop++) {
1470            iotaShuffle();
1471        }
1472    }
1473
1474    @Test
1475    void viewAsIntegeralLanesTest() {
1476#if[FP]
1477        Vector<?> asIntegral = SPECIES.zero().viewAsIntegralLanes();
1478        VectorSpecies<?> asIntegralSpecies = asIntegral.species();
1479        Assert.assertNotEquals(asIntegralSpecies.elementType(), SPECIES.elementType());
1480        Assert.assertEquals(asIntegralSpecies.vectorShape(), SPECIES.vectorShape());
1481        Assert.assertEquals(asIntegralSpecies.length(), SPECIES.length());
1482        Assert.assertEquals(asIntegral.viewAsFloatingLanes().species(), SPECIES);
1483#else[FP]
1484        Vector<?> asIntegral = SPECIES.zero().viewAsIntegralLanes();
1485        Assert.assertEquals(asIntegral.species(), SPECIES);
1486#end[FP]
1487    }
1488
1489#if[FP]
1490    @Test
1491    void viewAsFloatingLanesTest() {
1492        Vector<?> asFloating = SPECIES.zero().viewAsFloatingLanes();
1493        Assert.assertEquals(asFloating.species(), SPECIES);
1494    }
1495#else[FP]
1496#if[byteOrShort]
1497    @Test(expectedExceptions = UnsupportedOperationException.class)
1498    void viewAsFloatingLanesTest() {
1499        SPECIES.zero().viewAsFloatingLanes();
1500    }
1501#else[byteOrShort]
1502    @Test
1503    void viewAsFloatingLanesTest() {
1504        Vector<?> asFloating = SPECIES.zero().viewAsFloatingLanes();
1505        VectorSpecies<?> asFloatingSpecies = asFloating.species();
1506        Assert.assertNotEquals(asFloatingSpecies.elementType(), SPECIES.elementType());
1507        Assert.assertEquals(asFloatingSpecies.vectorShape(), SPECIES.vectorShape());
1508        Assert.assertEquals(asFloatingSpecies.length(), SPECIES.length());
1509        Assert.assertEquals(asFloating.viewAsIntegralLanes().species(), SPECIES);
1510    }
1511#end[byteOrShort]
1512#end[FP]
1513
1514#if[BITWISE]
1515    @Test
1516    // Test div by 0.
1517    static void bitwiseDivByZeroSmokeTest() {
1518        try {
1519            $abstractvectortype$ a = ($abstractvectortype$) SPECIES.broadcast(0).addIndex(1);
1520            $abstractvectortype$ b = ($abstractvectortype$) SPECIES.broadcast(0);
1521            a.div(b);
1522            Assert.fail();
1523        } catch (ArithmeticException e) {
1524        }
1525
1526        try {
1527            $abstractvectortype$ a = ($abstractvectortype$) SPECIES.broadcast(0).addIndex(1);
1528            $abstractvectortype$ b = ($abstractvectortype$) SPECIES.broadcast(0);
1529            VectorMask<$Boxtype$> m = a.lt(($type$) 1);
1530            a.div(b, m);
1531            Assert.fail();
1532        } catch (ArithmeticException e) {
1533        }
1534    }
1535#end[BITWISE]
1536