diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index faf71e3cea85f7..550e3ca70ca7d6 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3226,6 +3226,13 @@ class Compiler GenTree* gtNewSimdFloorNode( var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize); + GenTree* gtNewSimdFmaNode(var_types type, + GenTree* op1, + GenTree* op2, + GenTree* op3, + CorInfoType simdBaseJitType, + unsigned simdSize); + GenTree* gtNewSimdGetElementNode(var_types type, GenTree* op1, GenTree* op2, diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 99d2decc490981..8b6d515d1b559b 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -23390,6 +23390,61 @@ GenTree* Compiler::gtNewSimdFloorNode(var_types type, GenTree* op1, CorInfoType return gtNewSimdHWIntrinsicNode(type, op1, intrinsic, simdBaseJitType, simdSize); } +GenTree* Compiler::gtNewSimdFmaNode( + var_types type, GenTree* op1, GenTree* op2, GenTree* op3, CorInfoType simdBaseJitType, unsigned simdSize) +{ + assert(varTypeIsSIMD(type)); + assert(getSIMDTypeForSize(simdSize) == type); + + assert(op1 != nullptr); + assert(op1->TypeIs(type)); + + assert(op2 != nullptr); + assert(op2->TypeIs(type)); + + assert(op3 != nullptr); + assert(op3->TypeIs(type)); + + var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); + assert(varTypeIsFloating(simdBaseType)); + + NamedIntrinsic intrinsic = NI_Illegal; + +#if defined(TARGET_XARCH) + if (simdSize == 64) + { + assert(compIsaSupportedDebugOnly(InstructionSet_AVX512F)); + intrinsic = NI_AVX512F_FusedMultiplyAdd; + } + else + { + assert(compIsaSupportedDebugOnly(InstructionSet_FMA)); + intrinsic = NI_FMA_MultiplyAdd; + } +#elif defined(TARGET_ARM64) + assert(IsBaselineSimdIsaSupportedDebugOnly()); + + if (simdBaseType == TYP_DOUBLE) + { + intrinsic = (simdSize == 8) ? NI_AdvSimd_FusedMultiplyAddScalar : NI_AdvSimd_Arm64_FusedMultiplyAdd; + } + else + { + intrinsic = NI_AdvSimd_FusedMultiplyAdd; + } + + // AdvSimd.FusedMultiplyAdd expects (addend, left, right), while the APIs take (left, right, addend) + // We expect op1 and op2 to have already been spilled + + std::swap(op1, op3); +#else +#error Unsupported platform +#endif // !TARGET_XARCH && !TARGET_ARM64 + + assert(intrinsic != NI_Illegal); + return gtNewSimdHWIntrinsicNode(type, op1, op2, op3, intrinsic, simdBaseJitType, simdSize); +} + GenTree* Compiler::gtNewSimdGetElementNode( var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize) { diff --git a/src/coreclr/jit/hwintrinsicarm64.cpp b/src/coreclr/jit/hwintrinsicarm64.cpp index 4fb3716d9cdf6b..5a2154c9d1cf67 100644 --- a/src/coreclr/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/jit/hwintrinsicarm64.cpp @@ -1358,6 +1358,26 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, break; } + case NI_Vector64_FusedMultiplyAdd: + case NI_Vector128_FusedMultiplyAdd: + { + assert(sig->numArgs == 3); + assert(varTypeIsFloating(simdBaseType)); + + impSpillSideEffect(true, verCurrentState.esStackDepth - + 3 DEBUGARG("Spilling op1 side effects for FusedMultiplyAdd")); + + impSpillSideEffect(true, verCurrentState.esStackDepth - + 2 DEBUGARG("Spilling op2 side effects for FusedMultiplyAdd")); + + op3 = impSIMDPopStack(); + op2 = impSIMDPopStack(); + op1 = impSIMDPopStack(); + + retNode = gtNewSimdFmaNode(retType, op1, op2, op3, simdBaseJitType, simdSize); + break; + } + case NI_Vector64_get_AllBitsSet: case NI_Vector128_get_AllBitsSet: { @@ -1702,6 +1722,31 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, break; } + case NI_Vector64_MultiplyAddEstimate: + case NI_Vector128_MultiplyAddEstimate: + { + assert(sig->numArgs == 3); + assert(varTypeIsFloating(simdBaseType)); + + if (BlockNonDeterministicIntrinsics(mustExpand)) + { + break; + } + + impSpillSideEffect(true, verCurrentState.esStackDepth - + 3 DEBUGARG("Spilling op1 side effects for MultiplyAddEstimate")); + + impSpillSideEffect(true, verCurrentState.esStackDepth - + 2 DEBUGARG("Spilling op2 side effects for MultiplyAddEstimate")); + + op3 = impSIMDPopStack(); + op2 = impSIMDPopStack(); + op1 = impSIMDPopStack(); + + retNode = gtNewSimdFmaNode(retType, op1, op2, op3, simdBaseJitType, simdSize); + break; + } + case NI_Vector64_Narrow: case NI_Vector128_Narrow: { diff --git a/src/coreclr/jit/hwintrinsiclistarm64.h b/src/coreclr/jit/hwintrinsiclistarm64.h index 057b2cf0c8023c..a207ac5bc60405 100644 --- a/src/coreclr/jit/hwintrinsiclistarm64.h +++ b/src/coreclr/jit/hwintrinsiclistarm64.h @@ -56,6 +56,7 @@ HARDWARE_INTRINSIC(Vector64, EqualsAll, HARDWARE_INTRINSIC(Vector64, EqualsAny, 8, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector64, ExtractMostSignificantBits, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector64, Floor, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector64, FusedMultiplyAdd, 8, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector64, get_AllBitsSet, 8, 0, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector64, get_Indices, 8, 0, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector64, get_One, 8, 0, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) @@ -80,6 +81,7 @@ HARDWARE_INTRINSIC(Vector64, LoadUnsafe, HARDWARE_INTRINSIC(Vector64, Max, 8, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector64, Min, 8, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector64, Multiply, 8, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector64, MultiplyAddEstimate, 8, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector64, Narrow, 8, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector64, Negate, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector64, OnesComplement, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) @@ -169,6 +171,7 @@ HARDWARE_INTRINSIC(Vector128, EqualsAll, HARDWARE_INTRINSIC(Vector128, EqualsAny, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, ExtractMostSignificantBits, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, Floor, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector128, FusedMultiplyAdd, 16, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, get_AllBitsSet, 16, 0, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, get_Indices, 16, 0, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, get_One, 16, 0, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) @@ -195,6 +198,7 @@ HARDWARE_INTRINSIC(Vector128, LoadUnsafe, HARDWARE_INTRINSIC(Vector128, Max, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, Min, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, Multiply, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector128, MultiplyAddEstimate, 16, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, Narrow, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, Negate, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, OnesComplement, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) diff --git a/src/coreclr/jit/hwintrinsiclistxarch.h b/src/coreclr/jit/hwintrinsiclistxarch.h index a726cd624dcfd5..aed1d0b1dfb118 100644 --- a/src/coreclr/jit/hwintrinsiclistxarch.h +++ b/src/coreclr/jit/hwintrinsiclistxarch.h @@ -75,6 +75,7 @@ HARDWARE_INTRINSIC(Vector128, EqualsAll, HARDWARE_INTRINSIC(Vector128, EqualsAny, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, ExtractMostSignificantBits, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, Floor, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector128, FusedMultiplyAdd, 16, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, get_AllBitsSet, 16, 0, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, get_Indices, 16, 0, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, get_One, 16, 0, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) @@ -99,6 +100,7 @@ HARDWARE_INTRINSIC(Vector128, LoadUnsafe, HARDWARE_INTRINSIC(Vector128, Max, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, Min, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, Multiply, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector128, MultiplyAddEstimate, 16, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, Narrow, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, Negate, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, OnesComplement, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) @@ -185,6 +187,7 @@ HARDWARE_INTRINSIC(Vector256, EqualsAll, HARDWARE_INTRINSIC(Vector256, EqualsAny, 32, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector256, ExtractMostSignificantBits, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector256, Floor, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_AvxOnlyCompatible) +HARDWARE_INTRINSIC(Vector256, FusedMultiplyAdd, 32, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector256, get_AllBitsSet, 32, 0, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_AvxOnlyCompatible) HARDWARE_INTRINSIC(Vector256, get_Indices, 32, 0, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector256, get_One, 32, 0, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) @@ -211,6 +214,7 @@ HARDWARE_INTRINSIC(Vector256, LoadUnsafe, HARDWARE_INTRINSIC(Vector256, Max, 32, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector256, Min, 32, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector256, Multiply, 32, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector256, MultiplyAddEstimate, 32, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector256, Narrow, 32, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector256, Negate, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector256, OnesComplement, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_AvxOnlyCompatible) @@ -297,6 +301,7 @@ HARDWARE_INTRINSIC(Vector512, EqualsAll, HARDWARE_INTRINSIC(Vector512, EqualsAny, 64, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector512, ExtractMostSignificantBits, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector512, Floor, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector512, FusedMultiplyAdd, 64, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector512, get_AllBitsSet, 64, 0, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector512, get_Indices, 64, 0, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector512, get_One, 64, 0, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) @@ -324,6 +329,7 @@ HARDWARE_INTRINSIC(Vector512, LoadUnsafe, HARDWARE_INTRINSIC(Vector512, Max, 64, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector512, Min, 64, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector512, Multiply, 64, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector512, MultiplyAddEstimate, 64, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector512, Narrow, 64, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector512, Negate, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector512, OnesComplement, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp index 603d98cef20ecf..8aaee01f4c41c7 100644 --- a/src/coreclr/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/jit/hwintrinsicxarch.cpp @@ -2180,6 +2180,24 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, break; } + case NI_Vector128_FusedMultiplyAdd: + case NI_Vector256_FusedMultiplyAdd: + case NI_Vector512_FusedMultiplyAdd: + { + assert(sig->numArgs == 3); + assert(varTypeIsFloating(simdBaseType)); + + if (compOpportunisticallyDependsOn(InstructionSet_FMA)) + { + op3 = impSIMDPopStack(); + op2 = impSIMDPopStack(); + op1 = impSIMDPopStack(); + + retNode = gtNewSimdFmaNode(retType, op1, op2, op3, simdBaseJitType, simdSize); + } + break; + } + case NI_Vector128_get_AllBitsSet: case NI_Vector256_get_AllBitsSet: case NI_Vector512_get_AllBitsSet: @@ -2639,6 +2657,34 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, break; } + case NI_Vector128_MultiplyAddEstimate: + case NI_Vector256_MultiplyAddEstimate: + case NI_Vector512_MultiplyAddEstimate: + { + assert(sig->numArgs == 3); + assert(varTypeIsFloating(simdBaseType)); + + if (BlockNonDeterministicIntrinsics(mustExpand)) + { + break; + } + + op3 = impSIMDPopStack(); + op2 = impSIMDPopStack(); + op1 = impSIMDPopStack(); + + if (compExactlyDependsOn(InstructionSet_FMA)) + { + retNode = gtNewSimdFmaNode(retType, op1, op2, op3, simdBaseJitType, simdSize); + } + else + { + GenTree* mulNode = gtNewSimdBinOpNode(GT_MUL, retType, op1, op2, simdBaseJitType, simdSize); + retNode = gtNewSimdBinOpNode(GT_ADD, retType, mulNode, op3, simdBaseJitType, simdSize); + } + break; + } + case NI_Vector128_Narrow: case NI_Vector256_Narrow: case NI_Vector512_Narrow: diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 89f33319c8120a..85bd5d8dfbd166 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -3984,13 +3984,18 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, // Vector128.CreateScalarUnsafe(z) // ).ToScalar(); - GenTree* op3 = gtNewSimdCreateScalarUnsafeNode(TYP_SIMD16, impPopStack().val, callJitType, 16); - GenTree* op2 = gtNewSimdCreateScalarUnsafeNode(TYP_SIMD16, impPopStack().val, callJitType, 16); - GenTree* op1 = gtNewSimdCreateScalarUnsafeNode(TYP_SIMD16, impPopStack().val, callJitType, 16); - GenTree* res = + GenTree* op3 = impImplicitR4orR8Cast(impPopStack().val, callType); + GenTree* op2 = impImplicitR4orR8Cast(impPopStack().val, callType); + GenTree* op1 = impImplicitR4orR8Cast(impPopStack().val, callType); + + op3 = gtNewSimdCreateScalarUnsafeNode(TYP_SIMD16, op3, callJitType, 16); + op2 = gtNewSimdCreateScalarUnsafeNode(TYP_SIMD16, op2, callJitType, 16); + op1 = gtNewSimdCreateScalarUnsafeNode(TYP_SIMD16, op1, callJitType, 16); + + retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, op2, op3, NI_FMA_MultiplyAddScalar, callJitType, 16); - retNode = gtNewSimdToScalarNode(callType, res, callJitType, 16); + retNode = gtNewSimdToScalarNode(callType, retNode, callJitType, 16); break; } #elif defined(TARGET_ARM64) @@ -4005,9 +4010,19 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, // Vector64.Create{ScalarUnsafe}(x) // ).ToScalar(); - GenTree* op3 = gtNewSimdCreateScalarUnsafeNode(TYP_SIMD8, impPopStack().val, callJitType, 8); - GenTree* op2 = gtNewSimdCreateScalarUnsafeNode(TYP_SIMD8, impPopStack().val, callJitType, 8); - GenTree* op1 = gtNewSimdCreateScalarUnsafeNode(TYP_SIMD8, impPopStack().val, callJitType, 8); + impSpillSideEffect(true, verCurrentState.esStackDepth - + 3 DEBUGARG("Spilling op1 side effects for FusedMultiplyAdd")); + + impSpillSideEffect(true, verCurrentState.esStackDepth - + 2 DEBUGARG("Spilling op2 side effects for FusedMultiplyAdd")); + + GenTree* op3 = impImplicitR4orR8Cast(impPopStack().val, callType); + GenTree* op2 = impImplicitR4orR8Cast(impPopStack().val, callType); + GenTree* op1 = impImplicitR4orR8Cast(impPopStack().val, callType); + + op3 = gtNewSimdCreateScalarUnsafeNode(TYP_SIMD8, op3, callJitType, 8); + op2 = gtNewSimdCreateScalarUnsafeNode(TYP_SIMD8, op2, callJitType, 8); + op1 = gtNewSimdCreateScalarUnsafeNode(TYP_SIMD8, op1, callJitType, 8); // Note that AdvSimd.FusedMultiplyAddScalar(op1,op2,op3) corresponds to op1 + op2 * op3 // while Math{F}.FusedMultiplyAddScalar(op1,op2,op3) corresponds to op1 * op2 + op3 @@ -4145,6 +4160,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, break; } + case NI_System_Math_MultiplyAddEstimate: case NI_System_Math_ReciprocalEstimate: case NI_System_Math_ReciprocalSqrtEstimate: { @@ -7429,6 +7445,7 @@ bool Compiler::IsTargetIntrinsic(NamedIntrinsic intrinsicName) // instructions to directly compute round/ceiling/floor/truncate. case NI_System_Math_Abs: + case NI_System_Math_MultiplyAddEstimate: case NI_System_Math_ReciprocalEstimate: case NI_System_Math_ReciprocalSqrtEstimate: case NI_System_Math_Sqrt: @@ -7454,6 +7471,7 @@ bool Compiler::IsTargetIntrinsic(NamedIntrinsic intrinsicName) case NI_System_Math_Floor: case NI_System_Math_Max: case NI_System_Math_Min: + case NI_System_Math_MultiplyAddEstimate: case NI_System_Math_ReciprocalEstimate: case NI_System_Math_ReciprocalSqrtEstimate: case NI_System_Math_Round: @@ -7472,6 +7490,7 @@ bool Compiler::IsTargetIntrinsic(NamedIntrinsic intrinsicName) { case NI_System_Math_Abs: case NI_System_Math_Sqrt: + case NI_System_Math_MultiplyAddEstimate: case NI_System_Math_ReciprocalEstimate: case NI_System_Math_ReciprocalSqrtEstimate: return true; @@ -7492,6 +7511,7 @@ bool Compiler::IsTargetIntrinsic(NamedIntrinsic intrinsicName) return false; } + case NI_System_Math_MultiplyAddEstimate: case NI_System_Math_ReciprocalEstimate: return true; @@ -7550,6 +7570,7 @@ bool Compiler::IsMathIntrinsic(NamedIntrinsic intrinsicName) case NI_System_Math_MinMagnitude: case NI_System_Math_MinMagnitudeNumber: case NI_System_Math_MinNumber: + case NI_System_Math_MultiplyAddEstimate: case NI_System_Math_Pow: case NI_System_Math_ReciprocalEstimate: case NI_System_Math_ReciprocalSqrtEstimate: @@ -8786,9 +8807,7 @@ GenTree* Compiler::impEstimateIntrinsic(CORINFO_METHOD_HANDLE method, bool mustExpand) { var_types callType = JITtype2varType(callJitType); - assert(varTypeIsFloating(callType)); - assert(sig->numArgs == 1); if (BlockNonDeterministicIntrinsics(mustExpand)) { @@ -8804,13 +8823,46 @@ GenTree* Compiler::impEstimateIntrinsic(CORINFO_METHOD_HANDLE method, // We use compExactlyDependsOn since these are estimate APIs where // the behavior is explicitly allowed to differ across machines - var_types simdType = TYP_UNKNOWN; - NamedIntrinsic intrinsicId = NI_Illegal; + var_types simdType = TYP_UNKNOWN; + NamedIntrinsic intrinsicId = NI_Illegal; + bool swapOp1AndOp3 = false; switch (intrinsicName) { + case NI_System_Math_MultiplyAddEstimate: + { + assert(sig->numArgs == 3); + +#if defined(TARGET_XARCH) + if (compExactlyDependsOn(InstructionSet_FMA)) + { + simdType = TYP_SIMD16; + intrinsicId = NI_FMA_MultiplyAddScalar; + } +#elif defined(TARGET_ARM64) + if (compExactlyDependsOn(InstructionSet_AdvSimd)) + { + simdType = TYP_SIMD8; + intrinsicId = NI_AdvSimd_FusedMultiplyAddScalar; + + // AdvSimd.FusedMultiplyAdd expects (addend, left, right), while the APIs take (left, right, addend) + + impSpillSideEffect(true, verCurrentState.esStackDepth - + 3 DEBUGARG("Spilling op1 side effects for MultiplyAddEstimate")); + + impSpillSideEffect(true, verCurrentState.esStackDepth - + 2 DEBUGARG("Spilling op2 side effects for MultiplyAddEstimate")); + + swapOp1AndOp3 = true; + } +#endif // TARGET_ARM64 + break; + } + case NI_System_Math_ReciprocalEstimate: { + assert(sig->numArgs == 1); + #if defined(TARGET_XARCH) if (compExactlyDependsOn(InstructionSet_AVX512F)) { @@ -8844,6 +8896,8 @@ GenTree* Compiler::impEstimateIntrinsic(CORINFO_METHOD_HANDLE method, case NI_System_Math_ReciprocalSqrtEstimate: { + assert(sig->numArgs == 1); + #if defined(TARGET_XARCH) if (compExactlyDependsOn(InstructionSet_AVX512F)) { @@ -8875,15 +8929,47 @@ GenTree* Compiler::impEstimateIntrinsic(CORINFO_METHOD_HANDLE method, break; } + default: + { + unreached(); + } + } +#endif // FEATURE_HW_INTRINSICS + + GenTree* op3 = nullptr; + GenTree* op2 = nullptr; + GenTree* op1 = nullptr; + + switch (sig->numArgs) + { + case 3: + { + op3 = impImplicitR4orR8Cast(impPopStack().val, callType); + FALLTHROUGH; + } + + case 2: + { + op2 = impImplicitR4orR8Cast(impPopStack().val, callType); + FALLTHROUGH; + } + + case 1: + { + op1 = impImplicitR4orR8Cast(impPopStack().val, callType); + break; + } + default: { unreached(); } } +#if defined(FEATURE_HW_INTRINSICS) if (intrinsicId != NI_Illegal) { - unsigned simdSize = 0; + unsigned simdSize; if (simdType == TYP_SIMD8) { @@ -8895,29 +8981,62 @@ GenTree* Compiler::impEstimateIntrinsic(CORINFO_METHOD_HANDLE method, simdSize = 16; } - GenTree* op1 = impImplicitR4orR8Cast(impPopStack().val, callType); + switch (sig->numArgs) + { + case 3: + { + if (swapOp1AndOp3) + { + std::swap(op1, op3); + } + + op3 = gtNewSimdCreateScalarUnsafeNode(simdType, op3, callJitType, simdSize); + op2 = gtNewSimdCreateScalarUnsafeNode(simdType, op2, callJitType, simdSize); + op1 = gtNewSimdCreateScalarUnsafeNode(simdType, op1, callJitType, simdSize); - op1 = gtNewSimdCreateScalarUnsafeNode(simdType, op1, callJitType, simdSize); - op1 = gtNewSimdHWIntrinsicNode(simdType, op1, intrinsicId, callJitType, simdSize); + op1 = gtNewSimdHWIntrinsicNode(simdType, op1, op2, op3, intrinsicId, callJitType, simdSize); + break; + } + + case 1: + { + assert(!swapOp1AndOp3); + op1 = gtNewSimdCreateScalarUnsafeNode(simdType, op1, callJitType, simdSize); + op1 = gtNewSimdHWIntrinsicNode(simdType, op1, intrinsicId, callJitType, simdSize); + break; + } + + default: + { + unreached(); + } + } return gtNewSimdToScalarNode(callType, op1, callJitType, simdSize); } + + assert(!swapOp1AndOp3); #endif // FEATURE_HW_INTRINSICS + callType = genActualType(callType); + switch (intrinsicName) { + case NI_System_Math_MultiplyAddEstimate: + { + GenTree* mulNode = gtNewOperNode(GT_MUL, callType, op1, op2); + return gtNewOperNode(GT_ADD, callType, mulNode, op3); + } + case NI_System_Math_ReciprocalEstimate: case NI_System_Math_ReciprocalSqrtEstimate: { - GenTree* op1 = impImplicitR4orR8Cast(impPopStack().val, callType); - if (intrinsicName == NI_System_Math_ReciprocalSqrtEstimate) { assert(!IsIntrinsicImplementedByUserCall(NI_System_Math_Sqrt)); op1 = new (this, GT_INTRINSIC) GenTreeIntrinsic(genActualType(callType), op1, NI_System_Math_Sqrt, nullptr); } - return gtNewOperNode(GT_DIV, genActualType(callType), gtNewDconNode(1.0, callType), op1); } @@ -10523,6 +10642,10 @@ NamedIntrinsic Compiler::lookupPrimitiveFloatNamedIntrinsic(CORINFO_METHOD_HANDL result = NI_System_Math_MinNumber; } } + else if (strcmp(methodName, "MultiplyAddEstimate") == 0) + { + result = NI_System_Math_MultiplyAddEstimate; + } break; } diff --git a/src/coreclr/jit/namedintrinsiclist.h b/src/coreclr/jit/namedintrinsiclist.h index 25c0521461d854..de20de7bfbe5bd 100644 --- a/src/coreclr/jit/namedintrinsiclist.h +++ b/src/coreclr/jit/namedintrinsiclist.h @@ -50,6 +50,7 @@ enum NamedIntrinsic : unsigned short NI_System_Math_MinMagnitude, NI_System_Math_MinMagnitudeNumber, NI_System_Math_MinNumber, + NI_System_Math_MultiplyAddEstimate, NI_System_Math_Pow, NI_System_Math_ReciprocalEstimate, NI_System_Math_ReciprocalSqrtEstimate, diff --git a/src/coreclr/jit/simdashwintrinsic.cpp b/src/coreclr/jit/simdashwintrinsic.cpp index eadb82af79effd..f2df3915088c88 100644 --- a/src/coreclr/jit/simdashwintrinsic.cpp +++ b/src/coreclr/jit/simdashwintrinsic.cpp @@ -544,6 +544,18 @@ GenTree* Compiler::impSimdAsHWIntrinsicSpecial(NamedIntrinsic intrinsic, break; } + case NI_Vector2_MultiplyAddEstimate: + case NI_Vector3_MultiplyAddEstimate: + case NI_Vector4_MultiplyAddEstimate: + case NI_VectorT_MultiplyAddEstimate: + { + if (BlockNonDeterministicIntrinsics(mustExpand)) + { + return nullptr; + } + break; + } + #if defined(TARGET_XARCH) case NI_VectorT_ConvertToDouble: { @@ -839,6 +851,26 @@ GenTree* Compiler::impSimdAsHWIntrinsicSpecial(NamedIntrinsic intrinsic, } #endif // TARGET_XARCH + case NI_Vector2_FusedMultiplyAdd: + case NI_Vector3_FusedMultiplyAdd: + case NI_Vector4_FusedMultiplyAdd: + case NI_VectorT_FusedMultiplyAdd: + { + bool isFmaAccelerated = false; + +#if defined(TARGET_XARCH) + isFmaAccelerated = compOpportunisticallyDependsOn(InstructionSet_FMA); +#elif defined(TARGET_ARM64) + isFmaAccelerated = compOpportunisticallyDependsOn(InstructionSet_AdvSimd); +#endif + + if (!isFmaAccelerated) + { + return nullptr; + } + break; + } + #if defined(TARGET_XARCH) case NI_VectorT_Multiply: case NI_VectorT_op_Multiply: @@ -1796,6 +1828,14 @@ GenTree* Compiler::impSimdAsHWIntrinsicSpecial(NamedIntrinsic intrinsic, return gtNewSimdCndSelNode(retType, op1, op2, op3, simdBaseJitType, simdSize); } + case NI_Vector2_FusedMultiplyAdd: + case NI_Vector3_FusedMultiplyAdd: + case NI_Vector4_FusedMultiplyAdd: + case NI_VectorT_FusedMultiplyAdd: + { + return gtNewSimdFmaNode(retType, op1, op2, op3, simdBaseJitType, simdSize); + } + case NI_Vector2_Lerp: case NI_Vector3_Lerp: case NI_Vector4_Lerp: @@ -1837,6 +1877,28 @@ GenTree* Compiler::impSimdAsHWIntrinsicSpecial(NamedIntrinsic intrinsic, return gtNewSimdBinOpNode(GT_ADD, retType, op1, op2, simdBaseJitType, simdSize); } + case NI_Vector2_MultiplyAddEstimate: + case NI_Vector3_MultiplyAddEstimate: + case NI_Vector4_MultiplyAddEstimate: + case NI_VectorT_MultiplyAddEstimate: + { + bool isFmaAccelerated = false; + +#if defined(TARGET_XARCH) + isFmaAccelerated = compExactlyDependsOn(InstructionSet_FMA); +#elif defined(TARGET_ARM64) + isFmaAccelerated = compExactlyDependsOn(InstructionSet_AdvSimd); +#endif + + if (isFmaAccelerated) + { + return gtNewSimdFmaNode(retType, op1, op2, op3, simdBaseJitType, simdSize); + } + + GenTree* mulNode = gtNewSimdBinOpNode(GT_MUL, retType, op1, op2, simdBaseJitType, simdSize); + return gtNewSimdBinOpNode(GT_ADD, retType, mulNode, op3, simdBaseJitType, simdSize); + } + case NI_VectorT_StoreUnsafeIndex: { assert(retType == TYP_VOID); diff --git a/src/coreclr/jit/simdashwintrinsiclistarm64.h b/src/coreclr/jit/simdashwintrinsiclistarm64.h index 911306e712409c..e6f3cc0d6db46d 100644 --- a/src/coreclr/jit/simdashwintrinsiclistarm64.h +++ b/src/coreclr/jit/simdashwintrinsiclistarm64.h @@ -88,6 +88,7 @@ SIMD_AS_HWINTRINSIC_ID(Vector2, Distance, SIMD_AS_HWINTRINSIC_ID(Vector2, DistanceSquared, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_DistanceSquared, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector2, Divide, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_Divide, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector2, Dot, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_Dot, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector2, FusedMultiplyAdd, 3, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_FusedMultiplyAdd, NI_Illegal}, SimdAsHWIntrinsicFlag::SpillSideEffectsOp1 | SimdAsHWIntrinsicFlag::SpillSideEffectsOp2) SIMD_AS_HWINTRINSIC_ID(Vector2, get_Item, 0, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_get_Item, NI_Illegal}, SimdAsHWIntrinsicFlag::InstanceMethod | SimdAsHWIntrinsicFlag::BaseTypeFromThisArg) SIMD_AS_HWINTRINSIC_ID(Vector2, get_One, 0, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_get_One, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector2, get_UnitX, 0, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_get_UnitX, NI_Illegal}, SimdAsHWIntrinsicFlag::None) @@ -100,6 +101,7 @@ SIMD_AS_HWINTRINSIC_ID(Vector2, Lerp, SIMD_AS_HWINTRINSIC_ID(Vector2, Max, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_Max, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector2, Min, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_Min, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector2, Multiply, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_Multiply, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector2, MultiplyAddEstimate, 3, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_MultiplyAddEstimate, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector2, Negate, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_Negate, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector2, Normalize, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_Normalize, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector2, op_Addition, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_op_Addition, NI_Illegal}, SimdAsHWIntrinsicFlag::None) @@ -128,6 +130,7 @@ SIMD_AS_HWINTRINSIC_ID(Vector3, Distance, SIMD_AS_HWINTRINSIC_ID(Vector3, DistanceSquared, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_DistanceSquared, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector3, Divide, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_Divide, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector3, Dot, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_Dot, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector3, FusedMultiplyAdd, 3, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_FusedMultiplyAdd, NI_Illegal}, SimdAsHWIntrinsicFlag::SpillSideEffectsOp1 | SimdAsHWIntrinsicFlag::SpillSideEffectsOp2) SIMD_AS_HWINTRINSIC_ID(Vector3, get_Item, 0, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_get_Item, NI_Illegal}, SimdAsHWIntrinsicFlag::InstanceMethod | SimdAsHWIntrinsicFlag::BaseTypeFromThisArg) SIMD_AS_HWINTRINSIC_ID(Vector3, get_One, 0, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_get_One, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector3, get_UnitX, 0, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_get_UnitX, NI_Illegal}, SimdAsHWIntrinsicFlag::None) @@ -141,6 +144,7 @@ SIMD_AS_HWINTRINSIC_ID(Vector3, Lerp, SIMD_AS_HWINTRINSIC_ID(Vector3, Max, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_Max, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector3, Min, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_Min, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector3, Multiply, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_Multiply, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector3, MultiplyAddEstimate, 3, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_MultiplyAddEstimate, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector3, Negate, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_Negate, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector3, Normalize, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_Normalize, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector3, op_Addition, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_op_Addition, NI_Illegal}, SimdAsHWIntrinsicFlag::None) @@ -170,6 +174,7 @@ SIMD_AS_HWINTRINSIC_ID(Vector4, Distance, SIMD_AS_HWINTRINSIC_ID(Vector4, DistanceSquared, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_DistanceSquared, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector4, Divide, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_Divide, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector4, Dot, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_Dot, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector4, FusedMultiplyAdd, 3, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_FusedMultiplyAdd, NI_Illegal}, SimdAsHWIntrinsicFlag::SpillSideEffectsOp1 | SimdAsHWIntrinsicFlag::SpillSideEffectsOp2) SIMD_AS_HWINTRINSIC_ID(Vector4, get_Item, 0, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_get_Item, NI_Illegal}, SimdAsHWIntrinsicFlag::InstanceMethod | SimdAsHWIntrinsicFlag::BaseTypeFromThisArg) SIMD_AS_HWINTRINSIC_ID(Vector4, get_One, 0, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_get_One, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector4, get_UnitX, 0, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_get_UnitX, NI_Illegal}, SimdAsHWIntrinsicFlag::None) @@ -184,6 +189,7 @@ SIMD_AS_HWINTRINSIC_ID(Vector4, Lerp, SIMD_AS_HWINTRINSIC_ID(Vector4, Max, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_Max, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector4, Min, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_Min, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector4, Multiply, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_Multiply, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector4, MultiplyAddEstimate, 3, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_MultiplyAddEstimate, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector4, Negate, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_Negate, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector4, Normalize, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_Normalize, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector4, op_Addition, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_op_Addition, NI_Illegal}, SimdAsHWIntrinsicFlag::None) @@ -240,6 +246,7 @@ SIMD_AS_HWINTRINSIC_ID(VectorT, Equals, SIMD_AS_HWINTRINSIC_ID(VectorT, EqualsAll, 2, {NI_VectorT_EqualsAll, NI_VectorT_EqualsAll, NI_VectorT_EqualsAll, NI_VectorT_EqualsAll, NI_VectorT_EqualsAll, NI_VectorT_EqualsAll, NI_VectorT_EqualsAll, NI_VectorT_EqualsAll, NI_VectorT_EqualsAll, NI_VectorT_EqualsAll}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, EqualsAny, 2, {NI_VectorT_EqualsAny, NI_VectorT_EqualsAny, NI_VectorT_EqualsAny, NI_VectorT_EqualsAny, NI_VectorT_EqualsAny, NI_VectorT_EqualsAny, NI_VectorT_EqualsAny, NI_VectorT_EqualsAny, NI_VectorT_EqualsAny, NI_VectorT_EqualsAny}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, Floor, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_Floor, NI_VectorT_Floor}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, FusedMultiplyAdd, 3, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_FusedMultiplyAdd, NI_VectorT_FusedMultiplyAdd}, SimdAsHWIntrinsicFlag::SpillSideEffectsOp1 | SimdAsHWIntrinsicFlag::SpillSideEffectsOp2) SIMD_AS_HWINTRINSIC_ID(VectorT, get_AllBitsSet, 0, {NI_VectorT_get_AllBitsSet, NI_VectorT_get_AllBitsSet, NI_VectorT_get_AllBitsSet, NI_VectorT_get_AllBitsSet, NI_VectorT_get_AllBitsSet, NI_VectorT_get_AllBitsSet, NI_VectorT_get_AllBitsSet, NI_VectorT_get_AllBitsSet, NI_VectorT_get_AllBitsSet, NI_VectorT_get_AllBitsSet}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, get_Indices, 0, {NI_VectorT_get_Indices, NI_VectorT_get_Indices, NI_VectorT_get_Indices, NI_VectorT_get_Indices, NI_VectorT_get_Indices, NI_VectorT_get_Indices, NI_VectorT_get_Indices, NI_VectorT_get_Indices, NI_VectorT_get_Indices, NI_VectorT_get_Indices}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, get_Item, 2, {NI_VectorT_get_Item, NI_VectorT_get_Item, NI_VectorT_get_Item, NI_VectorT_get_Item, NI_VectorT_get_Item, NI_VectorT_get_Item, NI_VectorT_get_Item, NI_VectorT_get_Item, NI_VectorT_get_Item, NI_VectorT_get_Item}, SimdAsHWIntrinsicFlag::InstanceMethod | SimdAsHWIntrinsicFlag::BaseTypeFromThisArg) @@ -266,6 +273,7 @@ SIMD_AS_HWINTRINSIC_NM(VectorT, LoadUnsafeIndex, "LoadUnsafe", SIMD_AS_HWINTRINSIC_ID(VectorT, Max, 2, {NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, Min, 2, {NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, Multiply, 2, {NI_VectorT_Multiply, NI_VectorT_Multiply, NI_VectorT_Multiply, NI_VectorT_Multiply, NI_VectorT_Multiply, NI_VectorT_Multiply, NI_Illegal, NI_Illegal, NI_VectorT_Multiply, NI_VectorT_Multiply}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, MultiplyAddEstimate, 3, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_MultiplyAddEstimate, NI_VectorT_MultiplyAddEstimate}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, Narrow, 2, {NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow}, SimdAsHWIntrinsicFlag::KeepBaseTypeFromRet) SIMD_AS_HWINTRINSIC_ID(VectorT, Negate, 1, {NI_VectorT_Negate, NI_VectorT_Negate, NI_VectorT_Negate, NI_VectorT_Negate, NI_VectorT_Negate, NI_VectorT_Negate, NI_VectorT_Negate, NI_VectorT_Negate, NI_VectorT_Negate, NI_VectorT_Negate}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, OnesComplement, 2, {NI_VectorT_OnesComplement, NI_VectorT_OnesComplement, NI_VectorT_OnesComplement, NI_VectorT_OnesComplement, NI_VectorT_OnesComplement, NI_VectorT_OnesComplement, NI_VectorT_OnesComplement, NI_VectorT_OnesComplement, NI_VectorT_OnesComplement, NI_VectorT_OnesComplement}, SimdAsHWIntrinsicFlag::None) diff --git a/src/coreclr/jit/simdashwintrinsiclistxarch.h b/src/coreclr/jit/simdashwintrinsiclistxarch.h index dd1d6374bc248f..c0890478b80661 100644 --- a/src/coreclr/jit/simdashwintrinsiclistxarch.h +++ b/src/coreclr/jit/simdashwintrinsiclistxarch.h @@ -88,6 +88,7 @@ SIMD_AS_HWINTRINSIC_ID(Vector2, Distance, SIMD_AS_HWINTRINSIC_ID(Vector2, DistanceSquared, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_DistanceSquared, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector2, Divide, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_Divide, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector2, Dot, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_Dot, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector2, FusedMultiplyAdd, 3, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_FusedMultiplyAdd, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector2, get_Item, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_get_Item, NI_Illegal}, SimdAsHWIntrinsicFlag::InstanceMethod | SimdAsHWIntrinsicFlag::BaseTypeFromThisArg) SIMD_AS_HWINTRINSIC_ID(Vector2, get_One, 0, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_get_One, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector2, get_UnitX, 0, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_get_UnitX, NI_Illegal}, SimdAsHWIntrinsicFlag::None) @@ -100,6 +101,7 @@ SIMD_AS_HWINTRINSIC_ID(Vector2, Lerp, SIMD_AS_HWINTRINSIC_ID(Vector2, Max, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_Max, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector2, Min, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_Min, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector2, Multiply, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_Multiply, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector2, MultiplyAddEstimate, 3, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_MultiplyAddEstimate, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector2, Negate, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_Negate, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector2, Normalize, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_Normalize, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector2, op_Addition, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_op_Addition, NI_Illegal}, SimdAsHWIntrinsicFlag::None) @@ -128,6 +130,7 @@ SIMD_AS_HWINTRINSIC_ID(Vector3, Distance, SIMD_AS_HWINTRINSIC_ID(Vector3, DistanceSquared, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_DistanceSquared, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector3, Divide, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_Divide, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector3, Dot, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_Dot, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector3, FusedMultiplyAdd, 3, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_FusedMultiplyAdd, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector3, get_Item, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_get_Item, NI_Illegal}, SimdAsHWIntrinsicFlag::InstanceMethod | SimdAsHWIntrinsicFlag::BaseTypeFromThisArg) SIMD_AS_HWINTRINSIC_ID(Vector3, get_One, 0, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_get_One, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector3, get_UnitX, 0, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_get_UnitX, NI_Illegal}, SimdAsHWIntrinsicFlag::None) @@ -141,6 +144,7 @@ SIMD_AS_HWINTRINSIC_ID(Vector3, Lerp, SIMD_AS_HWINTRINSIC_ID(Vector3, Max, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_Max, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector3, Min, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_Min, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector3, Multiply, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_Multiply, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector3, MultiplyAddEstimate, 3, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_MultiplyAddEstimate, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector3, Negate, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_Negate, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector3, Normalize, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_Normalize, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector3, op_Addition, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_op_Addition, NI_Illegal}, SimdAsHWIntrinsicFlag::None) @@ -170,6 +174,7 @@ SIMD_AS_HWINTRINSIC_ID(Vector4, Distance, SIMD_AS_HWINTRINSIC_ID(Vector4, DistanceSquared, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_DistanceSquared, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector4, Divide, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_Divide, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector4, Dot, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_Dot, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector4, FusedMultiplyAdd, 3, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_FusedMultiplyAdd, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector4, get_Item, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_get_Item, NI_Illegal}, SimdAsHWIntrinsicFlag::InstanceMethod | SimdAsHWIntrinsicFlag::BaseTypeFromThisArg) SIMD_AS_HWINTRINSIC_ID(Vector4, get_One, 0, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_get_One, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector4, get_UnitX, 0, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_get_UnitX, NI_Illegal}, SimdAsHWIntrinsicFlag::None) @@ -184,6 +189,7 @@ SIMD_AS_HWINTRINSIC_ID(Vector4, Lerp, SIMD_AS_HWINTRINSIC_ID(Vector4, Max, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_Max, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector4, Min, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_Min, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector4, Multiply, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_Multiply, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector4, MultiplyAddEstimate, 3, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_MultiplyAddEstimate, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector4, Negate, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_Negate, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector4, Normalize, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_Normalize, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(Vector4, op_Addition, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_op_Addition, NI_Illegal}, SimdAsHWIntrinsicFlag::None) @@ -240,6 +246,7 @@ SIMD_AS_HWINTRINSIC_ID(VectorT, Equals, SIMD_AS_HWINTRINSIC_ID(VectorT, EqualsAll, 2, {NI_VectorT_EqualsAll, NI_VectorT_EqualsAll, NI_VectorT_EqualsAll, NI_VectorT_EqualsAll, NI_VectorT_EqualsAll, NI_VectorT_EqualsAll, NI_VectorT_EqualsAll, NI_VectorT_EqualsAll, NI_VectorT_EqualsAll, NI_VectorT_EqualsAll}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, EqualsAny, 2, {NI_VectorT_EqualsAny, NI_VectorT_EqualsAny, NI_VectorT_EqualsAny, NI_VectorT_EqualsAny, NI_VectorT_EqualsAny, NI_VectorT_EqualsAny, NI_VectorT_EqualsAny, NI_VectorT_EqualsAny, NI_VectorT_EqualsAny, NI_VectorT_EqualsAny}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, Floor, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_Floor, NI_VectorT_Floor}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, FusedMultiplyAdd, 3, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_FusedMultiplyAdd, NI_VectorT_FusedMultiplyAdd}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, get_AllBitsSet, 0, {NI_VectorT_get_AllBitsSet, NI_VectorT_get_AllBitsSet, NI_VectorT_get_AllBitsSet, NI_VectorT_get_AllBitsSet, NI_VectorT_get_AllBitsSet, NI_VectorT_get_AllBitsSet, NI_VectorT_get_AllBitsSet, NI_VectorT_get_AllBitsSet, NI_VectorT_get_AllBitsSet, NI_VectorT_get_AllBitsSet}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, get_Indices, 0, {NI_VectorT_get_Indices, NI_VectorT_get_Indices, NI_VectorT_get_Indices, NI_VectorT_get_Indices, NI_VectorT_get_Indices, NI_VectorT_get_Indices, NI_VectorT_get_Indices, NI_VectorT_get_Indices, NI_VectorT_get_Indices, NI_VectorT_get_Indices}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, get_Item, 2, {NI_VectorT_get_Item, NI_VectorT_get_Item, NI_VectorT_get_Item, NI_VectorT_get_Item, NI_VectorT_get_Item, NI_VectorT_get_Item, NI_VectorT_get_Item, NI_VectorT_get_Item, NI_VectorT_get_Item, NI_VectorT_get_Item}, SimdAsHWIntrinsicFlag::InstanceMethod | SimdAsHWIntrinsicFlag::BaseTypeFromThisArg) @@ -266,6 +273,7 @@ SIMD_AS_HWINTRINSIC_NM(VectorT, LoadUnsafeIndex, "LoadUnsafe", SIMD_AS_HWINTRINSIC_ID(VectorT, Max, 2, {NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, Min, 2, {NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, Multiply, 2, {NI_Illegal, NI_Illegal, NI_VectorT_Multiply, NI_VectorT_Multiply, NI_VectorT_Multiply, NI_VectorT_Multiply, NI_VectorT_Multiply, NI_VectorT_Multiply, NI_VectorT_Multiply, NI_VectorT_Multiply}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, MultiplyAddEstimate, 3, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_MultiplyAddEstimate, NI_VectorT_MultiplyAddEstimate}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, Narrow, 2, {NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow}, SimdAsHWIntrinsicFlag::KeepBaseTypeFromRet) SIMD_AS_HWINTRINSIC_ID(VectorT, Negate, 1, {NI_VectorT_Negate, NI_VectorT_Negate, NI_VectorT_Negate, NI_VectorT_Negate, NI_VectorT_Negate, NI_VectorT_Negate, NI_VectorT_Negate, NI_VectorT_Negate, NI_VectorT_Negate, NI_VectorT_Negate}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, OnesComplement, 1, {NI_VectorT_OnesComplement, NI_VectorT_OnesComplement, NI_VectorT_OnesComplement, NI_VectorT_OnesComplement, NI_VectorT_OnesComplement, NI_VectorT_OnesComplement, NI_VectorT_OnesComplement, NI_VectorT_OnesComplement, NI_VectorT_OnesComplement, NI_VectorT_OnesComplement}, SimdAsHWIntrinsicFlag::None) diff --git a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/VectorTestMemberData.cs b/src/libraries/Common/tests/System/Runtime/Intrinsics/VectorTestMemberData.cs similarity index 69% rename from src/libraries/System.Runtime.Intrinsics/tests/Vectors/VectorTestMemberData.cs rename to src/libraries/Common/tests/System/Runtime/Intrinsics/VectorTestMemberData.cs index 1579fa54e6af92..ab2381a97967e6 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/VectorTestMemberData.cs +++ b/src/libraries/Common/tests/System/Runtime/Intrinsics/VectorTestMemberData.cs @@ -292,5 +292,151 @@ public static IEnumerable Log2Single yield return new object[] { float.PositiveInfinity, float.PositiveInfinity, 0.0f }; } } + + public static IEnumerable MultiplyAddDouble + { + get + { + yield return new object[] { double.NegativeInfinity, double.NegativeInfinity, double.NegativeInfinity }; + yield return new object[] { double.NegativeInfinity, -0.0, double.NegativeInfinity }; + yield return new object[] { double.NegativeInfinity, -0.0, -3.1415926535897932 }; + yield return new object[] { double.NegativeInfinity, -0.0, -0.0 }; + yield return new object[] { double.NegativeInfinity, -0.0, double.NaN }; + yield return new object[] { double.NegativeInfinity, -0.0, 0.0 }; + yield return new object[] { double.NegativeInfinity, -0.0, 3.1415926535897932 }; + yield return new object[] { double.NegativeInfinity, -0.0, double.PositiveInfinity }; + yield return new object[] { double.NegativeInfinity, 0.0, double.NegativeInfinity }; + yield return new object[] { double.NegativeInfinity, 0.0, -3.1415926535897932 }; + yield return new object[] { double.NegativeInfinity, 0.0, -0.0 }; + yield return new object[] { double.NegativeInfinity, 0.0, double.NaN }; + yield return new object[] { double.NegativeInfinity, 0.0, 0.0 }; + yield return new object[] { double.NegativeInfinity, 0.0, 3.1415926535897932 }; + yield return new object[] { double.NegativeInfinity, 0.0, double.PositiveInfinity }; + yield return new object[] { double.NegativeInfinity, double.PositiveInfinity, double.PositiveInfinity }; + yield return new object[] {-1e308, 2.0, 1e308 }; + yield return new object[] {-1e308, 2.0, double.PositiveInfinity }; + yield return new object[] {-5, 4, -3 }; + yield return new object[] {-0.0, double.NegativeInfinity, double.NegativeInfinity }; + yield return new object[] {-0.0, double.NegativeInfinity, -3.1415926535897932 }; + yield return new object[] {-0.0, double.NegativeInfinity, -0.0 }; + yield return new object[] {-0.0, double.NegativeInfinity, double.NaN }; + yield return new object[] {-0.0, double.NegativeInfinity, 0.0 }; + yield return new object[] {-0.0, double.NegativeInfinity, 3.1415926535897932 }; + yield return new object[] {-0.0, double.NegativeInfinity, double.PositiveInfinity }; + yield return new object[] {-0.0, double.PositiveInfinity, double.NegativeInfinity }; + yield return new object[] {-0.0, double.PositiveInfinity, -3.1415926535897932 }; + yield return new object[] {-0.0, double.PositiveInfinity, -0.0 }; + yield return new object[] {-0.0, double.PositiveInfinity, double.NaN }; + yield return new object[] {-0.0, double.PositiveInfinity, 0.0 }; + yield return new object[] {-0.0, double.PositiveInfinity, 3.1415926535897932 }; + yield return new object[] {-0.0, double.PositiveInfinity, double.PositiveInfinity }; + yield return new object[] { 0.0, double.NegativeInfinity, double.NegativeInfinity }; + yield return new object[] { 0.0, double.NegativeInfinity, -3.1415926535897932 }; + yield return new object[] { 0.0, double.NegativeInfinity, -0.0 }; + yield return new object[] { 0.0, double.NegativeInfinity, double.NaN }; + yield return new object[] { 0.0, double.NegativeInfinity, 0.0 }; + yield return new object[] { 0.0, double.NegativeInfinity, 3.1415926535897932 }; + yield return new object[] { 0.0, double.NegativeInfinity, double.PositiveInfinity }; + yield return new object[] { 0.0, double.PositiveInfinity, double.NegativeInfinity }; + yield return new object[] { 0.0, double.PositiveInfinity, -3.1415926535897932 }; + yield return new object[] { 0.0, double.PositiveInfinity, -0.0 }; + yield return new object[] { 0.0, double.PositiveInfinity, double.NaN }; + yield return new object[] { 0.0, double.PositiveInfinity, 0.0 }; + yield return new object[] { 0.0, double.PositiveInfinity, 3.1415926535897932 }; + yield return new object[] { 0.0, double.PositiveInfinity, double.PositiveInfinity }; + yield return new object[] { 5, 4, 3 }; + yield return new object[] { 1e308, 2.0, -1e308 }; + yield return new object[] { 1e308, 2.0, double.NegativeInfinity }; + yield return new object[] { double.PositiveInfinity, double.NegativeInfinity, double.PositiveInfinity }; + yield return new object[] { double.PositiveInfinity, -0.0, double.NegativeInfinity }; + yield return new object[] { double.PositiveInfinity, -0.0, -3.1415926535897932 }; + yield return new object[] { double.PositiveInfinity, -0.0, -0.0 }; + yield return new object[] { double.PositiveInfinity, -0.0, double.NaN }; + yield return new object[] { double.PositiveInfinity, -0.0, 0.0 }; + yield return new object[] { double.PositiveInfinity, -0.0, 3.1415926535897932 }; + yield return new object[] { double.PositiveInfinity, -0.0, double.PositiveInfinity }; + yield return new object[] { double.PositiveInfinity, 0.0, double.NegativeInfinity }; + yield return new object[] { double.PositiveInfinity, 0.0, -3.1415926535897932 }; + yield return new object[] { double.PositiveInfinity, 0.0, -0.0 }; + yield return new object[] { double.PositiveInfinity, 0.0, double.NaN }; + yield return new object[] { double.PositiveInfinity, 0.0, 0.0 }; + yield return new object[] { double.PositiveInfinity, 0.0, 3.1415926535897932 }; + yield return new object[] { double.PositiveInfinity, 0.0, double.PositiveInfinity }; + yield return new object[] { double.PositiveInfinity, double.PositiveInfinity, double.NegativeInfinity }; + } + } + + public static IEnumerable MultiplyAddSingle + { + get + { + yield return new object[] { float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity }; + yield return new object[] { float.NegativeInfinity, -0.0f, float.NegativeInfinity }; + yield return new object[] { float.NegativeInfinity, -0.0f, -3.14159265f }; + yield return new object[] { float.NegativeInfinity, -0.0f, -0.0f }; + yield return new object[] { float.NegativeInfinity, -0.0f, float.NaN }; + yield return new object[] { float.NegativeInfinity, -0.0f, 0.0f }; + yield return new object[] { float.NegativeInfinity, -0.0f, 3.14159265f }; + yield return new object[] { float.NegativeInfinity, -0.0f, float.PositiveInfinity }; + yield return new object[] { float.NegativeInfinity, 0.0f, float.NegativeInfinity }; + yield return new object[] { float.NegativeInfinity, 0.0f, -3.14159265f }; + yield return new object[] { float.NegativeInfinity, 0.0f, -0.0f }; + yield return new object[] { float.NegativeInfinity, 0.0f, float.NaN }; + yield return new object[] { float.NegativeInfinity, 0.0f, 0.0f }; + yield return new object[] { float.NegativeInfinity, 0.0f, 3.14159265f }; + yield return new object[] { float.NegativeInfinity, 0.0f, float.PositiveInfinity }; + yield return new object[] { float.NegativeInfinity, float.PositiveInfinity, float.PositiveInfinity }; + yield return new object[] { -1e38f, 2.0f, 1e38f }; + yield return new object[] { -1e38f, 2.0f, float.PositiveInfinity }; + yield return new object[] { -5, 4, -3 }; + yield return new object[] { -0.0f, float.NegativeInfinity, float.NegativeInfinity }; + yield return new object[] { -0.0f, float.NegativeInfinity, -3.14159265f }; + yield return new object[] { -0.0f, float.NegativeInfinity, -0.0f }; + yield return new object[] { -0.0f, float.NegativeInfinity, float.NaN }; + yield return new object[] { -0.0f, float.NegativeInfinity, 0.0f }; + yield return new object[] { -0.0f, float.NegativeInfinity, 3.14159265f }; + yield return new object[] { -0.0f, float.NegativeInfinity, float.PositiveInfinity }; + yield return new object[] { -0.0f, float.PositiveInfinity, float.NegativeInfinity }; + yield return new object[] { -0.0f, float.PositiveInfinity, -3.14159265f }; + yield return new object[] { -0.0f, float.PositiveInfinity, -0.0f }; + yield return new object[] { -0.0f, float.PositiveInfinity, float.NaN }; + yield return new object[] { -0.0f, float.PositiveInfinity, 0.0f }; + yield return new object[] { -0.0f, float.PositiveInfinity, 3.14159265f }; + yield return new object[] { -0.0f, float.PositiveInfinity, float.PositiveInfinity }; + yield return new object[] { 0.0f, float.NegativeInfinity, float.NegativeInfinity }; + yield return new object[] { 0.0f, float.NegativeInfinity, -3.14159265f }; + yield return new object[] { 0.0f, float.NegativeInfinity, -0.0f }; + yield return new object[] { 0.0f, float.NegativeInfinity, float.NaN }; + yield return new object[] { 0.0f, float.NegativeInfinity, 0.0f }; + yield return new object[] { 0.0f, float.NegativeInfinity, 3.14159265f }; + yield return new object[] { 0.0f, float.NegativeInfinity, float.PositiveInfinity }; + yield return new object[] { 0.0f, float.PositiveInfinity, float.NegativeInfinity }; + yield return new object[] { 0.0f, float.PositiveInfinity, -3.14159265f }; + yield return new object[] { 0.0f, float.PositiveInfinity, -0.0f }; + yield return new object[] { 0.0f, float.PositiveInfinity, float.NaN }; + yield return new object[] { 0.0f, float.PositiveInfinity, 0.0f }; + yield return new object[] { 0.0f, float.PositiveInfinity, 3.14159265f }; + yield return new object[] { 0.0f, float.PositiveInfinity, float.PositiveInfinity }; + yield return new object[] { 5, 4, 3 }; + yield return new object[] { 1e38f, 2.0f, -1e38f }; + yield return new object[] { 1e38f, 2.0f, float.NegativeInfinity }; + yield return new object[] { float.PositiveInfinity, float.NegativeInfinity, float.PositiveInfinity }; + yield return new object[] { float.PositiveInfinity, -0.0f, float.NegativeInfinity }; + yield return new object[] { float.PositiveInfinity, -0.0f, -3.14159265f }; + yield return new object[] { float.PositiveInfinity, -0.0f, -0.0f }; + yield return new object[] { float.PositiveInfinity, -0.0f, float.NaN }; + yield return new object[] { float.PositiveInfinity, -0.0f, 0.0f }; + yield return new object[] { float.PositiveInfinity, -0.0f, 3.14159265f }; + yield return new object[] { float.PositiveInfinity, -0.0f, float.PositiveInfinity }; + yield return new object[] { float.PositiveInfinity, 0.0f, float.NegativeInfinity }; + yield return new object[] { float.PositiveInfinity, 0.0f, -3.14159265f }; + yield return new object[] { float.PositiveInfinity, 0.0f, -0.0f }; + yield return new object[] { float.PositiveInfinity, 0.0f, float.NaN }; + yield return new object[] { float.PositiveInfinity, 0.0f, 0.0f }; + yield return new object[] { float.PositiveInfinity, 0.0f, 3.14159265f }; + yield return new object[] { float.PositiveInfinity, 0.0f, float.PositiveInfinity }; + yield return new object[] { float.PositiveInfinity, float.PositiveInfinity, float.NegativeInfinity }; + } + } } } diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.FusedMultiplyAdd.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.FusedMultiplyAdd.cs index bf7b999378f8c8..42f36ec494a968 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.FusedMultiplyAdd.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.FusedMultiplyAdd.cs @@ -100,6 +100,17 @@ public static void FusedMultiplyAdd(ReadOnlySpan x, T y, ReadOnlySpan a public static Vector128 Invoke(Vector128 x, Vector128 y, Vector128 z) { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector128.FusedMultiplyAdd(x.AsDouble(), y.AsDouble(), z.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector128.FusedMultiplyAdd(x.AsSingle(), y.AsSingle(), z.AsSingle()).As(); + } +#else if (Fma.IsSupported) { if (typeof(T) == typeof(float)) return Fma.MultiplyAdd(x.AsSingle(), y.AsSingle(), z.AsSingle()).As(); @@ -137,10 +148,22 @@ public static Vector128 Invoke(Vector128 x, Vector128 y, Vector128 z double.FusedMultiplyAdd(xDoubles[0], yDoubles[0], zDoubles[0]), double.FusedMultiplyAdd(xDoubles[1], yDoubles[1], zDoubles[1])).As(); } +#endif } public static Vector256 Invoke(Vector256 x, Vector256 y, Vector256 z) { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector256.FusedMultiplyAdd(x.AsDouble(), y.AsDouble(), z.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector256.FusedMultiplyAdd(x.AsSingle(), y.AsSingle(), z.AsSingle()).As(); + } +#else if (Fma.IsSupported) { if (typeof(T) == typeof(float)) return Fma.MultiplyAdd(x.AsSingle(), y.AsSingle(), z.AsSingle()).As(); @@ -150,10 +173,22 @@ public static Vector256 Invoke(Vector256 x, Vector256 y, Vector256 z return Vector256.Create( Invoke(x.GetLower(), y.GetLower(), z.GetLower()), Invoke(x.GetUpper(), y.GetUpper(), z.GetUpper())); +#endif } public static Vector512 Invoke(Vector512 x, Vector512 y, Vector512 z) { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector512.FusedMultiplyAdd(x.AsDouble(), y.AsDouble(), z.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector512.FusedMultiplyAdd(x.AsSingle(), y.AsSingle(), z.AsSingle()).As(); + } +#else if (Avx512F.IsSupported) { if (typeof(T) == typeof(float)) return Avx512F.FusedMultiplyAdd(x.AsSingle(), y.AsSingle(), z.AsSingle()).As(); @@ -163,6 +198,7 @@ public static Vector512 Invoke(Vector512 x, Vector512 y, Vector512 z return Vector512.Create( Invoke(x.GetLower(), y.GetLower(), z.GetLower()), Invoke(x.GetUpper(), y.GetUpper(), z.GetUpper())); +#endif } } } diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MultiplyAddEstimate.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MultiplyAddEstimate.cs index d3edb01ca7bc56..d3e651c160e881 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MultiplyAddEstimate.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MultiplyAddEstimate.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.Arm; @@ -88,40 +89,51 @@ public static void MultiplyAddEstimate(ReadOnlySpan x, T y, ReadOnlySpan>(x, y, addend, destination); /// (x * y) + z - private readonly struct MultiplyAddEstimateOperator : ITernaryOperator where T : INumberBase + private readonly struct MultiplyAddEstimateOperator : ITernaryOperator + where T : INumberBase { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T Invoke(T x, T y, T z) { - // TODO https://github.com/dotnet/runtime/issues/98053: Use T.MultiplyAddEstimate when it's available. - +#if NET9_0_OR_GREATER + return T.MultiplyAddEstimate(x, y, z); +#else if (Fma.IsSupported || AdvSimd.IsSupported) { if (typeof(T) == typeof(Half)) { - Half result = Half.FusedMultiplyAdd(Unsafe.As(ref x), Unsafe.As(ref y), Unsafe.As(ref z)); - return Unsafe.As(ref result); + return (T)(object)Half.FusedMultiplyAdd((Half)(object)x, (Half)(object)y, (Half)(object)z); } if (typeof(T) == typeof(float)) { - float result = float.FusedMultiplyAdd(Unsafe.As(ref x), Unsafe.As(ref y), Unsafe.As(ref z)); - return Unsafe.As(ref result); + return (T)(object)float.FusedMultiplyAdd((float)(object)x, (float)(object)y, (float)(object)z); } if (typeof(T) == typeof(double)) { - double result = double.FusedMultiplyAdd(Unsafe.As(ref x), Unsafe.As(ref y), Unsafe.As(ref z)); - return Unsafe.As(ref result); + return (T)(object)double.FusedMultiplyAdd((double)(object)x, (double)(object)y, (double)(object)z); } } return (x * y) + z; +#endif } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Invoke(Vector128 x, Vector128 y, Vector128 z) { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector128.MultiplyAddEstimate(x.AsDouble(), y.AsDouble(), z.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector128.MultiplyAddEstimate(x.AsSingle(), y.AsSingle(), z.AsSingle()).As(); + } +#else if (Fma.IsSupported) { if (typeof(T) == typeof(float)) return Fma.MultiplyAdd(x.AsSingle(), y.AsSingle(), z.AsSingle()).As(); @@ -139,11 +151,23 @@ public static Vector128 Invoke(Vector128 x, Vector128 y, Vector128 z } return (x * y) + z; +#endif } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 Invoke(Vector256 x, Vector256 y, Vector256 z) { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector256.MultiplyAddEstimate(x.AsDouble(), y.AsDouble(), z.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector256.MultiplyAddEstimate(x.AsSingle(), y.AsSingle(), z.AsSingle()).As(); + } +#else if (Fma.IsSupported) { if (typeof(T) == typeof(float)) return Fma.MultiplyAdd(x.AsSingle(), y.AsSingle(), z.AsSingle()).As(); @@ -151,11 +175,23 @@ public static Vector256 Invoke(Vector256 x, Vector256 y, Vector256 z } return (x * y) + z; +#endif } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector512 Invoke(Vector512 x, Vector512 y, Vector512 z) { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector512.MultiplyAddEstimate(x.AsDouble(), y.AsDouble(), z.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector512.MultiplyAddEstimate(x.AsSingle(), y.AsSingle(), z.AsSingle()).As(); + } +#else if (Avx512F.IsSupported) { if (typeof(T) == typeof(float)) return Avx512F.FusedMultiplyAdd(x.AsSingle(), y.AsSingle(), z.AsSingle()).As(); @@ -163,6 +199,7 @@ public static Vector512 Invoke(Vector512 x, Vector512 y, Vector512 z } return (x * y) + z; +#endif } } } diff --git a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs index 531a379cf06e99..98b2db5e133652 100644 --- a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs +++ b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs @@ -262,6 +262,8 @@ public static partial class Vector public static System.Numerics.Vector Equals(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector Floor(System.Numerics.Vector value) { throw null; } public static System.Numerics.Vector Floor(System.Numerics.Vector value) { throw null; } + public static System.Numerics.Vector FusedMultiplyAdd(System.Numerics.Vector left, System.Numerics.Vector right, System.Numerics.Vector addend) { throw null; } + public static System.Numerics.Vector FusedMultiplyAdd(System.Numerics.Vector left, System.Numerics.Vector right, System.Numerics.Vector addend) { throw null; } public static T GetElement(this System.Numerics.Vector vector, int index) { throw null; } public static System.Numerics.Vector GreaterThan(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector GreaterThan(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } @@ -307,6 +309,8 @@ public static partial class Vector public static System.Numerics.Vector Multiply(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector Multiply(System.Numerics.Vector left, T right) { throw null; } public static System.Numerics.Vector Multiply(T left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector MultiplyAddEstimate(System.Numerics.Vector left, System.Numerics.Vector right, System.Numerics.Vector addend) { throw null; } + public static System.Numerics.Vector MultiplyAddEstimate(System.Numerics.Vector left, System.Numerics.Vector right, System.Numerics.Vector addend) { throw null; } public static System.Numerics.Vector Narrow(System.Numerics.Vector low, System.Numerics.Vector high) { throw null; } [System.CLSCompliantAttribute(false)] public static System.Numerics.Vector Narrow(System.Numerics.Vector low, System.Numerics.Vector high) { throw null; } @@ -433,6 +437,7 @@ public readonly void CopyTo(System.Span destination) { } public static float Dot(System.Numerics.Vector2 value1, System.Numerics.Vector2 value2) { throw null; } public readonly bool Equals(System.Numerics.Vector2 other) { throw null; } public override readonly bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; } + public static System.Numerics.Vector2 FusedMultiplyAdd(System.Numerics.Vector2 left, System.Numerics.Vector2 right, System.Numerics.Vector2 addend) { throw null; } public override readonly int GetHashCode() { throw null; } public readonly float Length() { throw null; } public readonly float LengthSquared() { throw null; } @@ -442,6 +447,7 @@ public readonly void CopyTo(System.Span destination) { } public static System.Numerics.Vector2 Multiply(System.Numerics.Vector2 left, System.Numerics.Vector2 right) { throw null; } public static System.Numerics.Vector2 Multiply(System.Numerics.Vector2 left, float right) { throw null; } public static System.Numerics.Vector2 Multiply(float left, System.Numerics.Vector2 right) { throw null; } + public static System.Numerics.Vector2 MultiplyAddEstimate(System.Numerics.Vector2 left, System.Numerics.Vector2 right, System.Numerics.Vector2 addend) { throw null; } public static System.Numerics.Vector2 Negate(System.Numerics.Vector2 value) { throw null; } public static System.Numerics.Vector2 Normalize(System.Numerics.Vector2 value) { throw null; } public static System.Numerics.Vector2 operator +(System.Numerics.Vector2 left, System.Numerics.Vector2 right) { throw null; } @@ -496,6 +502,7 @@ public readonly void CopyTo(System.Span destination) { } public static float Dot(System.Numerics.Vector3 vector1, System.Numerics.Vector3 vector2) { throw null; } public readonly bool Equals(System.Numerics.Vector3 other) { throw null; } public override readonly bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; } + public static System.Numerics.Vector3 FusedMultiplyAdd(System.Numerics.Vector3 left, System.Numerics.Vector3 right, System.Numerics.Vector3 addend) { throw null; } public override readonly int GetHashCode() { throw null; } public readonly float Length() { throw null; } public readonly float LengthSquared() { throw null; } @@ -505,6 +512,7 @@ public readonly void CopyTo(System.Span destination) { } public static System.Numerics.Vector3 Multiply(System.Numerics.Vector3 left, System.Numerics.Vector3 right) { throw null; } public static System.Numerics.Vector3 Multiply(System.Numerics.Vector3 left, float right) { throw null; } public static System.Numerics.Vector3 Multiply(float left, System.Numerics.Vector3 right) { throw null; } + public static System.Numerics.Vector3 MultiplyAddEstimate(System.Numerics.Vector3 left, System.Numerics.Vector3 right, System.Numerics.Vector3 addend) { throw null; } public static System.Numerics.Vector3 Negate(System.Numerics.Vector3 value) { throw null; } public static System.Numerics.Vector3 Normalize(System.Numerics.Vector3 value) { throw null; } public static System.Numerics.Vector3 operator +(System.Numerics.Vector3 left, System.Numerics.Vector3 right) { throw null; } @@ -559,6 +567,7 @@ public readonly void CopyTo(System.Span destination) { } public static float Dot(System.Numerics.Vector4 vector1, System.Numerics.Vector4 vector2) { throw null; } public readonly bool Equals(System.Numerics.Vector4 other) { throw null; } public override readonly bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; } + public static System.Numerics.Vector4 FusedMultiplyAdd(System.Numerics.Vector4 left, System.Numerics.Vector4 right, System.Numerics.Vector4 addend) { throw null; } public override readonly int GetHashCode() { throw null; } public readonly float Length() { throw null; } public readonly float LengthSquared() { throw null; } @@ -568,6 +577,7 @@ public readonly void CopyTo(System.Span destination) { } public static System.Numerics.Vector4 Multiply(System.Numerics.Vector4 left, System.Numerics.Vector4 right) { throw null; } public static System.Numerics.Vector4 Multiply(System.Numerics.Vector4 left, float right) { throw null; } public static System.Numerics.Vector4 Multiply(float left, System.Numerics.Vector4 right) { throw null; } + public static System.Numerics.Vector4 MultiplyAddEstimate(System.Numerics.Vector4 left, System.Numerics.Vector4 right, System.Numerics.Vector4 addend) { throw null; } public static System.Numerics.Vector4 Negate(System.Numerics.Vector4 value) { throw null; } public static System.Numerics.Vector4 Normalize(System.Numerics.Vector4 vector) { throw null; } public static System.Numerics.Vector4 operator +(System.Numerics.Vector4 left, System.Numerics.Vector4 right) { throw null; } diff --git a/src/libraries/System.Numerics.Vectors/tests/GenericVectorTests.cs b/src/libraries/System.Numerics.Vectors/tests/GenericVectorTests.cs index 97a65f0a84173e..02c7d3fa8a878a 100644 --- a/src/libraries/System.Numerics.Vectors/tests/GenericVectorTests.cs +++ b/src/libraries/System.Numerics.Vectors/tests/GenericVectorTests.cs @@ -8,6 +8,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; +using System.Runtime.Intrinsics.Tests.Vectors; using Xunit; using Xunit.Sdk; @@ -19,6 +20,32 @@ namespace System.Numerics.Tests [RequiresPreviewFeatures] public unsafe class GenericVectorTests { + /// Verifies that two values are equal, within the . + /// The expected value + /// The value to be compared against + /// The total variance allowed between the expected and actual results. + /// Thrown when the values are not equal + internal static void AssertEqual(Vector expected, Vector actual, Vector variance) + { + for (int i = 0; i < Vector.Count; i++) + { + AssertExtensions.Equal(expected.GetElement(i), actual.GetElement(i), variance.GetElement(i)); + } + } + + /// Verifies that two values are equal, within the . + /// The expected value + /// The value to be compared against + /// The total variance allowed between the expected and actual results. + /// Thrown when the values are not equal + internal static void AssertEqual(Vector expected, Vector actual, Vector variance) + { + for (int i = 0; i < Vector.Count; i++) + { + AssertExtensions.Equal(expected.GetElement(i), actual.GetElement(i), variance.GetElement(i)); + } + } + // Static constructor in top-level class\ static System.Numerics.Vector dummy; static GenericVectorTests() @@ -4508,5 +4535,37 @@ private static void TestCreateSequence(T start, T step) expected += step; } } + + [Theory] + [MemberData(nameof(VectorTestMemberData.MultiplyAddDouble), MemberType = typeof(VectorTestMemberData))] + public void FusedMultiplyAddDoubleTest(double left, double right, double addend) + { + Vector actualResult = Vector.FusedMultiplyAdd(new Vector(left), new Vector(right), new Vector(addend)); + AssertEqual(new Vector(double.FusedMultiplyAdd(left, right, addend)), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + public void FusedMultiplyAddSingleTest(float left, float right, float addend) + { + Vector actualResult = Vector.FusedMultiplyAdd(new Vector(left), new Vector(right), new Vector(addend)); + AssertEqual(new Vector(float.FusedMultiplyAdd(left, right, addend)), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(VectorTestMemberData.MultiplyAddDouble), MemberType = typeof(VectorTestMemberData))] + public void MultiplyAddEstimateDoubleTest(double left, double right, double addend) + { + Vector actualResult = Vector.MultiplyAddEstimate(new Vector(left), new Vector(right), new Vector(addend)); + AssertEqual(new Vector(double.MultiplyAddEstimate(left, right, addend)), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + public void MultiplyAddEstimateSingleTest(float left, float right, float addend) + { + Vector actualResult = Vector.MultiplyAddEstimate(new Vector(left), new Vector(right), new Vector(addend)); + AssertEqual(new Vector(float.MultiplyAddEstimate(left, right, addend)), actualResult, Vector.Zero); + } } } diff --git a/src/libraries/System.Numerics.Vectors/tests/System.Numerics.Vectors.Tests.csproj b/src/libraries/System.Numerics.Vectors/tests/System.Numerics.Vectors.Tests.csproj index 264fb0fe340d9c..243d1490ced0e5 100644 --- a/src/libraries/System.Numerics.Vectors/tests/System.Numerics.Vectors.Tests.csproj +++ b/src/libraries/System.Numerics.Vectors/tests/System.Numerics.Vectors.Tests.csproj @@ -18,5 +18,6 @@ + diff --git a/src/libraries/System.Numerics.Vectors/tests/Vector2Tests.cs b/src/libraries/System.Numerics.Vectors/tests/Vector2Tests.cs index 6bb05504afb8f1..853ad86480b17a 100644 --- a/src/libraries/System.Numerics.Vectors/tests/Vector2Tests.cs +++ b/src/libraries/System.Numerics.Vectors/tests/Vector2Tests.cs @@ -3,12 +3,24 @@ using System.Globalization; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.Tests.Vectors; using Xunit; namespace System.Numerics.Tests { public sealed class Vector2Tests { + /// Verifies that two values are equal, within the . + /// The expected value + /// The value to be compared against + /// The total variance allowed between the expected and actual results. + /// Thrown when the values are not equal + internal static void AssertEqual(Vector2 expected, Vector2 actual, Vector2 variance) + { + AssertExtensions.Equal(expected.X, actual.X, variance.X); + AssertExtensions.Equal(expected.Y, actual.Y, variance.Y); + } + [Fact] public void Vector2MarshalSizeTest() { @@ -1286,5 +1298,21 @@ private class EmbeddedVectorObject { public Vector2 FieldVector; } + + [Theory] + [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + public void FusedMultiplyAddSingleTest(float left, float right, float addend) + { + Vector2 actualResult = Vector2.FusedMultiplyAdd(new Vector2(left), new Vector2(right), new Vector2(addend)); + AssertEqual(new Vector2(float.FusedMultiplyAdd(left, right, addend)), actualResult, Vector2.Zero); + } + + [Theory] + [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + public void MultiplyAddEstimateSingleTest(float left, float right, float addend) + { + Vector2 actualResult = Vector2.MultiplyAddEstimate(new Vector2(left), new Vector2(right), new Vector2(addend)); + AssertEqual(new Vector2(float.MultiplyAddEstimate(left, right, addend)), actualResult, Vector2.Zero); + } } } diff --git a/src/libraries/System.Numerics.Vectors/tests/Vector3Tests.cs b/src/libraries/System.Numerics.Vectors/tests/Vector3Tests.cs index dc310461b61634..235d8b08c431b9 100644 --- a/src/libraries/System.Numerics.Vectors/tests/Vector3Tests.cs +++ b/src/libraries/System.Numerics.Vectors/tests/Vector3Tests.cs @@ -3,12 +3,25 @@ using System.Globalization; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.Tests.Vectors; using Xunit; namespace System.Numerics.Tests { public sealed class Vector3Tests { + /// Verifies that two values are equal, within the . + /// The expected value + /// The value to be compared against + /// The total variance allowed between the expected and actual results. + /// Thrown when the values are not equal + internal static void AssertEqual(Vector3 expected, Vector3 actual, Vector3 variance) + { + AssertExtensions.Equal(expected.X, actual.X, variance.X); + AssertExtensions.Equal(expected.Y, actual.Y, variance.Y); + AssertExtensions.Equal(expected.Z, actual.Z, variance.Z); + } + [Fact] public void Vector3MarshalSizeTest() { @@ -1335,5 +1348,21 @@ private class EmbeddedVectorObject { public Vector3 FieldVector; } + + [Theory] + [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + public void FusedMultiplyAddSingleTest(float left, float right, float addend) + { + Vector3 actualResult = Vector3.FusedMultiplyAdd(new Vector3(left), new Vector3(right), new Vector3(addend)); + AssertEqual(new Vector3(float.FusedMultiplyAdd(left, right, addend)), actualResult, Vector3.Zero); + } + + [Theory] + [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + public void MultiplyAddEstimateSingleTest(float left, float right, float addend) + { + Vector3 actualResult = Vector3.MultiplyAddEstimate(new Vector3(left), new Vector3(right), new Vector3(addend)); + AssertEqual(new Vector3(float.MultiplyAddEstimate(left, right, addend)), actualResult, Vector3.Zero); + } } } diff --git a/src/libraries/System.Numerics.Vectors/tests/Vector4Tests.cs b/src/libraries/System.Numerics.Vectors/tests/Vector4Tests.cs index 68a0878476d82d..041663f414430b 100644 --- a/src/libraries/System.Numerics.Vectors/tests/Vector4Tests.cs +++ b/src/libraries/System.Numerics.Vectors/tests/Vector4Tests.cs @@ -3,12 +3,26 @@ using System.Globalization; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.Tests.Vectors; using Xunit; namespace System.Numerics.Tests { public sealed class Vector4Tests { + /// Verifies that two values are equal, within the . + /// The expected value + /// The value to be compared against + /// The total variance allowed between the expected and actual results. + /// Thrown when the values are not equal + internal static void AssertEqual(Vector4 expected, Vector4 actual, Vector4 variance) + { + AssertExtensions.Equal(expected.X, actual.X, variance.X); + AssertExtensions.Equal(expected.Y, actual.Y, variance.Y); + AssertExtensions.Equal(expected.Z, actual.Z, variance.Z); + AssertExtensions.Equal(expected.W, actual.W, variance.W); + } + [Fact] public void Vector4MarshalSizeTest() { @@ -1709,5 +1723,21 @@ public struct Level7 } } #pragma warning restore 0169 + + [Theory] + [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + public void FusedMultiplyAddSingleTest(float left, float right, float addend) + { + Vector4 actualResult = Vector4.FusedMultiplyAdd(new Vector4(left), new Vector4(right), new Vector4(addend)); + AssertEqual(new Vector4(float.FusedMultiplyAdd(left, right, addend)), actualResult, Vector4.Zero); + } + + [Theory] + [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + public void MultiplyAddEstimateSingleTest(float left, float right, float addend) + { + Vector4 actualResult = Vector4.MultiplyAddEstimate(new Vector4(left), new Vector4(right), new Vector4(addend)); + AssertEqual(new Vector4(float.MultiplyAddEstimate(left, right, addend)), actualResult, Vector4.Zero); + } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Byte.cs b/src/libraries/System.Private.CoreLib/src/System/Byte.cs index 31a2bccf21bf88..0302bc2bc649dd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Byte.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Byte.cs @@ -678,6 +678,9 @@ public static byte CreateTruncating(TOther value) /// static byte INumberBase.MinMagnitudeNumber(byte x, byte y) => Min(x, y); + /// + static byte INumberBase.MultiplyAddEstimate(byte left, byte right, byte addend) => (byte)((left * right) + addend); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] static bool INumberBase.TryConvertFromChecked(TOther value, out byte result) => TryConvertFromChecked(value, out result); diff --git a/src/libraries/System.Private.CoreLib/src/System/Char.cs b/src/libraries/System.Private.CoreLib/src/System/Char.cs index a44d61f61a2aed..7df1b14afc0332 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Char.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Char.cs @@ -1509,6 +1509,9 @@ bool IBinaryInteger.TryWriteLittleEndian(Span destination, out int b /// static char INumberBase.MinMagnitudeNumber(char x, char y) => (char)Math.Min(x, y); + /// + static char INumberBase.MultiplyAddEstimate(char left, char right, char addend) => (char)((left * right) + addend); + static char INumberBase.Parse(string s, NumberStyles style, IFormatProvider? provider) => Parse(s); static char INumberBase.Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider) => Parse(s); diff --git a/src/libraries/System.Private.CoreLib/src/System/Decimal.cs b/src/libraries/System.Private.CoreLib/src/System/Decimal.cs index 189e54dcc1ef74..fc05bc065d4928 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Decimal.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Decimal.cs @@ -1498,6 +1498,9 @@ public static decimal MinMagnitude(decimal x, decimal y) /// static decimal INumberBase.MinMagnitudeNumber(decimal x, decimal y) => MinMagnitude(x, y); + /// + static decimal INumberBase.MultiplyAddEstimate(decimal left, decimal right, decimal addend) => (left * right) + addend; + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] static bool INumberBase.TryConvertFromChecked(TOther value, out decimal result) => TryConvertFromChecked(value, out result); diff --git a/src/libraries/System.Private.CoreLib/src/System/Double.cs b/src/libraries/System.Private.CoreLib/src/System/Double.cs index 6e6263f039049b..26e65460ef24f3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Double.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Double.cs @@ -1216,6 +1216,17 @@ public static double MinMagnitudeNumber(double x, double y) return y; } + /// + [Intrinsic] + public static double MultiplyAddEstimate(double left, double right, double addend) + { +#if MONO + return (left * right) + addend; +#else + return MultiplyAddEstimate(left, right, addend); +#endif + } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] static bool INumberBase.TryConvertFromChecked(TOther value, out double result) diff --git a/src/libraries/System.Private.CoreLib/src/System/Half.cs b/src/libraries/System.Private.CoreLib/src/System/Half.cs index d4459c5162366f..533521970c7e23 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Half.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Half.cs @@ -1920,6 +1920,9 @@ public static Half MinMagnitudeNumber(Half x, Half y) return y; } + /// + public static Half MultiplyAddEstimate(Half left, Half right, Half addend) => (Half)float.MultiplyAddEstimate((float)left, (float)right, (float)addend); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] static bool INumberBase.TryConvertFromChecked(TOther value, out Half result) diff --git a/src/libraries/System.Private.CoreLib/src/System/Int128.cs b/src/libraries/System.Private.CoreLib/src/System/Int128.cs index 0196af5fd51612..241c1c39e71d55 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int128.cs @@ -1521,6 +1521,9 @@ public static Int128 MinMagnitude(Int128 x, Int128 y) /// static Int128 INumberBase.MinMagnitudeNumber(Int128 x, Int128 y) => MinMagnitude(x, y); + /// + static Int128 INumberBase.MultiplyAddEstimate(Int128 left, Int128 right, Int128 addend) => (left * right) + addend; + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] static bool INumberBase.TryConvertFromChecked(TOther value, out Int128 result) => TryConvertFromChecked(value, out result); diff --git a/src/libraries/System.Private.CoreLib/src/System/Int16.cs b/src/libraries/System.Private.CoreLib/src/System/Int16.cs index af144fb860c921..e963c0df013272 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int16.cs @@ -876,6 +876,9 @@ public static short MinMagnitude(short x, short y) /// static short INumberBase.MinMagnitudeNumber(short x, short y) => MinMagnitude(x, y); + /// + static short INumberBase.MultiplyAddEstimate(short left, short right, short addend) => (short)((left * right) + addend); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] static bool INumberBase.TryConvertFromChecked(TOther value, out short result) => TryConvertFromChecked(value, out result); diff --git a/src/libraries/System.Private.CoreLib/src/System/Int32.cs b/src/libraries/System.Private.CoreLib/src/System/Int32.cs index 2f91c2c2a59702..e0406ecbd5c083 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int32.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int32.cs @@ -911,6 +911,9 @@ public static int MinMagnitude(int x, int y) /// static int INumberBase.MinMagnitudeNumber(int x, int y) => MinMagnitude(x, y); + /// + static int INumberBase.MultiplyAddEstimate(int left, int right, int addend) => (left * right) + addend; + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] static bool INumberBase.TryConvertFromChecked(TOther value, out int result) => TryConvertFromChecked(value, out result); diff --git a/src/libraries/System.Private.CoreLib/src/System/Int64.cs b/src/libraries/System.Private.CoreLib/src/System/Int64.cs index ca170d8c903ed0..54d69da8b2273f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int64.cs @@ -908,6 +908,9 @@ public static long MinMagnitude(long x, long y) /// static long INumberBase.MinMagnitudeNumber(long x, long y) => MinMagnitude(x, y); + /// + static long INumberBase.MultiplyAddEstimate(long left, long right, long addend) => (long)((left * right) + addend); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] static bool INumberBase.TryConvertFromChecked(TOther value, out long result) => TryConvertFromChecked(value, out result); diff --git a/src/libraries/System.Private.CoreLib/src/System/IntPtr.cs b/src/libraries/System.Private.CoreLib/src/System/IntPtr.cs index 3dd33c2c66b82d..fb2dec11f30640 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IntPtr.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IntPtr.cs @@ -919,6 +919,9 @@ public static nint MinMagnitude(nint x, nint y) /// static nint INumberBase.MinMagnitudeNumber(nint x, nint y) => MinMagnitude(x, y); + /// + static nint INumberBase.MultiplyAddEstimate(nint left, nint right, nint addend) => (left * right) + addend; + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] static bool INumberBase.TryConvertFromChecked(TOther value, out nint result) => TryConvertFromChecked(value, out result); diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/INumberBase.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/INumberBase.cs index 7e5acfafe75aeb..eca30a3c3ea12d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/INumberBase.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/INumberBase.cs @@ -258,6 +258,17 @@ static virtual TSelf CreateTruncating(TOther value) /// For this method matches the IEEE 754:2019 minimumMagnitudeNumber function. This requires NaN inputs to not be propagated back to the caller and for -0.0 to be treated as less than +0.0. static abstract TSelf MinMagnitudeNumber(TSelf x, TSelf y); + /// Computes an estimate of ( * ) + . + /// The value to be multiplied with . + /// The value to be multiplied with . + /// The value to be added to the result of multiplied by . + /// An estimate of ( * ) + . + /// + /// On hardware that natively supports , this may return a result that was rounded as one ternary operation. + /// On hardware without specialized support, this may just return ( * ) + . + /// + static virtual TSelf MultiplyAddEstimate(TSelf left, TSelf right, TSelf addend) => (left * right) + addend; + /// Parses a string into a value. /// The string to parse. /// A bitwise combination of number styles that can be present in . diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs index 8a5961bb314b0f..6bbdf2f7423068 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs @@ -668,6 +668,54 @@ public static Vector Floor(Vector value) return result; } + /// Computes ( * ) + , rounded as one ternary operation. + /// The vector to be multiplied with . + /// The vector to be multiplied with . + /// The vector to be added to the result of multiplied by . + /// ( * ) + , rounded as one ternary operation. + /// + /// This computes ( * ) as if to infinite precision, adds to that result as if to infinite precision, and finally rounds to the nearest representable value. + /// This differs from the non-fused sequence which would compute ( * ) as if to infinite precision, round the result to the nearest representable value, add to the rounded result as if to infinite precision, and finally round to the nearest representable value. + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector FusedMultiplyAdd(Vector left, Vector right, Vector addend) + { + Unsafe.SkipInit(out Vector result); + + for (int index = 0; index < Vector.Count; index++) + { + double value = double.FusedMultiplyAdd(left.GetElementUnsafe(index), right.GetElementUnsafe(index), addend.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + + /// Computes ( * ) + , rounded as one ternary operation. + /// The vector to be multiplied with . + /// The vector to be multiplied with . + /// The vector to be added to the result of multiplied by . + /// ( * ) + , rounded as one ternary operation. + /// + /// This computes ( * ) as if to infinite precision, adds to that result as if to infinite precision, and finally rounds to the nearest representable value. + /// This differs from the non-fused sequence which would compute ( * ) as if to infinite precision, round the result to the nearest representable value, add to the rounded result as if to infinite precision, and finally round to the nearest representable value. + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector FusedMultiplyAdd(Vector left, Vector right, Vector addend) + { + Unsafe.SkipInit(out Vector result); + + for (int index = 0; index < Vector.Count; index++) + { + float value = float.FusedMultiplyAdd(left.GetElementUnsafe(index), right.GetElementUnsafe(index), addend.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + /// Gets the element at the specified index. /// The type of the elements in the vector. /// The vector to get the element from. @@ -1194,6 +1242,38 @@ public static Vector Min(Vector left, Vector right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector Multiply(T left, Vector right) => left * right; + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector MultiplyAddEstimate(Vector left, Vector right, Vector addend) + { + Unsafe.SkipInit(out Vector result); + + for (int index = 0; index < Vector.Count; index++) + { + double element = double.MultiplyAddEstimate(left.GetElementUnsafe(index), right.GetElementUnsafe(index), addend.GetElementUnsafe(index)); + result.SetElementUnsafe(index, element); + } + + return result; + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector MultiplyAddEstimate(Vector left, Vector right, Vector addend) + { + Unsafe.SkipInit(out Vector result); + + for (int index = 0; index < Vector.Count; index++) + { + float element = float.MultiplyAddEstimate(left.GetElementUnsafe(index), right.GetElementUnsafe(index), addend.GetElementUnsafe(index)); + result.SetElementUnsafe(index, element); + } + + return result; + } + /// Narrows two instances into one . /// The vector that will be narrowed to the lower half of the result vector. /// The vector that will be narrowed to the upper half of the result vector. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs index e57dee217803ff..2b27fe4f961e3d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs @@ -326,6 +326,17 @@ public static float Dot(Vector2 value1, Vector2 value2) + (value1.Y * value2.Y); } + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 FusedMultiplyAdd(Vector2 left, Vector2 right, Vector2 addend) + { + return new Vector2( + float.FusedMultiplyAdd(left.X, right.X, addend.X), + float.FusedMultiplyAdd(left.Y, right.Y, addend.Y) + ); + } + /// Performs a linear interpolation between two vectors based on the given weighting. /// The first vector. /// The second vector. @@ -402,6 +413,17 @@ public static Vector2 Multiply(float left, Vector2 right) return left * right; } + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 MultiplyAddEstimate(Vector2 left, Vector2 right, Vector2 addend) + { + return new Vector2( + float.MultiplyAddEstimate(left.X, right.X, addend.X), + float.MultiplyAddEstimate(left.Y, right.Y, addend.Y) + ); + } + /// Negates a specified vector. /// The vector to negate. /// The negated vector. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs index c4739ce80502c5..382b6838193bdd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs @@ -368,6 +368,18 @@ public static float Dot(Vector3 vector1, Vector3 vector2) + (vector1.Z * vector2.Z); } + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 FusedMultiplyAdd(Vector3 left, Vector3 right, Vector3 addend) + { + return new Vector3( + float.FusedMultiplyAdd(left.X, right.X, addend.X), + float.FusedMultiplyAdd(left.Y, right.Y, addend.Y), + float.FusedMultiplyAdd(left.Z, right.Z, addend.Z) + ); + } + /// Performs a linear interpolation between two vectors based on the given weighting. /// The first vector. /// The second vector. @@ -443,6 +455,18 @@ public static Vector3 Multiply(float left, Vector3 right) return left * right; } + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 MultiplyAddEstimate(Vector3 left, Vector3 right, Vector3 addend) + { + return new Vector3( + float.MultiplyAddEstimate(left.X, right.X, addend.X), + float.MultiplyAddEstimate(left.Y, right.Y, addend.Y), + float.MultiplyAddEstimate(left.Z, right.Z, addend.Z) + ); + } + /// Negates a specified vector. /// The vector to negate. /// The negated vector. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs index 831b4f50d2556f..6a1a1c39c869c3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs @@ -384,6 +384,19 @@ public static float Dot(Vector4 vector1, Vector4 vector2) + (vector1.W * vector2.W); } + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 FusedMultiplyAdd(Vector4 left, Vector4 right, Vector4 addend) + { + return new Vector4( + float.FusedMultiplyAdd(left.X, right.X, addend.X), + float.FusedMultiplyAdd(left.Y, right.Y, addend.Y), + float.FusedMultiplyAdd(left.Z, right.Z, addend.Z), + float.FusedMultiplyAdd(left.W, right.W, addend.W) + ); + } + /// Performs a linear interpolation between two vectors based on the given weighting. /// The first vector. /// The second vector. @@ -464,6 +477,19 @@ public static Vector4 Multiply(float left, Vector4 right) return left * right; } + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 MultiplyAddEstimate(Vector4 left, Vector4 right, Vector4 addend) + { + return new Vector4( + float.MultiplyAddEstimate(left.X, right.X, addend.X), + float.MultiplyAddEstimate(left.Y, right.Y, addend.Y), + float.MultiplyAddEstimate(left.Z, right.Z, addend.Z), + float.MultiplyAddEstimate(left.W, right.W, addend.W) + ); + } + /// Negates a specified vector. /// The vector to negate. /// The negated vector. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs index b314daec02a93c..344f528a45c5a1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs @@ -1389,6 +1389,9 @@ public static NFloat CreateTruncating(TOther value) /// public static NFloat MinMagnitudeNumber(NFloat x, NFloat y) => new NFloat(NativeType.MinMagnitudeNumber(x._value, y._value)); + /// + public static NFloat MultiplyAddEstimate(NFloat left, NFloat right, NFloat addend) => new NFloat(NativeType.MultiplyAddEstimate(left._value, right._value, addend._value)); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] static bool INumberBase.TryConvertFromChecked(TOther value, out NFloat result) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs index 4080b06c92b77b..1cb989eedba4d2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs @@ -1567,6 +1567,28 @@ internal static Vector128 Floor(Vector128 vector) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Floor(Vector128 vector) => Floor(vector); + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 FusedMultiplyAdd(Vector128 left, Vector128 right, Vector128 addend) + { + return Create( + Vector64.FusedMultiplyAdd(left._lower, right._lower, addend._lower), + Vector64.FusedMultiplyAdd(left._upper, right._upper, addend._upper) + ); + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 FusedMultiplyAdd(Vector128 left, Vector128 right, Vector128 addend) + { + return Create( + Vector64.FusedMultiplyAdd(left._lower, right._lower, addend._lower), + Vector64.FusedMultiplyAdd(left._upper, right._upper, addend._upper) + ); + } + /// Gets the element at the specified index. /// The type of the elements in the vector. /// The vector to get the element from. @@ -2008,6 +2030,28 @@ public static Vector128 Min(Vector128 left, Vector128 right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Multiply(T left, Vector128 right) => left * right; + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 MultiplyAddEstimate(Vector128 left, Vector128 right, Vector128 addend) + { + return Create( + Vector64.MultiplyAddEstimate(left._lower, right._lower, addend._lower), + Vector64.MultiplyAddEstimate(left._upper, right._upper, addend._upper) + ); + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 MultiplyAddEstimate(Vector128 left, Vector128 right, Vector128 addend) + { + return Create( + Vector64.MultiplyAddEstimate(left._lower, right._lower, addend._lower), + Vector64.MultiplyAddEstimate(left._upper, right._upper, addend._upper) + ); + } + /// Narrows two instances into one . /// The vector that will be narrowed to the lower half of the result vector. /// The vector that will be narrowed to the upper half of the result vector. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs index 4d174eef197544..01591e0aa20cbc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs @@ -5,6 +5,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; namespace System.Runtime.Intrinsics @@ -1546,6 +1547,28 @@ internal static Vector256 Floor(Vector256 vector) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 Floor(Vector256 vector) => Floor(vector); + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 FusedMultiplyAdd(Vector256 left, Vector256 right, Vector256 addend) + { + return Create( + Vector128.FusedMultiplyAdd(left._lower, right._lower, addend._lower), + Vector128.FusedMultiplyAdd(left._upper, right._upper, addend._upper) + ); + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 FusedMultiplyAdd(Vector256 left, Vector256 right, Vector256 addend) + { + return Create( + Vector128.FusedMultiplyAdd(left._lower, right._lower, addend._lower), + Vector128.FusedMultiplyAdd(left._upper, right._upper, addend._upper) + ); + } + /// Gets the element at the specified index. /// The type of the input vector. /// The vector to get the element from. @@ -1985,6 +2008,28 @@ public static Vector256 Min(Vector256 left, Vector256 right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 Multiply(T left, Vector256 right) => left * right; + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 MultiplyAddEstimate(Vector256 left, Vector256 right, Vector256 addend) + { + return Create( + Vector128.MultiplyAddEstimate(left._lower, right._lower, addend._lower), + Vector128.MultiplyAddEstimate(left._upper, right._upper, addend._upper) + ); + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 MultiplyAddEstimate(Vector256 left, Vector256 right, Vector256 addend) + { + return Create( + Vector128.MultiplyAddEstimate(left._lower, right._lower, addend._lower), + Vector128.MultiplyAddEstimate(left._upper, right._upper, addend._upper) + ); + } + /// Narrows two instances into one . /// The vector that will be narrowed to the lower half of the result vector. /// The vector that will be narrowed to the upper half of the result vector. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs index d63f12afb64d9c..bf24a68ffc81e2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs @@ -5,6 +5,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; namespace System.Runtime.Intrinsics @@ -1593,6 +1594,28 @@ internal static Vector512 Floor(Vector512 vector) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector512 Floor(Vector512 vector) => Floor(vector); + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 FusedMultiplyAdd(Vector512 left, Vector512 right, Vector512 addend) + { + return Create( + Vector256.FusedMultiplyAdd(left._lower, right._lower, addend._lower), + Vector256.FusedMultiplyAdd(left._upper, right._upper, addend._upper) + ); + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 FusedMultiplyAdd(Vector512 left, Vector512 right, Vector512 addend) + { + return Create( + Vector256.FusedMultiplyAdd(left._lower, right._lower, addend._lower), + Vector256.FusedMultiplyAdd(left._upper, right._upper, addend._upper) + ); + } + /// Gets the element at the specified index. /// The type of the input vector. /// The vector to get the element from. @@ -2032,6 +2055,27 @@ public static Vector512 Min(Vector512 left, Vector512 right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector512 Multiply(T left, Vector512 right) => left * right; + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 MultiplyAddEstimate(Vector512 left, Vector512 right, Vector512 addend) + { + return Create( + Vector256.MultiplyAddEstimate(left._lower, right._lower, addend._lower), + Vector256.MultiplyAddEstimate(left._upper, right._upper, addend._upper) + ); + } + + /// + [Intrinsic] + public static Vector512 MultiplyAddEstimate(Vector512 left, Vector512 right, Vector512 addend) + { + return Create( + Vector256.MultiplyAddEstimate(left._lower, right._lower, addend._lower), + Vector256.MultiplyAddEstimate(left._upper, right._upper, addend._upper) + ); + } + /// Narrows two instances into one . /// The vector that will be narrowed to the lower half of the result vector. /// The vector that will be narrowed to the upper half of the result vector. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs index f3e35f7ecc36fc..78b15f643ac284 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs @@ -6,6 +6,8 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics.Arm; +using System.Runtime.Intrinsics.X86; +using System.Text; namespace System.Runtime.Intrinsics { @@ -1232,7 +1234,7 @@ internal static Vector64 Exp(Vector64 vector) for (int index = 0; index < Vector64.Count; index++) { - T value = T.Exp(vector.GetElement(index)); + T value = T.Exp(vector.GetElementUnsafe(index)); result.SetElementUnsafe(index, value); } @@ -1342,6 +1344,54 @@ internal static Vector64 Floor(Vector64 vector) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector64 Floor(Vector64 vector) => Floor(vector); + /// Computes ( * ) + , rounded as one ternary operation. + /// The vector to be multiplied with . + /// The vector to be multiplied with . + /// The vector to be added to the result of multiplied by . + /// ( * ) + , rounded as one ternary operation. + /// + /// This computes ( * ) as if to infinite precision, adds to that result as if to infinite precision, and finally rounds to the nearest representable value. + /// This differs from the non-fused sequence which would compute ( * ) as if to infinite precision, round the result to the nearest representable value, add to the rounded result as if to infinite precision, and finally round to the nearest representable value. + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector64 FusedMultiplyAdd(Vector64 left, Vector64 right, Vector64 addend) + { + Unsafe.SkipInit(out Vector64 result); + + for (int index = 0; index < Vector64.Count; index++) + { + double value = double.FusedMultiplyAdd(left.GetElementUnsafe(index), right.GetElementUnsafe(index), addend.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + + /// Computes ( * ) + , rounded as one ternary operation. + /// The vector to be multiplied with . + /// The vector to be multiplied with . + /// The vector to be added to the result of multiplied by . + /// ( * ) + , rounded as one ternary operation. + /// + /// This computes ( * ) as if to infinite precision, adds to that result as if to infinite precision, and finally rounds to the nearest representable value. + /// This differs from the non-fused sequence which would compute ( * ) as if to infinite precision, round the result to the nearest representable value, add to the rounded result as if to infinite precision, and finally round to the nearest representable value. + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector64 FusedMultiplyAdd(Vector64 left, Vector64 right, Vector64 addend) + { + Unsafe.SkipInit(out Vector64 result); + + for (int index = 0; index < Vector64.Count; index++) + { + float value = float.FusedMultiplyAdd(left.GetElementUnsafe(index), right.GetElementUnsafe(index), addend.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + /// Gets the element at the specified index. /// The type of the elements in the vector. /// The vector to get the element from. @@ -1693,7 +1743,7 @@ internal static Vector64 Log(Vector64 vector) for (int index = 0; index < Vector64.Count; index++) { - T value = T.Log(vector.GetElement(index)); + T value = T.Log(vector.GetElementUnsafe(index)); result.SetElementUnsafe(index, value); } @@ -1739,7 +1789,7 @@ internal static Vector64 Log2(Vector64 vector) for (int index = 0; index < Vector64.Count; index++) { - T value = T.Log2(vector.GetElement(index)); + T value = T.Log2(vector.GetElementUnsafe(index)); result.SetElementUnsafe(index, value); } @@ -1850,6 +1900,54 @@ public static Vector64 Min(Vector64 left, Vector64 right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector64 Multiply(T left, Vector64 right) => left * right; + /// Computes an estimate of ( * ) + . + /// The vector to be multiplied with . + /// The vector to be multiplied with . + /// The vector to be added to the result of multiplied by . + /// An estimate of ( * ) + . + /// + /// On hardware that natively supports , this may return a result that was rounded as one ternary operation. + /// On hardware without specialized support, this may just return ( * ) + . + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector64 MultiplyAddEstimate(Vector64 left, Vector64 right, Vector64 addend) + { + Unsafe.SkipInit(out Vector64 result); + + for (int index = 0; index < Vector64.Count; index++) + { + double element = double.MultiplyAddEstimate(left.GetElementUnsafe(index), right.GetElementUnsafe(index), addend.GetElementUnsafe(index)); + result.SetElementUnsafe(index, element); + } + + return result; + } + + /// Computes an estimate of ( * ) + . + /// The vector to be multiplied with . + /// The vector to be multiplied with . + /// The vector to be added to the result of multiplied by . + /// An estimate of ( * ) + . + /// + /// On hardware that natively supports , this may return a result that was rounded as one ternary operation. + /// On hardware without specialized support, this may just return ( * ) + . + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector64 MultiplyAddEstimate(Vector64 left, Vector64 right, Vector64 addend) + { + Unsafe.SkipInit(out Vector64 result); + + for (int index = 0; index < Vector64.Count; index++) + { + float element = float.MultiplyAddEstimate(left.GetElementUnsafe(index), right.GetElementUnsafe(index), addend.GetElementUnsafe(index)); + result.SetElementUnsafe(index, element); + } + + return result; + } + /// Narrows two instances into one . /// The vector that will be narrowed to the lower half of the result vector. /// The vector that will be narrowed to the upper half of the result vector. diff --git a/src/libraries/System.Private.CoreLib/src/System/SByte.cs b/src/libraries/System.Private.CoreLib/src/System/SByte.cs index fb4734d41b69f6..00bce51b3a2bab 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SByte.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SByte.cs @@ -837,6 +837,9 @@ public static sbyte MinMagnitude(sbyte x, sbyte y) /// static sbyte INumberBase.MinMagnitudeNumber(sbyte x, sbyte y) => MinMagnitude(x, y); + /// + static sbyte INumberBase.MultiplyAddEstimate(sbyte left, sbyte right, sbyte addend) => (sbyte)((left * right) + addend); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] static bool INumberBase.TryConvertFromChecked(TOther value, out sbyte result) => TryConvertFromChecked(value, out result); diff --git a/src/libraries/System.Private.CoreLib/src/System/Single.cs b/src/libraries/System.Private.CoreLib/src/System/Single.cs index bf7c06a935dfb2..88c923892309c1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Single.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Single.cs @@ -1199,6 +1199,19 @@ public static float MinMagnitudeNumber(float x, float y) return y; } + + + /// + [Intrinsic] + public static float MultiplyAddEstimate(float left, float right, float addend) + { +#if MONO + return (left * right) + addend; +#else + return MultiplyAddEstimate(left, right, addend); +#endif + } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] static bool INumberBase.TryConvertFromChecked(TOther value, out float result) diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt128.cs b/src/libraries/System.Private.CoreLib/src/System/UInt128.cs index ec195239ca9831..f988ab886ec835 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt128.cs @@ -1588,6 +1588,9 @@ public static UInt128 CreateTruncating(TOther value) /// static UInt128 INumberBase.MinMagnitudeNumber(UInt128 x, UInt128 y) => Min(x, y); + /// + static UInt128 INumberBase.MultiplyAddEstimate(UInt128 left, UInt128 right, UInt128 addend) => (left * right) + addend; + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] static bool INumberBase.TryConvertFromChecked(TOther value, out UInt128 result) => TryConvertFromChecked(value, out result); diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt16.cs b/src/libraries/System.Private.CoreLib/src/System/UInt16.cs index fcc863a6310a83..999ad1bedd9c65 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt16.cs @@ -707,6 +707,9 @@ public static ushort CreateTruncating(TOther value) /// static ushort INumberBase.MinMagnitudeNumber(ushort x, ushort y) => Min(x, y); + /// + static ushort INumberBase.MultiplyAddEstimate(ushort left, ushort right, ushort addend) => (ushort)((left * right) + addend); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] static bool INumberBase.TryConvertFromChecked(TOther value, out ushort result) => TryConvertFromChecked(value, out result); diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt32.cs b/src/libraries/System.Private.CoreLib/src/System/UInt32.cs index 8487630193ec51..07603a068449de 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt32.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt32.cs @@ -740,6 +740,9 @@ public static uint CreateTruncating(TOther value) /// static uint INumberBase.MinMagnitudeNumber(uint x, uint y) => Min(x, y); + /// + static uint INumberBase.MultiplyAddEstimate(uint left, uint right, uint addend) => (left * right) + addend; + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] static bool INumberBase.TryConvertFromChecked(TOther value, out uint result) => TryConvertFromChecked(value, out result); diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt64.cs b/src/libraries/System.Private.CoreLib/src/System/UInt64.cs index dc12c5c006a82b..3d95d606ee1979 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt64.cs @@ -739,6 +739,9 @@ public static ulong CreateTruncating(TOther value) /// static ulong INumberBase.MinMagnitudeNumber(ulong x, ulong y) => Min(x, y); + /// + static ulong INumberBase.MultiplyAddEstimate(ulong left, ulong right, ulong addend) => (left * right) + addend; + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] static bool INumberBase.TryConvertFromChecked(TOther value, out ulong result) => TryConvertFromChecked(value, out result); diff --git a/src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs b/src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs index 42c58a5d0baa88..2659d5d6c14f25 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs @@ -758,6 +758,9 @@ public static nuint CreateTruncating(TOther value) /// static nuint INumberBase.MinMagnitudeNumber(nuint x, nuint y) => Min(x, y); + /// + static nuint INumberBase.MultiplyAddEstimate(nuint left, nuint right, nuint addend) => (nuint)((left * right) + addend); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] static bool INumberBase.TryConvertFromChecked(TOther value, out nuint result) => TryConvertFromChecked(value, out result); diff --git a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs index f7665833c0a758..5c47f26a0177dc 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -1395,6 +1395,7 @@ public static void Free(void* ptr) { } public static System.Runtime.InteropServices.NFloat MinMagnitude(System.Runtime.InteropServices.NFloat x, System.Runtime.InteropServices.NFloat y) { throw null; } public static System.Runtime.InteropServices.NFloat MinMagnitudeNumber(System.Runtime.InteropServices.NFloat x, System.Runtime.InteropServices.NFloat y) { throw null; } public static System.Runtime.InteropServices.NFloat MinNumber(System.Runtime.InteropServices.NFloat x, System.Runtime.InteropServices.NFloat y) { throw null; } + public static System.Runtime.InteropServices.NFloat MultiplyAddEstimate(System.Runtime.InteropServices.NFloat left, System.Runtime.InteropServices.NFloat right, System.Runtime.InteropServices.NFloat addend) { throw null; } public static System.Runtime.InteropServices.NFloat operator +(System.Runtime.InteropServices.NFloat left, System.Runtime.InteropServices.NFloat right) { throw null; } public static explicit operator checked byte (System.Runtime.InteropServices.NFloat value) { throw null; } public static explicit operator checked char (System.Runtime.InteropServices.NFloat value) { throw null; } diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index d4f4cf393cb9d6..665f5d41ee98d1 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -168,6 +168,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector128 vector, public static uint ExtractMostSignificantBits(this System.Runtime.Intrinsics.Vector128 vector) { throw null; } public static System.Runtime.Intrinsics.Vector128 Floor(System.Runtime.Intrinsics.Vector128 vector) { throw null; } public static System.Runtime.Intrinsics.Vector128 Floor(System.Runtime.Intrinsics.Vector128 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector128 FusedMultiplyAdd(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right, System.Runtime.Intrinsics.Vector128 addend) { throw null; } + public static System.Runtime.Intrinsics.Vector128 FusedMultiplyAdd(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right, System.Runtime.Intrinsics.Vector128 addend) { throw null; } public static T GetElement(this System.Runtime.Intrinsics.Vector128 vector, int index) { throw null; } public static System.Runtime.Intrinsics.Vector64 GetLower(this System.Runtime.Intrinsics.Vector128 vector) { throw null; } public static System.Runtime.Intrinsics.Vector64 GetUpper(this System.Runtime.Intrinsics.Vector128 vector) { throw null; } @@ -203,6 +205,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector128 vector, public static System.Runtime.Intrinsics.Vector128 Multiply(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } public static System.Runtime.Intrinsics.Vector128 Multiply(System.Runtime.Intrinsics.Vector128 left, T right) { throw null; } public static System.Runtime.Intrinsics.Vector128 Multiply(T left, System.Runtime.Intrinsics.Vector128 right) { throw null; } + public static System.Runtime.Intrinsics.Vector128 MultiplyAddEstimate(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right, System.Runtime.Intrinsics.Vector128 addend) { throw null; } + public static System.Runtime.Intrinsics.Vector128 MultiplyAddEstimate(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right, System.Runtime.Intrinsics.Vector128 addend) { throw null; } public static System.Runtime.Intrinsics.Vector128 Narrow(System.Runtime.Intrinsics.Vector128 lower, System.Runtime.Intrinsics.Vector128 upper) { throw null; } [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector128 Narrow(System.Runtime.Intrinsics.Vector128 lower, System.Runtime.Intrinsics.Vector128 upper) { throw null; } @@ -509,6 +513,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector256 vector, public static uint ExtractMostSignificantBits(this System.Runtime.Intrinsics.Vector256 vector) { throw null; } public static System.Runtime.Intrinsics.Vector256 Floor(System.Runtime.Intrinsics.Vector256 vector) { throw null; } public static System.Runtime.Intrinsics.Vector256 Floor(System.Runtime.Intrinsics.Vector256 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector256 FusedMultiplyAdd(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right, System.Runtime.Intrinsics.Vector256 addend) { throw null; } + public static System.Runtime.Intrinsics.Vector256 FusedMultiplyAdd(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right, System.Runtime.Intrinsics.Vector256 addend) { throw null; } public static T GetElement(this System.Runtime.Intrinsics.Vector256 vector, int index) { throw null; } public static System.Runtime.Intrinsics.Vector128 GetLower(this System.Runtime.Intrinsics.Vector256 vector) { throw null; } public static System.Runtime.Intrinsics.Vector128 GetUpper(this System.Runtime.Intrinsics.Vector256 vector) { throw null; } @@ -544,6 +550,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector256 vector, public static System.Runtime.Intrinsics.Vector256 Multiply(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } public static System.Runtime.Intrinsics.Vector256 Multiply(System.Runtime.Intrinsics.Vector256 left, T right) { throw null; } public static System.Runtime.Intrinsics.Vector256 Multiply(T left, System.Runtime.Intrinsics.Vector256 right) { throw null; } + public static System.Runtime.Intrinsics.Vector256 MultiplyAddEstimate(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right, System.Runtime.Intrinsics.Vector256 addend) { throw null; } + public static System.Runtime.Intrinsics.Vector256 MultiplyAddEstimate(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right, System.Runtime.Intrinsics.Vector256 addend) { throw null; } public static System.Runtime.Intrinsics.Vector256 Narrow(System.Runtime.Intrinsics.Vector256 lower, System.Runtime.Intrinsics.Vector256 upper) { throw null; } [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector256 Narrow(System.Runtime.Intrinsics.Vector256 lower, System.Runtime.Intrinsics.Vector256 upper) { throw null; } @@ -850,6 +858,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector512 vector, public static ulong ExtractMostSignificantBits(this System.Runtime.Intrinsics.Vector512 vector) { throw null; } public static System.Runtime.Intrinsics.Vector512 Floor(System.Runtime.Intrinsics.Vector512 vector) { throw null; } public static System.Runtime.Intrinsics.Vector512 Floor(System.Runtime.Intrinsics.Vector512 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector512 FusedMultiplyAdd(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right, System.Runtime.Intrinsics.Vector512 addend) { throw null; } + public static System.Runtime.Intrinsics.Vector512 FusedMultiplyAdd(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right, System.Runtime.Intrinsics.Vector512 addend) { throw null; } public static T GetElement(this System.Runtime.Intrinsics.Vector512 vector, int index) { throw null; } public static System.Runtime.Intrinsics.Vector256 GetLower(this System.Runtime.Intrinsics.Vector512 vector) { throw null; } public static System.Runtime.Intrinsics.Vector256 GetUpper(this System.Runtime.Intrinsics.Vector512 vector) { throw null; } @@ -885,6 +895,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector512 vector, public static System.Runtime.Intrinsics.Vector512 Multiply(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } public static System.Runtime.Intrinsics.Vector512 Multiply(System.Runtime.Intrinsics.Vector512 left, T right) { throw null; } public static System.Runtime.Intrinsics.Vector512 Multiply(T left, System.Runtime.Intrinsics.Vector512 right) { throw null; } + public static System.Runtime.Intrinsics.Vector512 MultiplyAddEstimate(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right, System.Runtime.Intrinsics.Vector512 addend) { throw null; } + public static System.Runtime.Intrinsics.Vector512 MultiplyAddEstimate(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right, System.Runtime.Intrinsics.Vector512 addend) { throw null; } public static System.Runtime.Intrinsics.Vector512 Narrow(System.Runtime.Intrinsics.Vector512 lower, System.Runtime.Intrinsics.Vector512 upper) { throw null; } [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector512 Narrow(System.Runtime.Intrinsics.Vector512 lower, System.Runtime.Intrinsics.Vector512 upper) { throw null; } @@ -1165,6 +1177,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector64 vector, public static uint ExtractMostSignificantBits(this System.Runtime.Intrinsics.Vector64 vector) { throw null; } public static System.Runtime.Intrinsics.Vector64 Floor(System.Runtime.Intrinsics.Vector64 vector) { throw null; } public static System.Runtime.Intrinsics.Vector64 Floor(System.Runtime.Intrinsics.Vector64 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector64 FusedMultiplyAdd(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right, System.Runtime.Intrinsics.Vector64 addend) { throw null; } + public static System.Runtime.Intrinsics.Vector64 FusedMultiplyAdd(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right, System.Runtime.Intrinsics.Vector64 addend) { throw null; } public static T GetElement(this System.Runtime.Intrinsics.Vector64 vector, int index) { throw null; } public static bool GreaterThanAll(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static bool GreaterThanAny(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } @@ -1198,6 +1212,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector64 vector, public static System.Runtime.Intrinsics.Vector64 Multiply(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static System.Runtime.Intrinsics.Vector64 Multiply(System.Runtime.Intrinsics.Vector64 left, T right) { throw null; } public static System.Runtime.Intrinsics.Vector64 Multiply(T left, System.Runtime.Intrinsics.Vector64 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 MultiplyAddEstimate(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right, System.Runtime.Intrinsics.Vector64 addend) { throw null; } + public static System.Runtime.Intrinsics.Vector64 MultiplyAddEstimate(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right, System.Runtime.Intrinsics.Vector64 addend) { throw null; } public static System.Runtime.Intrinsics.Vector64 Narrow(System.Runtime.Intrinsics.Vector64 lower, System.Runtime.Intrinsics.Vector64 upper) { throw null; } [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector64 Narrow(System.Runtime.Intrinsics.Vector64 lower, System.Runtime.Intrinsics.Vector64 upper) { throw null; } diff --git a/src/libraries/System.Runtime.Intrinsics/tests/System.Runtime.Intrinsics.Tests.csproj b/src/libraries/System.Runtime.Intrinsics/tests/System.Runtime.Intrinsics.Tests.csproj index f4dee9ab306cd1..b8fc0641259d47 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/System.Runtime.Intrinsics.Tests.csproj +++ b/src/libraries/System.Runtime.Intrinsics/tests/System.Runtime.Intrinsics.Tests.csproj @@ -13,7 +13,7 @@ - + diff --git a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs index d01939ec548f97..ce4f1d8fcf3e65 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs +++ b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs @@ -4874,6 +4874,38 @@ public void Log2SingleTest(float value, float expectedResult, float variance) AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Create(variance)); } + [Theory] + [MemberData(nameof(VectorTestMemberData.MultiplyAddDouble), MemberType = typeof(VectorTestMemberData))] + public void FusedMultiplyAddDoubleTest(double left, double right, double addend) + { + Vector128 actualResult = Vector128.FusedMultiplyAdd(Vector128.Create(left), Vector128.Create(right), Vector128.Create(addend)); + AssertEqual(Vector128.Create(double.FusedMultiplyAdd(left, right, addend)), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + public void FusedMultiplyAddSingleTest(float left, float right, float addend) + { + Vector128 actualResult = Vector128.FusedMultiplyAdd(Vector128.Create(left), Vector128.Create(right), Vector128.Create(addend)); + AssertEqual(Vector128.Create(float.FusedMultiplyAdd(left, right, addend)), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(VectorTestMemberData.MultiplyAddDouble), MemberType = typeof(VectorTestMemberData))] + public void MultiplyAddEstimateDoubleTest(double left, double right, double addend) + { + Vector128 actualResult = Vector128.MultiplyAddEstimate(Vector128.Create(left), Vector128.Create(right), Vector128.Create(addend)); + AssertEqual(Vector128.Create(double.MultiplyAddEstimate(left, right, addend)), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + public void MultiplyAddEstimateSingleTest(float left, float right, float addend) + { + Vector128 actualResult = Vector128.MultiplyAddEstimate(Vector128.Create(left), Vector128.Create(right), Vector128.Create(addend)); + AssertEqual(Vector128.Create(float.MultiplyAddEstimate(left, right, addend)), actualResult, Vector128.Zero); + } + [Fact] [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] public void ConvertToInt32Test() diff --git a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector256Tests.cs b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector256Tests.cs index d3698db4e5b23d..d264cd47771208 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector256Tests.cs +++ b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector256Tests.cs @@ -5889,6 +5889,38 @@ public void Log2SingleTest(float value, float expectedResult, float variance) AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Create(variance)); } + [Theory] + [MemberData(nameof(VectorTestMemberData.MultiplyAddDouble), MemberType = typeof(VectorTestMemberData))] + public void FusedMultiplyAddDoubleTest(double left, double right, double addend) + { + Vector256 actualResult = Vector256.FusedMultiplyAdd(Vector256.Create(left), Vector256.Create(right), Vector256.Create(addend)); + AssertEqual(Vector256.Create(double.FusedMultiplyAdd(left, right, addend)), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + public void FusedMultiplyAddSingleTest(float left, float right, float addend) + { + Vector256 actualResult = Vector256.FusedMultiplyAdd(Vector256.Create(left), Vector256.Create(right), Vector256.Create(addend)); + AssertEqual(Vector256.Create(float.FusedMultiplyAdd(left, right, addend)), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(VectorTestMemberData.MultiplyAddDouble), MemberType = typeof(VectorTestMemberData))] + public void MultiplyAddEstimateDoubleTest(double left, double right, double addend) + { + Vector256 actualResult = Vector256.MultiplyAddEstimate(Vector256.Create(left), Vector256.Create(right), Vector256.Create(addend)); + AssertEqual(Vector256.Create(double.MultiplyAddEstimate(left, right, addend)), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + public void MultiplyAddEstimateSingleTest(float left, float right, float addend) + { + Vector256 actualResult = Vector256.MultiplyAddEstimate(Vector256.Create(left), Vector256.Create(right), Vector256.Create(addend)); + AssertEqual(Vector256.Create(float.MultiplyAddEstimate(left, right, addend)), actualResult, Vector256.Zero); + } + [Fact] [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] public void ConvertToInt32Test() diff --git a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector512Tests.cs b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector512Tests.cs index f4cbb180fce9f1..93ecf183070ecb 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector512Tests.cs +++ b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector512Tests.cs @@ -5322,6 +5322,38 @@ public void Log2SingleTest(float value, float expectedResult, float variance) AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Create(variance)); } + [Theory] + [MemberData(nameof(VectorTestMemberData.MultiplyAddDouble), MemberType = typeof(VectorTestMemberData))] + public void FusedMultiplyAddDoubleTest(double left, double right, double addend) + { + Vector512 actualResult = Vector512.FusedMultiplyAdd(Vector512.Create(left), Vector512.Create(right), Vector512.Create(addend)); + AssertEqual(Vector512.Create(double.FusedMultiplyAdd(left, right, addend)), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + public void FusedMultiplyAddSingleTest(float left, float right, float addend) + { + Vector512 actualResult = Vector512.FusedMultiplyAdd(Vector512.Create(left), Vector512.Create(right), Vector512.Create(addend)); + AssertEqual(Vector512.Create(float.FusedMultiplyAdd(left, right, addend)), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(VectorTestMemberData.MultiplyAddDouble), MemberType = typeof(VectorTestMemberData))] + public void MultiplyAddEstimateDoubleTest(double left, double right, double addend) + { + Vector512 actualResult = Vector512.MultiplyAddEstimate(Vector512.Create(left), Vector512.Create(right), Vector512.Create(addend)); + AssertEqual(Vector512.Create(double.MultiplyAddEstimate(left, right, addend)), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + public void MultiplyAddEstimateSingleTest(float left, float right, float addend) + { + Vector512 actualResult = Vector512.MultiplyAddEstimate(Vector512.Create(left), Vector512.Create(right), Vector512.Create(addend)); + AssertEqual(Vector512.Create(float.MultiplyAddEstimate(left, right, addend)), actualResult, Vector512.Zero); + } + [Fact] [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] public void ConvertToInt32Test() diff --git a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector64Tests.cs b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector64Tests.cs index 18c1d3b05af17a..c42580263a038f 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector64Tests.cs +++ b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector64Tests.cs @@ -4289,6 +4289,38 @@ public void Log2SingleTest(float value, float expectedResult, float variance) AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Create(variance)); } + [Theory] + [MemberData(nameof(VectorTestMemberData.MultiplyAddDouble), MemberType = typeof(VectorTestMemberData))] + public void FusedMultiplyAddDoubleTest(double left, double right, double addend) + { + Vector64 actualResult = Vector64.FusedMultiplyAdd(Vector64.Create(left), Vector64.Create(right), Vector64.Create(addend)); + AssertEqual(Vector64.Create(double.FusedMultiplyAdd(left, right, addend)), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + public void FusedMultiplyAddSingleTest(float left, float right, float addend) + { + Vector64 actualResult = Vector64.FusedMultiplyAdd(Vector64.Create(left), Vector64.Create(right), Vector64.Create(addend)); + AssertEqual(Vector64.Create(float.FusedMultiplyAdd(left, right, addend)), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(VectorTestMemberData.MultiplyAddDouble), MemberType = typeof(VectorTestMemberData))] + public void MultiplyAddEstimateDoubleTest(double left, double right, double addend) + { + Vector64 actualResult = Vector64.MultiplyAddEstimate(Vector64.Create(left), Vector64.Create(right), Vector64.Create(addend)); + AssertEqual(Vector64.Create(double.MultiplyAddEstimate(left, right, addend)), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + public void MultiplyAddEstimateSingleTest(float left, float right, float addend) + { + Vector64 actualResult = Vector64.MultiplyAddEstimate(Vector64.Create(left), Vector64.Create(right), Vector64.Create(addend)); + AssertEqual(Vector64.Create(float.MultiplyAddEstimate(left, right, addend)), actualResult, Vector64.Zero); + } + [Fact] [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] public void ConvertToInt32Test() diff --git a/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs b/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs index eb870ed17e3d5d..5ac9e6237bea3e 100644 --- a/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs +++ b/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs @@ -215,6 +215,7 @@ namespace System.Numerics static bool System.Numerics.INumberBase.IsZero(System.Numerics.BigInteger value) { throw null; } static System.Numerics.BigInteger System.Numerics.INumberBase.MaxMagnitudeNumber(System.Numerics.BigInteger x, System.Numerics.BigInteger y) { throw null; } static System.Numerics.BigInteger System.Numerics.INumberBase.MinMagnitudeNumber(System.Numerics.BigInteger x, System.Numerics.BigInteger y) { throw null; } + static System.Numerics.BigInteger System.Numerics.INumberBase.MultiplyAddEstimate(System.Numerics.BigInteger left, System.Numerics.BigInteger right, System.Numerics.BigInteger addend) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromChecked(TOther value, out System.Numerics.BigInteger result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromSaturating(TOther value, out System.Numerics.BigInteger result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromTruncating(TOther value, out System.Numerics.BigInteger result) { throw null; } @@ -364,6 +365,7 @@ namespace System.Numerics static bool System.Numerics.INumberBase.IsZero(System.Numerics.Complex value) { throw null; } static System.Numerics.Complex System.Numerics.INumberBase.MaxMagnitudeNumber(System.Numerics.Complex x, System.Numerics.Complex y) { throw null; } static System.Numerics.Complex System.Numerics.INumberBase.MinMagnitudeNumber(System.Numerics.Complex x, System.Numerics.Complex y) { throw null; } + static System.Numerics.Complex System.Numerics.INumberBase.MultiplyAddEstimate(System.Numerics.Complex left, System.Numerics.Complex right, System.Numerics.Complex addend) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromChecked(TOther value, out System.Numerics.Complex result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromSaturating(TOther value, out System.Numerics.Complex result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromTruncating(TOther value, out System.Numerics.Complex result) { throw null; } diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs index 62fc443b8d4bc6..2ca6c7a1bf5ab3 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs @@ -4138,6 +4138,9 @@ public static BigInteger MinMagnitude(BigInteger x, BigInteger y) /// static BigInteger INumberBase.MinMagnitudeNumber(BigInteger x, BigInteger y) => MinMagnitude(x, y); + /// + static BigInteger INumberBase.MultiplyAddEstimate(BigInteger left, BigInteger right, BigInteger addend) => (left * right) + addend; + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] static bool INumberBase.TryConvertFromChecked(TOther value, out BigInteger result) => TryConvertFromChecked(value, out result); diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Complex.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Complex.cs index 88f8ef25fe205b..8d6b7abbfdbd9b 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Complex.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Complex.cs @@ -1466,6 +1466,23 @@ static Complex INumberBase.MinMagnitudeNumber(Complex x, Complex y) return y; } + /// + static Complex INumberBase.MultiplyAddEstimate(Complex left, Complex right, Complex addend) + { + // Multiplication: (a + bi)(c + di) = (ac - bd) + (bc + ad)i + // Addition: (a + bi) + (c + di) = (a + c) + (b + d)i + + double result_realpart = addend.m_real; + result_realpart = double.MultiplyAddEstimate(-left.m_imaginary, right.m_imaginary, result_realpart); + result_realpart = double.MultiplyAddEstimate(left.m_real, right.m_real, result_realpart); + + double result_imaginarypart = addend.m_imaginary; + result_imaginarypart = double.MultiplyAddEstimate(left.m_real, right.m_imaginary, result_imaginarypart); + result_imaginarypart = double.MultiplyAddEstimate(left.m_imaginary, right.m_real, result_imaginarypart); + + return new Complex(result_realpart, result_imaginarypart); + } + /// public static Complex Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider) { diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 0c2d57c8f5eafd..dc231ad5101a23 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -876,6 +876,7 @@ public static void SetByte(System.Array array, int index, byte value) { } static byte System.Numerics.INumberBase.MaxMagnitudeNumber(byte x, byte y) { throw null; } static byte System.Numerics.INumberBase.MinMagnitude(byte x, byte y) { throw null; } static byte System.Numerics.INumberBase.MinMagnitudeNumber(byte x, byte y) { throw null; } + static byte System.Numerics.INumberBase.MultiplyAddEstimate(byte left, byte right, byte addend) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromChecked(TOther value, out byte result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromSaturating(TOther value, out byte result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromTruncating(TOther value, out byte result) { throw null; } @@ -1063,6 +1064,7 @@ public CannotUnloadAppDomainException(string? message, System.Exception? innerEx static char System.Numerics.INumberBase.MaxMagnitudeNumber(char x, char y) { throw null; } static char System.Numerics.INumberBase.MinMagnitude(char x, char y) { throw null; } static char System.Numerics.INumberBase.MinMagnitudeNumber(char x, char y) { throw null; } + static char System.Numerics.INumberBase.MultiplyAddEstimate(char left, char right, char addend) { throw null; } static char System.Numerics.INumberBase.Parse(System.ReadOnlySpan s, System.Globalization.NumberStyles style, System.IFormatProvider? provider) { throw null; } static char System.Numerics.INumberBase.Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider? provider) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromChecked(TOther value, out char result) { throw null; } @@ -2111,6 +2113,7 @@ public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, S static bool System.Numerics.INumberBase.IsZero(decimal value) { throw null; } static decimal System.Numerics.INumberBase.MaxMagnitudeNumber(decimal x, decimal y) { throw null; } static decimal System.Numerics.INumberBase.MinMagnitudeNumber(decimal x, decimal y) { throw null; } + static decimal System.Numerics.INumberBase.MultiplyAddEstimate(decimal left, decimal right, decimal addend) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromChecked(TOther value, out decimal result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromSaturating(TOther value, out decimal result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromTruncating(TOther value, out decimal result) { throw null; } @@ -2318,6 +2321,7 @@ public DivideByZeroException(string? message, System.Exception? innerException) public static double MinMagnitude(double x, double y) { throw null; } public static double MinMagnitudeNumber(double x, double y) { throw null; } public static double MinNumber(double x, double y) { throw null; } + public static double MultiplyAddEstimate(double left, double right, double addend) { throw null; } public static bool operator ==(double left, double right) { throw null; } public static bool operator >(double left, double right) { throw null; } public static bool operator >=(double left, double right) { throw null; } @@ -2941,6 +2945,7 @@ public enum GCNotificationStatus public static System.Half MinMagnitude(System.Half x, System.Half y) { throw null; } public static System.Half MinMagnitudeNumber(System.Half x, System.Half y) { throw null; } public static System.Half MinNumber(System.Half x, System.Half y) { throw null; } + public static System.Half MultiplyAddEstimate(System.Half left, System.Half right, System.Half addend) { throw null; } public static System.Half operator +(System.Half left, System.Half right) { throw null; } public static explicit operator checked byte (System.Half value) { throw null; } public static explicit operator checked char (System.Half value) { throw null; } @@ -3364,6 +3369,7 @@ public InsufficientMemoryException(string? message, System.Exception? innerExcep static bool System.Numerics.INumberBase.IsZero(System.Int128 value) { throw null; } static System.Int128 System.Numerics.INumberBase.MaxMagnitudeNumber(System.Int128 x, System.Int128 y) { throw null; } static System.Int128 System.Numerics.INumberBase.MinMagnitudeNumber(System.Int128 x, System.Int128 y) { throw null; } + static System.Int128 System.Numerics.INumberBase.MultiplyAddEstimate(System.Int128 left, System.Int128 right, System.Int128 addend) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromChecked(TOther value, out System.Int128 result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromSaturating(TOther value, out System.Int128 result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromTruncating(TOther value, out System.Int128 result) { throw null; } @@ -3495,6 +3501,7 @@ public InsufficientMemoryException(string? message, System.Exception? innerExcep static bool System.Numerics.INumberBase.IsZero(short value) { throw null; } static short System.Numerics.INumberBase.MaxMagnitudeNumber(short x, short y) { throw null; } static short System.Numerics.INumberBase.MinMagnitudeNumber(short x, short y) { throw null; } + static short System.Numerics.INumberBase.MultiplyAddEstimate(short left, short right, short addend) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromChecked(TOther value, out short result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromSaturating(TOther value, out short result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromTruncating(TOther value, out short result) { throw null; } @@ -3634,6 +3641,7 @@ public InsufficientMemoryException(string? message, System.Exception? innerExcep static bool System.Numerics.INumberBase.IsZero(int value) { throw null; } static int System.Numerics.INumberBase.MaxMagnitudeNumber(int x, int y) { throw null; } static int System.Numerics.INumberBase.MinMagnitudeNumber(int x, int y) { throw null; } + static int System.Numerics.INumberBase.MultiplyAddEstimate(int left, int right, int addend) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromChecked(TOther value, out int result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromSaturating(TOther value, out int result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromTruncating(TOther value, out int result) { throw null; } @@ -3773,6 +3781,7 @@ public InsufficientMemoryException(string? message, System.Exception? innerExcep static bool System.Numerics.INumberBase.IsZero(long value) { throw null; } static long System.Numerics.INumberBase.MaxMagnitudeNumber(long x, long y) { throw null; } static long System.Numerics.INumberBase.MinMagnitudeNumber(long x, long y) { throw null; } + static long System.Numerics.INumberBase.MultiplyAddEstimate(long left, long right, long addend) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromChecked(TOther value, out long result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromSaturating(TOther value, out long result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromTruncating(TOther value, out long result) { throw null; } @@ -3914,6 +3923,7 @@ public InsufficientMemoryException(string? message, System.Exception? innerExcep static bool System.Numerics.INumberBase.IsZero(nint value) { throw null; } static nint System.Numerics.INumberBase.MaxMagnitudeNumber(nint x, nint y) { throw null; } static nint System.Numerics.INumberBase.MinMagnitudeNumber(nint x, nint y) { throw null; } + static nint System.Numerics.INumberBase.MultiplyAddEstimate(nint left, nint right, nint addend) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromChecked(TOther value, out nint result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromSaturating(TOther value, out nint result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromTruncating(TOther value, out nint result) { throw null; } @@ -4918,6 +4928,7 @@ public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, S static bool System.Numerics.INumberBase.IsZero(sbyte value) { throw null; } static sbyte System.Numerics.INumberBase.MaxMagnitudeNumber(sbyte x, sbyte y) { throw null; } static sbyte System.Numerics.INumberBase.MinMagnitudeNumber(sbyte x, sbyte y) { throw null; } + static sbyte System.Numerics.INumberBase.MultiplyAddEstimate(sbyte left, sbyte right, sbyte addend) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromChecked(TOther value, out sbyte result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromSaturating(TOther value, out sbyte result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromTruncating(TOther value, out sbyte result) { throw null; } @@ -5061,6 +5072,7 @@ public SerializableAttribute() { } public static float MinMagnitude(float x, float y) { throw null; } public static float MinMagnitudeNumber(float x, float y) { throw null; } public static float MinNumber(float x, float y) { throw null; } + public static float MultiplyAddEstimate(float left, float right, float addend) { throw null; } public static bool operator ==(float left, float right) { throw null; } public static bool operator >(float left, float right) { throw null; } public static bool operator >=(float left, float right) { throw null; } @@ -6575,6 +6587,7 @@ public TypeUnloadedException(string? message, System.Exception? innerException) static System.UInt128 System.Numerics.INumberBase.MaxMagnitudeNumber(System.UInt128 x, System.UInt128 y) { throw null; } static System.UInt128 System.Numerics.INumberBase.MinMagnitude(System.UInt128 x, System.UInt128 y) { throw null; } static System.UInt128 System.Numerics.INumberBase.MinMagnitudeNumber(System.UInt128 x, System.UInt128 y) { throw null; } + static System.UInt128 System.Numerics.INumberBase.MultiplyAddEstimate(System.UInt128 left, System.UInt128 right, System.UInt128 addend) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromChecked(TOther value, out System.UInt128 result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromSaturating(TOther value, out System.UInt128 result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromTruncating(TOther value, out System.UInt128 result) { throw null; } @@ -6706,6 +6719,7 @@ public TypeUnloadedException(string? message, System.Exception? innerException) static ushort System.Numerics.INumberBase.MaxMagnitudeNumber(ushort x, ushort y) { throw null; } static ushort System.Numerics.INumberBase.MinMagnitude(ushort x, ushort y) { throw null; } static ushort System.Numerics.INumberBase.MinMagnitudeNumber(ushort x, ushort y) { throw null; } + static ushort System.Numerics.INumberBase.MultiplyAddEstimate(ushort left, ushort right, ushort addend) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromChecked(TOther value, out ushort result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromSaturating(TOther value, out ushort result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromTruncating(TOther value, out ushort result) { throw null; } @@ -6845,6 +6859,7 @@ public TypeUnloadedException(string? message, System.Exception? innerException) static uint System.Numerics.INumberBase.MaxMagnitudeNumber(uint x, uint y) { throw null; } static uint System.Numerics.INumberBase.MinMagnitude(uint x, uint y) { throw null; } static uint System.Numerics.INumberBase.MinMagnitudeNumber(uint x, uint y) { throw null; } + static uint System.Numerics.INumberBase.MultiplyAddEstimate(uint left, uint right, uint addend) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromChecked(TOther value, out uint result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromSaturating(TOther value, out uint result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromTruncating(TOther value, out uint result) { throw null; } @@ -6984,6 +6999,7 @@ public TypeUnloadedException(string? message, System.Exception? innerException) static ulong System.Numerics.INumberBase.MaxMagnitudeNumber(ulong x, ulong y) { throw null; } static ulong System.Numerics.INumberBase.MinMagnitude(ulong x, ulong y) { throw null; } static ulong System.Numerics.INumberBase.MinMagnitudeNumber(ulong x, ulong y) { throw null; } + static ulong System.Numerics.INumberBase.MultiplyAddEstimate(ulong left, ulong right, ulong addend) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromChecked(TOther value, out ulong result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromSaturating(TOther value, out ulong result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromTruncating(TOther value, out ulong result) { throw null; } @@ -7122,6 +7138,7 @@ public TypeUnloadedException(string? message, System.Exception? innerException) static nuint System.Numerics.INumberBase.MaxMagnitudeNumber(nuint x, nuint y) { throw null; } static nuint System.Numerics.INumberBase.MinMagnitude(nuint x, nuint y) { throw null; } static nuint System.Numerics.INumberBase.MinMagnitudeNumber(nuint x, nuint y) { throw null; } + static nuint System.Numerics.INumberBase.MultiplyAddEstimate(nuint left, nuint right, nuint addend) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromChecked(TOther value, out nuint result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromSaturating(TOther value, out nuint result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromTruncating(TOther value, out nuint result) { throw null; } @@ -10929,6 +10946,7 @@ static virtual TSelf CreateTruncating(TOther value) static abstract TSelf MaxMagnitudeNumber(TSelf x, TSelf y); static abstract TSelf MinMagnitude(TSelf x, TSelf y); static abstract TSelf MinMagnitudeNumber(TSelf x, TSelf y); + static virtual TSelf MultiplyAddEstimate(TSelf left, TSelf right, TSelf addend) { throw null; } static virtual TSelf Parse(System.ReadOnlySpan utf8Text, System.Globalization.NumberStyles style, System.IFormatProvider? provider) { throw null; } static abstract TSelf Parse(System.ReadOnlySpan s, System.Globalization.NumberStyles style, System.IFormatProvider? provider); static abstract TSelf Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider? provider);