1 /* 2 * Copyright (c) 2018, 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 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @modules jdk.incubator.vector 27 * @run testng/othervm -ea -esa $vectorteststype$ 28 */ 29 30 import jdk.incubator.vector.Vector.Shape; 31 import jdk.incubator.vector.Vector.Species; 32 import jdk.incubator.vector.Vector; 33 34 #if[Byte] 35 import jdk.incubator.vector.ByteVector; 36 #end[Byte] 37 #if[Float] 38 import jdk.incubator.vector.FloatVector; 39 #end[Float] 40 #if[Int] 41 import jdk.incubator.vector.IntVector; 42 #end[Int] 43 #if[Double] 44 import jdk.incubator.vector.DoubleVector; 45 #end[Double] 46 #if[Short] 47 import jdk.incubator.vector.ShortVector; 48 #end[Short] 49 #if[Long] 50 import jdk.incubator.vector.LongVector; 51 #end[Long] 52 53 import org.testng.Assert; 54 import org.testng.annotations.DataProvider; 55 import org.testng.annotations.Test; 56 57 import java.lang.Integer; 58 import java.util.List; 59 #if[!byteOrShort] 60 import java.util.Arrays; 61 #end[!byteOrShort] 62 import java.util.function.BiFunction; 63 import java.util.function.IntFunction; 64 import java.util.stream.Collectors; 65 import java.util.stream.Stream; 66 67 @Test 68 public class $vectorteststype$ extends AbstractVectorTest { 69 70 #if[MaxBit] 71 static final Species<$Wideboxtype$> SPECIES = 72 $Type$Vector.SPECIES_MAX; 73 #else[MaxBit] 74 static final Species<$Wideboxtype$> SPECIES = 75 $Type$Vector.SPECIES_$bits$; 76 #end[MaxBit] 77 78 static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); 79 80 #if[MaxBit] 81 static Shape getMaxBit() { 82 return Shape.S_Max_BIT; 83 } 84 85 #end[MaxBit] 86 interface FUnOp { 87 $type$ apply($type$ a); 88 } 89 90 static void assertArraysEquals($type$[] a, $type$[] r, FUnOp f) { 91 int i = 0; 92 try { 93 for (; i < a.length; i++) { 94 Assert.assertEquals(r[i], f.apply(a[i])); 95 } 96 } catch (AssertionError e) { 97 Assert.assertEquals(r[i], f.apply(a[i]), "at index #" + i + ", input = " + a[i]); 98 } 99 } 100 101 static void assertArraysEquals($type$[] a, $type$[] r, boolean[] mask, FUnOp f) { 102 int i = 0; 103 try { 104 for (; i < a.length; i++) { 105 Assert.assertEquals(r[i], mask[i % SPECIES.length()] ? f.apply(a[i]) : a[i]); 106 } 107 } catch (AssertionError e) { 108 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()]); 109 } 110 } 111 112 interface FReductionOp { 113 $type$ apply($type$[] a, int idx); 114 } 115 116 interface FReductionAllOp { 117 $type$ apply($type$[] a); 118 } 119 120 static void assertReductionArraysEquals($type$[] a, $type$[] b, $type$ c, 121 FReductionOp f, FReductionAllOp fa) { 122 int i = 0; 123 try { 124 Assert.assertEquals(c, fa.apply(a)); 125 for (; i < a.length; i += SPECIES.length()) { 126 Assert.assertEquals(b[i], f.apply(a, i)); 127 } 128 } catch (AssertionError e) { 129 Assert.assertEquals(c, fa.apply(a), "Final result is incorrect!"); 130 Assert.assertEquals(b[i], f.apply(a, i), "at index #" + i); 131 } 132 } 133 134 interface FBoolReductionOp { 135 boolean apply(boolean[] a, int idx); 136 } 137 138 static void assertReductionBoolArraysEquals(boolean[] a, boolean[] b, FBoolReductionOp f) { 139 int i = 0; 140 try { 141 for (; i < a.length; i += SPECIES.length()) { 142 Assert.assertEquals(f.apply(a, i), b[i]); 143 } 144 } catch (AssertionError e) { 145 Assert.assertEquals(f.apply(a, i), b[i], "at index #" + i); 146 } 147 } 148 149 static void assertInsertArraysEquals($type$[] a, $type$[] b, $type$ element, int index) { 150 int i = 0; 151 try { 152 for (; i < a.length; i += 1) { 153 if(i%SPECIES.length() == index) { 154 Assert.assertEquals(b[i], element); 155 } else { 156 Assert.assertEquals(b[i], a[i]); 157 } 158 } 159 } catch (AssertionError e) { 160 if (i%SPECIES.length() == index) { 161 Assert.assertEquals(b[i], element, "at index #" + i); 162 } else { 163 Assert.assertEquals(b[i], a[i], "at index #" + i); 164 } 165 } 166 } 167 168 static void assertRearrangeArraysEquals($type$[] a, $type$[] r, int[] order, int vector_len) { 169 int i = 0, j = 0; 170 try { 171 for (; i < a.length; i += vector_len) { 172 for (j = 0; j < vector_len; j++) { 173 Assert.assertEquals(r[i+j], a[i+order[i+j]]); 174 } 175 } 176 } catch (AssertionError e) { 177 int idx = i + j; 178 Assert.assertEquals(r[i+j], a[i+order[i+j]], "at index #" + idx + ", input = " + a[i+order[i+j]]); 179 } 180 } 181 182 interface FBinOp { 183 $type$ apply($type$ a, $type$ b); 184 } 185 186 interface FBinMaskOp { 187 $type$ apply($type$ a, $type$ b, boolean m); 188 189 static FBinMaskOp lift(FBinOp f) { 190 return (a, b, m) -> m ? f.apply(a, b) : a; 191 } 192 } 193 194 static void assertArraysEquals($type$[] a, $type$[] b, $type$[] r, FBinOp f) { 195 int i = 0; 196 try { 197 for (; i < a.length; i++) { 198 Assert.assertEquals(r[i], f.apply(a[i], b[i])); 199 } 200 } catch (AssertionError e) { 201 Assert.assertEquals(f.apply(a[i], b[i]), r[i], "(" + a[i] + ", " + b[i] + ") at index #" + i); 202 } 203 } 204 205 static void assertArraysEquals($type$[] a, $type$[] b, $type$[] r, boolean[] mask, FBinOp f) { 206 assertArraysEquals(a, b, r, mask, FBinMaskOp.lift(f)); 207 } 208 209 static void assertArraysEquals($type$[] a, $type$[] b, $type$[] r, boolean[] mask, FBinMaskOp f) { 210 int i = 0; 211 try { 212 for (; i < a.length; i++) { 213 Assert.assertEquals(r[i], f.apply(a[i], b[i], mask[i % SPECIES.length()])); 214 } 215 } catch (AssertionError err) { 216 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()]); 217 } 218 } 219 220 static void assertShiftArraysEquals($type$[] a, $type$[] b, $type$[] r, FBinOp f) { 221 int i = 0; 222 int j = 0; 223 try { 224 for (; j < a.length; j += SPECIES.length()) { 225 for (i = 0; i < SPECIES.length(); i++) { 226 Assert.assertEquals(f.apply(a[i+j], b[j]), r[i+j]); 227 } 228 } 229 } catch (AssertionError e) { 230 Assert.assertEquals(f.apply(a[i+j], b[j]), r[i+j], "at index #" + i + ", " + j); 231 } 232 } 233 234 static void assertShiftArraysEquals($type$[] a, $type$[] b, $type$[] r, boolean[] mask, FBinOp f) { 235 assertShiftArraysEquals(a, b, r, mask, FBinMaskOp.lift(f)); 236 } 237 238 static void assertShiftArraysEquals($type$[] a, $type$[] b, $type$[] r, boolean[] mask, FBinMaskOp f) { 239 int i = 0; 240 int j = 0; 241 try { 242 for (; j < a.length; j += SPECIES.length()) { 243 for (i = 0; i < SPECIES.length(); i++) { 244 Assert.assertEquals(r[i+j], f.apply(a[i+j], b[j], mask[i])); 245 } 246 } 247 } catch (AssertionError err) { 248 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]); 249 } 250 } 251 252 #if[FP] 253 interface FTernOp { 254 $type$ apply($type$ a, $type$ b, $type$ c); 255 } 256 257 interface FTernMaskOp { 258 $type$ apply($type$ a, $type$ b, $type$ c, boolean m); 259 260 static FTernMaskOp lift(FTernOp f) { 261 return (a, b, c, m) -> m ? f.apply(a, b, c) : a; 262 } 263 } 264 265 static void assertArraysEquals($type$[] a, $type$[] b, $type$[] c, $type$[] r, FTernOp f) { 266 int i = 0; 267 try { 268 for (; i < a.length; i++) { 269 Assert.assertEquals(r[i], f.apply(a[i], b[i], c[i])); 270 } 271 } catch (AssertionError e) { 272 Assert.assertEquals(r[i], f.apply(a[i], b[i], c[i]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b[i] + ", input3 = " + c[i]); 273 } 274 } 275 276 static void assertArraysEquals($type$[] a, $type$[] b, $type$[] c, $type$[] r, boolean[] mask, FTernOp f) { 277 assertArraysEquals(a, b, c, r, mask, FTernMaskOp.lift(f)); 278 } 279 280 static void assertArraysEquals($type$[] a, $type$[] b, $type$[] c, $type$[] r, boolean[] mask, FTernMaskOp f) { 281 int i = 0; 282 try { 283 for (; i < a.length; i++) { 284 Assert.assertEquals(r[i], f.apply(a[i], b[i], c[i], mask[i % SPECIES.length()])); 285 } 286 } catch (AssertionError err) { 287 Assert.assertEquals(r[i], f.apply(a[i], b[i], c[i], mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " 288 + b[i] + ", input3 = " + c[i] + ", mask = " + mask[i % SPECIES.length()]); 289 } 290 } 291 292 static boolean isWithin1Ulp($type$ actual, $type$ expected) { 293 if ($Type$.isNaN(expected) && !$Type$.isNaN(actual)) { 294 return false; 295 } else if (!$Type$.isNaN(expected) && $Type$.isNaN(actual)) { 296 return false; 297 } 298 299 $type$ low = Math.nextDown(expected); 300 $type$ high = Math.nextUp(expected); 301 302 if ($Type$.compare(low, expected) > 0) { 303 return false; 304 } 305 306 if ($Type$.compare(high, expected) < 0) { 307 return false; 308 } 309 310 return true; 311 } 312 313 static void assertArraysEqualsWithinOneUlp($type$[] a, $type$[] r, FUnOp mathf, FUnOp strictmathf) { 314 int i = 0; 315 try { 316 // Check that result is within 1 ulp of strict math or equivalent to math implementation. 317 for (; i < a.length; i++) { 318 Assert.assertTrue($Type$.compare(r[i], mathf.apply(a[i])) == 0 || 319 isWithin1Ulp(r[i], strictmathf.apply(a[i]))); 320 } 321 } catch (AssertionError e) { 322 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])); 323 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])); 324 } 325 } 326 327 static void assertArraysEqualsWithinOneUlp($type$[] a, $type$[] b, $type$[] r, FBinOp mathf, FBinOp strictmathf) { 328 int i = 0; 329 try { 330 // Check that result is within 1 ulp of strict math or equivalent to math implementation. 331 for (; i < a.length; i++) { 332 Assert.assertTrue($Type$.compare(r[i], mathf.apply(a[i], b[i])) == 0 || 333 isWithin1Ulp(r[i], strictmathf.apply(a[i], b[i]))); 334 } 335 } catch (AssertionError e) { 336 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])); 337 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])); 338 } 339 } 340 #end[FP] 341 342 interface FBinArrayOp { 343 $type$ apply($type$[] a, int b); 344 } 345 346 static void assertArraysEquals($type$[] a, $type$[] r, FBinArrayOp f) { 347 int i = 0; 348 try { 349 for (; i < a.length; i++) { 350 Assert.assertEquals(f.apply(a, i), r[i]); 351 } 352 } catch (AssertionError e) { 353 Assert.assertEquals(f.apply(a,i), r[i], "at index #" + i); 354 } 355 } 356 #if[!byteOrShort] 357 interface FGatherScatterOp { 358 $type$[] apply($type$[] a, int ix, int[] b, int iy); 359 } 360 361 static void assertArraysEquals($type$[] a, int[] b, $type$[] r, FGatherScatterOp f) { 362 int i = 0; 363 try { 364 for (; i < a.length; i += SPECIES.length()) { 365 Assert.assertEquals(Arrays.copyOfRange(r, i, i+SPECIES.length()), 366 f.apply(a, i, b, i)); 367 } 368 } catch (AssertionError e) { 369 $type$[] ref = f.apply(a, i, b, i); 370 $type$[] res = Arrays.copyOfRange(r, i, i+SPECIES.length()); 371 Assert.assertEquals(ref, res, 372 "(ref: " + Arrays.toString(ref) + ", res: " + Arrays.toString(res) + ", a: " 373 + Arrays.toString(Arrays.copyOfRange(a, i, i+SPECIES.length())) 374 + ", b: " 375 + Arrays.toString(Arrays.copyOfRange(b, i, i+SPECIES.length())) 376 + " at index #" + i); 377 } 378 } 379 380 #end[!byteOrShort] 381 382 static final List<IntFunction<$type$[]>> $TYPE$_GENERATORS = List.of( 383 withToString("$type$[-i * 5]", (int s) -> { 384 return fill(s * 1000, 385 i -> ($type$)(-i * 5)); 386 }), 387 withToString("$type$[i * 5]", (int s) -> { 388 return fill(s * 1000, 389 i -> ($type$)(i * 5)); 390 }), 391 withToString("$type$[i + 1]", (int s) -> { 392 return fill(s * 1000, 393 i -> ((($type$)(i + 1) == 0) ? 1 : ($type$)(i + 1))); 394 }), 395 withToString("$type$[cornerCaseValue(i)]", (int s) -> { 396 return fill(s * 1000, 397 i -> cornerCaseValue(i)); 398 }) 399 ); 400 401 // Create combinations of pairs 402 // @@@ Might be sensitive to order e.g. div by 0 403 static final List<List<IntFunction<$type$[]>>> $TYPE$_GENERATOR_PAIRS = 404 Stream.of($TYPE$_GENERATORS.get(0)). 405 flatMap(fa -> $TYPE$_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). 406 collect(Collectors.toList()); 407 408 @DataProvider 409 public Object[][] boolUnaryOpProvider() { 410 return BOOL_ARRAY_GENERATORS.stream(). 411 map(f -> new Object[]{f}). 412 toArray(Object[][]::new); 413 } 414 415 #if[FP] 416 static final List<List<IntFunction<$type$[]>>> $TYPE$_GENERATOR_TRIPLES = 417 $TYPE$_GENERATOR_PAIRS.stream(). 418 flatMap(pair -> $TYPE$_GENERATORS.stream().map(f -> List.of(pair.get(0), pair.get(1), f))). 419 collect(Collectors.toList()); 420 #end[FP] 421 422 @DataProvider 423 public Object[][] $type$BinaryOpProvider() { 424 return $TYPE$_GENERATOR_PAIRS.stream().map(List::toArray). 425 toArray(Object[][]::new); 426 } 427 428 @DataProvider 429 public Object[][] $type$IndexedOpProvider() { 430 return $TYPE$_GENERATOR_PAIRS.stream().map(List::toArray). 431 toArray(Object[][]::new); 432 } 433 434 @DataProvider 435 public Object[][] $type$BinaryOpMaskProvider() { 436 return BOOLEAN_MASK_GENERATORS.stream(). 437 flatMap(fm -> $TYPE$_GENERATOR_PAIRS.stream().map(lfa -> { 438 return Stream.concat(lfa.stream(), Stream.of(fm)).toArray(); 439 })). 440 toArray(Object[][]::new); 441 } 442 443 #if[FP] 444 @DataProvider 445 public Object[][] $type$TernaryOpProvider() { 446 return $TYPE$_GENERATOR_TRIPLES.stream().map(List::toArray). 447 toArray(Object[][]::new); 448 } 449 450 @DataProvider 451 public Object[][] $type$TernaryOpMaskProvider() { 452 return BOOLEAN_MASK_GENERATORS.stream(). 453 flatMap(fm -> $TYPE$_GENERATOR_TRIPLES.stream().map(lfa -> { 454 return Stream.concat(lfa.stream(), Stream.of(fm)).toArray(); 455 })). 456 toArray(Object[][]::new); 457 } 458 #end[FP] 459 460 @DataProvider 461 public Object[][] $type$UnaryOpProvider() { 462 return $TYPE$_GENERATORS.stream(). 463 map(f -> new Object[]{f}). 464 toArray(Object[][]::new); 465 } 466 467 @DataProvider 468 public Object[][] $type$UnaryOpMaskProvider() { 469 return BOOLEAN_MASK_GENERATORS.stream(). 470 flatMap(fm -> $TYPE$_GENERATORS.stream().map(fa -> { 471 return new Object[] {fa, fm}; 472 })). 473 toArray(Object[][]::new); 474 } 475 476 @DataProvider 477 public Object[][] $type$UnaryOpShuffleProvider() { 478 return INT_SHUFFLE_GENERATORS.stream(). 479 flatMap(fs -> $TYPE$_GENERATORS.stream().map(fa -> { 480 return new Object[] {fa, fs}; 481 })). 482 toArray(Object[][]::new); 483 } 484 485 @DataProvider 486 public Object[][] $type$UnaryOpIndexProvider() { 487 return INT_INDEX_GENERATORS.stream(). 488 flatMap(fs -> $TYPE$_GENERATORS.stream().map(fa -> { 489 return new Object[] {fa, fs}; 490 })). 491 toArray(Object[][]::new); 492 } 493 494 495 static final List<IntFunction<$type$[]>> $TYPE$_COMPARE_GENERATORS = List.of( 496 withToString("$type$[i]", (int s) -> { 497 return fill(s * 1000, 498 i -> ($type$)i); 499 }), 500 withToString("$type$[i + 1]", (int s) -> { 501 return fill(s * 1000, 502 i -> ($type$)(i + 1)); 503 }), 504 withToString("$type$[i - 2]", (int s) -> { 505 return fill(s * 1000, 506 i -> ($type$)(i - 2)); 507 }), 508 withToString("$type$[zigZag(i)]", (int s) -> { 509 return fill(s * 1000, 510 i -> i%3 == 0 ? ($type$)i : (i%3 == 1 ? ($type$)(i + 1) : ($type$)(i - 2))); 511 }), 512 withToString("$type$[cornerCaseValue(i)]", (int s) -> { 513 return fill(s * 1000, 514 i -> cornerCaseValue(i)); 515 }) 516 ); 517 518 static final List<List<IntFunction<$type$[]>>> $TYPE$_COMPARE_GENERATOR_PAIRS = 519 $TYPE$_COMPARE_GENERATORS.stream(). 520 flatMap(fa -> $TYPE$_COMPARE_GENERATORS.stream().map(fb -> List.of(fa, fb))). 521 collect(Collectors.toList()); 522 523 @DataProvider 524 public Object[][] $type$CompareOpProvider() { 525 return $TYPE$_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). 526 toArray(Object[][]::new); 527 } 528 529 interface To$Type$F { 530 $type$ apply(int i); 531 } 532 533 static $type$[] fill(int s , To$Type$F f) { 534 return fill(new $type$[s], f); 535 } 536 537 static $type$[] fill($type$[] a, To$Type$F f) { 538 for (int i = 0; i < a.length; i++) { 539 a[i] = f.apply(i); 540 } 541 return a; 542 } 543 544 static $type$ cornerCaseValue(int i) { 545 #if[FP] 546 switch(i % 7) { 547 case 0: 548 return $Wideboxtype$.MAX_VALUE; 549 case 1: 550 return $Wideboxtype$.MIN_VALUE; 551 case 2: 552 return $Wideboxtype$.NEGATIVE_INFINITY; 553 case 3: 554 return $Wideboxtype$.POSITIVE_INFINITY; 555 case 4: 556 return $Wideboxtype$.NaN; 557 case 5: 558 return ($type$)0.0; 559 default: 560 return ($type$)-0.0; 561 } 562 #else[FP] 563 switch(i % 5) { 564 case 0: 565 return $Wideboxtype$.MAX_VALUE; 566 case 1: 567 return $Wideboxtype$.MIN_VALUE; 568 case 2: 569 return $Wideboxtype$.MIN_VALUE; 570 case 3: 571 return $Wideboxtype$.MAX_VALUE; 572 default: 573 return ($type$)0; 574 } 575 #end[FP] 576 } 577 static $type$ get($type$[] a, int i) { 578 return ($type$) a[i]; 579 } 580 581 static final IntFunction<$type$[]> fr = (vl) -> { 582 int length = 1000 * vl; 583 return new $type$[length]; 584 }; 585 586 static final IntFunction<boolean[]> fmr = (vl) -> { 587 int length = 1000 * vl; 588 return new boolean[length]; 589 };