From 218fc5e8fafd7d4df7c1cc43195e6f58a4479d3a Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Sun, 22 Feb 2026 23:38:00 +0100 Subject: [PATCH 01/14] * look for previous unconditional store and treat it as else --- src/coreclr/jit/ifconversion.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/coreclr/jit/ifconversion.cpp b/src/coreclr/jit/ifconversion.cpp index 0acda646e0d9e6..75be182e2d8c57 100644 --- a/src/coreclr/jit/ifconversion.cpp +++ b/src/coreclr/jit/ifconversion.cpp @@ -366,6 +366,11 @@ bool OptIfConversionDsc::IfConvertCheckStmts(BasicBlock* fromBlock, IfConvertOpe // void OptIfConversionDsc::IfConvertJoinStmts(BasicBlock* fromBlock) { + if (fromBlock == m_startBlock) + { + return; + } + Statement* stmtList1 = m_startBlock->firstStmt(); Statement* stmtList2 = fromBlock->firstStmt(); Statement* stmtLast1 = m_startBlock->lastStmt(); @@ -696,6 +701,27 @@ bool OptIfConversionDsc::optIfConvert(int* pReachabilityBudget) GenTree* selectFalseInput; if (m_mainOper == GT_STORE_LCL_VAR) { + if (!m_doElseConversion) + { + // Look for a previous unconditional store to the same lclVar which is equivalent to an else case + Statement* last = m_startBlock->lastStmt(); + unsigned lclNum = m_thenOperation.node->AsLclVar()->GetLclNum(); + + for (Statement* stmt = last->GetPrevStmt(); stmt != last; stmt = stmt->GetPrevStmt()) + { + GenTree* tree = stmt->GetRootNode(); + if (tree->OperIs(GT_STORE_LCL_VAR) && (tree->AsLclVar()->GetLclNum() == lclNum)) + { + m_doElseConversion = true; + m_elseOperation.block = m_startBlock; + m_elseOperation.stmt = stmt; + m_elseOperation.node = tree; + + break; + } + } + } + selectFalseInput = m_thenOperation.node->AsLclVar()->Data(); selectTrueInput = m_doElseConversion ? m_elseOperation.node->AsLclVar()->Data() : nullptr; From aad43762f6aecbc88708b557426479879ba49a0c Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Sun, 22 Feb 2026 23:41:16 +0100 Subject: [PATCH 02/14] * update comment --- src/coreclr/jit/ifconversion.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/ifconversion.cpp b/src/coreclr/jit/ifconversion.cpp index 75be182e2d8c57..70fd57e4fb2bea 100644 --- a/src/coreclr/jit/ifconversion.cpp +++ b/src/coreclr/jit/ifconversion.cpp @@ -703,7 +703,7 @@ bool OptIfConversionDsc::optIfConvert(int* pReachabilityBudget) { if (!m_doElseConversion) { - // Look for a previous unconditional store to the same lclVar which is equivalent to an else case + // If we don't have an else case look for a previous unconditional store and treat that as the else Statement* last = m_startBlock->lastStmt(); unsigned lclNum = m_thenOperation.node->AsLclVar()->GetLclNum(); From 66a710c69da7e6e36ffcb721e85cdf1ee31c42f9 Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Mon, 23 Feb 2026 03:49:03 +0100 Subject: [PATCH 03/14] * check for side effects --- src/coreclr/jit/ifconversion.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/coreclr/jit/ifconversion.cpp b/src/coreclr/jit/ifconversion.cpp index 70fd57e4fb2bea..c27e31b4be7fe2 100644 --- a/src/coreclr/jit/ifconversion.cpp +++ b/src/coreclr/jit/ifconversion.cpp @@ -710,12 +710,17 @@ bool OptIfConversionDsc::optIfConvert(int* pReachabilityBudget) for (Statement* stmt = last->GetPrevStmt(); stmt != last; stmt = stmt->GetPrevStmt()) { GenTree* tree = stmt->GetRootNode(); - if (tree->OperIs(GT_STORE_LCL_VAR) && (tree->AsLclVar()->GetLclNum() == lclNum)) + if (tree->OperIs(GT_STORE_LCL_VAR)) { - m_doElseConversion = true; - m_elseOperation.block = m_startBlock; - m_elseOperation.stmt = stmt; - m_elseOperation.node = tree; + GenTree* val = tree->AsLclVar()->Data(); + + if ((val->gtFlags & (GTF_SIDE_EFFECT | GTF_ORDER_SIDEEFF)) == 0) + { + m_doElseConversion = true; + m_elseOperation.block = m_startBlock; + m_elseOperation.stmt = stmt; + m_elseOperation.node = tree; + } break; } From 19846af331b1b25a4783eedcdb13186cfbb994d6 Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Mon, 23 Feb 2026 05:35:02 +0100 Subject: [PATCH 04/14] * fix bug where substitution was done even when JTRUE depends on the lclVar --- src/coreclr/jit/ifconversion.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/ifconversion.cpp b/src/coreclr/jit/ifconversion.cpp index c27e31b4be7fe2..1cc67353750571 100644 --- a/src/coreclr/jit/ifconversion.cpp +++ b/src/coreclr/jit/ifconversion.cpp @@ -714,7 +714,9 @@ bool OptIfConversionDsc::optIfConvert(int* pReachabilityBudget) { GenTree* val = tree->AsLclVar()->Data(); - if ((val->gtFlags & (GTF_SIDE_EFFECT | GTF_ORDER_SIDEEFF)) == 0) + bool noSideEffects = (val->gtFlags & (GTF_SIDE_EFFECT | GTF_ORDER_SIDEEFF)) == 0; + bool condDependsOnLclVar = m_compiler->gtHasRef(m_cond, lclNum); + if (noSideEffects && !condDependsOnLclVar) { m_doElseConversion = true; m_elseOperation.block = m_startBlock; From bacd2dcbbaf68f9870ec81a3703acdb34266a743 Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Tue, 24 Feb 2026 02:47:10 +0100 Subject: [PATCH 05/14] * also ignore cases where lclVar is used in store --- src/coreclr/jit/ifconversion.cpp | 47 ++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/src/coreclr/jit/ifconversion.cpp b/src/coreclr/jit/ifconversion.cpp index 1cc67353750571..da33859bc852e5 100644 --- a/src/coreclr/jit/ifconversion.cpp +++ b/src/coreclr/jit/ifconversion.cpp @@ -703,28 +703,39 @@ bool OptIfConversionDsc::optIfConvert(int* pReachabilityBudget) { if (!m_doElseConversion) { - // If we don't have an else case look for a previous unconditional store and treat that as the else - Statement* last = m_startBlock->lastStmt(); - unsigned lclNum = m_thenOperation.node->AsLclVar()->GetLclNum(); - - for (Statement* stmt = last->GetPrevStmt(); stmt != last; stmt = stmt->GetPrevStmt()) + // If we don't have an else case look for previous unconditional store and treat that as the else. + // Abort if the condition or store depend on lclVar: + // + // short lclVar = (short)arg1; + // if (lclVar > 3) { // Used in condition! + // lclVar = (short)(lclVar + 3); // Used in store! + // } + + GenTreeLclVar* store = m_thenOperation.node->AsLclVar(); + unsigned storeLclNum = store->GetLclNum(); + + bool lclVarUsedInCondOrStore = + m_compiler->gtHasRef(m_cond, storeLclNum) || m_compiler->gtHasRef(store->Data(), storeLclNum); + if (!lclVarUsedInCondOrStore) { - GenTree* tree = stmt->GetRootNode(); - if (tree->OperIs(GT_STORE_LCL_VAR)) - { - GenTree* val = tree->AsLclVar()->Data(); + Statement* last = m_startBlock->lastStmt(); - bool noSideEffects = (val->gtFlags & (GTF_SIDE_EFFECT | GTF_ORDER_SIDEEFF)) == 0; - bool condDependsOnLclVar = m_compiler->gtHasRef(m_cond, lclNum); - if (noSideEffects && !condDependsOnLclVar) + for (Statement* stmt = last->GetPrevStmt(); stmt != last; stmt = stmt->GetPrevStmt()) + { + GenTree* tree = stmt->GetRootNode(); + if (tree->OperIs(GT_STORE_LCL_VAR)) { - m_doElseConversion = true; - m_elseOperation.block = m_startBlock; - m_elseOperation.stmt = stmt; - m_elseOperation.node = tree; + GenTree* storeValue = tree->AsLclVar()->Data(); + if ((storeValue->gtFlags & (GTF_SIDE_EFFECT | GTF_ORDER_SIDEEFF)) == 0) + { + m_doElseConversion = true; + m_elseOperation.block = m_startBlock; + m_elseOperation.stmt = stmt; + m_elseOperation.node = tree; + } + + break; } - - break; } } } From 208cc34789a60acabacd5ca6f40dd4d14fb40242 Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Tue, 24 Feb 2026 04:59:09 +0100 Subject: [PATCH 06/14] * forgot to check for the correct store --- src/coreclr/jit/ifconversion.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/coreclr/jit/ifconversion.cpp b/src/coreclr/jit/ifconversion.cpp index da33859bc852e5..becae4f7f80478 100644 --- a/src/coreclr/jit/ifconversion.cpp +++ b/src/coreclr/jit/ifconversion.cpp @@ -719,22 +719,24 @@ bool OptIfConversionDsc::optIfConvert(int* pReachabilityBudget) if (!lclVarUsedInCondOrStore) { Statement* last = m_startBlock->lastStmt(); - for (Statement* stmt = last->GetPrevStmt(); stmt != last; stmt = stmt->GetPrevStmt()) { GenTree* tree = stmt->GetRootNode(); if (tree->OperIs(GT_STORE_LCL_VAR)) { - GenTree* storeValue = tree->AsLclVar()->Data(); - if ((storeValue->gtFlags & (GTF_SIDE_EFFECT | GTF_ORDER_SIDEEFF)) == 0) + GenTreeLclVar* prevStore = tree->AsLclVar(); + if (prevStore->GetLclNum() == storeLclNum) { - m_doElseConversion = true; - m_elseOperation.block = m_startBlock; - m_elseOperation.stmt = stmt; - m_elseOperation.node = tree; + if ((prevStore->Data()->gtFlags & (GTF_SIDE_EFFECT | GTF_ORDER_SIDEEFF)) == 0) + { + m_doElseConversion = true; + m_elseOperation.block = m_startBlock; + m_elseOperation.stmt = stmt; + m_elseOperation.node = tree; + } + + break; } - - break; } } } From 604b77bab08ccf755c14a30004416c34980f5518 Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Mon, 9 Mar 2026 21:24:37 +0100 Subject: [PATCH 07/14] * simplify and rename FindFlow() * simplify IfConvertCheckStmts * small things --- src/coreclr/jit/ifconversion.cpp | 360 +++++++------------------------ 1 file changed, 75 insertions(+), 285 deletions(-) diff --git a/src/coreclr/jit/ifconversion.cpp b/src/coreclr/jit/ifconversion.cpp index 0b9e11c962e8fb..20fb6530bc13e4 100644 --- a/src/coreclr/jit/ifconversion.cpp +++ b/src/coreclr/jit/ifconversion.cpp @@ -45,16 +45,11 @@ class OptIfConversionDsc IfConvertOperation m_thenOperation; // The single operation in the Then case. IfConvertOperation m_elseOperation; // The single operation in the Else case. - int m_checkLimit = 4; // Max number of chained blocks to allow in both the True and Else cases. - genTreeOps m_mainOper = GT_COUNT; // The main oper of the if conversion. bool m_doElseConversion = false; // Does the If conversion have an else statement. - bool m_flowFound = false; // Has a valid flow been found. - bool IfConvertCheckInnerBlockFlow(BasicBlock* block); - bool IfConvertCheckThenFlow(); - void IfConvertFindFlow(); - bool IfConvertCheckStmts(BasicBlock* fromBlock, IfConvertOperation* foundOperation); + bool IfConvertCheckFlow(); + bool IfConvertCheckStmts(BasicBlock* block, IfConvertOperation* foundOperation); GenTree* TryTransformSelectOperOrLocal(GenTree* oper, GenTree* lcl); GenTree* TryTransformSelectOperOrZero(GenTree* oper, GenTree* lcl); @@ -68,290 +63,103 @@ class OptIfConversionDsc }; //----------------------------------------------------------------------------- -// IfConvertCheckInnerBlockFlow -// -// Check if the flow of a block is valid for use as an inner block (either a Then or Else block) -// in an If Conversion. -// -// Assumptions: -// m_startBlock and m_doElseConversion are set. -// -// Arguments: -// block -- Block to check. -// -// Returns: -// True if Checks are ok, else false. -// -bool OptIfConversionDsc::IfConvertCheckInnerBlockFlow(BasicBlock* block) -{ - // Block should have a single successor or be a return. - if (!(block->GetUniqueSucc() != nullptr || (m_doElseConversion && (block->KindIs(BBJ_RETURN))))) - { - return false; - } - - // Check that we have linear flow and are still in the same EH region - - if (block->GetUniquePred(m_compiler) == nullptr) - { - return false; - } - - if (!BasicBlock::sameEHRegion(block, m_startBlock)) - { - return false; - } - - return true; -} - -//----------------------------------------------------------------------------- -// IfConvertCheckThenFlow -// -// Check all the Then blocks between m_startBlock and m_finalBlock are valid. +// IfConvertCheckFlow // -// Assumptions: -// m_startBlock, m_finalBlock and m_doElseConversion are set. -// -// Returns: -// If a conversion is found, then set m_flowFound and return true. -// If a conversion is not found, and it's ok to keep searching, return true. -// Otherwise, return false. +// Check if there is a valid flow from m_startBlock to a final block. // // Notes: -// Sets m_flowFound and m_mainOper. +// Sets m_finalBlock, m_doElseConversion and m_mainOper. // -bool OptIfConversionDsc::IfConvertCheckThenFlow() +bool OptIfConversionDsc::IfConvertCheckFlow() { - m_flowFound = false; - BasicBlock* thenBlock = m_startBlock->GetFalseTarget(); + BasicBlock* falseBb = m_startBlock->GetFalseTarget(); + BasicBlock* trueBb = m_startBlock->GetTrueTarget(); - for (int thenLimit = 0; thenLimit < m_checkLimit; thenLimit++) + if (falseBb->GetUniquePred(m_compiler) == nullptr) { - if (!IfConvertCheckInnerBlockFlow(thenBlock)) - { - // Then block is not in a valid flow. - return true; - } - BasicBlock* thenBlockNext = thenBlock->GetUniqueSucc(); - - if (thenBlockNext == m_finalBlock) - { - // All the Then blocks up to m_finalBlock are in a valid flow. - m_flowFound = true; - if (thenBlock->KindIs(BBJ_RETURN)) - { - assert(m_finalBlock == nullptr); - m_mainOper = GT_RETURN; - } - else - { - m_mainOper = GT_STORE_LCL_VAR; - } - return true; - } - - if (thenBlockNext == nullptr) - { - // Invalid Then and Else combination. - return false; - } - - thenBlock = thenBlockNext; - } - - // Nothing found. Still valid to continue. - return true; -} - -//----------------------------------------------------------------------------- -// IfConvertFindFlow -// -// Find a valid if conversion flow from m_startBlock to a final block. -// There might be multiple Then and Else blocks in the flow - use m_checkLimit to limit this. -// -// Notes: -// Sets m_flowFound, m_finalBlock, m_doElseConversion and m_mainOper. -// -void OptIfConversionDsc::IfConvertFindFlow() -{ - // First check for flow with no else case. The final block is the destination of the jump. - m_doElseConversion = false; - m_finalBlock = m_startBlock->GetTrueTarget(); - assert(m_finalBlock != nullptr); - if (!IfConvertCheckThenFlow() || m_flowFound) - { - // Either the flow is invalid, or a flow was found. - return; + return false; } - // Look for flows with else blocks. The final block is the block after the else block. - m_doElseConversion = true; - for (int elseLimit = 0; elseLimit < m_checkLimit; elseLimit++) - { - BasicBlock* elseBlock = m_finalBlock; - if (elseBlock == nullptr || !IfConvertCheckInnerBlockFlow(elseBlock)) - { - // Need a valid else block in a valid flow . - return; - } - - m_finalBlock = elseBlock->GetUniqueSucc(); + m_doElseConversion = trueBb->GetUniquePred(m_compiler) != nullptr; + m_finalBlock = m_doElseConversion ? trueBb->GetUniqueSucc() : trueBb; + m_mainOper = (m_finalBlock == nullptr && trueBb->KindIs(BBJ_RETURN)) ? GT_RETURN : GT_STORE_LCL_VAR; - if (!IfConvertCheckThenFlow() || m_flowFound) - { - // Either the flow is invalid, or a flow was found. - return; - } - } + return falseBb->GetUniqueSucc() == m_finalBlock; } //----------------------------------------------------------------------------- // IfConvertCheckStmts // -// From the given block to the final block, check all the statements and nodes are -// valid for an If conversion. Chain of blocks must contain only a single local -// store and no other operations. +// Check whether the statements in the block are valid for an If conversion. +// It must contain only a single RETURN or STORE node. NOPs are ignored. // // Arguments: -// fromBlock - Block inside the if statement to start from (Either Then or Else path). -// foundOperation - Returns the found operation. +// block - Block to check +// foundOperation - The found operation // // Returns: -// If everything is valid, then set foundOperation to the store and return true. -// Otherwise return false. +// True if the statements are valid for an If conversion. In that case foundOperation is also set. // -bool OptIfConversionDsc::IfConvertCheckStmts(BasicBlock* fromBlock, IfConvertOperation* foundOperation) +bool OptIfConversionDsc::IfConvertCheckStmts(BasicBlock* block, IfConvertOperation* foundOperation) { bool found = false; - for (BasicBlock* block = fromBlock; block != m_finalBlock; block = block->GetUniqueSucc()) + // Can all the nodes within the block be made to conditionally execute? + for (Statement* stmt : block->Statements()) { - assert(block != nullptr); - - // Can all the nodes within the block be made to conditionally execute? - for (Statement* const stmt : block->Statements()) + GenTree* tree = stmt->GetRootNode(); + if (tree->OperIs(GT_STORE_LCL_VAR, GT_RETURN)) { - GenTree* tree = stmt->GetRootNode(); - switch (tree->OperGet()) + // Operation has multiple statements which is not supported by SELECT + if (found) { - case GT_STORE_LCL_VAR: - { - // Only one per operation per block can be conditionally executed. - if (found) - { - return false; - } - - // Ensure the local has integer type. - if (!varTypeIsIntegralOrI(tree)) - { - return false; - } - -#ifndef TARGET_64BIT - // Disallow 64-bit operands on 32-bit targets as the backend currently cannot - // handle contained relops efficiently after decomposition. - if (varTypeIsLong(tree)) - { - return false; - } -#endif - GenTree* op1 = tree->AsLclVar()->Data(); - - // Ensure it won't cause any additional side effects. - if ((op1->gtFlags & (GTF_SIDE_EFFECT | GTF_ORDER_SIDEEFF)) != 0) - { - return false; - } - - // Ensure the source isn't a phi. - if (op1->OperIs(GT_PHI)) - { - return false; - } - - // Evaluating unconditionally effectively has the same effect as reordering - // with the condition (for example, the condition could be an explicit bounds - // check and the operand could read an array element). Disallow this except - // for some common cases that we know are always side effect free. - if (((m_cond->gtFlags & GTF_ORDER_SIDEEFF) != 0) && !op1->IsInvariant() && !op1->OperIsLocal()) - { - return false; - } - - found = true; - foundOperation->block = block; - foundOperation->stmt = stmt; - foundOperation->node = tree; - break; - } + return false; + } - case GT_RETURN: - { - // GT_SWIFT_ERROR_RET not supported - GenTree* const retVal = tree->gtGetOp1(); - - // Only allow RETURNs if else conversion is being used. - if (!m_doElseConversion) - { - return false; - } - - // Only one per operation per block can be conditionally executed. - if (found || retVal == nullptr) - { - return false; - } - - // Ensure the operation has integer type. - if (!varTypeIsIntegralOrI(tree)) - { - return false; - } + // Ensure the operation has integer type. + if (!varTypeIsIntegralOrI(tree)) + { + return false; + } #ifndef TARGET_64BIT - // Disallow 64-bit operands on 32-bit targets as the backend currently cannot - // handle contained relops efficiently after decomposition. - if (varTypeIsLong(tree)) - { - return false; - } + // Disallow 64-bit operands on 32-bit targets as the backend currently cannot + // handle contained relops efficiently after decomposition. + if (varTypeIsLong(tree)) + { + return false; + } #endif - // Ensure it won't cause any additional side effects. - if ((retVal->gtFlags & (GTF_SIDE_EFFECT | GTF_ORDER_SIDEEFF)) != 0) - { - return false; - } - - // Evaluating unconditionally effectively has the same effect as reordering - // with the condition (for example, the condition could be an explicit bounds - // check and the operand could read an array element). Disallow this except - // for some common cases that we know are always side effect free. - if (((m_cond->gtFlags & GTF_ORDER_SIDEEFF) != 0) && !retVal->IsInvariant() && - !retVal->OperIsLocal()) - { - return false; - } - - found = true; - foundOperation->block = block; - foundOperation->stmt = stmt; - foundOperation->node = tree; - break; - } + GenTree* op1 = tree->gtGetOp1(); - // These do not need conditional execution. - case GT_NOP: - break; + // Ensure it won't cause any additional side effects. + if ((op1->gtFlags & (GTF_SIDE_EFFECT | GTF_ORDER_SIDEEFF)) != 0) + { + return false; + } - // Cannot optimise this block. - default: - return false; + // Evaluating unconditionally effectively has the same effect as reordering + // with the condition (for example, the condition could be an explicit bounds + // check and the operand could read an array element). Disallow this except + // for some common cases that we know are always side effect free. + if (((m_cond->gtFlags & GTF_ORDER_SIDEEFF) != 0) && !op1->IsInvariant() && !op1->OperIsLocal()) + { + return false; } + + found = true; + foundOperation->block = block; + foundOperation->stmt = stmt; + foundOperation->node = tree; + } + else if (!tree->OperIs(GT_NOP)) + { + // Cannot optimise this block. + return false; } } + return found; } @@ -365,22 +173,13 @@ void OptIfConversionDsc::IfConvertDump() { m_compiler->fgDumpBlock(m_startBlock); - bool beforeTransformation = m_startBlock->KindIs(BBJ_COND); - if (beforeTransformation) + // Then & Else only exist before the transformation + if (m_startBlock->KindIs(BBJ_COND)) { - // Dump all Then blocks - for (BasicBlock* bb = m_startBlock->GetFalseTarget(); bb != m_finalBlock; bb = bb->GetUniqueSucc()) - { - m_compiler->fgDumpBlock(bb); - } - + m_compiler->fgDumpBlock(m_startBlock->GetFalseTarget()); if (m_doElseConversion) { - // Dump all Else blocks - for (BasicBlock* bb = m_startBlock->GetTrueTarget(); bb != m_finalBlock; bb = bb->GetUniqueSucc()) - { - m_compiler->fgDumpBlock(bb); - } + m_compiler->fgDumpBlock(m_startBlock->GetTrueTarget()); } } } @@ -545,34 +344,32 @@ bool OptIfConversionDsc::optIfConvert(int* pReachabilityBudget) return false; } - // Does the block end by branching via a JTRUE after a compare? - if (!m_startBlock->KindIs(BBJ_COND) || (m_startBlock->NumSucc() != 2)) + if (m_startBlock->StatementCount() == 0) { return false; } - // Verify the test block ends with a condition that we can manipulate. GenTree* last = m_startBlock->lastStmt()->GetRootNode(); - noway_assert(last->OperIs(GT_JTRUE)); - m_cond = last->gtGetOp1(); - if (!m_cond->OperIsCompare()) + if (!(last->OperIs(GT_JTRUE))) { return false; } // Look for valid flow of Then and Else blocks. - IfConvertFindFlow(); - if (!m_flowFound) + if (!IfConvertCheckFlow()) { return false; } + m_cond = last->gtGetOp1(); + // Check the Then and Else blocks have a single operation each. if (!IfConvertCheckStmts(m_startBlock->GetFalseTarget(), &m_thenOperation)) { return false; } assert(m_thenOperation.node->OperIs(GT_STORE_LCL_VAR, GT_RETURN)); + if (m_doElseConversion) { if (!IfConvertCheckStmts(m_startBlock->GetTrueTarget(), &m_elseOperation)) @@ -752,16 +549,9 @@ bool OptIfConversionDsc::optIfConvert(int* pReachabilityBudget) // Remove all Then/Else blocks auto removeBlocks = [&](BasicBlock* start) { - m_compiler->fgRemoveAllRefPreds(start, m_startBlock); start->bbWeight = BB_ZERO_WEIGHT; - assert(start->bbPreds == nullptr); - - for (BasicBlock* bb = start; bb != m_finalBlock;) - { - BasicBlock* next = bb->GetUniqueSucc(); - m_compiler->fgRemoveBlock(bb, true); - bb = next; - } + m_compiler->fgRemoveAllRefPreds(start, m_startBlock); + m_compiler->fgRemoveBlock(start, true); }; removeBlocks(falseBb); if (m_doElseConversion) From 3450c6409c54a40c769f1c9f224b2b84c02eccb3 Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Tue, 10 Mar 2026 02:33:37 +0100 Subject: [PATCH 08/14] * try fix CI 'block != nullptr' --- src/coreclr/jit/ifconversion.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/ifconversion.cpp b/src/coreclr/jit/ifconversion.cpp index 20fb6530bc13e4..eeb7dda475cda7 100644 --- a/src/coreclr/jit/ifconversion.cpp +++ b/src/coreclr/jit/ifconversion.cpp @@ -82,7 +82,19 @@ bool OptIfConversionDsc::IfConvertCheckFlow() m_doElseConversion = trueBb->GetUniquePred(m_compiler) != nullptr; m_finalBlock = m_doElseConversion ? trueBb->GetUniqueSucc() : trueBb; - m_mainOper = (m_finalBlock == nullptr && trueBb->KindIs(BBJ_RETURN)) ? GT_RETURN : GT_STORE_LCL_VAR; + m_mainOper = GT_STORE_LCL_VAR; + + if (m_doElseConversion && m_finalBlock == nullptr) + { + if (falseBb->KindIs(BBJ_RETURN) && trueBb->KindIs(BBJ_RETURN)) + { + m_mainOper = GT_RETURN; + } + else + { + return false; + } + } return falseBb->GetUniqueSucc() == m_finalBlock; } @@ -360,7 +372,7 @@ bool OptIfConversionDsc::optIfConvert(int* pReachabilityBudget) { return false; } - + JITDUMP("valid flow\n"); m_cond = last->gtGetOp1(); // Check the Then and Else blocks have a single operation each. From 5c1616c5d263ec7ef07a1da4b8bc8224cdf3b97c Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Wed, 11 Mar 2026 10:50:30 +0100 Subject: [PATCH 09/14] * add and check assert(m_doElseConversion) in CI --- src/coreclr/jit/ifconversion.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/coreclr/jit/ifconversion.cpp b/src/coreclr/jit/ifconversion.cpp index eeb7dda475cda7..9fa0830c305613 100644 --- a/src/coreclr/jit/ifconversion.cpp +++ b/src/coreclr/jit/ifconversion.cpp @@ -84,8 +84,9 @@ bool OptIfConversionDsc::IfConvertCheckFlow() m_finalBlock = m_doElseConversion ? trueBb->GetUniqueSucc() : trueBb; m_mainOper = GT_STORE_LCL_VAR; - if (m_doElseConversion && m_finalBlock == nullptr) + if (m_finalBlock == nullptr) { + assert(m_doElseConversion); if (falseBb->KindIs(BBJ_RETURN) && trueBb->KindIs(BBJ_RETURN)) { m_mainOper = GT_RETURN; @@ -188,10 +189,10 @@ void OptIfConversionDsc::IfConvertDump() // Then & Else only exist before the transformation if (m_startBlock->KindIs(BBJ_COND)) { - m_compiler->fgDumpBlock(m_startBlock->GetFalseTarget()); + m_compiler->fgDumpBlock(m_thenOperation.block); if (m_doElseConversion) { - m_compiler->fgDumpBlock(m_startBlock->GetTrueTarget()); + m_compiler->fgDumpBlock(m_elseOperation.block); } } } @@ -356,7 +357,7 @@ bool OptIfConversionDsc::optIfConvert(int* pReachabilityBudget) return false; } - if (m_startBlock->StatementCount() == 0) + if (m_startBlock->firstStmt() == nullptr) { return false; } @@ -372,7 +373,7 @@ bool OptIfConversionDsc::optIfConvert(int* pReachabilityBudget) { return false; } - JITDUMP("valid flow\n"); + m_cond = last->gtGetOp1(); // Check the Then and Else blocks have a single operation each. From 43ed6999932b13dfc3c39572e6461da3459ddc7b Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Fri, 13 Mar 2026 04:24:49 +0100 Subject: [PATCH 10/14] * plural to singluar in comment --- src/coreclr/jit/ifconversion.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/coreclr/jit/ifconversion.cpp b/src/coreclr/jit/ifconversion.cpp index 9fa0830c305613..c8dbcbddb61bb2 100644 --- a/src/coreclr/jit/ifconversion.cpp +++ b/src/coreclr/jit/ifconversion.cpp @@ -560,16 +560,16 @@ bool OptIfConversionDsc::optIfConvert(int* pReachabilityBudget) } assert(m_startBlock->GetUniqueSucc() == m_finalBlock); - // Remove all Then/Else blocks - auto removeBlocks = [&](BasicBlock* start) { + // Remove Then/Else block + auto removeBlock = [&](BasicBlock* start) { start->bbWeight = BB_ZERO_WEIGHT; m_compiler->fgRemoveAllRefPreds(start, m_startBlock); m_compiler->fgRemoveBlock(start, true); }; - removeBlocks(falseBb); + removeBlock(falseBb); if (m_doElseConversion) { - removeBlocks(trueBb); + removeBlock(trueBb); } #ifdef DEBUG From 44dcf06ede33028194f871f76f70ddb547899394 Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Tue, 17 Mar 2026 03:13:12 +0100 Subject: [PATCH 11/14] * update IR in comment * add 'assert(m_cond->OperIsCompare())' * combine IfConvertCheckFlow + IfConvertCheckStmts into new IfConvertCheck * get m_mainOper from m_thenOperation instead of flow check --- src/coreclr/jit/ifconversion.cpp | 137 ++++++++++++++----------------- 1 file changed, 62 insertions(+), 75 deletions(-) diff --git a/src/coreclr/jit/ifconversion.cpp b/src/coreclr/jit/ifconversion.cpp index c8dbcbddb61bb2..1b44fa798a8043 100644 --- a/src/coreclr/jit/ifconversion.cpp +++ b/src/coreclr/jit/ifconversion.cpp @@ -48,6 +48,7 @@ class OptIfConversionDsc genTreeOps m_mainOper = GT_COUNT; // The main oper of the if conversion. bool m_doElseConversion = false; // Does the If conversion have an else statement. + bool IfConvertCheck(); bool IfConvertCheckFlow(); bool IfConvertCheckStmts(BasicBlock* block, IfConvertOperation* foundOperation); @@ -62,13 +63,62 @@ class OptIfConversionDsc bool optIfConvert(int* pReachabilityBudget); }; +//----------------------------------------------------------------------------- +// IfConvertCheck +// +// Check whether the JTRUE block and its successors can be expressed as a SELECT. +// In the process, get the data required to perform the transformation. +// Notes: +// Sets m_finalBlock, m_doElseConversion, m_thenOperation, m_elseOperation and m_mainOper +// +bool OptIfConversionDsc::IfConvertCheck() +{ + if (!IfConvertCheckFlow()) + { + return false; + } + + if (!IfConvertCheckStmts(m_startBlock->GetFalseTarget(), &m_thenOperation)) + { + return false; + } + + m_mainOper = m_thenOperation.node->OperGet(); + assert(m_mainOper == GT_RETURN || m_mainOper == GT_STORE_LCL_VAR); + + if (m_doElseConversion) + { + if (!IfConvertCheckStmts(m_startBlock->GetTrueTarget(), &m_elseOperation)) + { + return false; + } + + // Both operations are the same node type. + assert(m_thenOperation.node->OperGet() == m_elseOperation.node->OperGet()); + + // Currently can only support Else Store Blocks that have the same destination as the Then block. + if (m_mainOper == GT_STORE_LCL_VAR) + { + unsigned lclNumThen = m_thenOperation.node->AsLclVarCommon()->GetLclNum(); + unsigned lclNumElse = m_elseOperation.node->AsLclVarCommon()->GetLclNum(); + + if (lclNumThen != lclNumElse) + { + return false; + } + } + } + + return true; +} + //----------------------------------------------------------------------------- // IfConvertCheckFlow // // Check if there is a valid flow from m_startBlock to a final block. // // Notes: -// Sets m_finalBlock, m_doElseConversion and m_mainOper. +// Sets m_finalBlock and m_doElseConversion. // bool OptIfConversionDsc::IfConvertCheckFlow() { @@ -82,19 +132,12 @@ bool OptIfConversionDsc::IfConvertCheckFlow() m_doElseConversion = trueBb->GetUniquePred(m_compiler) != nullptr; m_finalBlock = m_doElseConversion ? trueBb->GetUniqueSucc() : trueBb; - m_mainOper = GT_STORE_LCL_VAR; - if (m_finalBlock == nullptr) + // m_finalBlock is only allowed to be null if both return. + // E.g: Then block exits by throwing an exception => we bail here. + if (m_finalBlock == nullptr && (!falseBb->KindIs(BBJ_RETURN) || !trueBb->KindIs(BBJ_RETURN))) { - assert(m_doElseConversion); - if (falseBb->KindIs(BBJ_RETURN) && trueBb->KindIs(BBJ_RETURN)) - { - m_mainOper = GT_RETURN; - } - else - { - return false; - } + return false; } return falseBb->GetUniqueSucc() == m_finalBlock; @@ -250,9 +293,6 @@ void OptIfConversionDsc::IfConvertDump() // the existing value of local var 0 is used: // // ------------ BB03 [009..00D) -> BB05 (always), preds={BB02} succs={BB05} -// STMT00004 -// * NOP void -// // STMT00005 // * STORE_LCL_VAR int V00 arg0 // \--* SELECT int @@ -262,9 +302,6 @@ void OptIfConversionDsc::IfConvertDump() // +--* CNS_INT int 5 $47 // \--* LCL_VAR int V00 // -// ------------ BB04 [00D..010), preds={} succs={BB05} -// -// // Example of simple if conversion with an else condition // // This is similar to the simple if conversion above, but with an else statement @@ -291,9 +328,6 @@ void OptIfConversionDsc::IfConvertDump() // Again this is squashed into a single block, with the SELECT node handling both cases. // // ------------ BB03 [009..00D) -> BB05 (always), preds={BB02} succs={BB05} -// STMT00004 -// * NOP void -// // STMT00005 // * STORE_LCL_VAR int V00 arg0 // \--* SELECT int @@ -303,12 +337,6 @@ void OptIfConversionDsc::IfConvertDump() // +--* CNS_INT int 5 $47 // +--* CNS_INT int 9 $48 // -// STMT00006 -// * NOP void -// -// ------------ BB04 [00D..010), preds={} succs={BB06} -// ------------ BB05 [00D..010), preds={} succs={BB06} -// // Alternatively, an if conversion with an else condition may use RETURNs. // return (x < 7) ? 5 : 9; // @@ -319,22 +347,19 @@ void OptIfConversionDsc::IfConvertDump() // +--* LCL_VAR int V02 // \--* CNS_INT int 7 $46 // -// ------------ BB04 [00D..010), preds={BB03} succs={BB06} +// ------------ BB04 [00D..010) (return), preds={BB03} succs={} // STMT00005 // * RETURN int $VN.Void // +--* CNS_INT int 5 $41 // -// ------------ BB05 [00D..010), preds={BB03} succs={BB06} +// ------------ BB05 [00D..010) (return), preds={BB03} succs={} // STMT00006 // * RETURN int $VN.Void // +--* CNS_INT int 9 $43 // // becomes: // -// ------------ BB03 [009..00D) -> BB05 (always), preds={BB02} succs={BB05} -// STMT00004 -// * NOP void -// +// ------------ BB03 [009..00D) (return), preds={BB02} succs={} // STMT00005 // * RETURN int $VN.Void // \--* SELECT int @@ -344,12 +369,6 @@ void OptIfConversionDsc::IfConvertDump() // +--* CNS_INT int 5 $41 // +--* CNS_INT int 9 $43 // -// STMT00006 -// * NOP void -// -// ------------ BB04 [00D..010), preds={} succs={BB06} -// ------------ BB05 [00D..010), preds={} succs={BB06} -// bool OptIfConversionDsc::optIfConvert(int* pReachabilityBudget) { if ((*pReachabilityBudget) <= 0) @@ -363,50 +382,18 @@ bool OptIfConversionDsc::optIfConvert(int* pReachabilityBudget) } GenTree* last = m_startBlock->lastStmt()->GetRootNode(); - if (!(last->OperIs(GT_JTRUE))) + if (!last->OperIs(GT_JTRUE)) { return false; } - - // Look for valid flow of Then and Else blocks. - if (!IfConvertCheckFlow()) - { - return false; - } - + m_cond = last->gtGetOp1(); + assert(m_cond->OperIsCompare()); - // Check the Then and Else blocks have a single operation each. - if (!IfConvertCheckStmts(m_startBlock->GetFalseTarget(), &m_thenOperation)) + if (!IfConvertCheck()) { return false; } - assert(m_thenOperation.node->OperIs(GT_STORE_LCL_VAR, GT_RETURN)); - - if (m_doElseConversion) - { - if (!IfConvertCheckStmts(m_startBlock->GetTrueTarget(), &m_elseOperation)) - { - return false; - } - - // Both operations must be the same node type. - if (m_thenOperation.node->OperGet() != m_elseOperation.node->OperGet()) - { - return false; - } - - // Currently can only support Else Store Blocks that have the same destination as the Then block. - if (m_thenOperation.node->OperIs(GT_STORE_LCL_VAR)) - { - unsigned lclNumThen = m_thenOperation.node->AsLclVarCommon()->GetLclNum(); - unsigned lclNumElse = m_elseOperation.node->AsLclVarCommon()->GetLclNum(); - if (lclNumThen != lclNumElse) - { - return false; - } - } - } #ifdef DEBUG if (m_compiler->verbose) From cba3e37ea0e6070e4467432d4f2258794898fbc0 Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Thu, 19 Mar 2026 01:47:15 +0100 Subject: [PATCH 12/14] * rebase * rework --- src/coreclr/jit/ifconversion.cpp | 65 ++++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 8 deletions(-) diff --git a/src/coreclr/jit/ifconversion.cpp b/src/coreclr/jit/ifconversion.cpp index 1b44fa798a8043..8a40d777d53fc3 100644 --- a/src/coreclr/jit/ifconversion.cpp +++ b/src/coreclr/jit/ifconversion.cpp @@ -92,7 +92,49 @@ bool OptIfConversionDsc::IfConvertCheck() { return false; } + } + else + { + assert(m_mainOper == GT_STORE_LCL_VAR); + + GenTreeLclVar* thenStore = m_thenOperation.node->AsLclVar(); + unsigned lclNum = thenStore->GetLclNum(); + + bool lclVarUsedInThen = m_compiler->gtHasRef(thenStore->Data(), lclNum); + if (!lclVarUsedInThen) + { + Statement* last = m_startBlock->lastStmt(); + Statement* stmt = last; + do + { + GenTree* tree = stmt->GetRootNode(); + + if (tree->OperIs(GT_STORE_LCL_VAR)) + { + GenTreeLclVar* prevStore = tree->AsLclVar(); + if (prevStore->GetLclNum() == lclNum) + { + m_doElseConversion = true; + m_elseOperation.block = m_startBlock; + m_elseOperation.stmt = stmt; + m_elseOperation.node = tree; + + break; + } + } + + if (m_compiler->gtHasRef(tree, lclNum)) + { + break; + } + + stmt = stmt->GetPrevStmt(); + } while (stmt != last); + } + } + if (m_doElseConversion) + { // Both operations are the same node type. assert(m_thenOperation.node->OperGet() == m_elseOperation.node->OperGet()); @@ -232,10 +274,12 @@ void OptIfConversionDsc::IfConvertDump() // Then & Else only exist before the transformation if (m_startBlock->KindIs(BBJ_COND)) { - m_compiler->fgDumpBlock(m_thenOperation.block); + JITDUMP("\nThen case:"); + m_compiler->fgDumpStmtTree(m_thenOperation.block, m_thenOperation.stmt); if (m_doElseConversion) { - m_compiler->fgDumpBlock(m_elseOperation.block); + JITDUMP("\nElse case:"); + m_compiler->fgDumpStmtTree(m_elseOperation.block, m_elseOperation.stmt); } } } @@ -398,12 +442,13 @@ bool OptIfConversionDsc::optIfConvert(int* pReachabilityBudget) #ifdef DEBUG if (m_compiler->verbose) { - JITDUMP("\nConditionally executing " FMT_BB, m_thenOperation.block->bbNum); + JITDUMP("JTRUE block is " FMT_BB ". ", m_startBlock->bbNum); + JITDUMP("Using " FMT_STMT " (Then) ", m_thenOperation.stmt->GetID()); if (m_doElseConversion) { - JITDUMP(" and " FMT_BB, m_elseOperation.block->bbNum); + JITDUMP("and " FMT_STMT " (Else) ", m_elseOperation.stmt->GetID()); } - JITDUMP(" inside " FMT_BB "\n", m_startBlock->bbNum); + JITDUMP("in the conversion.\n"); IfConvertDump(); } #endif @@ -419,7 +464,7 @@ bool OptIfConversionDsc::optIfConvert(int* pReachabilityBudget) { thenCost = m_thenOperation.node->AsLclVar()->Data()->GetCostEx() + (m_compiler->gtIsLikelyRegVar(m_thenOperation.node) ? 0 : 2); - if (m_doElseConversion) + if (m_doElseConversion && m_elseOperation.block != m_startBlock) { elseCost = m_elseOperation.node->AsLclVar()->Data()->GetCostEx() + (m_compiler->gtIsLikelyRegVar(m_elseOperation.node) ? 0 : 2); @@ -526,6 +571,10 @@ bool OptIfConversionDsc::optIfConvert(int* pReachabilityBudget) m_compiler->fgSetStmtSeq(m_thenOperation.stmt); // Replace JTRUE with STORE(SELECT)/RETURN(SELECT) statement + if (m_doElseConversion && m_elseOperation.block == m_startBlock) + { + m_compiler->fgRemoveStmt(m_startBlock, m_elseOperation.stmt); + } m_compiler->fgInsertStmtBefore(m_startBlock, m_startBlock->lastStmt(), m_thenOperation.stmt); m_compiler->fgRemoveStmt(m_startBlock, m_startBlock->lastStmt()); m_thenOperation.block->SetFirstStmt(nullptr); @@ -542,7 +591,7 @@ bool OptIfConversionDsc::optIfConvert(int* pReachabilityBudget) else { FlowEdge* newEdge = - m_doElseConversion ? m_compiler->fgAddRefPred(m_finalBlock, m_startBlock) : m_startBlock->GetTrueEdge(); + (m_doElseConversion && m_elseOperation.block != m_startBlock) ? m_compiler->fgAddRefPred(m_finalBlock, m_startBlock) : m_startBlock->GetTrueEdge(); m_startBlock->SetKindAndTargetEdge(BBJ_ALWAYS, newEdge); } assert(m_startBlock->GetUniqueSucc() == m_finalBlock); @@ -554,7 +603,7 @@ bool OptIfConversionDsc::optIfConvert(int* pReachabilityBudget) m_compiler->fgRemoveBlock(start, true); }; removeBlock(falseBb); - if (m_doElseConversion) + if (m_doElseConversion && m_elseOperation.block != m_startBlock) { removeBlock(trueBb); } From e25d9b4e00f1c40f654e1873a3ec50df3b901cae Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Thu, 19 Mar 2026 01:51:43 +0100 Subject: [PATCH 13/14] * fix git pls --- src/coreclr/jit/ifconversion.cpp | 41 ++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/coreclr/jit/ifconversion.cpp b/src/coreclr/jit/ifconversion.cpp index 8a40d777d53fc3..af3a24d532af81 100644 --- a/src/coreclr/jit/ifconversion.cpp +++ b/src/coreclr/jit/ifconversion.cpp @@ -522,6 +522,47 @@ bool OptIfConversionDsc::optIfConvert(int* pReachabilityBudget) GenTree* selectFalseInput; if (m_mainOper == GT_STORE_LCL_VAR) { + if (!m_doElseConversion) + { + // If we don't have an else case look for previous unconditional store and treat that as the else. + // Abort if the condition or store depend on lclVar: + // + // short lclVar = (short)arg1; + // if (lclVar > 3) { // Used in condition! + // lclVar = (short)(lclVar + 3); // Used in store! + // } + + GenTreeLclVar* store = m_thenOperation.node->AsLclVar(); + unsigned storeLclNum = store->GetLclNum(); + + bool lclVarUsedInCondOrStore = + m_compiler->gtHasRef(m_cond, storeLclNum) || m_compiler->gtHasRef(store->Data(), storeLclNum); + if (!lclVarUsedInCondOrStore) + { + Statement* last = m_startBlock->lastStmt(); + for (Statement* stmt = last->GetPrevStmt(); stmt != last; stmt = stmt->GetPrevStmt()) + { + GenTree* tree = stmt->GetRootNode(); + if (tree->OperIs(GT_STORE_LCL_VAR)) + { + GenTreeLclVar* prevStore = tree->AsLclVar(); + if (prevStore->GetLclNum() == storeLclNum) + { + if ((prevStore->Data()->gtFlags & (GTF_SIDE_EFFECT | GTF_ORDER_SIDEEFF)) == 0) + { + m_doElseConversion = true; + m_elseOperation.block = m_startBlock; + m_elseOperation.stmt = stmt; + m_elseOperation.node = tree; + } + + break; + } + } + } + } + } + selectFalseInput = m_thenOperation.node->AsLclVar()->Data(); selectTrueInput = m_doElseConversion ? m_elseOperation.node->AsLclVar()->Data() : nullptr; From cb3d47ae3de72fd5c4291a76cc02d7ccbff1fe00 Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Thu, 19 Mar 2026 01:59:14 +0100 Subject: [PATCH 14/14] * remove old --- src/coreclr/jit/ifconversion.cpp | 41 -------------------------------- 1 file changed, 41 deletions(-) diff --git a/src/coreclr/jit/ifconversion.cpp b/src/coreclr/jit/ifconversion.cpp index af3a24d532af81..8a40d777d53fc3 100644 --- a/src/coreclr/jit/ifconversion.cpp +++ b/src/coreclr/jit/ifconversion.cpp @@ -522,47 +522,6 @@ bool OptIfConversionDsc::optIfConvert(int* pReachabilityBudget) GenTree* selectFalseInput; if (m_mainOper == GT_STORE_LCL_VAR) { - if (!m_doElseConversion) - { - // If we don't have an else case look for previous unconditional store and treat that as the else. - // Abort if the condition or store depend on lclVar: - // - // short lclVar = (short)arg1; - // if (lclVar > 3) { // Used in condition! - // lclVar = (short)(lclVar + 3); // Used in store! - // } - - GenTreeLclVar* store = m_thenOperation.node->AsLclVar(); - unsigned storeLclNum = store->GetLclNum(); - - bool lclVarUsedInCondOrStore = - m_compiler->gtHasRef(m_cond, storeLclNum) || m_compiler->gtHasRef(store->Data(), storeLclNum); - if (!lclVarUsedInCondOrStore) - { - Statement* last = m_startBlock->lastStmt(); - for (Statement* stmt = last->GetPrevStmt(); stmt != last; stmt = stmt->GetPrevStmt()) - { - GenTree* tree = stmt->GetRootNode(); - if (tree->OperIs(GT_STORE_LCL_VAR)) - { - GenTreeLclVar* prevStore = tree->AsLclVar(); - if (prevStore->GetLclNum() == storeLclNum) - { - if ((prevStore->Data()->gtFlags & (GTF_SIDE_EFFECT | GTF_ORDER_SIDEEFF)) == 0) - { - m_doElseConversion = true; - m_elseOperation.block = m_startBlock; - m_elseOperation.stmt = stmt; - m_elseOperation.node = tree; - } - - break; - } - } - } - } - } - selectFalseInput = m_thenOperation.node->AsLclVar()->Data(); selectTrueInput = m_doElseConversion ? m_elseOperation.node->AsLclVar()->Data() : nullptr;