Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ARM64-SVE: Add TrigonometricSelectCoefficient, TrigonometricStartingValue #104681

Merged
merged 3 commits into from
Jul 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/coreclr/jit/hwintrinsiclistarm64sve.h
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ HARDWARE_INTRINSIC(Sve, TestFirstTrue,
HARDWARE_INTRINSIC(Sve, TestLastTrue, -1, 2, true, {INS_sve_ptest, INS_sve_ptest, INS_sve_ptest, INS_sve_ptest, INS_sve_ptest, INS_sve_ptest, INS_sve_ptest, INS_sve_ptest, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen)
HARDWARE_INTRINSIC(Sve, TransposeEven, -1, 2, true, {INS_sve_trn1, INS_sve_trn1, INS_sve_trn1, INS_sve_trn1, INS_sve_trn1, INS_sve_trn1, INS_sve_trn1, INS_sve_trn1, INS_sve_trn1, INS_sve_trn1}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_SpecialCodeGen)
HARDWARE_INTRINSIC(Sve, TransposeOdd, -1, 2, true, {INS_sve_trn2, INS_sve_trn2, INS_sve_trn2, INS_sve_trn2, INS_sve_trn2, INS_sve_trn2, INS_sve_trn2, INS_sve_trn2, INS_sve_trn2, INS_sve_trn2}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_SpecialCodeGen)
HARDWARE_INTRINSIC(Sve, TrigonometricSelectCoefficient, -1, 2, true, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ftssel, INS_sve_ftssel}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_BaseTypeFromFirstArg)
HARDWARE_INTRINSIC(Sve, TrigonometricStartingValue, -1, 2, true, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ftsmul, INS_sve_ftsmul}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_BaseTypeFromFirstArg)
HARDWARE_INTRINSIC(Sve, UnzipEven, -1, 2, true, {INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_SpecialCodeGen)
HARDWARE_INTRINSIC(Sve, UnzipOdd, -1, 2, true, {INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_SpecialCodeGen)
HARDWARE_INTRINSIC(Sve, VectorTableLookup, -1, 2, true, {INS_sve_tbl, INS_sve_tbl, INS_sve_tbl, INS_sve_tbl, INS_sve_tbl, INS_sve_tbl, INS_sve_tbl, INS_sve_tbl, INS_sve_tbl, INS_sve_tbl}, HW_Category_SIMD, HW_Flag_Scalable)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8617,6 +8617,36 @@ internal Arm64() { }
public static unsafe Vector<ulong> TransposeOdd(Vector<ulong> left, Vector<ulong> right) { throw new PlatformNotSupportedException(); }


/// Trigonometric select coefficient

/// <summary>
/// svfloat64_t svtssel[_f64](svfloat64_t op1, svuint64_t op2)
/// FTSSEL Zresult.D, Zop1.D, Zop2.D
/// </summary>
public static unsafe Vector<double> TrigonometricSelectCoefficient(Vector<double> value, Vector<ulong> selector) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svfloat32_t svtssel[_f32](svfloat32_t op1, svuint32_t op2)
/// FTSSEL Zresult.S, Zop1.S, Zop2.S
/// </summary>
public static unsafe Vector<float> TrigonometricSelectCoefficient(Vector<float> value, Vector<uint> selector) { throw new PlatformNotSupportedException(); }


/// Trigonometric starting value

/// <summary>
/// svfloat64_t svtsmul[_f64](svfloat64_t op1, svuint64_t op2)
/// FTSMUL Zresult.D, Zop1.D, Zop2.D
/// </summary>
public static unsafe Vector<double> TrigonometricStartingValue(Vector<double> value, Vector<ulong> sign) { throw new PlatformNotSupportedException(); }

/// <summary>
/// svfloat32_t svtsmul[_f32](svfloat32_t op1, svuint32_t op2)
/// FTSMUL Zresult.S, Zop1.S, Zop2.S
/// </summary>
public static unsafe Vector<float> TrigonometricStartingValue(Vector<float> value, Vector<uint> sign) { throw new PlatformNotSupportedException(); }


/// UnzipEven : Concatenate even elements from two inputs

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8662,6 +8662,36 @@ internal Arm64() { }
public static unsafe Vector<ulong> TransposeOdd(Vector<ulong> left, Vector<ulong> right) => TransposeOdd(left, right);


/// Trigonometric select coefficient

/// <summary>
/// svfloat64_t svtssel[_f64](svfloat64_t op1, svuint64_t op2)
/// FTSSEL Zresult.D, Zop1.D, Zop2.D
/// </summary>
public static unsafe Vector<double> TrigonometricSelectCoefficient(Vector<double> value, Vector<ulong> selector) => TrigonometricSelectCoefficient(value, selector);

/// <summary>
/// svfloat32_t svtssel[_f32](svfloat32_t op1, svuint32_t op2)
/// FTSSEL Zresult.S, Zop1.S, Zop2.S
/// </summary>
public static unsafe Vector<float> TrigonometricSelectCoefficient(Vector<float> value, Vector<uint> selector) => TrigonometricSelectCoefficient(value, selector);


/// Trigonometric starting value

/// <summary>
/// svfloat64_t svtsmul[_f64](svfloat64_t op1, svuint64_t op2)
/// FTSMUL Zresult.D, Zop1.D, Zop2.D
/// </summary>
public static unsafe Vector<double> TrigonometricStartingValue(Vector<double> value, Vector<ulong> sign) => TrigonometricStartingValue(value, sign);

/// <summary>
/// svfloat32_t svtsmul[_f32](svfloat32_t op1, svuint32_t op2)
/// FTSMUL Zresult.S, Zop1.S, Zop2.S
/// </summary>
public static unsafe Vector<float> TrigonometricStartingValue(Vector<float> value, Vector<uint> sign) => TrigonometricStartingValue(value, sign);


/// UnzipEven : Concatenate even elements from two inputs

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5600,6 +5600,11 @@ internal Arm64() { }
public static System.Numerics.Vector<uint> TransposeOdd(System.Numerics.Vector<uint> left, System.Numerics.Vector<uint> right) { throw null; }
public static System.Numerics.Vector<ulong> TransposeOdd(System.Numerics.Vector<ulong> left, System.Numerics.Vector<ulong> right) { throw null; }

public static System.Numerics.Vector<double> TrigonometricSelectCoefficient(System.Numerics.Vector<double> value, System.Numerics.Vector<ulong> selector) { throw null; }
public static System.Numerics.Vector<float> TrigonometricSelectCoefficient(System.Numerics.Vector<float> value, System.Numerics.Vector<uint> selector) { throw null; }
public static System.Numerics.Vector<double> TrigonometricStartingValue(System.Numerics.Vector<double> value, System.Numerics.Vector<ulong> sign) { throw null; }
public static System.Numerics.Vector<float> TrigonometricStartingValue(System.Numerics.Vector<float> value, System.Numerics.Vector<uint> sign) { throw null; }

public static System.Numerics.Vector<sbyte> UnzipEven(System.Numerics.Vector<sbyte> left, System.Numerics.Vector<sbyte> right) { throw null; }
public static System.Numerics.Vector<short> UnzipEven(System.Numerics.Vector<short> left, System.Numerics.Vector<short> right) { throw null; }
public static System.Numerics.Vector<int> UnzipEven(System.Numerics.Vector<int> left, System.Numerics.Vector<int> right) { throw null; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4152,6 +4152,11 @@
("SveVecReduceUnOpTest.template", new Dictionary<string, string> { ["TestName"] = "Sve_XorAcross_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "XorAcross", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateReduceOpResult"] = "Helpers.XorAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}),
("SveVecReduceUnOpTest.template", new Dictionary<string, string> { ["TestName"] = "Sve_XorAcross_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "XorAcross", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateReduceOpResult"] = "Helpers.XorAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}),

("SveVecBinOpDifferentTypesTest.template", new Dictionary<string, string> {["TestName"] = "Sve_TrigonometricSelectCoefficient_float_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "TrigonometricSelectCoefficient", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "((left[i] <= (Math.PI / 4)) && (left[i] > (-Math.PI / 4))) && (Helpers.TrigonometricSelectCoefficient(left[i], right[i]) != result[i])", ["GetIterResult"] = "((left[i] <= (Math.PI / 4)) && (left[i] > (-Math.PI / 4))) ? Helpers.TrigonometricSelectCoefficient(left[i], right[i]) : result[i]"}),
("SveVecBinOpDifferentTypesTest.template", new Dictionary<string, string> {["TestName"] = "Sve_TrigonometricSelectCoefficient_double_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "TrigonometricSelectCoefficient", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "((left[i] <= (Math.PI / 4)) && (left[i] > (-Math.PI / 4))) && (Helpers.TrigonometricSelectCoefficient(left[i], right[i]) != result[i])", ["GetIterResult"] = "((left[i] <= (Math.PI / 4)) && (left[i] > (-Math.PI / 4))) ? Helpers.TrigonometricSelectCoefficient(left[i], right[i]) : result[i]"}),
("SveVecBinOpDifferentTypesTest.template", new Dictionary<string, string> {["TestName"] = "Sve_TrigonometricStartingValue_float_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "TrigonometricStartingValue", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "((left[i] <= (Math.PI / 4)) && (left[i] > (-Math.PI / 4))) && (Helpers.TrigonometricStartingValue(left[i], right[i]) != result[i])", ["GetIterResult"] = "((left[i] <= (Math.PI / 4)) && (left[i] > (-Math.PI / 4))) ? Helpers.TrigonometricStartingValue(left[i], right[i]) : result[i]"}),
("SveVecBinOpDifferentTypesTest.template", new Dictionary<string, string> {["TestName"] = "Sve_TrigonometricStartingValue_double_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "TrigonometricStartingValue", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "((left[i] <= (Math.PI / 4)) && (left[i] > (-Math.PI / 4))) && (Helpers.TrigonometricStartingValue(left[i], right[i]) != result[i])", ["GetIterResult"] = "((left[i] <= (Math.PI / 4)) && (left[i] > (-Math.PI / 4))) ? Helpers.TrigonometricStartingValue(left[i], right[i]) : result[i]"}),

("SveVecPairBinOpTest.template", new Dictionary<string, string> { ["TestName"] = "SveUnzipEven_float", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}),
("SveVecPairBinOpTest.template", new Dictionary<string, string> { ["TestName"] = "SveUnzipEven_double", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}),
("SveVecPairBinOpTest.template", new Dictionary<string, string> { ["TestName"] = "SveUnzipEven_sbyte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}),
Expand Down
60 changes: 60 additions & 0 deletions src/tests/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5218,6 +5218,36 @@ public static float MultiplyExtended(float op1, float op2)
}
}

public static float TrigonometricSelectCoefficient(float op1, uint op2)
kunalspathak marked this conversation as resolved.
Show resolved Hide resolved
{
float result = ((op2 % 2) == 0) ? op1 : (float)1.0;
bool isNegative = (op2 & 0b10) == 0b10;

if (isNegative != (result < 0))
{
result *= -1;
}

return result;
}

public static float TrigonometricStartingValue(float op1, uint op2)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are we sure we are taking into account all the possibilities of the operation? https://docsmirror.github.io/A64/2023-06/shared_pseudocode.html#impl-shared.FPMul.3? @SwapnilGaikwad, can we double check this one?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic in the helper function is correct for the valid input (-π/4 < x <= π/4). However, behaviour of the instruction may be undefined if the input falls outside the valid range.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amanasifkhalid - for our testing purpose, we would certainly fall out of valid range. how does the API behave for them? wondering if test is robust enough to not fail for invalid values or we at least handle them?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've verified we are generating out-of-range values, though the tests are still passing. I can constrain the inputs to this test to ensure we don't go out of range to avoid potential undefined behavior.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've verified we are generating out-of-range values, though the tests are still passing.

that's interesting. so undefined could be that sometime they will pass and sometime they won't.

I can constrain the inputs to this test to ensure we don't go out of range to avoid potential undefined behavior.

Or probably constaint the validation for only the lanes that had valid inputs? that way we will still have coverage for invalid values, which realistically someone can pass in?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or probably constaint the validation for only the lanes that had valid inputs? that way we will still have coverage for invalid values, which realistically someone can pass in?

That sounds like a better idea. I'll update the validation logic to do this.

{
float result = op1 * op1;

if (float.IsNaN(result))
{
return result;
}

if ((op2 % 2) == 1)
{
result *= -1;
}

return result;
}

public static float FPExponentialAccelerator(uint op1)
{
uint index = op1 & 0b111111;
Expand Down Expand Up @@ -5338,6 +5368,36 @@ public static double MultiplyExtended(double op1, double op2)
}
}

public static double TrigonometricSelectCoefficient(double op1, ulong op2)
{
double result = ((op2 % 2) == 0) ? op1 : 1.0;
bool isNegative = (op2 & 0b10) == 0b10;

if (isNegative != (result < 0))
{
result *= -1;
}

return result;
}

public static double TrigonometricStartingValue(double op1, ulong op2)
{
double result = op1 * op1;

if (double.IsNaN(result))
{
return result;
}

if ((op2 % 2) == 1)
{
result *= -1;
}

return result;
}

public static double FPExponentialAccelerator(ulong op1)
{
ulong index = op1 & 0b111111;
Expand Down
Loading