< prev index next >

src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Vector.java

Print this page
*** 1,7 ***
  /*
!  * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.  Oracle designates this
--- 1,7 ---
  /*
!  * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.  Oracle designates this

*** 22,11 ***
   * or visit www.oracle.com if you need additional information or have any
   * questions.
   */
  package jdk.incubator.vector;
  
! import java.nio.ByteBuffer;
  import java.nio.ByteOrder;
  import java.util.Arrays;
  
  /**
   * A
--- 22,12 ---
   * or visit www.oracle.com if you need additional information or have any
   * questions.
   */
  package jdk.incubator.vector;
  
! import jdk.incubator.foreign.MemorySegment;
+ 
  import java.nio.ByteOrder;
  import java.util.Arrays;
  
  /**
   * A

*** 761,15 ***
   *
   * In such cases memory order corresponds exactly to lane order.  The
   * first vector lane value occupies the first position in memory, and so on,
   * up to the length of the vector. Further, the memory order of stored
   * vector lanes corresponds to increasing index values in a Java array or
!  * in a {@link java.nio.ByteBuffer}.
   *
   * <p> Byte order for lane storage is chosen such that the stored
   * vector values can be read or written as single primitive values,
!  * within the array or buffer that holds the vector, producing the
   * same values as the lane-wise values within the vector.
   * This fact is independent of the convenient fiction that lane values
   * inside of vectors are stored in little-endian order.
   *
   * <p> For example,
--- 762,15 ---
   *
   * In such cases memory order corresponds exactly to lane order.  The
   * first vector lane value occupies the first position in memory, and so on,
   * up to the length of the vector. Further, the memory order of stored
   * vector lanes corresponds to increasing index values in a Java array or
!  * in a {@link jdk.incubator.foreign.MemorySegment}.
   *
   * <p> Byte order for lane storage is chosen such that the stored
   * vector values can be read or written as single primitive values,
!  * within the array or segment that holds the vector, producing the
   * same values as the lane-wise values within the vector.
   * This fact is independent of the convenient fiction that lane values
   * inside of vectors are stored in little-endian order.
   *
   * <p> For example,

*** 1037,10 ***
--- 1038,16 ---
   * {@code VectorShuffle} object, which acts as an routing table
   * mapping source lanes to destination lanes.  A {@code VectorShuffle}
   * can encode a mathematical permutation as well as many other
   * patterns of data movement.
   *
+  * <li>The {@link #compress(VectorMask)} and {@link #expand(VectorMask)}
+  * methods, which select up to {@code VLENGTH} lanes from an
+  * input vector, and assemble them in lane order.  The selection of lanes
+  * is controlled by a {@code VectorMask}, with set lane elements mapping, by
+  * compression or expansion in lane order, source lanes to destination lanes.
+  *
   * </ul>
   * <p> Some vector operations are not lane-wise, but rather move data
   * across lane boundaries.  Such operations are typically rare in SIMD
   * code, though they are sometimes necessary for specific algorithms
   * that manipulate data formats at a low level, and/or require SIMD

*** 2687,10 ***
--- 2694,50 ---
       * @see VectorShuffle#laneIsValid()
       * @see #slice(int,Vector)
       */
      public abstract Vector<E> rearrange(VectorShuffle<E> s, Vector<E> v);
  
+     /**
+      * Compresses the lane elements of this vector selecting lanes
+      * under the control of a specific mask.
+      *
+      * This is a cross-lane operation that compresses the lane
+      * elements of this vector as selected by the specified mask.
+      *
+      * For each lane {@code N} of the mask, if the mask at
+      * lane {@code N} is set, the element at lane {@code N}
+      * of input vector is selected and stored into the output
+      * vector contiguously starting from the lane {@code 0}.
+      * All the upper remaining lanes, if any, of the output
+      * vector are set to zero.
+      *
+      * @param m the mask controlling the compression
+      * @return the compressed lane elements of this vector
+      * @since 19
+      */
+     public abstract Vector<E> compress(VectorMask<E> m);
+ 
+     /**
+      * Expands the lane elements of this vector
+      * under the control of a specific mask.
+      *
+      * This is a cross-lane operation that expands the contiguous lane
+      * elements of this vector into lanes of an output vector
+      * as selected by the specified mask.
+      *
+      * For each lane {@code N} of the mask, if the mask at
+      * lane {@code N} is set, the next contiguous element of input vector
+      * starting from lane {@code 0} is selected and stored into the output
+      * vector at lane {@code N}.
+      * All the remaining lanes, if any, of the output vector are set to zero.
+      *
+      * @param m the mask controlling the compression
+      * @return the expanded lane elements of this vector
+      * @since 19
+      */
+     public abstract Vector<E> expand(VectorMask<E> m);
+ 
      /**
       * Using index values stored in the lanes of this vector,
       * assemble values stored in second vector {@code v}.
       * The second vector thus serves as a table, whose
       * elements are selected by indexes in the current vector.

*** 2852,30 ***
       * <p> If the old and new species have different shape, this is a
       * <em>shape-changing</em> operation, and may have special
       * implementation costs.
       *
       * <p> The method behaves as if this vector is stored into a byte
!      * buffer or array using little-endian byte ordering and then the
!      * desired vector is loaded from the same byte buffer or array
-      * using the same ordering.
       *
       * <p> The following pseudocode illustrates the behavior:
       * <pre>{@code
       * int domSize = this.byteSize();
       * int ranSize = species.vectorByteSize();
       * int M = (domSize > ranSize ? domSize / ranSize : ranSize / domSize);
       * assert Math.abs(part) < M;
       * assert (part == 0) || (part > 0) == (domSize > ranSize);
!      * byte[] ra = new byte[Math.max(domSize, ranSize)];
       * if (domSize > ranSize) {  // expansion
!      *     this.intoByteArray(ra, 0, ByteOrder.native());
       *     int origin = part * ranSize;
!      *     return species.fromByteArray(ra, origin, ByteOrder.native());
       * } else {  // contraction or size-invariant
       *     int origin = (-part) * domSize;
!      *     this.intoByteArray(ra, origin, ByteOrder.native());
!      *     return species.fromByteArray(ra, 0, ByteOrder.native());
       * }
       * }</pre>
       *
       * @apiNote Although this method is defined as if the vectors in
       * question were loaded or stored into memory, memory semantics
--- 2899,29 ---
       * <p> If the old and new species have different shape, this is a
       * <em>shape-changing</em> operation, and may have special
       * implementation costs.
       *
       * <p> The method behaves as if this vector is stored into a byte
!      * array using little-endian byte ordering and then the desired vector is loaded from the same byte
!      * array using the same ordering.
       *
       * <p> The following pseudocode illustrates the behavior:
       * <pre>{@code
       * int domSize = this.byteSize();
       * int ranSize = species.vectorByteSize();
       * int M = (domSize > ranSize ? domSize / ranSize : ranSize / domSize);
       * assert Math.abs(part) < M;
       * assert (part == 0) || (part > 0) == (domSize > ranSize);
!      * MemorySegment ms = MemorySegment.ofArray(new byte[Math.max(domSize, ranSize)]);
       * if (domSize > ranSize) {  // expansion
!      *     this.intoMemorySegment(ms, 0, ByteOrder.native());
       *     int origin = part * ranSize;
!      *     return species.fromMemorySegment(ms, origin, ByteOrder.native());
       * } else {  // contraction or size-invariant
       *     int origin = (-part) * domSize;
!      *     this.intoMemorySegment(ms, origin, ByteOrder.native());
!      *     return species.fromMemorySegment(ms, 0, ByteOrder.native());
       * }
       * }</pre>
       *
       * @apiNote Although this method is defined as if the vectors in
       * question were loaded or stored into memory, memory semantics

*** 2908,12 ***
       * within the same vector, such as
       * {@link Vector#reinterpretAsInts()}.
       *
       * @return a {@code ByteVector} with the same shape and information content
       * @see Vector#reinterpretShape(VectorSpecies,int)
!      * @see IntVector#intoByteArray(byte[], int, ByteOrder)
!      * @see FloatVector#intoByteArray(byte[], int, ByteOrder)
       * @see VectorSpecies#withLanes(Class)
       */
      public abstract ByteVector reinterpretAsBytes();
  
      /**
--- 2954,12 ---
       * within the same vector, such as
       * {@link Vector#reinterpretAsInts()}.
       *
       * @return a {@code ByteVector} with the same shape and information content
       * @see Vector#reinterpretShape(VectorSpecies,int)
!      * @see IntVector#intoMemorySegment(jdk.incubator.foreign.MemorySegment, long, java.nio.ByteOrder)
!      * @see FloatVector#intoMemorySegment(jdk.incubator.foreign.MemorySegment, long, java.nio.ByteOrder)
       * @see VectorSpecies#withLanes(Class)
       */
      public abstract ByteVector reinterpretAsBytes();
  
      /**

*** 3317,130 ***
      public abstract <F> Vector<F> check(VectorSpecies<F> species);
  
      //Array stores
  
      /**
!      * Stores this vector into a byte array starting at an offset
!      * using explicit byte order.
       * <p>
       * Bytes are extracted from primitive lane elements according
       * to the specified byte ordering.
       * The lanes are stored according to their
       * <a href="Vector.html#lane-order">memory ordering</a>.
       * <p>
       * This method behaves as if it calls
!      * {@link #intoByteBuffer(ByteBuffer,int,ByteOrder,VectorMask)
!      * intoByteBuffer()} as follows:
       * <pre>{@code
-      * var bb = ByteBuffer.wrap(a);
       * var m = maskAll(true);
!      * intoByteBuffer(bb, offset, bo, m);
       * }</pre>
       *
!      * @param a the byte array
!      * @param offset the offset into the array
       * @param bo the intended byte order
       * @throws IndexOutOfBoundsException
       *         if {@code offset+N*ESIZE < 0}
!      *         or {@code offset+(N+1)*ESIZE > a.length}
       *         for any lane {@code N} in the vector
       */
!     public abstract void intoByteArray(byte[] a, int offset,
-                                        ByteOrder bo);
  
      /**
!      * Stores this vector into a byte array starting at an offset
!      * using explicit byte order and a mask.
-      * <p>
-      * Bytes are extracted from primitive lane elements according
-      * to the specified byte ordering.
-      * The lanes are stored according to their
-      * <a href="Vector.html#lane-order">memory ordering</a>.
-      * <p>
-      * This method behaves as if it calls
-      * {@link #intoByteBuffer(ByteBuffer,int,ByteOrder,VectorMask)
-      * intoByteBuffer()} as follows:
-      * <pre>{@code
-      * var bb = ByteBuffer.wrap(a);
-      * intoByteBuffer(bb, offset, bo, m);
-      * }</pre>
-      *
-      * @param a the byte array
-      * @param offset the offset into the array
-      * @param bo the intended byte order
-      * @param m the mask controlling lane selection
-      * @throws IndexOutOfBoundsException
-      *         if {@code offset+N*ESIZE < 0}
-      *         or {@code offset+(N+1)*ESIZE > a.length}
-      *         for any lane {@code N} in the vector
-      *         where the mask is set
-      */
-     public abstract void intoByteArray(byte[] a, int offset,
-                                        ByteOrder bo,
-                                        VectorMask<E> m);
- 
-     /**
-      * Stores this vector into a byte buffer starting at an offset
-      * using explicit byte order.
-      * <p>
-      * Bytes are extracted from primitive lane elements according
-      * to the specified byte ordering.
-      * The lanes are stored according to their
-      * <a href="Vector.html#lane-order">memory ordering</a>.
-      * <p>
-      * This method behaves as if it calls
-      * {@link #intoByteBuffer(ByteBuffer,int,ByteOrder,VectorMask)
-      * intoByteBuffer()} as follows:
-      * <pre>{@code
-      * var m = maskAll(true);
-      * intoByteBuffer(bb, offset, bo, m);
-      * }</pre>
-      *
-      * @param bb the byte buffer
-      * @param offset the offset into the array
-      * @param bo the intended byte order
-      * @throws IndexOutOfBoundsException
-      *         if {@code offset+N*ESIZE < 0}
-      *         or {@code offset+(N+1)*ESIZE > bb.limit()}
-      *         for any lane {@code N} in the vector
-      * @throws java.nio.ReadOnlyBufferException
-      *         if the byte buffer is read-only
-      */
-     public abstract void intoByteBuffer(ByteBuffer bb, int offset, ByteOrder bo);
- 
-     /**
-      * Stores this vector into a byte buffer starting at an offset
-      * using explicit byte order and a mask.
       * <p>
       * Bytes are extracted from primitive lane elements according
       * to the specified byte ordering.
       * The lanes are stored according to their
       * <a href="Vector.html#lane-order">memory ordering</a>.
       * <p>
       * The following pseudocode illustrates the behavior, where
!      * the primitive element type is not of {@code byte},
-      * {@code EBuffer} is the primitive buffer type, {@code ETYPE} is the
       * primitive element type, and {@code EVector} is the primitive
       * vector type for this vector:
       * <pre>{@code
-      * EBuffer eb = bb.duplicate()
-      *     .position(offset)
-      *     .order(bo).asEBuffer();
       * ETYPE[] a = this.toArray();
       * for (int n = 0; n < a.length; n++) {
       *     if (m.laneIsSet(n)) {
!      *         eb.put(n, a[n]);
       *     }
       * }
       * }</pre>
-      * When the primitive element type is of {@code byte} the primitive
-      * byte buffer is obtained as follows, where operation on the buffer
-      * remains the same as in the prior pseudocode:
-      * <pre>{@code
-      * ByteBuffer eb = bb.duplicate()
-      *     .position(offset);
-      * }</pre>
       *
       * @implNote
       * This operation is likely to be more efficient if
       * the specified byte order is the same as
       * {@linkplain ByteOrder#nativeOrder()
--- 3363,65 ---
      public abstract <F> Vector<F> check(VectorSpecies<F> species);
  
      //Array stores
  
      /**
!      * Stores this vector into a {@linkplain MemorySegment memory segment}
!      * starting at an offset using explicit byte order.
       * <p>
       * Bytes are extracted from primitive lane elements according
       * to the specified byte ordering.
       * The lanes are stored according to their
       * <a href="Vector.html#lane-order">memory ordering</a>.
       * <p>
       * This method behaves as if it calls
!      * {@link #intoMemorySegment(MemorySegment,long,ByteOrder,VectorMask)
!      * intoMemorySegment()} as follows:
       * <pre>{@code
       * var m = maskAll(true);
!      * intoMemorySegment(ms, offset, bo, m);
       * }</pre>
       *
!      * @param ms the memory segment
!      * @param offset the offset into the memory segment
       * @param bo the intended byte order
       * @throws IndexOutOfBoundsException
       *         if {@code offset+N*ESIZE < 0}
!      *         or {@code offset+(N+1)*ESIZE > ms.byteSize()}
       *         for any lane {@code N} in the vector
+      * @throws UnsupportedOperationException
+      *         if the memory segment is read-only
+      * @throws IllegalArgumentException if the memory segment is a heap segment that is
+      *         not backed by a {@code byte[]} array.
+      * @throws IllegalStateException if the memory segment's session is not alive,
+      *         or if access occurs from a thread other than the thread owning the session.
+      * @since 19
       */
!     public abstract void intoMemorySegment(MemorySegment ms, long offset, ByteOrder bo);
  
      /**
!      * Stores this vector into a {@linkplain MemorySegment memory segment}
!      * starting at an offset using explicit byte order and a mask.
       * <p>
       * Bytes are extracted from primitive lane elements according
       * to the specified byte ordering.
       * The lanes are stored according to their
       * <a href="Vector.html#lane-order">memory ordering</a>.
       * <p>
       * The following pseudocode illustrates the behavior, where
!      * {@code JAVA_E} is the layout of the primitive element type, {@code ETYPE} is the
       * primitive element type, and {@code EVector} is the primitive
       * vector type for this vector:
       * <pre>{@code
       * ETYPE[] a = this.toArray();
+      * var slice = ms.asSlice(offset)
       * for (int n = 0; n < a.length; n++) {
       *     if (m.laneIsSet(n)) {
!      *         slice.setAtIndex(ValueLayout.JAVA_E.withBitAlignment(8), n);
       *     }
       * }
       * }</pre>
       *
       * @implNote
       * This operation is likely to be more efficient if
       * the specified byte order is the same as
       * {@linkplain ByteOrder#nativeOrder()

*** 3449,24 ***
       * the bytes of lane values.
       * In the special case where {@code ETYPE} is
       * {@code byte}, the byte order argument is
       * ignored.
       *
!      * @param bb the byte buffer
!      * @param offset the offset into the array
       * @param bo the intended byte order
       * @param m the mask controlling lane selection
       * @throws IndexOutOfBoundsException
       *         if {@code offset+N*ESIZE < 0}
!      *         or {@code offset+(N+1)*ESIZE > bb.limit()}
       *         for any lane {@code N} in the vector
       *         where the mask is set
!      * @throws java.nio.ReadOnlyBufferException
!      *         if the byte buffer is read-only
!      */
!     public abstract void intoByteBuffer(ByteBuffer bb, int offset,
!                                         ByteOrder bo, VectorMask<E> m);
  
      /**
       * Returns a packed array containing all the lane values.
       * The array length is the same as the vector length.
       * The element type of the array is the same as the element
--- 3430,29 ---
       * the bytes of lane values.
       * In the special case where {@code ETYPE} is
       * {@code byte}, the byte order argument is
       * ignored.
       *
!      * @param ms the memory segment
!      * @param offset the offset into the memory segment
       * @param bo the intended byte order
       * @param m the mask controlling lane selection
       * @throws IndexOutOfBoundsException
       *         if {@code offset+N*ESIZE < 0}
!      *         or {@code offset+(N+1)*ESIZE > ms.byteSize()}
       *         for any lane {@code N} in the vector
       *         where the mask is set
!      * @throws UnsupportedOperationException
!      *         if the memory segment is read-only
!      * @throws IllegalArgumentException if the memory segment is a heap segment that is
!      *         not backed by a {@code byte[]} array.
!      * @throws IllegalStateException if the memory segment's session is not alive,
+      *         or if access occurs from a thread other than the thread owning the session.
+      * @since 19
+      */
+     public abstract void intoMemorySegment(MemorySegment ms, long offset,
+                                            ByteOrder bo, VectorMask<E> m);
  
      /**
       * Returns a packed array containing all the lane values.
       * The array length is the same as the vector length.
       * The element type of the array is the same as the element
< prev index next >