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