@@ -4515,49 +4515,35 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
45154515 case NI_System_Math_Log:
45164516 case NI_System_Math_Log2:
45174517 case NI_System_Math_Log10:
4518- #if defined TARGET_ARM64 || defined TARGET_XARCH
4518+ #if defined TARGET_ARM64
45194519 // ARM64 has fmax/fmin which are IEEE754:2019 minimum/maximum compatible
45204520 // TODO-XARCH-CQ: Enable this for XARCH when one of the arguments is a constant
45214521 // so we can then emit maxss/minss and avoid NaN/-0.0 handling
45224522 case NI_System_Math_Max:
45234523 case NI_System_Math_Min:
4524- {
4525- #if defined FEATURE_HW_INTRINSICS && defined TARGET_XARCH
4524+ #endif
45264525
4526+ #if defined FEATURE_HW_INTRINSICS && defined TARGET_XARCH
4527+ case NI_System_Math_Max:
4528+ case NI_System_Math_Min:
4529+ {
45274530 assert(varTypeIsFloating(callType));
45284531
4529- GenTree* op2 = impStackTop(0).val;
4530- GenTree* op1 = impStackTop(1).val;
4531-
4532- if (false && (op2->IsCnsFltOrDbl() || op1->IsCnsFltOrDbl()))
4532+ if (sig->numArgs == 2 && (impStackTop().val->IsCnsFltOrDbl() || impStackTop(1).val->IsCnsFltOrDbl()))
45334533 {
4534- op2 = impPopStack().val;
4535- op1 = impPopStack().val;
4534+ GenTree* op2 = impPopStack().val;
4535+ GenTree* op1 = impPopStack().val;
45364536
4537- var_types insType;
4538- unsigned int insSimdSize;
4539- NamedIntrinsic hwintrinsicName;
4540-
4541- if (callType == TYP_DOUBLE)
4542- {
4543- insType = TYP_SIMD32;
4544- insSimdSize = 32;
4545- hwintrinsicName = (ni == NI_System_Math_Max) ? NI_SSE2_Max: NI_SSE2_Min;
4546- }
4547- else
4548- {
4549- insType = TYP_SIMD16;
4550- insSimdSize = 16;
4551- hwintrinsicName = (ni == NI_System_Math_Max) ? NI_SSE_Max : NI_SSE_Min;
4552- }
4537+ unsigned int insSimdSize = (callType == TYP_DOUBLE) ? 32 : 16;
45534538
45544539 // IEEE 754 spec requires:
45554540 // 1. If both operands are 0 of either sign
4556- // 2. If either of operands is NaN handles (if both operands are NaN) too
4557- // 3. If either of operands is (-0.0) and instructions is Math.Min
4558- // 3. If either of operands is (+0.0) and instructions is Math.Max
4541+ // IsFloatPositiveZero is used for both operands, because the sign doesn't matter
4542+ // 2. If either of operands is NaN (handles if both operands are NaN too)
4543+ // 3. If either of operands is (-0.0) and an instruction is Math.Min
4544+ // 3. If either of operands is (+0.0) and an instruction is Math.Max
45594545 // Then op2 is returned;
4560- if ((op1->IsFloatPositiveZero() && op2->IsFloatPositiveZero()) ||
4546+ if ((op1->IsFloatPositiveZero() && op2->IsFloatPositiveZero()) ||
45614547 (op1->IsFloatNaN() || op2->IsFloatNaN()) ||
45624548 (ni == NI_System_Math_Min && (op1->IsFloatNegativeZero() || op2->IsFloatNegativeZero())) ||
45634549 (ni == NI_System_Math_Max && (op1->IsFloatPositiveZero() || op2->IsFloatPositiveZero())))
@@ -4567,19 +4553,16 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
45674553 break;
45684554 }
45694555
4570- op2 = gtNewSimdHWIntrinsicNode(insType, op2, NI_Vector128_CreateScalarUnsafe, callJitType, insSimdSize);
4571- op1 = gtNewSimdHWIntrinsicNode(insType, op1, NI_Vector128_CreateScalarUnsafe, callJitType, insSimdSize);
4572-
4573- GenTree* res = gtNewSimdHWIntrinsicNode(insType, op1, op2, hwintrinsicName, callJitType, insSimdSize);
4574- retNode = gtNewSimdHWIntrinsicNode(callType, res, NI_Vector128_ToScalar, callJitType, insSimdSize);
4556+ // If it's any other constant then it needs to be op1 for both (Math.Min/Math.Max).
4557+ retNode = gtNewSimdHWIntrinsicNode(callType, op1, NI_Vector128_ToScalar, callJitType, insSimdSize);
45754558 break;
45764559 }
45774560
4561+ // Go down to the direct Math.Min/Math.Max call
45784562 break;
4579-
4580- #endif
45814563 }
45824564#endif
4565+
45834566 case NI_System_Math_Pow:
45844567 case NI_System_Math_Round:
45854568 case NI_System_Math_Sin:
0 commit comments