diff --git a/src/coreclr/jit/ifconversion.cpp b/src/coreclr/jit/ifconversion.cpp index 51636fe614809b..1f18ea9ccf7913 100644 --- a/src/coreclr/jit/ifconversion.cpp +++ b/src/coreclr/jit/ifconversion.cpp @@ -56,6 +56,7 @@ class OptIfConversionDsc GenTree* TrySelectToCnsOpCond(GenTreeConditional* select); GenTree* TrySelectToLclOpCond(GenTreeConditional* select); GenTree* TrySelectToCondOpLcl(GenTreeConditional* select); + GenTree* TrySelectToMinMax(GenTreeConditional* select); #ifdef DEBUG void IfConvertDump(); @@ -205,7 +206,7 @@ bool OptIfConversionDsc::IfConvertCheckStmts(BasicBlock* block, IfConvertOperati } // Ensure the operation has integer type. - if (!varTypeIsIntegralOrI(tree)) + if (!varTypeIsIntegralOrI(tree) && !varTypeIsFloating(tree)) { return false; } @@ -636,14 +637,20 @@ bool OptIfConversionDsc::optIfConvert(int* pReachabilityBudget) } } -#ifdef TARGET_RISCV64 if (select->OperIs(GT_SELECT)) { +#ifdef TARGET_RISCV64 JITDUMP("Skipping if-conversion that could not be optimized to ordinary operations\n"); return true; - } #endif + // We only produce float SELECTs for optimization into non-SELECTs, otherwise bail + if (varTypeIsFloating(select)) + { + return true; + } + } + // Use the SELECT as the source of the Then STORE/RETURN. m_thenOperation.node->AddAllEffectsFlags(select); if (m_mainOper == GT_STORE_LCL_VAR) @@ -739,6 +746,12 @@ GenTree* OptIfConversionDsc::TryOptimizeSelect(GenTreeConditional* select) return opt; } + opt = TrySelectToMinMax(select); + if (opt != nullptr) + { + return opt; + } + return nullptr; } @@ -960,6 +973,47 @@ GenTree* OptIfConversionDsc::TrySelectToCondOpLcl(GenTreeConditional* select) return nullptr; } +GenTree* OptIfConversionDsc::TrySelectToMinMax(GenTreeConditional* select) +{ +#ifdef TARGET_XARCH + GenTree* condInput = select->gtCond; + GenTree* trueInput = select->gtOp1; + GenTree* falseInput = select->gtOp2; + + if (!varTypeIsFloating(select) || !varTypeIsFloating(condInput->gtGetOp1()) || + !varTypeIsFloating(condInput->gtGetOp2())) + { + return nullptr; + } + + GenCondition cond = GenCondition::FromFloatRelop(condInput); + if (cond.IsUnordered() || !cond.Is(GenCondition::Code::FLT, GenCondition::Code::FGT)) + { + return nullptr; + } + + bool isMax = cond.Is(GenCondition::Code::FGT); + bool reversed = !GenTree::Compare(trueInput, condInput->gtGetOp1()); + if (reversed) + { + // 'return a > b ? b : a;' has a GT but computes the min + isMax = !isMax; + std::swap(trueInput, falseInput); + } + + if (GenTree::Compare(trueInput, condInput->gtGetOp1()) && + GenTree::Compare(falseInput, condInput->gtGetOp2()->gtEffectiveVal())) + { + return m_compiler->gtNewSimdMinMaxNativeNode(select->TypeGet(), + reversed ? condInput->gtGetOp2() : condInput->gtGetOp1(), + reversed ? condInput->gtGetOp1() : condInput->gtGetOp2(), + select->TypeGet(), 0, isMax); + } + +#endif + return nullptr; +} + //----------------------------------------------------------------------------- // optIfConversion: If conversion //