@@ -1966,6 +1966,12 @@ bool Compiler::fgBlockIsGoodTailDuplicationCandidate(BasicBlock* target, unsigne
1966
1966
return false ;
1967
1967
}
1968
1968
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
+
1969
1975
Statement* const lastStmt = target->lastStmt ();
1970
1976
Statement* const firstStmt = target->FirstNonPhiDef ();
1971
1977
@@ -2265,6 +2271,108 @@ bool Compiler::fgOptimizeUncondBranchToSimpleCond(BasicBlock* block, BasicBlock*
2265
2271
return true ;
2266
2272
}
2267
2273
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
+
2268
2376
// -------------------------------------------------------------
2269
2377
// fgRemoveConditionalJump:
2270
2378
// Optimize a BBJ_COND block that unconditionally jumps to the same target
@@ -5176,10 +5284,35 @@ bool Compiler::fgUpdateFlowGraph(bool doTailDuplication /* = false */,
5176
5284
{
5177
5285
assert (block->KindIs (BBJ_COND));
5178
5286
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
+ }
5183
5316
}
5184
5317
}
5185
5318
0 commit comments