1 /*
  2  * Copyright (c) 2017, 2022, 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.incubator.foreign.MemorySegment;
 28 import jdk.internal.vm.annotation.ForceInline;
 29 import jdk.internal.vm.annotation.Stable;

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