/* * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have * questions. */ /* * @test * @modules jdk.incubator.vector * @run testng/othervm -ea -esa $vectorteststype$ */ import jdk.incubator.vector.Vector.Shape; import jdk.incubator.vector.Vector.Species; import jdk.incubator.vector.Vector; #if[Byte] import jdk.incubator.vector.ByteVector; #end[Byte] #if[Float] import jdk.incubator.vector.FloatVector; #end[Float] #if[Int] import jdk.incubator.vector.IntVector; #end[Int] #if[Double] import jdk.incubator.vector.DoubleVector; #end[Double] #if[Short] import jdk.incubator.vector.ShortVector; #end[Short] #if[Long] import jdk.incubator.vector.LongVector; #end[Long] import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.lang.Integer; import java.util.List; #if[!byteOrShort] import java.util.Arrays; #end[!byteOrShort] import java.util.function.BiFunction; import java.util.function.IntFunction; import java.util.stream.Collectors; import java.util.stream.Stream; @Test public class $vectorteststype$ extends AbstractVectorTest { #if[MaxBit] static final Species<$Wideboxtype$> SPECIES = $Type$Vector.SPECIES_MAX; #else[MaxBit] static final Species<$Wideboxtype$> SPECIES = $Type$Vector.SPECIES_$bits$; #end[MaxBit] static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); #if[MaxBit] static Shape getMaxBit() { return Shape.S_Max_BIT; } #end[MaxBit] interface FUnOp { $type$ apply($type$ a); } static void assertArraysEquals($type$[] a, $type$[] r, FUnOp f) { int i = 0; try { for (; i < a.length; i++) { Assert.assertEquals(r[i], f.apply(a[i])); } } catch (AssertionError e) { Assert.assertEquals(r[i], f.apply(a[i]), "at index #" + i + ", input = " + a[i]); } } static void assertArraysEquals($type$[] a, $type$[] r, boolean[] mask, FUnOp f) { int i = 0; try { for (; i < a.length; i++) { Assert.assertEquals(r[i], mask[i % SPECIES.length()] ? f.apply(a[i]) : a[i]); } } catch (AssertionError e) { 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()]); } } interface FReductionOp { $type$ apply($type$[] a, int idx); } interface FReductionAllOp { $type$ apply($type$[] a); } static void assertReductionArraysEquals($type$[] a, $type$[] b, $type$ c, FReductionOp f, FReductionAllOp fa) { int i = 0; try { Assert.assertEquals(c, fa.apply(a)); for (; i < a.length; i += SPECIES.length()) { Assert.assertEquals(b[i], f.apply(a, i)); } } catch (AssertionError e) { Assert.assertEquals(c, fa.apply(a), "Final result is incorrect!"); Assert.assertEquals(b[i], f.apply(a, i), "at index #" + i); } } interface FBoolReductionOp { boolean apply(boolean[] a, int idx); } static void assertReductionBoolArraysEquals(boolean[] a, boolean[] b, FBoolReductionOp f) { int i = 0; try { for (; i < a.length; i += SPECIES.length()) { Assert.assertEquals(f.apply(a, i), b[i]); } } catch (AssertionError e) { Assert.assertEquals(f.apply(a, i), b[i], "at index #" + i); } } static void assertInsertArraysEquals($type$[] a, $type$[] b, $type$ element, int index) { int i = 0; try { for (; i < a.length; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(b[i], element); } else { Assert.assertEquals(b[i], a[i]); } } } catch (AssertionError e) { if (i%SPECIES.length() == index) { Assert.assertEquals(b[i], element, "at index #" + i); } else { Assert.assertEquals(b[i], a[i], "at index #" + i); } } } static void assertRearrangeArraysEquals($type$[] a, $type$[] r, int[] order, int vector_len) { int i = 0, j = 0; try { for (; i < a.length; i += vector_len) { for (j = 0; j < vector_len; j++) { Assert.assertEquals(r[i+j], a[i+order[i+j]]); } } } catch (AssertionError e) { int idx = i + j; Assert.assertEquals(r[i+j], a[i+order[i+j]], "at index #" + idx + ", input = " + a[i+order[i+j]]); } } interface FBinOp { $type$ apply($type$ a, $type$ b); } interface FBinMaskOp { $type$ apply($type$ a, $type$ b, boolean m); static FBinMaskOp lift(FBinOp f) { return (a, b, m) -> m ? f.apply(a, b) : a; } } static void assertArraysEquals($type$[] a, $type$[] b, $type$[] r, FBinOp f) { int i = 0; try { for (; i < a.length; i++) { Assert.assertEquals(r[i], f.apply(a[i], b[i])); } } catch (AssertionError e) { Assert.assertEquals(f.apply(a[i], b[i]), r[i], "(" + a[i] + ", " + b[i] + ") at index #" + i); } } static void assertArraysEquals($type$[] a, $type$[] b, $type$[] r, boolean[] mask, FBinOp f) { assertArraysEquals(a, b, r, mask, FBinMaskOp.lift(f)); } static void assertArraysEquals($type$[] a, $type$[] b, $type$[] r, boolean[] mask, FBinMaskOp f) { int i = 0; try { for (; i < a.length; i++) { Assert.assertEquals(r[i], f.apply(a[i], b[i], mask[i % SPECIES.length()])); } } catch (AssertionError err) { 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()]); } } static void assertShiftArraysEquals($type$[] a, $type$[] b, $type$[] r, FBinOp f) { int i = 0; int j = 0; try { for (; j < a.length; j += SPECIES.length()) { for (i = 0; i < SPECIES.length(); i++) { Assert.assertEquals(f.apply(a[i+j], b[j]), r[i+j]); } } } catch (AssertionError e) { Assert.assertEquals(f.apply(a[i+j], b[j]), r[i+j], "at index #" + i + ", " + j); } } static void assertShiftArraysEquals($type$[] a, $type$[] b, $type$[] r, boolean[] mask, FBinOp f) { assertShiftArraysEquals(a, b, r, mask, FBinMaskOp.lift(f)); } static void assertShiftArraysEquals($type$[] a, $type$[] b, $type$[] r, boolean[] mask, FBinMaskOp f) { int i = 0; int j = 0; try { for (; j < a.length; j += SPECIES.length()) { for (i = 0; i < SPECIES.length(); i++) { Assert.assertEquals(r[i+j], f.apply(a[i+j], b[j], mask[i])); } } } catch (AssertionError err) { 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]); } } #if[FP] interface FTernOp { $type$ apply($type$ a, $type$ b, $type$ c); } interface FTernMaskOp { $type$ apply($type$ a, $type$ b, $type$ c, boolean m); static FTernMaskOp lift(FTernOp f) { return (a, b, c, m) -> m ? f.apply(a, b, c) : a; } } static void assertArraysEquals($type$[] a, $type$[] b, $type$[] c, $type$[] r, FTernOp f) { int i = 0; try { for (; i < a.length; i++) { Assert.assertEquals(r[i], f.apply(a[i], b[i], c[i])); } } catch (AssertionError e) { Assert.assertEquals(r[i], f.apply(a[i], b[i], c[i]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b[i] + ", input3 = " + c[i]); } } static void assertArraysEquals($type$[] a, $type$[] b, $type$[] c, $type$[] r, boolean[] mask, FTernOp f) { assertArraysEquals(a, b, c, r, mask, FTernMaskOp.lift(f)); } static void assertArraysEquals($type$[] a, $type$[] b, $type$[] c, $type$[] r, boolean[] mask, FTernMaskOp f) { int i = 0; try { for (; i < a.length; i++) { Assert.assertEquals(r[i], f.apply(a[i], b[i], c[i], mask[i % SPECIES.length()])); } } catch (AssertionError err) { Assert.assertEquals(r[i], f.apply(a[i], b[i], c[i], mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b[i] + ", input3 = " + c[i] + ", mask = " + mask[i % SPECIES.length()]); } } static boolean isWithin1Ulp($type$ actual, $type$ expected) { if ($Type$.isNaN(expected) && !$Type$.isNaN(actual)) { return false; } else if (!$Type$.isNaN(expected) && $Type$.isNaN(actual)) { return false; } $type$ low = Math.nextDown(expected); $type$ high = Math.nextUp(expected); if ($Type$.compare(low, expected) > 0) { return false; } if ($Type$.compare(high, expected) < 0) { return false; } return true; } static void assertArraysEqualsWithinOneUlp($type$[] a, $type$[] r, FUnOp mathf, FUnOp strictmathf) { int i = 0; try { // Check that result is within 1 ulp of strict math or equivalent to math implementation. for (; i < a.length; i++) { Assert.assertTrue($Type$.compare(r[i], mathf.apply(a[i])) == 0 || isWithin1Ulp(r[i], strictmathf.apply(a[i]))); } } catch (AssertionError e) { 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])); 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])); } } static void assertArraysEqualsWithinOneUlp($type$[] a, $type$[] b, $type$[] r, FBinOp mathf, FBinOp strictmathf) { int i = 0; try { // Check that result is within 1 ulp of strict math or equivalent to math implementation. for (; i < a.length; i++) { Assert.assertTrue($Type$.compare(r[i], mathf.apply(a[i], b[i])) == 0 || isWithin1Ulp(r[i], strictmathf.apply(a[i], b[i]))); } } catch (AssertionError e) { 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])); 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])); } } #end[FP] interface FBinArrayOp { $type$ apply($type$[] a, int b); } static void assertArraysEquals($type$[] a, $type$[] r, FBinArrayOp f) { int i = 0; try { for (; i < a.length; i++) { Assert.assertEquals(f.apply(a, i), r[i]); } } catch (AssertionError e) { Assert.assertEquals(f.apply(a,i), r[i], "at index #" + i); } } #if[!byteOrShort] interface FGatherScatterOp { $type$[] apply($type$[] a, int ix, int[] b, int iy); } static void assertArraysEquals($type$[] a, int[] b, $type$[] r, FGatherScatterOp f) { int i = 0; try { for (; i < a.length; i += SPECIES.length()) { Assert.assertEquals(Arrays.copyOfRange(r, i, i+SPECIES.length()), f.apply(a, i, b, i)); } } catch (AssertionError e) { $type$[] ref = f.apply(a, i, b, i); $type$[] res = Arrays.copyOfRange(r, i, i+SPECIES.length()); Assert.assertEquals(ref, res, "(ref: " + Arrays.toString(ref) + ", res: " + Arrays.toString(res) + ", a: " + Arrays.toString(Arrays.copyOfRange(a, i, i+SPECIES.length())) + ", b: " + Arrays.toString(Arrays.copyOfRange(b, i, i+SPECIES.length())) + " at index #" + i); } } #end[!byteOrShort] static final List> $TYPE$_GENERATORS = List.of( withToString("$type$[-i * 5]", (int s) -> { return fill(s * 1000, i -> ($type$)(-i * 5)); }), withToString("$type$[i * 5]", (int s) -> { return fill(s * 1000, i -> ($type$)(i * 5)); }), withToString("$type$[i + 1]", (int s) -> { return fill(s * 1000, i -> ((($type$)(i + 1) == 0) ? 1 : ($type$)(i + 1))); }), withToString("$type$[cornerCaseValue(i)]", (int s) -> { return fill(s * 1000, i -> cornerCaseValue(i)); }) ); // Create combinations of pairs // @@@ Might be sensitive to order e.g. div by 0 static final List>> $TYPE$_GENERATOR_PAIRS = Stream.of($TYPE$_GENERATORS.get(0)). flatMap(fa -> $TYPE$_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); @DataProvider public Object[][] boolUnaryOpProvider() { return BOOL_ARRAY_GENERATORS.stream(). map(f -> new Object[]{f}). toArray(Object[][]::new); } #if[FP] static final List>> $TYPE$_GENERATOR_TRIPLES = $TYPE$_GENERATOR_PAIRS.stream(). flatMap(pair -> $TYPE$_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). collect(Collectors.toList()); #end[FP] @DataProvider public Object[][] $type$BinaryOpProvider() { return $TYPE$_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } @DataProvider public Object[][] $type$IndexedOpProvider() { return $TYPE$_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } @DataProvider public Object[][] $type$BinaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). flatMap(fm -> $TYPE$_GENERATOR_PAIRS.stream().map(lfa -> { return Stream.concat(lfa.stream(), Stream.of(fm)).toArray(); })). toArray(Object[][]::new); } #if[FP] @DataProvider public Object[][] $type$TernaryOpProvider() { return $TYPE$_GENERATOR_TRIPLES.stream().map(List::toArray). toArray(Object[][]::new); } @DataProvider public Object[][] $type$TernaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). flatMap(fm -> $TYPE$_GENERATOR_TRIPLES.stream().map(lfa -> { return Stream.concat(lfa.stream(), Stream.of(fm)).toArray(); })). toArray(Object[][]::new); } #end[FP] @DataProvider public Object[][] $type$UnaryOpProvider() { return $TYPE$_GENERATORS.stream(). map(f -> new Object[]{f}). toArray(Object[][]::new); } @DataProvider public Object[][] $type$UnaryOpMaskProvider() { return BOOLEAN_MASK_GENERATORS.stream(). flatMap(fm -> $TYPE$_GENERATORS.stream().map(fa -> { return new Object[] {fa, fm}; })). toArray(Object[][]::new); } @DataProvider public Object[][] $type$UnaryOpShuffleProvider() { return INT_SHUFFLE_GENERATORS.stream(). flatMap(fs -> $TYPE$_GENERATORS.stream().map(fa -> { return new Object[] {fa, fs}; })). toArray(Object[][]::new); } @DataProvider public Object[][] $type$UnaryOpIndexProvider() { return INT_INDEX_GENERATORS.stream(). flatMap(fs -> $TYPE$_GENERATORS.stream().map(fa -> { return new Object[] {fa, fs}; })). toArray(Object[][]::new); } static final List> $TYPE$_COMPARE_GENERATORS = List.of( withToString("$type$[i]", (int s) -> { return fill(s * 1000, i -> ($type$)i); }), withToString("$type$[i + 1]", (int s) -> { return fill(s * 1000, i -> ($type$)(i + 1)); }), withToString("$type$[i - 2]", (int s) -> { return fill(s * 1000, i -> ($type$)(i - 2)); }), withToString("$type$[zigZag(i)]", (int s) -> { return fill(s * 1000, i -> i%3 == 0 ? ($type$)i : (i%3 == 1 ? ($type$)(i + 1) : ($type$)(i - 2))); }), withToString("$type$[cornerCaseValue(i)]", (int s) -> { return fill(s * 1000, i -> cornerCaseValue(i)); }) ); static final List>> $TYPE$_COMPARE_GENERATOR_PAIRS = $TYPE$_COMPARE_GENERATORS.stream(). flatMap(fa -> $TYPE$_COMPARE_GENERATORS.stream().map(fb -> List.of(fa, fb))). collect(Collectors.toList()); @DataProvider public Object[][] $type$CompareOpProvider() { return $TYPE$_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). toArray(Object[][]::new); } interface To$Type$F { $type$ apply(int i); } static $type$[] fill(int s , To$Type$F f) { return fill(new $type$[s], f); } static $type$[] fill($type$[] a, To$Type$F f) { for (int i = 0; i < a.length; i++) { a[i] = f.apply(i); } return a; } static $type$ cornerCaseValue(int i) { #if[FP] switch(i % 7) { case 0: return $Wideboxtype$.MAX_VALUE; case 1: return $Wideboxtype$.MIN_VALUE; case 2: return $Wideboxtype$.NEGATIVE_INFINITY; case 3: return $Wideboxtype$.POSITIVE_INFINITY; case 4: return $Wideboxtype$.NaN; case 5: return ($type$)0.0; default: return ($type$)-0.0; } #else[FP] switch(i % 5) { case 0: return $Wideboxtype$.MAX_VALUE; case 1: return $Wideboxtype$.MIN_VALUE; case 2: return $Wideboxtype$.MIN_VALUE; case 3: return $Wideboxtype$.MAX_VALUE; default: return ($type$)0; } #end[FP] } static $type$ get($type$[] a, int i) { return ($type$) a[i]; } static final IntFunction<$type$[]> fr = (vl) -> { int length = 1000 * vl; return new $type$[length]; }; static final IntFunction fmr = (vl) -> { int length = 1000 * vl; return new boolean[length]; };