Skip to content

[API Proposal]: Arm64: FEAT_SVE: firstfaulting #94004

Closed
@a74nh

Description

@a74nh
namespace System.Runtime.Intrinsics.Arm;

/// VectorT Summary
public abstract partial class Sve : AdvSimd /// Feature: FEAT_SVE  Category: firstfaulting
{

  /// T: [int, uint], [long, ulong]
  public static unsafe Vector<T> GatherVectorByteZeroExtendFirstFaulting(Vector<T> mask, Vector<T2> bases); // LDFF1B

  /// T: uint, ulong
  public static unsafe Vector<T> GatherVectorByteZeroExtendFirstFaulting(Vector<T> mask, Vector<T> bases); // LDFF1B

  /// T: int, uint, long, ulong
  public static unsafe Vector<T> GatherVectorByteZeroExtendFirstFaulting(Vector<T> mask, byte* base, Vector<T> offsets); // LDFF1B

  /// T: [uint, int], [int, uint], [ulong, long], [long, ulong]
  public static unsafe Vector<T> GatherVectorByteZeroExtendFirstFaulting(Vector<T> mask, byte* base, Vector<T2> offsets); // LDFF1B

  /// T: [int, uint], [long, ulong]
  public static unsafe Vector<T> GatherVectorByteZeroExtendFirstFaulting(Vector<T> mask, Vector<T2> bases, long offset); // LDFF1B

  /// T: uint, ulong
  public static unsafe Vector<T> GatherVectorByteZeroExtendFirstFaulting(Vector<T> mask, Vector<T> bases, long offset); // LDFF1B

  /// T: [float, uint], [int, uint], [double, ulong], [long, ulong]
  public static unsafe Vector<T> GatherVectorFirstFaulting(Vector<T> mask, Vector<T2> bases); // LDFF1W or LDFF1D

  /// T: uint, ulong
  public static unsafe Vector<T> GatherVectorFirstFaulting(Vector<T> mask, Vector<T> bases); // LDFF1W or LDFF1D

  /// T: [float, int], [uint, int], [float, uint], [int, uint], [double, long], [ulong, long], [double, ulong], [long, ulong]
  public static unsafe Vector<T> GatherVectorFirstFaulting(Vector<T> mask, T* base, Vector<T2> offsets); // LDFF1W or LDFF1D

  /// T: int, uint, long, ulong
  public static unsafe Vector<T> GatherVectorFirstFaulting(Vector<T> mask, T* base, Vector<T> offsets); // LDFF1W or LDFF1D

  /// T: [float, int], [uint, int], [float, uint], [int, uint], [double, long], [ulong, long], [double, ulong], [long, ulong]
  public static unsafe Vector<T> GatherVectorFirstFaulting(Vector<T> mask, T* base, Vector<T2> indices); // LDFF1W or LDFF1D

  /// T: int, uint, long, ulong
  public static unsafe Vector<T> GatherVectorFirstFaulting(Vector<T> mask, T* base, Vector<T> indices); // LDFF1W or LDFF1D

  /// T: [float, uint], [int, uint], [double, ulong], [long, ulong]
  public static unsafe Vector<T> GatherVectorFirstFaulting(Vector<T> mask, Vector<T2> bases, long offset); // LDFF1W or LDFF1D

  /// T: uint, ulong
  public static unsafe Vector<T> GatherVectorFirstFaulting(Vector<T> mask, Vector<T> bases, long offset); // LDFF1W or LDFF1D

  /// T: [float, uint], [int, uint], [double, ulong], [long, ulong]
  public static unsafe Vector<T> GatherVectorFirstFaulting(Vector<T> mask, Vector<T2> bases, long index); // LDFF1W or LDFF1D

  /// T: uint, ulong
  public static unsafe Vector<T> GatherVectorFirstFaulting(Vector<T> mask, Vector<T> bases, long index); // LDFF1W or LDFF1D

  /// T: [int, uint], [long, ulong]
  public static unsafe Vector<T> GatherVectorInt16SignExtendFirstFaulting(Vector<T> mask, Vector<T2> bases); // LDFF1SH

  /// T: uint, ulong
  public static unsafe Vector<T> GatherVectorInt16SignExtendFirstFaulting(Vector<T> mask, Vector<T> bases); // LDFF1SH

  /// T: int, uint, long, ulong
  public static unsafe Vector<T> GatherVectorInt16SignExtendFirstFaulting(Vector<T> mask, short* base, Vector<T> offsets); // LDFF1SH

  /// T: [uint, int], [int, uint], [ulong, long], [long, ulong]
  public static unsafe Vector<T> GatherVectorInt16SignExtendFirstFaulting(Vector<T> mask, short* base, Vector<T2> offsets); // LDFF1SH

  /// T: int, uint, long, ulong
  public static unsafe Vector<T> GatherVectorInt16SignExtendFirstFaulting(Vector<T> mask, short* base, Vector<T> indices); // LDFF1SH

  /// T: [uint, int], [int, uint], [ulong, long], [long, ulong]
  public static unsafe Vector<T> GatherVectorInt16SignExtendFirstFaulting(Vector<T> mask, short* base, Vector<T2> indices); // LDFF1SH

  /// T: [int, uint], [long, ulong]
  public static unsafe Vector<T> GatherVectorInt16SignExtendFirstFaulting(Vector<T> mask, Vector<T2> bases, long offset); // LDFF1SH

  /// T: uint, ulong
  public static unsafe Vector<T> GatherVectorInt16SignExtendFirstFaulting(Vector<T> mask, Vector<T> bases, long offset); // LDFF1SH

  /// T: [int, uint], [long, ulong]
  public static unsafe Vector<T> GatherVectorInt16SignExtendFirstFaulting(Vector<T> mask, Vector<T2> bases, long index); // LDFF1SH

  /// T: uint, ulong
  public static unsafe Vector<T> GatherVectorInt16SignExtendFirstFaulting(Vector<T> mask, Vector<T> bases, long index); // LDFF1SH

  /// T: [int, uint], [long, ulong]
  public static unsafe Vector<T> GatherVectorInt16ZeroExtendFirstFaulting(Vector<T> mask, Vector<T2> bases); // LDFF1H

  /// T: uint, ulong
  public static unsafe Vector<T> GatherVectorInt16ZeroExtendFirstFaulting(Vector<T> mask, Vector<T> bases); // LDFF1H

  /// T: int, uint, long, ulong
  public static unsafe Vector<T> GatherVectorInt16ZeroExtendFirstFaulting(Vector<T> mask, ushort* base, Vector<T> offsets); // LDFF1H

  /// T: [uint, int], [int, uint], [ulong, long], [long, ulong]
  public static unsafe Vector<T> GatherVectorInt16ZeroExtendFirstFaulting(Vector<T> mask, ushort* base, Vector<T2> offsets); // LDFF1H

  /// T: int, uint, long, ulong
  public static unsafe Vector<T> GatherVectorInt16ZeroExtendFirstFaulting(Vector<T> mask, ushort* base, Vector<T> indices); // LDFF1H

  /// T: [uint, int], [int, uint], [ulong, long], [long, ulong]
  public static unsafe Vector<T> GatherVectorInt16ZeroExtendFirstFaulting(Vector<T> mask, ushort* base, Vector<T2> indices); // LDFF1H

  /// T: [int, uint], [long, ulong]
  public static unsafe Vector<T> GatherVectorInt16ZeroExtendFirstFaulting(Vector<T> mask, Vector<T2> bases, long offset); // LDFF1H

  /// T: uint, ulong
  public static unsafe Vector<T> GatherVectorInt16ZeroExtendFirstFaulting(Vector<T> mask, Vector<T> bases, long offset); // LDFF1H

  /// T: [int, uint], [long, ulong]
  public static unsafe Vector<T> GatherVectorInt16ZeroExtendFirstFaulting(Vector<T> mask, Vector<T2> bases, long index); // LDFF1H

  /// T: uint, ulong
  public static unsafe Vector<T> GatherVectorInt16ZeroExtendFirstFaulting(Vector<T> mask, Vector<T> bases, long index); // LDFF1H

  public static unsafe Vector<long> GatherVectorInt32SignExtendFirstFaulting(Vector<long> mask, Vector<ulong> bases); // LDFF1SW

  public static unsafe Vector<ulong> GatherVectorInt32SignExtendFirstFaulting(Vector<ulong> mask, Vector<ulong> bases); // LDFF1SW

  /// T: long, ulong
  public static unsafe Vector<T> GatherVectorInt32SignExtendFirstFaulting(Vector<T> mask, int* base, Vector<T> offsets); // LDFF1SW

  /// T: [ulong, long], [long, ulong]
  public static unsafe Vector<T> GatherVectorInt32SignExtendFirstFaulting(Vector<T> mask, int* base, Vector<T2> offsets); // LDFF1SW

  /// T: long, ulong
  public static unsafe Vector<T> GatherVectorInt32SignExtendFirstFaulting(Vector<T> mask, int* base, Vector<T> indices); // LDFF1SW

  /// T: [ulong, long], [long, ulong]
  public static unsafe Vector<T> GatherVectorInt32SignExtendFirstFaulting(Vector<T> mask, int* base, Vector<T2> indices); // LDFF1SW

  public static unsafe Vector<long> GatherVectorInt32SignExtendFirstFaulting(Vector<long> mask, Vector<ulong> bases, long offset); // LDFF1SW

  public static unsafe Vector<ulong> GatherVectorInt32SignExtendFirstFaulting(Vector<ulong> mask, Vector<ulong> bases, long offset); // LDFF1SW

  public static unsafe Vector<long> GatherVectorInt32SignExtendFirstFaulting(Vector<long> mask, Vector<ulong> bases, long index); // LDFF1SW

  public static unsafe Vector<ulong> GatherVectorInt32SignExtendFirstFaulting(Vector<ulong> mask, Vector<ulong> bases, long index); // LDFF1SW

  public static unsafe Vector<long> GatherVectorInt32ZeroExtendFirstFaulting(Vector<long> mask, Vector<ulong> bases); // LDFF1W

  public static unsafe Vector<ulong> GatherVectorInt32ZeroExtendFirstFaulting(Vector<ulong> mask, Vector<ulong> bases); // LDFF1W

  /// T: long, ulong
  public static unsafe Vector<T> GatherVectorInt32ZeroExtendFirstFaulting(Vector<T> mask, uint* base, Vector<T> offsets); // LDFF1W

  /// T: [ulong, long], [long, ulong]
  public static unsafe Vector<T> GatherVectorInt32ZeroExtendFirstFaulting(Vector<T> mask, uint* base, Vector<T2> offsets); // LDFF1W

  /// T: long, ulong
  public static unsafe Vector<T> GatherVectorInt32ZeroExtendFirstFaulting(Vector<T> mask, uint* base, Vector<T> indices); // LDFF1W

  /// T: [ulong, long], [long, ulong]
  public static unsafe Vector<T> GatherVectorInt32ZeroExtendFirstFaulting(Vector<T> mask, uint* base, Vector<T2> indices); // LDFF1W

  public static unsafe Vector<long> GatherVectorInt32ZeroExtendFirstFaulting(Vector<long> mask, Vector<ulong> bases, long offset); // LDFF1W

  public static unsafe Vector<ulong> GatherVectorInt32ZeroExtendFirstFaulting(Vector<ulong> mask, Vector<ulong> bases, long offset); // LDFF1W

  public static unsafe Vector<long> GatherVectorInt32ZeroExtendFirstFaulting(Vector<long> mask, Vector<ulong> bases, long index); // LDFF1W

  public static unsafe Vector<ulong> GatherVectorInt32ZeroExtendFirstFaulting(Vector<ulong> mask, Vector<ulong> bases, long index); // LDFF1W

  /// T: [int, uint], [long, ulong]
  public static unsafe Vector<T> GatherVectorSByteSignExtendFirstFaulting(Vector<T> mask, Vector<T2> bases); // LDFF1SB

  /// T: uint, ulong
  public static unsafe Vector<T> GatherVectorSByteSignExtendFirstFaulting(Vector<T> mask, Vector<T> bases); // LDFF1SB

  /// T: int, uint, long, ulong
  public static unsafe Vector<T> GatherVectorSByteSignExtendFirstFaulting(Vector<T> mask, sbyte* base, Vector<T> offsets); // LDFF1SB

  /// T: [uint, int], [int, uint], [ulong, long], [long, ulong]
  public static unsafe Vector<T> GatherVectorSByteSignExtendFirstFaulting(Vector<T> mask, sbyte* base, Vector<T2> offsets); // LDFF1SB

  /// T: [int, uint], [long, ulong]
  public static unsafe Vector<T> GatherVectorSByteSignExtendFirstFaulting(Vector<T> mask, Vector<T2> bases, long offset); // LDFF1SB

  /// T: uint, ulong
  public static unsafe Vector<T> GatherVectorSByteSignExtendFirstFaulting(Vector<T> mask, Vector<T> bases, long offset); // LDFF1SB

  /// T: sbyte, short, int, long, byte, ushort, uint, ulong
  public static unsafe Vector<T> GetFFR(); // RDFFR // predicated

  /// T: short, int, long, ushort, uint, ulong
  public static unsafe Vector<T> LoadVectorByteZeroExtendFirstFaulting(byte* address); // LDFF1B // predicated

  /// T: float, double, sbyte, short, int, long, byte, ushort, uint, ulong
  public static unsafe Vector<T> LoadVectorFirstFaulting(T* address); // LDFF1W or LDFF1D or LDFF1B or LDFF1H // predicated

  /// T: int, long, uint, ulong
  public static unsafe Vector<T> LoadVectorInt16SignExtendFirstFaulting(short* address); // LDFF1SH // predicated

  /// T: int, long, uint, ulong
  public static unsafe Vector<T> LoadVectorInt16ZeroExtendFirstFaulting(ushort* address); // LDFF1H // predicated

  /// T: long, ulong
  public static unsafe Vector<T> LoadVectorInt32SignExtendFirstFaulting(int* address); // LDFF1SW // predicated

  /// T: long, ulong
  public static unsafe Vector<T> LoadVectorInt32ZeroExtendFirstFaulting(uint* address); // LDFF1W // predicated

  /// T: short, int, long, ushort, uint, ulong
  public static unsafe Vector<T> LoadVectorSByteSignExtendFirstFaulting(sbyte* address); // LDFF1SB // predicated

  public static unsafe void SetFFR(); // SETFFR

  /// T: sbyte, short, int, long, byte, ushort, uint, ulong
  public static unsafe void WriteFFR(Vector<T> value); // WRFFR

  /// total method signatures: 72

}

First Faulting Loads

Each First Faulting LoadVector method matches a non-faulting version in #94006.

Loads a vector element by element. If loading that element would cause a fault, then stop the load and set the first faulting register for each element that completed. If no elements fault, then the load completes as per the non-faulting version.

After calling a first faulting load, the first faulting mask should always be read to determine if the load completed.

GetFFR(), SetFFR() and WriteFFR() are used to access the ffr mask for the last first faulting load.

// Look for the 0 at the end of the buffer
long strlen(byte *buffer)
{
  long i = 0;
  Sve.SetFFR();

  while (1)
  {
    // Load data from the buffer. maskfrr contains the elements that were loaded.
    Vector<byte> data = Sve.LoadVectorFirstFaulting(buffer + i);
    Vector<byte> maskfrr = Sve.GetFFR(all);

    // Look for zeros in the loaded data   
    Vector<byte> zeromask = Sve.ConditionalSelect(maskfrr, Sve.CompareEquals(data, 0), Vector<byte>.Zero);

    if (Sve.ConditionalSelect(Sve.MaskTestAnyTrue(zeromask))) {
      // There was a zero in the loaded data. Increment up to the zero and exit the loop
      zeromask = Sve.BreakBefore(zeromask);
      i += Sve.GetActiveElementCount(zeromask);  
      break;
    } else if (Sve.MaskTestLastTrue(maskffr)) {
      // Final bit in the ffr mask is set, therefore the load completed. Increment and continue.
      i += Sve.Count8BitElements();
    } else {
      // The load faulted. Increment by the number of loaded elements and continue.
      Sve.SetFFR();
      i += Sve.GetActiveElementCount(maskfrr);
    }
  }  

  return i;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions