1 /* 2 * Copyright (c) 2017, 2021, 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 java.util.Objects; 28 29 import jdk.internal.vm.annotation.ForceInline; 30 31 import static jdk.incubator.vector.VectorOperators.*; 32 33 abstract class AbstractMask<E> extends VectorMask<E> { 34 AbstractMask(boolean[] bits) { 35 super(bits); 36 } 37 38 /*package-private*/ 39 abstract boolean[] getBits(); 40 41 // Unary operator 42 43 interface MUnOp { 44 boolean apply(int i, boolean a); 45 } 46 47 abstract AbstractMask<E> uOp(MUnOp f); 48 49 // Binary operator 50 51 interface MBinOp { 52 boolean apply(int i, boolean a, boolean b); 53 } 54 55 abstract AbstractMask<E> bOp(VectorMask<E> o, MBinOp f); 56 57 /*package-private*/ 58 abstract AbstractSpecies<E> vspecies(); 59 60 @Override 61 @ForceInline 62 public final VectorSpecies<E> vectorSpecies() { 63 return vspecies(); 64 } 65 66 @Override 67 @ForceInline 68 public boolean laneIsSet(int i) { 69 int length = length(); 70 Objects.checkIndex(i, length); 71 if (length <= Long.SIZE) { 72 return ((toLong() >>> i) & 1L) == 1; 73 } else { 74 return getBits()[i]; 75 } 76 } 77 78 @Override 79 public void intoArray(boolean[] bits, int i) { 80 System.arraycopy(getBits(), 0, bits, i, length()); 81 } 82 83 @Override 84 public boolean[] toArray() { 85 return getBits().clone(); 86 } 87 88 @Override 89 @ForceInline 90 @SuppressWarnings("unchecked") 91 public 92 <F> VectorMask<F> check(Class<F> elementType) { 93 if (vectorSpecies().elementType() != elementType) { 94 throw AbstractSpecies.checkFailed(this, elementType); 95 } 96 return (VectorMask<F>) this; 97 } 98 99 @Override 100 @ForceInline 101 @SuppressWarnings("unchecked") 102 public 103 <F> VectorMask<F> check(VectorSpecies<F> species) { 104 if (species != vectorSpecies()) { 105 throw AbstractSpecies.checkFailed(this, species); 106 } 107 return (VectorMask<F>) this; 108 } 109 110 @Override 111 @ForceInline 112 @SuppressWarnings("unchecked") 113 <F> VectorMask<F> check(Class<? extends VectorMask<F>> maskClass, Vector<F> vector) { 114 if (!sameSpecies(maskClass, vector)) { 115 throw AbstractSpecies.checkFailed(this, vector); 116 } 117 return (VectorMask<F>) this; 118 } 119 120 @ForceInline 121 private <F> boolean sameSpecies(Class<? extends VectorMask<F>> maskClass, Vector<F> vector) { 122 boolean same = getClass() == maskClass; 123 assert (same == (vectorSpecies() == vector.species())) : same; 124 return same; 125 } 126 127 @Override 128 public VectorMask<E> andNot(VectorMask<E> m) { 129 return and(m.not()); 130 } 131 132 /*package-private*/ 133 static boolean anyTrueHelper(boolean[] bits) { 134 // FIXME: Maybe use toLong() != 0 here. 135 for (boolean i : bits) { 136 if (i) return true; 137 } 138 return false; 139 } 140 141 /*package-private*/ 142 static boolean allTrueHelper(boolean[] bits) { 143 // FIXME: Maybe use not().toLong() == 0 here. 144 for (boolean i : bits) { 145 if (!i) return false; 146 } 147 return true; 148 } 149 150 /*package-private*/ 151 static int trueCountHelper(boolean[] bits) { 152 int c = 0; 153 for (boolean i : bits) { 154 if (i) c++; 155 } 156 return c; 157 } 158 159 /*package-private*/ 160 static int firstTrueHelper(boolean[] bits) { 161 for (int i = 0; i < bits.length; i++) { 162 if (bits[i]) return i; 163 } 164 return bits.length; 165 } 166 167 /*package-private*/ 168 static int lastTrueHelper(boolean[] bits) { 169 for (int i = bits.length-1; i >= 0; i--) { 170 if (bits[i]) return i; 171 } 172 return -1; 173 } 174 175 /*package-private*/ 176 static long toLongHelper(boolean[] bits) { 177 long res = 0; 178 long set = 1; 179 for (int i = 0; i < bits.length; i++) { 180 res = bits[i] ? res | set : res; 181 set = set << 1; 182 } 183 return res; 184 } 185 186 @Override 187 @ForceInline 188 public VectorMask<E> indexInRange(int offset, int limit) { 189 int vlength = length(); 190 Vector<E> iota = vectorSpecies().zero().addIndex(1); 191 VectorMask<E> badMask = checkIndex0(offset, limit, iota, vlength); 192 return this.andNot(badMask); 193 } 194 195 /*package-private*/ 196 @ForceInline 197 AbstractVector<E> 198 toVectorTemplate() { 199 AbstractSpecies<E> vsp = vspecies(); 200 Vector<E> zero = vsp.broadcast(0); 201 Vector<E> mone = vsp.broadcast(-1); 202 // -1 will result in the most significant bit being set in 203 // addition to some or all other lane bits. 204 // For integral types, *all* lane bits will be set. 205 // The bits for -1.0 are like {0b10111*0000*}. 206 // FIXME: Use a conversion intrinsic for this operation. 207 // https://bugs.openjdk.java.net/browse/JDK-8225740 208 return (AbstractVector<E>) zero.blend(mone, this); 209 } 210 211 /** 212 * Test if a masked memory access at a given offset into an array 213 * of the given length will stay within the array. 214 * The per-lane offsets are iota*esize. 215 */ 216 /*package-private*/ 217 @ForceInline 218 void checkIndexByLane(int offset, int alength, 219 Vector<E> iota, 220 int esize) { 221 if (VectorIntrinsics.VECTOR_ACCESS_OOB_CHECK == 0) { 222 return; 223 } 224 // Although the specification is simple, the implementation is 225 // tricky, because the value iota*esize might possibly 226 // overflow. So we calculate our test values as scalars, 227 // clipping to the range [-1..VLENGTH], and test them against 228 // the unscaled iota vector, whose values are in [0..VLENGTH-1]. 229 int vlength = length(); 230 VectorMask<E> badMask; 231 if (esize == 1) { 232 badMask = checkIndex0(offset, alength, iota, vlength); 233 } else if (offset >= 0) { 234 // Masked access to multi-byte lanes in byte array. 235 // It could be aligned anywhere. 236 int elemCount = Math.min(vlength, (alength - offset) / esize); 237 badMask = checkIndex0(0, elemCount, iota, vlength); 238 } else { 239 int clipOffset = Math.max(offset, -(vlength * esize)); 240 badMask = checkIndex0(clipOffset, alength, 241 iota.lanewise(VectorOperators.MUL, esize), 242 vlength * esize); 243 } 244 badMask = badMask.and(this); 245 if (badMask.anyTrue()) { 246 int badLane = badMask.firstTrue(); 247 throw ((AbstractMask<E>)badMask) 248 .checkIndexFailed(offset, badLane, alength, esize); 249 } 250 } 251 252 private 253 @ForceInline 254 VectorMask<E> checkIndex0(int offset, int alength, 255 Vector<E> iota, int vlength) { 256 // An active lane is bad if its number is greater than 257 // alength-offset, since when added to offset it will step off 258 // of the end of the array. To avoid overflow when 259 // converting, clip the comparison value to [0..vlength] 260 // inclusive. 261 int indexLimit = Math.max(0, Math.min(alength - offset, vlength)); 262 VectorMask<E> badMask = 263 iota.compare(GE, iota.broadcast(indexLimit)); 264 if (offset < 0) { 265 // An active lane is bad if its number is less than 266 // -offset, because when added to offset it will then 267 // address an array element at a negative index. To avoid 268 // overflow when converting, clip the comparison value at 269 // vlength. This specific expression works correctly even 270 // when offset is Integer.MIN_VALUE. 271 int firstGoodIndex = -Math.max(offset, -vlength); 272 VectorMask<E> badMask2 = 273 iota.compare(LT, iota.broadcast(firstGoodIndex)); 274 if (indexLimit >= vlength) { 275 badMask = badMask2; // 1st badMask is all true 276 } else { 277 badMask = badMask.or(badMask2); 278 } 279 } 280 return badMask; 281 } 282 283 private IndexOutOfBoundsException checkIndexFailed(int offset, int lane, 284 int alength, int esize) { 285 String msg = String.format("Masked range check failed: "+ 286 "vector mask %s out of bounds at "+ 287 "index %d+%d in array of length %d", 288 this, offset, lane * esize, alength); 289 if (esize != 1) { 290 msg += String.format(" (each lane spans %d array elements)", esize); 291 } 292 throw new IndexOutOfBoundsException(msg); 293 } 294 295 }