1 /* 2 * Copyright (c) 2017, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package jdk.incubator.vector; 26 27 import jdk.internal.vm.annotation.ForceInline; 28 import jdk.internal.vm.annotation.Stable; 29 import java.nio.ByteOrder; 30 import java.lang.reflect.Array; 31 import java.util.Arrays; 32 import java.util.function.Function; 33 import java.util.function.IntUnaryOperator; 34 35 abstract class AbstractSpecies<E> extends jdk.internal.vm.vector.VectorSupport.VectorSpecies<E> 36 implements VectorSpecies<E> { 37 @Stable 38 final VectorShape vectorShape; 39 @Stable 40 final LaneType laneType; 41 @Stable 42 final int laneCount; 43 @Stable 44 final int laneCountLog2P1; 45 @Stable 46 final Class<? extends AbstractVector<E>> vectorType; 47 @Stable 48 final Class<? extends AbstractMask<E>> maskType; 49 @Stable 50 final Function<Object, ? extends AbstractVector<E>> vectorFactory; 51 52 @Stable 53 final VectorShape indexShape; 54 @Stable 55 final int maxScale, minScale; 56 @Stable 57 final int vectorBitSize, vectorByteSize; 58 AbstractSpecies(VectorShape vectorShape, LaneType laneType, Class<? extends AbstractVector<E>> vectorType, Class<? extends AbstractMask<E>> maskType, Function<Object, ? extends AbstractVector<E>> vectorFactory)59 AbstractSpecies(VectorShape vectorShape, 60 LaneType laneType, 61 Class<? extends AbstractVector<E>> vectorType, 62 Class<? extends AbstractMask<E>> maskType, 63 Function<Object, ? extends AbstractVector<E>> vectorFactory) { 64 this.vectorShape = vectorShape; 65 this.laneType = laneType; 66 this.vectorType = vectorType; 67 this.maskType = maskType; 68 this.vectorFactory = vectorFactory; 69 70 // derived values: 71 int bitSize = vectorShape.vectorBitSize(); 72 int byteSize = bitSize / Byte.SIZE; 73 assert(byteSize * 8 == bitSize); 74 this.vectorBitSize = bitSize; 75 this.vectorByteSize = byteSize; 76 int elementSize = laneType.elementSize; 77 this.laneCount = bitSize / elementSize; 78 assert(laneCount > 0); // could be 1 for mono-vector (double in v64) 79 this.laneCountLog2P1 = Integer.numberOfTrailingZeros(laneCount) + 1; 80 81 // Note: The shape might be the max-shape, 82 // if there is no vector this large. 83 int indexBitSize = Integer.SIZE * laneCount; 84 this.indexShape = VectorShape.forIndexBitSize(indexBitSize, elementSize); 85 86 // What are the largest and smallest scale factors that, 87 // when multiplied times the elements in [0..VLENGTH], 88 // inclusive, do not overflow the ETYPE? 89 int precision = laneType.elementPrecision; 90 if (precision >= Integer.SIZE) { 91 // No overflow possible from int*int. 92 this.maxScale = Integer.MAX_VALUE; 93 this.minScale = Integer.MIN_VALUE; 94 } else { 95 boolean isfp = (laneType.elementKind == 'F'); 96 long x = laneCount; 97 long maxScale = ((1L << precision)-(isfp?0:1)) / x; 98 long minScale = (-1L << precision) / x; 99 this.maxScale = (int) maxScale; 100 this.minScale = (int) minScale; 101 } 102 } 103 104 @Stable //lazy JIT constant 105 AbstractSpecies<Integer> indexSpecies; 106 107 @Stable //lazy JIT constant 108 AbstractShuffle<Byte> swapBytesShuffle; 109 110 @Stable //lazy JIT constant 111 AbstractVector<E> dummyVector; 112 113 @Override 114 @ForceInline length()115 public final int length() { 116 return laneCount; 117 } 118 119 // Inside the implementation we use the more descriptive 120 // term laneCount: 121 122 /*package-private*/ 123 @ForceInline laneCount()124 final int laneCount() { 125 return laneCount; 126 } 127 128 /*package-private*/ 129 @ForceInline laneCountLog2()130 final int laneCountLog2() { 131 return laneCountLog2P1 - 1; // subtract one from stable value 132 } 133 134 @Override 135 @ForceInline 136 @SuppressWarnings("unchecked") 137 //NOT FINAL: SPECIALIZED elementType()138 public Class<E> elementType() { 139 return (Class<E>) laneType.elementType; 140 } 141 142 // FIXME: appeal to general method (see https://bugs.openjdk.java.net/browse/JDK-6176992) 143 // replace usages of this method and remove 144 @ForceInline 145 @SuppressWarnings("unchecked") 146 //NOT FINAL: SPECIALIZED genericElementType()147 Class<E> genericElementType() { 148 return (Class<E>) laneType.genericElementType; 149 } 150 151 @Override 152 @ForceInline 153 //NOT FINAL: SPECIALIZED vectorType()154 public Class<? extends AbstractVector<E>> vectorType() { 155 return vectorType; 156 } 157 158 @Override 159 @ForceInline maskType()160 public final Class<? extends AbstractMask<E>> maskType() { 161 return maskType; 162 } 163 164 @Override 165 @ForceInline elementSize()166 public final int elementSize() { 167 return laneType.elementSize; 168 } 169 170 /*package-private*/ 171 @ForceInline elementByteSize()172 final int elementByteSize() { 173 return laneType.elementSize / Byte.SIZE; 174 } 175 176 @Override 177 @ForceInline vectorShape()178 public final VectorShape vectorShape() { 179 return vectorShape; 180 } 181 182 @ForceInline 183 /*package-private*/ indexShape()184 final VectorShape indexShape() { 185 return indexShape; 186 } 187 188 @Override 189 @ForceInline vectorBitSize()190 public final int vectorBitSize() { 191 return vectorBitSize; 192 } 193 194 @Override 195 @ForceInline vectorByteSize()196 public final int vectorByteSize() { 197 return vectorByteSize; 198 } 199 200 @Override 201 @ForceInline loopBound(int length)202 public final int loopBound(int length) { 203 return VectorIntrinsics.roundDown(length, laneCount); 204 } 205 206 @Override 207 @ForceInline indexInRange(int offset, int limit)208 public final VectorMask<E> indexInRange(int offset, int limit) { 209 return maskAll(true).indexInRange(offset, limit); 210 } 211 212 @Override 213 @ForceInline withLanes(Class<F> newType)214 public final <F> VectorSpecies<F> withLanes(Class<F> newType) { 215 return withLanes(LaneType.of(newType)).check(newType); 216 } 217 218 @ForceInline 219 /*package-private*/ 220 final withLanes(LaneType newType)221 AbstractSpecies<?> withLanes(LaneType newType) { 222 if (newType == laneType) return this; 223 return findSpecies(newType, vectorShape); 224 } 225 226 @ForceInline 227 /*package-private*/ asIntegral()228 AbstractSpecies<?> asIntegral() { 229 return withLanes(laneType.asIntegral()); 230 } 231 232 @ForceInline 233 /*package-private*/ asFloating()234 AbstractSpecies<?> asFloating() { 235 return withLanes(laneType.asFloating()); 236 } 237 238 @Override 239 @ForceInline 240 @SuppressWarnings("unchecked") withShape(VectorShape newShape)241 public final VectorSpecies<E> withShape(VectorShape newShape) { 242 if (newShape == vectorShape) return this; 243 return (VectorSpecies<E>) findSpecies(laneType, newShape); 244 } 245 246 @ForceInline 247 /*package-private*/ indexSpecies()248 AbstractSpecies<Integer> indexSpecies() { 249 // This JITs to a constant value: 250 AbstractSpecies<Integer> sp = indexSpecies; 251 if (sp != null) return sp; 252 return indexSpecies = findSpecies(LaneType.INT, indexShape).check0(int.class); 253 } 254 255 @ForceInline 256 /*package-private*/ 257 @SuppressWarnings("unchecked") byteSpecies()258 AbstractSpecies<Byte> byteSpecies() { 259 // This JITs to a constant value: 260 return (AbstractSpecies<Byte>) withLanes(LaneType.BYTE); 261 } 262 263 @ForceInline 264 /*package-private*/ swapBytesShuffle()265 AbstractShuffle<Byte> swapBytesShuffle() { 266 // This JITs to a constant value: 267 AbstractShuffle<Byte> sh = swapBytesShuffle; 268 if (sh != null) return sh; 269 return swapBytesShuffle = makeSwapBytesShuffle(); 270 } makeSwapBytesShuffle()271 private AbstractShuffle<Byte> makeSwapBytesShuffle() { 272 int vbytes = vectorByteSize(); 273 int lbytes = elementByteSize(); 274 int[] sourceIndexes = new int[vbytes]; 275 for (int i = 0; i < vbytes; i++) { 276 sourceIndexes[i] = i ^ (lbytes-1); 277 } 278 return (AbstractShuffle<Byte>) 279 VectorShuffle.fromValues(byteSpecies(), sourceIndexes); 280 } 281 /*package-private*/ fromIntValues(int[] values)282 abstract Vector<E> fromIntValues(int[] values); 283 284 /** 285 * Do not use a dummy except to call methods on it when you don't 286 * care about the lane values. The main benefit of it is to 287 * populate the type profile, which then allows the JIT to derive 288 * constant values for dummy.species(), the current species, and 289 * then for all of its attributes: ETYPE, VLENGTH, VSHAPE, etc. 290 */ 291 @ForceInline 292 /*package-private*/ dummyVector()293 AbstractVector<E> dummyVector() { 294 // This JITs to a constant value: 295 AbstractVector<E> dummy = dummyVector; 296 if (dummy != null) return dummy; 297 // The rest of this computation is probably not JIT-ted. 298 return makeDummyVector(); 299 } makeDummyVector()300 private AbstractVector<E> makeDummyVector() { 301 Object za = Array.newInstance(elementType(), laneCount); 302 return dummyVector = vectorFactory.apply(za); 303 // This is the only use of vectorFactory. 304 // All other factory requests are routed 305 // through the dummy vector. 306 } 307 308 /** 309 * Build a mask by directly calling its constructor. 310 * It is an error if the array is aliased elsewhere. 311 */ 312 @ForceInline 313 /*package-private*/ maskFactory(boolean[] bits)314 AbstractMask<E> maskFactory(boolean[] bits) { 315 return dummyVector().maskFromArray(bits); 316 } 317 318 public final 319 @Override 320 @ForceInline shuffleFromArray(int[] sourceIndexes, int offset)321 VectorShuffle<E> shuffleFromArray(int[] sourceIndexes, int offset) { 322 return dummyVector().shuffleFromArray(sourceIndexes, offset); 323 } 324 325 public final 326 @Override 327 @ForceInline shuffleFromValues(int... sourceIndexes)328 VectorShuffle<E> shuffleFromValues(int... sourceIndexes) { 329 return dummyVector().shuffleFromArray(sourceIndexes, 0); 330 } 331 332 public final 333 @Override 334 @ForceInline shuffleFromOp(IntUnaryOperator fn)335 VectorShuffle<E> shuffleFromOp(IntUnaryOperator fn) { 336 return dummyVector().shuffleFromOp(fn); 337 } 338 339 public final 340 @Override 341 @ForceInline iotaShuffle(int start, int step, boolean wrap)342 VectorShuffle<E> iotaShuffle(int start, int step, boolean wrap) { 343 AbstractShuffle<E> res; 344 if (start == 0 && step == 1) 345 return dummyVector().iotaShuffle(); 346 else 347 return dummyVector().iotaShuffle(start, step, wrap); 348 } 349 350 @ForceInline 351 @Override fromByteArray(byte[] a, int offset, ByteOrder bo)352 public final Vector<E> fromByteArray(byte[] a, int offset, ByteOrder bo) { 353 return dummyVector() 354 .fromByteArray0(a, offset) 355 .maybeSwap(bo); 356 } 357 358 @Override loadMask(boolean[] bits, int offset)359 public VectorMask<E> loadMask(boolean[] bits, int offset) { 360 return VectorMask.fromArray(this, bits, offset); 361 } 362 363 // Define zero and iota when we know the ETYPE and VSHAPE. zero()364 public abstract AbstractVector<E> zero(); iota()365 /*package-private*/ abstract AbstractVector<E> iota(); 366 367 // Constructing vectors from raw bits. 368 369 /*package-private*/ longToElementBits(long e)370 abstract long longToElementBits(long e); 371 372 /*package-private*/ broadcastBits(long bits)373 abstract AbstractVector<E> broadcastBits(long bits); 374 375 /*package-private*/ badElementBits(long iv, Object cv)376 final IllegalArgumentException badElementBits(long iv, Object cv) { 377 String msg = String.format("Vector creation failed: "+ 378 "value %s cannot be represented in ETYPE %s"+ 379 "; result of cast is %s", 380 iv, 381 elementType(), 382 cv); 383 return new IllegalArgumentException(msg); 384 } 385 386 /*package-private*/ 387 static badArrayBits(Object iv, boolean isInt, long cv)388 final IllegalArgumentException badArrayBits(Object iv, 389 boolean isInt, 390 long cv) { 391 String msg = String.format("Array creation failed: "+ 392 "lane value %s cannot be represented in %s"+ 393 "; result of cast is %s", 394 iv, 395 (isInt ? "int" : "long"), 396 cv); 397 return new IllegalArgumentException(msg); 398 } 399 400 /*package-private*/ iotaArray()401 Object iotaArray() { 402 // Create an iota array. It's OK if this is really slow, 403 // because it happens only once per species. 404 Object ia = Array.newInstance(laneType.elementType, 405 laneCount); 406 assert(ia.getClass() == laneType.arrayType); 407 checkValue(laneCount-1); // worst case 408 for (int i = 0; i < laneCount; i++) { 409 if ((byte)i == i) 410 Array.setByte(ia, i, (byte)i); 411 else if ((short)i == i) 412 Array.setShort(ia, i, (short)i); 413 else 414 Array.setInt(ia, i, i); 415 assert(Array.getDouble(ia, i) == i); 416 } 417 return ia; 418 } 419 420 @ForceInline 421 /*package-private*/ checkScale(int scale)422 void checkScale(int scale) { 423 if (scale > 0) { 424 if (scale <= maxScale) return; 425 } else { // scale <= 0 426 if (scale >= minScale) return; 427 } 428 throw checkScaleFailed(scale); 429 } checkScaleFailed(int scale)430 private IllegalArgumentException checkScaleFailed(int scale) { 431 String msg = String.format("%s: cannot represent VLENGTH*%d", 432 this, scale); 433 return new IllegalArgumentException(msg); 434 } 435 436 /*package-private*/ 437 interface RVOp { apply(int i)438 long apply(int i); // supply raw element bits 439 } 440 441 /*package-private*/ rvOp(RVOp f)442 abstract AbstractVector<E> rvOp(RVOp f); 443 444 /*package-private*/ 445 interface FOpm { apply(int i)446 boolean apply(int i); 447 } 448 opm(FOpm f)449 AbstractMask<E> opm(FOpm f) { 450 boolean[] res = new boolean[laneCount]; 451 for (int i = 0; i < res.length; i++) { 452 res[i] = f.apply(i); 453 } 454 return dummyVector().maskFromArray(res); 455 } 456 457 @Override 458 @ForceInline 459 public final check(Class<F> elementType)460 <F> VectorSpecies<F> check(Class<F> elementType) { 461 return check0(elementType); 462 } 463 464 @ForceInline 465 @SuppressWarnings("unchecked") 466 /*package-private*/ final check0(Class<F> elementType)467 <F> AbstractSpecies<F> check0(Class<F> elementType) { 468 if (elementType != this.elementType()) { 469 throw AbstractSpecies.checkFailed(this, elementType); 470 } 471 return (AbstractSpecies<F>) this; 472 } 473 474 @ForceInline 475 /*package-private*/ check(LaneType laneType)476 AbstractSpecies<E> check(LaneType laneType) { 477 if (laneType != this.laneType) { 478 throw AbstractSpecies.checkFailed(this, laneType); 479 } 480 return this; 481 } 482 483 484 @Override 485 @ForceInline partLimit(VectorSpecies<?> toSpecies, boolean lanewise)486 public int partLimit(VectorSpecies<?> toSpecies, boolean lanewise) { 487 AbstractSpecies<?> rsp = (AbstractSpecies<?>) toSpecies; 488 int inSizeLog2 = this.vectorShape.vectorBitSizeLog2; 489 int outSizeLog2 = rsp.vectorShape.vectorBitSizeLog2; 490 if (lanewise) { 491 inSizeLog2 += (rsp.laneType.elementSizeLog2 - 492 this.laneType.elementSizeLog2); 493 } 494 int diff = (inSizeLog2 - outSizeLog2); 495 // Let's try a branch-free version of this. 496 int sign = (diff >> -1); 497 //d = Math.abs(diff); 498 //d = (sign == 0 ? diff : sign == -1 ? 1 + ~diff); 499 int d = (diff ^ sign) - sign; 500 // Compute sgn(diff) << abs(diff), but replace 1 by 0. 501 return ((sign | 1) << d) & ~1; 502 } 503 504 /** 505 * Helper for throwing CheckCastExceptions, 506 * used by the various Vector*.check(*) methods. 507 */ 508 /*package-private*/ checkFailed(Object what, Object required)509 static ClassCastException checkFailed(Object what, Object required) { 510 // Find a species for the thing that's failing. 511 AbstractSpecies<?> whatSpecies = null; 512 String where; 513 if (what instanceof VectorSpecies) { 514 whatSpecies = (AbstractSpecies<?>) what; 515 where = whatSpecies.toString(); 516 } else if (what instanceof Vector) { 517 whatSpecies = (AbstractSpecies<?>) ((Vector<?>) what).species(); 518 where = "a Vector<"+whatSpecies.genericElementType()+">"; 519 } else if (what instanceof VectorMask) { 520 whatSpecies = (AbstractSpecies<?>) ((VectorMask<?>) what).vectorSpecies(); 521 where = "a VectorMask<"+whatSpecies.genericElementType()+">"; 522 } else if (what instanceof VectorShuffle) { 523 whatSpecies = (AbstractSpecies<?>) ((VectorShuffle<?>) what).vectorSpecies(); 524 where = "a VectorShuffle<"+whatSpecies.genericElementType()+">"; 525 } else { 526 where = what.toString(); 527 } 528 529 Object found = null; 530 if (whatSpecies != null) { 531 if (required instanceof VectorSpecies) { 532 // required is a VectorSpecies; found the wrong species 533 found = whatSpecies; 534 } else if (required instanceof Vector) { 535 // same VectorSpecies required; found the wrong species 536 found = whatSpecies; 537 required = ((Vector<?>)required).species(); 538 } else if (required instanceof Class) { 539 // required is a Class; found the wrong ETYPE 540 Class<?> requiredClass = (Class<?>) required; 541 LaneType requiredType = LaneType.forClassOrNull(requiredClass); 542 found = whatSpecies.elementType(); 543 if (requiredType == null) { 544 required = required + " (not a valid lane type)"; 545 } else if (!requiredClass.isPrimitive()) { 546 required = required + " (should be " + requiredType + ")"; 547 } 548 } else if (required instanceof LaneType) { 549 // required is a LaneType; found the wrong ETYPE 550 required = ((LaneType) required).elementType; 551 found = whatSpecies.elementType(); 552 } else if (required instanceof Integer) { 553 // required is a length; species has wrong VLENGTH 554 required = required + " lanes"; 555 found = whatSpecies.length(); 556 } 557 } 558 if (found == null) found = "bad value"; 559 560 String msg = where+": required "+required+" but found "+found; 561 return new ClassCastException(msg); 562 } 563 564 private static final @Stable AbstractSpecies<?>[][] CACHES 565 = new AbstractSpecies<?>[LaneType.SK_LIMIT][VectorShape.SK_LIMIT]; 566 567 // Helper functions for finding species: 568 569 /*package-private*/ 570 @ForceInline 571 static <E> findSpecies(Class<E> elementType, LaneType laneType, VectorShape shape)572 AbstractSpecies<E> findSpecies(Class<E> elementType, 573 LaneType laneType, 574 VectorShape shape) { 575 assert(elementType == laneType.elementType); 576 return findSpecies(laneType, shape).check0(elementType); 577 } 578 579 /*package-private*/ 580 @ForceInline 581 static findSpecies(LaneType laneType, VectorShape shape)582 AbstractSpecies<?> findSpecies(LaneType laneType, 583 VectorShape shape) { 584 // The JIT can see into this cache. 585 // Therefore it is useful to arrange for constant 586 // arguments to this method. If the cache 587 // is full when the JIT runs, the cache item becomes 588 // a compile-time constant. And then all the @Stable 589 // fields of the AbstractSpecies are also constants. 590 AbstractSpecies<?> s = CACHES[laneType.switchKey][shape.switchKey]; 591 if (s != null) return s; 592 return computeSpecies(laneType, shape); 593 } 594 595 private static computeSpecies(LaneType laneType, VectorShape shape)596 AbstractSpecies<?> computeSpecies(LaneType laneType, 597 VectorShape shape) { 598 AbstractSpecies<?> s = null; 599 // enum-switches don't optimize properly JDK-8161245 600 switch (laneType.switchKey) { 601 case LaneType.SK_FLOAT: 602 s = FloatVector.species(shape); break; 603 case LaneType.SK_DOUBLE: 604 s = DoubleVector.species(shape); break; 605 case LaneType.SK_BYTE: 606 s = ByteVector.species(shape); break; 607 case LaneType.SK_SHORT: 608 s = ShortVector.species(shape); break; 609 case LaneType.SK_INT: 610 s = IntVector.species(shape); break; 611 case LaneType.SK_LONG: 612 s = LongVector.species(shape); break; 613 } 614 if (s == null) { 615 // NOTE: The result of this method is guaranteed to be 616 // non-null. Later calls to ".check" also ensure this. 617 // If this method hits a NPE, it is because a helper 618 // method EVector.species() has returned a null value, and 619 // that is because a SPECIES_X static constant has not yet 620 // been initialized. And that, in turn, is because 621 // somebody is calling this method way too early during 622 // bootstrapping. 623 throw new AssertionError("bootstrap problem"); 624 } 625 assert(s.laneType == laneType) : s + "!=" + laneType; 626 assert(s.vectorShape == shape) : s + "!=" + shape; 627 CACHES[laneType.switchKey][shape.switchKey] = s; 628 return s; 629 } 630 631 @Override toString()632 public final String toString() { 633 return "Species["+laneType+", "+laneCount+", "+vectorShape+"]"; 634 } 635 636 @Override equals(Object obj)637 public final boolean equals(Object obj) { 638 if (obj instanceof AbstractSpecies) { 639 AbstractSpecies<?> that = (AbstractSpecies<?>) obj; 640 return (this.laneType == that.laneType && 641 this.laneCount == that.laneCount && 642 this.vectorShape == that.vectorShape); 643 } 644 return this == obj; 645 } 646 647 /** 648 * Returns a hash code value for the shuffle, 649 * based on the lane source indexes and the vector species. 650 * 651 * @return a hash code value for this shuffle 652 */ 653 @Override hashCode()654 public final int hashCode() { 655 int[] a = { laneType.ordinal(), laneCount, vectorShape.ordinal() }; 656 return Arrays.hashCode(a); 657 } 658 } 659