1 /*
2  * Copyright (c) 2019, 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 
30 import static jdk.internal.vm.vector.VectorSupport.*;
31 import static jdk.incubator.vector.VectorIntrinsics.*;
32 
33 /**
34  * Local type witness for primitive types int.class, etc.
35  * It caches all sorts of goodies that we can't put on java.lang.Class.
36  */
37 enum LaneType {
38     FLOAT(float.class, Float.class, float[].class, 'F', 24, Float.SIZE, T_FLOAT),
39     DOUBLE(double.class, Double.class, double[].class, 'F', 53, Double.SIZE, T_DOUBLE),
40     BYTE(byte.class, Byte.class, byte[].class, 'I', -1, Byte.SIZE, T_BYTE),
41     SHORT(short.class, Short.class, short[].class, 'I', -1, Short.SIZE, T_SHORT),
42     INT(int.class, Integer.class, int[].class, 'I', -1, Integer.SIZE, T_INT),
43     LONG(long.class, Long.class, long[].class, 'I', -1, Long.SIZE, T_LONG);
44 
LaneType(Class<?> elementType, Class<?> genericElementType, Class<?> arrayType, char elementKind, int elementPrecision, int elementSize, int basicType)45     LaneType(Class<?> elementType,
46              Class<?> genericElementType,
47              Class<?> arrayType,
48              char elementKind,
49              int elementPrecision,
50              int elementSize,
51              int basicType) {
52         if (elementPrecision <= 0)
53             elementPrecision += elementSize;
54         this.elementType = elementType;
55         this.genericElementType = genericElementType;
56         this.arrayType = arrayType;
57         this.elementKind = elementKind;
58         this.elementPrecision = elementPrecision;
59         this.elementSize = elementSize;
60         this.elementSizeLog2 = Integer.numberOfTrailingZeros(elementSize);
61         assert(elementSize == (1 << elementSizeLog2));
62         this.switchKey = 1+ordinal();
63         this.printName = elementType.getSimpleName();
64         // Note: If we ever have non-standard lane sizes, such as
65         // int:128 or int:4 or float:16, report the size in the
66         // printName.  If we do unsigned or vector or bit lane types,
67         // report that condition also.
68         this.typeChar = printName.toUpperCase().charAt(0);
69         assert("FDBSIL".indexOf(typeChar) == ordinal()) : this;
70         // Same as in JVMS, org.objectweb.asm.Opcodes, etc.:
71         this.basicType = basicType;
72         assert(basicType ==
73                ( (elementSizeLog2 - /*lg(Byte.SIZE)*/ 3)
74                  | (elementKind == 'F' ? 4 : 8))) : this;
75         assert("....zcFDBSILoav..".charAt(basicType) == typeChar);
76     }
77 
78     final Class<?> elementType;
79     final Class<?> arrayType;
80     final Class<?> genericElementType;
81     final int elementSize;
82     final int elementSizeLog2;
83     final int elementPrecision;
84     final char elementKind; // 'I' or 'F'
85     final int switchKey;  // 1+ordinal(), which is non-zero
86     final String printName;
87     final char typeChar; // one of "BSILFD"
88     final int basicType;  // lg(size/8) | (kind=='F'?4:kind=='I'?8)
89 
90     private @Stable LaneType asIntegral;
91     private @Stable LaneType asFloating;
92 
93     @Override
toString()94     public String toString() {
95         return printName;
96     }
97 
asIntegral()98     LaneType asIntegral() {
99         return asIntegral.check();
100     }
101 
asFloating()102     LaneType asFloating() {
103         if (asFloating == null) {
104             throw badElementType(elementType, "either int or long, to reinterpret as float or double");
105         }
106         return asFloating;
107     }
108 
109     /** Decode a class mirror for an element type into an enum. */
110     @ForceInline
of(Class<?> elementType)111     static LaneType of(Class<?> elementType) {
112         // The following two lines are expected to
113         // constant fold in the JIT, if the argument
114         // is constant and this method is inlined.
115         int c0 = elementType.getName().charAt(0);
116         LaneType type = ENUM_FROM_C0[c0 & C0_MASK];
117         // This line can short-circuit if a valid
118         // elementType constant was passed:
119         if (type != null && type.elementType == elementType) {
120             return type;
121         }
122         // Come here if something went wrong.
123         return ofSlow(elementType);
124     }
ofSlow(Class<?> elementType)125     private static LaneType ofSlow(Class<?> elementType) {
126         for (LaneType type : ENUM_VALUES) {
127             if (type.elementType == elementType) {
128                 return type;
129             }
130         }
131         throw badElementType(elementType, "a primitive type such as byte.class with a known bit-size");
132     }
133 
134     /**
135      * Finds a LaneType for the given query-type.
136      * The element type, box type, and array type are
137      * all matched.  May be helpful for error messages.
138      */
139     /*package-private*/
forClassOrNull(Class<?> queryType)140     static LaneType forClassOrNull(Class<?> queryType) {
141         for (LaneType type : ENUM_VALUES) {
142             if (type.genericElementType == queryType) {
143                 return type;
144             }
145             if (type.elementType == queryType) {
146                 return type;
147             }
148             if (type.arrayType == queryType) {
149                 return type;
150             }
151         }
152         return null;
153     }
154 
check(Class<?> expectedType)155     LaneType check(Class<?> expectedType) {
156         if (expectedType == this.elementType)
157             return this;
158         throw badElementType(this.elementType, expectedType);
159     }
160 
161     private static
badElementType(Class<?> elementType, Object expected)162     RuntimeException badElementType(Class<?> elementType, Object expected) {
163         String msg = String.format("Bad vector element type: %s (should be %s)",
164                                    elementType, expected);
165         if (expected instanceof Class) {
166             // Failure mode for check().
167             return new ClassCastException(msg);
168         } else {
169             // Failure mode for VectorSpecies.{of*,withLanes}.
170             return new UnsupportedOperationException(msg);
171         }
172     }
173 
174     // Switch keys for local use.
175     // We need these because switches keyed on enums
176     // don't optimize properly; see JDK-8161245
177 
178     static final int
179         SK_FLOAT    = 1,
180         SK_DOUBLE   = 2,
181         SK_BYTE     = 3,
182         SK_SHORT    = 4,
183         SK_INT      = 5,
184         SK_LONG     = 6,
185         SK_LIMIT    = 7;
186 
187     /*package-private*/
188     @ForceInline
ofSwitchKey(int sk)189     static LaneType ofSwitchKey(int sk) {
190         return ENUM_FROM_SK[sk].check();
191     }
192 
193     /*package-private*/
194     @ForceInline
ofBasicType(int bt)195     static LaneType ofBasicType(int bt) {
196         return ENUM_FROM_BT[bt].check();
197     }
198 
199     /*package-private*/
check()200     @ForceInline final LaneType check() { return this; }
201 
202     // Constant-foldable tables mapping ordinals, switch keys,
203     // and first characters of type names to enum values.
204 
205     @Stable private static final LaneType[] ENUM_VALUES;
206     @Stable private static final LaneType[] ENUM_FROM_SK;
207     @Stable private static final LaneType[] ENUM_FROM_C0;
208     @Stable private static final LaneType[] ENUM_FROM_BT;
209     private static final int C0_MASK = 0x0F, BT_MASK = 0x0F;
210     static {
211         LaneType[] values = values().clone();
212         LaneType[] valuesByKey = new LaneType[1+values.length];
213         LaneType[] valuesByC0  = new LaneType[C0_MASK+1];
214         LaneType[] valuesByBT  = new LaneType[BT_MASK+1];
215         for (int ord = 0; ord < values.length; ord++) {
216             int key = 1+ord;
217             LaneType value = values[ord];
218             valuesByKey[key] = value;
219             try {
assert(LaneType.class .getDeclaredField(R+value.name()) .get(null).equals(key))220                 assert(LaneType.class
221                        .getDeclaredField("SK_"+value.name())
222                        .get(null).equals(key));
223             } catch (ReflectiveOperationException ex) {
224                 throw new AssertionError(ex);
225             }
226             int c0 = value.elementType.getName().charAt(0);
227             c0 &= C0_MASK;
assert(valuesByC0[c0] == null)228             assert(valuesByC0[c0] == null);
229             valuesByC0[c0] = value;
assert(valuesByBT[value.basicType] == null)230             assert(valuesByBT[value.basicType] == null);
231             valuesByBT[value.basicType] = value;
232             // set up asIntegral
233             if (value.elementKind == 'I') {
234                 value.asIntegral = value;
235             } else {
236                 for (LaneType v : values) {
237                     if (v.elementKind == 'I' &&
238                         v.elementSize == value.elementSize) {
239                         value.asIntegral = v;
240                         break;
241                     }
242                 }
243             }
244             // set up asFloating
245             if (value.elementKind == 'F') {
246                 value.asFloating = value;
247             } else {
248                 for (LaneType v : values) {
249                     if (v.elementKind == 'F' &&
250                         v.elementSize == value.elementSize) {
251                         value.asFloating = v;
252                         break;
253                     }
254                 }
255             }
256         }
257         // Test the asIntegral/asFloating links:
258         for (LaneType lt : values) {
259             if (lt.elementKind == 'I') {
assert(lt.asIntegral == lt)260                 assert(lt.asIntegral == lt);
261                 if (lt.asFloating == null) {
262                     assert(lt.elementSize < Float.SIZE);
263                 } else {
264                     assert(lt.asFloating.elementKind == 'F' &&
265                            lt.asFloating.elementSize == lt.elementSize);
266                 }
267             } else {
268                 assert(lt.elementKind == 'F');
269                 assert(lt.asFloating == lt);
270                 assert(lt.asIntegral.elementKind == 'I' &&
271                        lt.asIntegral.elementSize == lt.elementSize);
272             }
273         }
274         ENUM_VALUES = values;
275         ENUM_FROM_SK = valuesByKey;
276         ENUM_FROM_C0 = valuesByC0;
277         ENUM_FROM_BT = valuesByBT;
278     }
279 
280     static {
281         assert(ofBasicType(T_FLOAT) == FLOAT);
282         assert(ofBasicType(T_DOUBLE) == DOUBLE);
283         assert(ofBasicType(T_BYTE) == BYTE);
284         assert(ofBasicType(T_SHORT) == SHORT);
285         assert(ofBasicType(T_INT) == INT);
286         assert(ofBasicType(T_LONG) == LONG);
287     }
288 }
289