From 604b77bab08ccf755c14a30004416c34980f5518 Mon Sep 17 00:00:00 2001 From: BoyBaykiller Date: Mon, 9 Mar 2026 21:24:37 +0100 Subject: [PATCH 1/5] * 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 2/5] * 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 3/5] * 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 4/5] * 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 5/5] * 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)