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