1 /* 2 * Copyright (c) 2017, 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 23 * questions. 24 */ 25 package jdk.incubator.vector; 26 27 import jdk.internal.vm.annotation.ForceInline; 28 import java.util.function.IntUnaryOperator; 29 30 /** 31 * A {@code VectorShuffle} represents an ordered immutable sequence of 32 * {@code int} values. A VectorShuffle can be used with a shuffle accepting 33 * vector operation to control the rearrangement of lane elements of input 34 * vectors 35 * <p> 36 * The number of values in the sequence is referred to as the shuffle 37 * {@link #length() length}. The length also corresponds to the number of 38 * shuffle lanes. The lane element at lane index {@code N} (from {@code 0}, 39 * inclusive, to length, exclusive) corresponds to the {@code N + 1}'th 40 * value in the sequence. 41 * A VectorShuffle and Vector of the same element type and shape have the same 42 * number of lanes. 43 * <p> 44 * A VectorShuffle describes how a lane element of a vector may cross lanes from 45 * its lane index, {@code i} say, to another lane index whose value is the 46 * shuffle's lane element at lane index {@code i}. VectorShuffle lane elements 47 * will be in the range of {@code 0} (inclusive) to the shuffle length 48 * (exclusive), and therefore cannot induce out of bounds errors when 49 * used with vectors operations and vectors of the same length. 50 * 51 * @param <E> the boxed element type of this mask 52 */ 53 public abstract class VectorShuffle<E> { 54 VectorShuffle() {} 55 56 /** 57 * Returns the species of this shuffle. 58 * 59 * @return the species of this shuffle 60 */ 61 public abstract VectorSpecies<E> species(); 62 63 /** 64 * Returns the number of shuffle lanes (the length). 65 * 66 * @return the number of shuffle lanes 67 */ 68 public int length() { return species().length(); } 69 70 /** 71 * Converts this shuffle to a shuffle of the given species of element type {@code F}. 72 * <p> 73 * For each shuffle lane, where {@code N} is the lane index, the 74 * shuffle element at index {@code N} is placed, unmodified, into the 75 * resulting shuffle at index {@code N}. 76 * 77 * @param species species of desired shuffle 78 * @param <F> the boxed element type of the species 79 * @return a shuffle converted by shape and element type 80 * @throws IllegalArgumentException if this shuffle length and the 81 * species length differ 82 */ 83 public abstract <F> VectorShuffle<F> cast(VectorSpecies<F> species); 84 85 /** 86 * Returns a shuffle of mapped indexes where each lane element is 87 * the result of applying a mapping function to the corresponding lane 88 * index. 89 * <p> 90 * Care should be taken to ensure VectorShuffle values produced from this 91 * method are consumed as constants to ensure optimal generation of 92 * code. For example, values held in static final fields or values 93 * held in loop constant local variables. 94 * <p> 95 * This method behaves as if a shuffle is created from an array of 96 * mapped indexes as follows: 97 * <pre>{@code 98 * int[] a = new int[species.length()]; 99 * for (int i = 0; i < a.length; i++) { 100 * a[i] = f.applyAsInt(i); 101 * } 102 * return VectorShuffle.fromValues(a); 103 * }</pre> 104 * 105 * @param species shuffle species 106 * @param f the lane index mapping function 107 * @return a shuffle of mapped indexes 108 * @see Vector#shuffle(IntUnaryOperator) 109 */ 110 @ForceInline 111 public static <E> VectorShuffle<E> shuffle(VectorSpecies<E> species, IntUnaryOperator f) { 112 return ((AbstractSpecies<E>) species).shuffleFromOpFactory.apply(f); 113 } 114 115 /** 116 * Returns a shuffle where each lane element is the value of its 117 * corresponding lane index. 118 * <p> 119 * This method behaves as if a shuffle is created from an identity 120 * index mapping function as follows: 121 * <pre>{@code 122 * return VectorShuffle.shuffle(i -> i); 123 * }</pre> 124 * 125 * @param species shuffle species 126 * @return a shuffle of lane indexes 127 * @see Vector#shuffleIota() 128 */ 129 @ForceInline 130 public static <E> VectorShuffle<E> shuffleIota(VectorSpecies<E> species) { 131 return ((AbstractSpecies<E>) species).shuffleFromOpFactory.apply(AbstractShuffle.IDENTITY); 132 } 133 134 /** 135 * Returns a shuffle with lane elements set to sequential {@code int} values starting from {@code start}. 136 * <p> 137 * This method behaves as if a shuffle is created from an identity 138 * index mapping function as follows: 139 * <pre>{@code 140 * return VectorShuffle.shuffle(i -> i + start); 141 * }</pre> 142 * 143 * @param species shuffle species 144 * @param start starting value of sequence 145 * @return a shuffle of lane indexes 146 * @see Vector#shuffleIota(int) 147 */ 148 @ForceInline 149 public static <E> VectorShuffle<E> shuffleIota(VectorSpecies<E> species, int start) { 150 return ((AbstractSpecies<E>) species).shuffleFromOpFactory.apply(i -> i + start); 151 } 152 153 /** 154 * Returns a shuffle with lane elements set to sequential {@code int} values starting from {@code start} 155 * and looping around species length. 156 * <p> 157 * This method behaves as if a shuffle is created from an identity 158 * index mapping function as follows: 159 * <pre>{@code 160 * return VectorShuffle.shuffle(i -> (i + start) & (species.length() - 1)); 161 * }</pre> 162 * 163 * @param species shuffle species 164 * @param start starting value of sequence 165 * @return a shuffle of lane indexes 166 * @see Vector#shuffleOffset(int) 167 */ 168 @ForceInline 169 public static <E> VectorShuffle<E> shuffleOffset(VectorSpecies<E> species, int start) { 170 return ((AbstractSpecies<E>) species).shuffleFromOpFactory.apply(i -> (i + start) & (species.length() - 1)); 171 } 172 173 /** 174 * Returns a shuffle where each lane element is set to a given 175 * {@code int} value logically AND'ed by the species length minus one. 176 * <p> 177 * For each shuffle lane, where {@code N} is the shuffle lane index, the 178 * the {@code int} value at index {@code N} logically AND'ed by 179 * {@code species.length() - 1} is placed into the resulting shuffle at 180 * lane index {@code N}. 181 * 182 * @param species shuffle species 183 * @param ixs the given {@code int} values 184 * @return a shuffle where each lane element is set to a given 185 * {@code int} value 186 * @throws IndexOutOfBoundsException if the number of int values is 187 * {@code < species.length()} 188 * @see Vector#shuffleFromValues(int...) 189 */ 190 @ForceInline 191 public static <E> VectorShuffle<E> fromValues(VectorSpecies<E> species, int... ixs) { 192 return ((AbstractSpecies<E>) species).shuffleFromArrayFactory.apply(ixs, 0); 193 } 194 195 /** 196 * Loads a shuffle from an {@code int} array starting at an offset. 197 * <p> 198 * For each shuffle lane, where {@code N} is the shuffle lane index, the 199 * array element at index {@code i + N} logically AND'ed by 200 * {@code species.length() - 1} is placed into the resulting shuffle at lane 201 * index {@code N}. 202 * 203 * @param species shuffle species 204 * @param ixs the {@code int} array 205 * @param offset the offset into the array 206 * @return a shuffle loaded from the {@code int} array 207 * @throws IndexOutOfBoundsException if {@code offset < 0}, or 208 * {@code offset > ixs.length - species.length()} 209 * @see Vector#shuffleFromArray(int[], int) 210 */ 211 @ForceInline 212 public static <E> VectorShuffle<E> fromArray(VectorSpecies<E> species, int[] ixs, int offset) { 213 return ((AbstractSpecies<E>) species).shuffleFromArrayFactory.apply(ixs, offset); 214 } 215 216 /** 217 * Returns an {@code int} array containing the lane elements of this 218 * shuffle. 219 * <p> 220 * This method behaves as if it {@link #intoArray(int[], int)} stores} 221 * this shuffle into an allocated array and returns that array as 222 * follows: 223 * <pre>{@code 224 * int[] a = new int[this.length()]; 225 * VectorShuffle.intoArray(a, 0); 226 * return a; 227 * }</pre> 228 * 229 * @return an array containing the the lane elements of this vector 230 */ 231 public abstract int[] toArray(); 232 233 /** 234 * Stores this shuffle into an {@code int} array starting at offset. 235 * <p> 236 * For each shuffle lane, where {@code N} is the shuffle lane index, 237 * the lane element at index {@code N} is stored into the array at index 238 * {@code i + N}. 239 * 240 * @param a the array 241 * @param offset the offset into the array 242 * @throws IndexOutOfBoundsException if {@code i < 0}, or 243 * {@code offset > a.length - this.length()} 244 */ 245 public abstract void intoArray(int[] a, int offset); 246 247 /** 248 * Converts this shuffle into a vector, creating a vector from shuffle 249 * lane elements (int values) cast to the vector element type. 250 * <p> 251 * This method behaves as if it returns the result of creating a 252 * vector given an {@code int} array obtained from this shuffle's 253 * lane elements, as follows: 254 * <pre>{@code 255 * int[] sa = this.toArray(); 256 * $type$[] va = new $type$[a.length]; 257 * for (int i = 0; i < a.length; i++) { 258 * va[i] = ($type$) sa[i]; 259 * } 260 * return IntVector.fromArray(va, 0); 261 * }</pre> 262 * 263 * @return a vector representation of this shuffle 264 */ 265 public abstract Vector<E> toVector(); 266 267 /** 268 * Gets the {@code int} lane element at lane index {@code i} 269 * 270 * @param i the lane index 271 * @return the {@code int} lane element at lane index {@code i} 272 */ 273 public int lane(int i) { return toArray()[i]; } 274 275 /** 276 * Rearranges the lane elements of this shuffle selecting lane indexes 277 * controlled by another shuffle. 278 * <p> 279 * For each lane of the specified shuffle, at lane index {@code N} with lane 280 * element {@code I}, the lane element at {@code I} from this shuffle is 281 * selected and placed into the resulting shuffle at {@code N}. 282 * 283 * @param s the shuffle controlling lane index selection 284 * @return the rearrangement of the lane elements of this shuffle 285 */ 286 public abstract VectorShuffle<E> rearrange(VectorShuffle<E> s); 287 }