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.misc.Unsafe;
  28 import jdk.internal.vm.annotation.ForceInline;
  29 
  30 import java.util.Objects;
  31 
  32 /**
  33  * A {@code VectorMask} represents an ordered immutable sequence of {@code boolean}
  34  * values.  Some vector operations accept masks to
  35  * control the selection and operation of lane elements of input vectors.
  36  * <p>
  37  * The number of values in the sequence is referred to as the VectorMask
  38  * {@link #length() length}. The length also corresponds to the number of
  39  * VectorMask lanes.  The lane element at lane index {@code N} (from {@code 0},
  40  * inclusive, to length, exclusive) corresponds to the {@code N + 1}'th
  41  * value in the sequence.
  42  * A VectorMask and Vector of the same element type and shape have the same number
  43  * of lanes.
  44  * <p>
  45  * A lane is said to be <em>set</em> if the lane element is {@code true},
  46  * otherwise a lane is said to be <em>unset</em> if the lane element is
  47  * {@code false}.
  48  * <p>
  49  * VectorMask declares a limited set of unary, binary and reduction operations.
  50  * <ul>
  51  * <li>
  52  * A lane-wise unary operation operates on one input mask and produces a
  53  * result mask.
  54  * For each lane of the input mask the
  55  * lane element is operated on using the specified scalar unary operation and
  56  * the boolean result is placed into the mask result at the same lane.
  57  * The following pseudocode expresses the behavior of this operation category:
  58  *
  59  * <pre>{@code
  60  * VectorMask<E> a = ...;
  61  * boolean[] ar = new boolean[a.length()];
  62  * for (int i = 0; i < a.length(); i++) {
  63  *     ar[i] = scalar_unary_op(a.isSet(i));
  64  * }
  65  * VectorMask<E> r = VectorMask.fromArray(a.species(), ar, 0);
  66  * }</pre>
  67  *
  68  * <li>
  69  * A lane-wise binary operation operates on two input
  70  * masks to produce a result mask.
  71  * For each lane of the two input masks a and b,
  72  * the corresponding lane elements from a and b are operated on
  73  * using the specified scalar binary operation and the boolean result is placed
  74  * into the mask result at the same lane.
  75  * The following pseudocode expresses the behavior of this operation category:
  76  *
  77  * <pre>{@code
  78  * VectorMask<E> a = ...;
  79  * VectorMask<E> b = ...;
  80  * boolean[] ar = new boolean[a.length()];
  81  * for (int i = 0; i < a.length(); i++) {
  82  *     ar[i] = scalar_binary_op(a.isSet(i), b.isSet(i));
  83  * }
  84  * VectorMask<E> r = VectorMask.fromArray(a.species(), ar, 0);
  85  * }</pre>
  86  *
  87  * <li>
  88  * A cross-lane reduction operation accepts an input mask and produces a scalar result.
  89  * For each lane of the input mask the lane element is operated on, together with a scalar accumulation value,
  90  * using the specified scalar binary operation.  The scalar result is the final value of the accumulator. The
  91  * following pseudocode expresses the behaviour of this operation category:
  92  *
  93  * <pre>{@code
  94  * Mask<E> a = ...;
  95  * int acc = zero_for_scalar_binary_op;  // 0, or 1 for &
  96  * for (int i = 0; i < a.length(); i++) {
  97  *      acc = scalar_binary_op(acc, a.isSet(i) ? 1 : 0);  // & | +
  98  * }
  99  * return acc;  // maybe boolean (acc != 0)
 100  * }</pre>
 101  *
 102  * </ul>
 103  * @param <E> the boxed element type of this mask
 104  */
 105 public abstract class VectorMask<E> {
 106     VectorMask() {}
 107 
 108     /**
 109      * Returns the species of this mask.
 110      *
 111      * @return the species of this mask
 112      */
 113     public abstract VectorSpecies<E> species();
 114 
 115     /**
 116      * Returns the number of mask lanes (the length).
 117      *
 118      * @return the number of mask lanes
 119      */
 120     public int length() { return species().length(); }
 121 
 122     /**
 123      * Returns a mask where each lane is set or unset according to given
 124      * {@code boolean} values
 125      * <p>
 126      * For each mask lane, where {@code N} is the mask lane index,
 127      * if the given {@code boolean} value at index {@code N} is {@code true}
 128      * then the mask lane at index {@code N} is set, otherwise it is unset.
 129      *
 130      * @param species mask species
 131      * @param bits the given {@code boolean} values
 132      * @return a mask where each lane is set or unset according to the given {@code boolean} value
 133      * @throws IndexOutOfBoundsException if {@code bits.length < species.length()}
 134      */
 135     @ForceInline
 136     public static <E> VectorMask<E> fromValues(VectorSpecies<E> species, boolean... bits) {
 137         return fromArray(species, bits, 0);
 138     }
 139 
 140     /**
 141      * Loads a mask from a {@code boolean} array starting at an offset.
 142      * <p>
 143      * For each mask lane, where {@code N} is the mask lane index,
 144      * if the array element at index {@code ix + N} is {@code true} then the
 145      * mask lane at index {@code N} is set, otherwise it is unset.
 146      *
 147      * @param species mask species
 148      * @param bits the {@code boolean} array
 149      * @param offset the offset into the array
 150      * @return the mask loaded from a {@code boolean} array
 151      * @throws IndexOutOfBoundsException if {@code offset < 0}, or
 152      * {@code offset > bits.length - species.length()}
 153      */
 154     @ForceInline
 155     @SuppressWarnings("unchecked")
 156     public static <E> VectorMask<E> fromArray(VectorSpecies<E> species, boolean[] bits, int offset) {
 157         Objects.requireNonNull(bits);
 158         offset = VectorIntrinsics.checkIndex(offset, bits.length, species.length());
 159         return VectorIntrinsics.load((Class<VectorMask<E>>) species.maskType(), species.elementType(), species.length(),
 160                 bits, (long) offset + Unsafe.ARRAY_BOOLEAN_BASE_OFFSET,
 161                 bits, offset, species,
 162                 (boolean[] c, int idx, VectorSpecies<E> s) -> ((AbstractSpecies<E>)s).opm(n -> c[idx + n]));
 163     }
 164 
 165     /**
 166      * Returns a mask where all lanes are set.
 167      *
 168      * @param species mask species
 169      * @return a mask where all lanes are set
 170      */
 171     @ForceInline
 172     @SuppressWarnings("unchecked")
 173     public static <E> VectorMask<E> maskAllTrue(VectorSpecies<E> species) {
 174         return VectorIntrinsics.broadcastCoerced((Class<VectorMask<E>>) species.maskType(), species.elementType(), species.length(),
 175                 -1,  species,
 176                 ((z, s) -> AbstractMask.trueMask(s)));
 177     }
 178 
 179     /**
 180      * Returns a mask where all lanes are unset.
 181      *
 182      * @param species mask species
 183      * @return a mask where all lanes are unset
 184      */
 185     @ForceInline
 186     @SuppressWarnings("unchecked")
 187     public static <E> VectorMask<E> maskAllFalse(VectorSpecies<E> species) {
 188         return VectorIntrinsics.broadcastCoerced((Class<VectorMask<E>>) species.maskType(), species.elementType(), species.length(),
 189                 0, species,
 190                 ((z, s) -> AbstractMask.falseMask(s)));
 191     }
 192 
 193     /**
 194      * Converts this mask to a mask of the given species shape of element type {@code F}.
 195      * <p>
 196      * For each mask lane, where {@code N} is the lane index, if the
 197      * mask lane at index {@code N} is set, then the mask lane at index
 198      * {@code N} of the resulting mask is set, otherwise that mask lane is
 199      * not set.
 200      *
 201      * @param s the species of the desired mask
 202      * @param <F> the boxed element type of the species
 203      * @return a mask converted by shape and element type
 204      * @throws IllegalArgumentException if this mask length and the species
 205      * length differ
 206      */
 207     public abstract <F> VectorMask<F> cast(VectorSpecies<F> s);
 208 
 209     /**
 210      * Returns the lane elements of this mask packed into a {@code long}
 211      * value for at most the first 64 lane elements.
 212      * <p>
 213      * The lane elements are packed in the order of least significant bit
 214      * to most significant bit.
 215      * For each mask lane where {@code N} is the mask lane index, if the
 216      * mask lane is set then the {@code N}'th bit is set to one in the
 217      * resulting {@code long} value, otherwise the {@code N}'th bit is set
 218      * to zero.
 219      *
 220      * @return the lane elements of this mask packed into a {@code long}
 221      * value.
 222      */
 223     public abstract long toLong();
 224 
 225     /**
 226      * Returns an {@code boolean} array containing the lane elements of this
 227      * mask.
 228      * <p>
 229      * This method behaves as if it {@link #intoArray(boolean[], int)} stores}
 230      * this mask into an allocated array and returns that array as
 231      * follows:
 232      * <pre>{@code
 233      * boolean[] a = new boolean[this.length()];
 234      * this.intoArray(a, 0);
 235      * return a;
 236      * }</pre>
 237      *
 238      * @return an array containing the the lane elements of this vector
 239      */
 240     public abstract boolean[] toArray();
 241 
 242     /**
 243      * Stores this mask into a {@code boolean} array starting at offset.
 244      * <p>
 245      * For each mask lane, where {@code N} is the mask lane index,
 246      * the lane element at index {@code N} is stored into the array at index
 247      * {@code i + N}.
 248      *
 249      * @param a the array
 250      * @param offset the offset into the array
 251      * @throws IndexOutOfBoundsException if {@code offset < 0}, or
 252      * {@code offset > a.length - this.length()}
 253      */
 254     public abstract void intoArray(boolean[] a, int offset);
 255 
 256     /**
 257      * Returns {@code true} if any of the mask lanes are set.
 258      *
 259      * @return {@code true} if any of the mask lanes are set, otherwise
 260      * {@code false}.
 261      */
 262     public abstract boolean anyTrue();
 263 
 264     /**
 265      * Returns {@code true} if all of the mask lanes are set.
 266      *
 267      * @return {@code true} if all of the mask lanes are set, otherwise
 268      * {@code false}.
 269      */
 270     public abstract boolean allTrue();
 271 
 272     /**
 273      * Returns the number of mask lanes that are set.
 274      *
 275      * @return the number of mask lanes that are set.
 276      */
 277     public abstract int trueCount();
 278 
 279     /**
 280      * Logically ands this mask with an input mask.
 281      * <p>
 282      * This is a lane-wise binary operation which applies the logical and operation
 283      * ({@code &&}) to each lane.
 284      *
 285      * @param o the input mask
 286      * @return the result of logically and'ing this mask with an input mask
 287      */
 288     public abstract VectorMask<E> and(VectorMask<E> o);
 289 
 290     /**
 291      * Logically ors this mask with an input mask.
 292      * <p>
 293      * This is a lane-wise binary operation which applies the logical or operation
 294      * ({@code ||}) to each lane.
 295      *
 296      * @param o the input mask
 297      * @return the result of logically or'ing this mask with an input mask
 298      */
 299     public abstract VectorMask<E> or(VectorMask<E> o);
 300 
 301     /**
 302      * Logically negates this mask.
 303      * <p>
 304      * This is a lane-wise unary operation which applies the logical not operation
 305      * ({@code !}) to each lane.
 306      *
 307      * @return the result of logically negating this mask.
 308      */
 309     public abstract VectorMask<E> not();
 310 
 311     /**
 312      * Returns a vector representation of this mask.
 313      * <p>
 314      * For each mask lane, where {@code N} is the mask lane index,
 315      * if the mask lane is set then an element value whose most significant
 316      * bit is set is placed into the resulting vector at lane index
 317      * {@code N}, otherwise the default element value is placed into the
 318      * resulting vector at lane index {@code N}.
 319      *
 320      * @return a vector representation of this mask.
 321      */
 322     public abstract Vector<E> toVector();
 323 
 324     /**
 325      * Tests if the lane at index {@code i} is set
 326      * @param i the lane index
 327      *
 328      * @return true if the lane at index {@code i} is set, otherwise false
 329      */
 330     public abstract boolean lane(int i);
 331 
 332     /**
 333      * Tests if the lane at index {@code i} is set
 334      * @param i the lane index
 335      * @return true if the lane at index {@code i} is set, otherwise false
 336      * @see #lane
 337      */
 338     public boolean isSet(int i) {
 339         return lane(i);
 340     }
 341 }