@@ -1966,6 +1966,12 @@ bool Compiler::fgBlockIsGoodTailDuplicationCandidate(BasicBlock* target, unsigne
19661966 return false ;
19671967 }
19681968
1969+ // No point duplicating this block if it would not remove (part of) the join.
1970+ if (target->TrueTargetIs (target) || target->FalseTargetIs (target))
1971+ {
1972+ return false ;
1973+ }
1974+
19691975 Statement* const lastStmt = target->lastStmt ();
19701976 Statement* const firstStmt = target->FirstNonPhiDef ();
19711977
@@ -2265,6 +2271,108 @@ bool Compiler::fgOptimizeUncondBranchToSimpleCond(BasicBlock* block, BasicBlock*
22652271 return true ;
22662272}
22672273
2274+ // -------------------------------------------------------------
2275+ // fgFoldSimpleCondByForwardSub:
2276+ // Try to refine the flow of a block that may have just been tail duplicated
2277+ // or compacted.
2278+ //
2279+ // Arguments:
2280+ // block - block that was tail duplicated or compacted
2281+ //
2282+ // Returns Value:
2283+ // true if control flow was changed
2284+ //
2285+ bool Compiler::fgFoldSimpleCondByForwardSub (BasicBlock* block)
2286+ {
2287+ assert (block->KindIs (BBJ_COND));
2288+ GenTree* jtrue = block->lastStmt ()->GetRootNode ();
2289+ assert (jtrue->OperIs (GT_JTRUE));
2290+
2291+ GenTree* relop = jtrue->gtGetOp1 ();
2292+ if (!relop->OperIsCompare ())
2293+ {
2294+ return false ;
2295+ }
2296+
2297+ GenTree* op1 = relop->gtGetOp1 ();
2298+ GenTree* op2 = relop->gtGetOp2 ();
2299+
2300+ GenTree** lclUse;
2301+ GenTreeLclVarCommon* lcl;
2302+
2303+ if (op1->OperIs (GT_LCL_VAR) && op2->IsIntegralConst ())
2304+ {
2305+ lclUse = &relop->AsOp ()->gtOp1 ;
2306+ lcl = op1->AsLclVarCommon ();
2307+ }
2308+ else if (op2->OperIs (GT_LCL_VAR) && op1->IsIntegralConst ())
2309+ {
2310+ lclUse = &relop->AsOp ()->gtOp2 ;
2311+ lcl = op2->AsLclVarCommon ();
2312+ }
2313+ else
2314+ {
2315+ return false ;
2316+ }
2317+
2318+ Statement* secondLastStmt = block->lastStmt ()->GetPrevStmt ();
2319+ if ((secondLastStmt == nullptr ) || (secondLastStmt == block->lastStmt ()))
2320+ {
2321+ return false ;
2322+ }
2323+
2324+ GenTree* prevTree = secondLastStmt->GetRootNode ();
2325+ if (!prevTree->OperIs (GT_STORE_LCL_VAR))
2326+ {
2327+ return false ;
2328+ }
2329+
2330+ GenTreeLclVarCommon* store = prevTree->AsLclVarCommon ();
2331+ if (store->GetLclNum () != lcl->GetLclNum ())
2332+ {
2333+ return false ;
2334+ }
2335+
2336+ if (!store->Data ()->IsIntegralConst ())
2337+ {
2338+ return false ;
2339+ }
2340+
2341+ if (genActualType (store) != genActualType (store->Data ()) || (genActualType (store) != genActualType (lcl)))
2342+ {
2343+ return false ;
2344+ }
2345+
2346+ JITDUMP (" Forward substituting local after jump threading. Before:\n " );
2347+ DISPSTMT (block->lastStmt ());
2348+
2349+ JITDUMP (" \n After:\n " );
2350+
2351+ LclVarDsc* varDsc = lvaGetDesc (lcl);
2352+ GenTree* newData = gtCloneExpr (store->Data ());
2353+ if (varTypeIsSmall (varDsc) && fgCastNeeded (store->Data (), varDsc->TypeGet ()))
2354+ {
2355+ newData = gtNewCastNode (TYP_INT, newData, false , varDsc->TypeGet ());
2356+ newData = gtFoldExpr (newData);
2357+ }
2358+
2359+ *lclUse = newData;
2360+ DISPSTMT (block->lastStmt ());
2361+
2362+ JITDUMP (" \n Now trying to fold...\n " );
2363+ jtrue->AsUnOp ()->gtOp1 = gtFoldExpr (relop);
2364+ DISPSTMT (block->lastStmt ());
2365+
2366+ Compiler::FoldResult result = fgFoldConditional (block);
2367+ if (result != Compiler::FoldResult::FOLD_DID_NOTHING)
2368+ {
2369+ assert (block->KindIs (BBJ_ALWAYS));
2370+ return true ;
2371+ }
2372+
2373+ return false ;
2374+ }
2375+
22682376// -------------------------------------------------------------
22692377// fgRemoveConditionalJump:
22702378// Optimize a BBJ_COND block that unconditionally jumps to the same target
@@ -5176,10 +5284,35 @@ bool Compiler::fgUpdateFlowGraph(bool doTailDuplication /* = false */,
51765284 {
51775285 assert (block->KindIs (BBJ_COND));
51785286 assert (bNext == block->Next ());
5179- change = true ;
5180- modified = true ;
5181- bDest = block->GetTrueTarget ();
5182- bFalseDest = block->GetFalseTarget ();
5287+ change = true ;
5288+ modified = true ;
5289+
5290+ if (fgFoldSimpleCondByForwardSub (block))
5291+ {
5292+ // It is likely another pred of the target now can
5293+ // similarly have its control flow straightened out.
5294+ // Try to compact it and repeat the optimization for
5295+ // it.
5296+ if (bDest->bbRefs == 1 )
5297+ {
5298+ BasicBlock* otherPred = bDest->bbPreds ->getSourceBlock ();
5299+ JITDUMP (" Trying to compact last pred " FMT_BB " of " FMT_BB " that we now bypass\n " ,
5300+ otherPred->bbNum , bDest->bbNum );
5301+ if (fgCanCompactBlock (otherPred))
5302+ {
5303+ fgCompactBlock (otherPred);
5304+ fgFoldSimpleCondByForwardSub (otherPred);
5305+ }
5306+ }
5307+
5308+ assert (block->KindIs (BBJ_ALWAYS));
5309+ bDest = block->GetTarget ();
5310+ }
5311+ else
5312+ {
5313+ bDest = block->GetTrueTarget ();
5314+ bFalseDest = block->GetFalseTarget ();
5315+ }
51835316 }
51845317 }
51855318
0 commit comments