Skip to content

Commit 879b904

Browse files
authored
JIT: simple redundant compare optimization (#43811)
For a relop, walk up the dominator tree to see if any dominating block has a similar compare. If so, and there's just one path from that block to the relop, the relop's value is known. Closes #11909.
1 parent c4feddb commit 879b904

File tree

1 file changed

+163
-6
lines changed

1 file changed

+163
-6
lines changed

src/coreclr/src/jit/assertionprop.cpp

Lines changed: 163 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3203,18 +3203,175 @@ GenTree* Compiler::optAssertionProp_RelOp(ASSERT_VALARG_TP assertions, GenTree*
32033203
return optAssertionPropLocal_RelOp(assertions, tree, stmt);
32043204
}
32053205

3206-
/*************************************************************************************
3207-
*
3208-
* Given the set of "assertions" to look up a relop assertion about the relop "tree",
3209-
* perform Value numbering based relop assertion propagation on the tree.
3210-
*
3211-
*/
3206+
//------------------------------------------------------------------------
3207+
// optAssertionProp: try and optimize a relop via assertion propagation
3208+
// (and dominator based redundant branch elimination)
3209+
//
3210+
// Arguments:
3211+
// assertions - set of live assertions
3212+
// tree - tree to possibly optimize
3213+
// stmt - statement containing the tree
3214+
//
3215+
// Returns:
3216+
// The modified tree, or nullptr if no assertion prop took place.
3217+
//
3218+
// Notes:
3219+
// Redundant branch elimination doesn't rely on assertions currently,
3220+
// it is done here out of convenience.
3221+
//
32123222
GenTree* Compiler::optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions, GenTree* tree, Statement* stmt)
32133223
{
32143224
GenTree* newTree = tree;
32153225
GenTree* op1 = tree->AsOp()->gtOp1;
32163226
GenTree* op2 = tree->AsOp()->gtOp2;
32173227

3228+
// First, walk up the dom tree and see if any dominating block has branched on
3229+
// exactly this tree's VN...
3230+
//
3231+
BasicBlock* prevBlock = compCurBB;
3232+
BasicBlock* domBlock = compCurBB->bbIDom;
3233+
int relopValue = -1;
3234+
3235+
while (domBlock != nullptr)
3236+
{
3237+
if (prevBlock == compCurBB)
3238+
{
3239+
JITDUMP("\nVN relop, checking " FMT_BB " for redundancy\n", compCurBB->bbNum);
3240+
}
3241+
3242+
// Check the current dominator
3243+
//
3244+
JITDUMP(" ... checking dom " FMT_BB "\n", domBlock->bbNum);
3245+
3246+
if (domBlock->bbJumpKind == BBJ_COND)
3247+
{
3248+
Statement* const domJumpStmt = domBlock->lastStmt();
3249+
GenTree* const domJumpTree = domJumpStmt->GetRootNode();
3250+
assert(domJumpTree->OperIs(GT_JTRUE));
3251+
GenTree* const domCmpTree = domJumpTree->AsOp()->gtGetOp1();
3252+
3253+
if (domCmpTree->OperKind() & GTK_RELOP)
3254+
{
3255+
ValueNum domCmpVN = domCmpTree->GetVN(VNK_Conservative);
3256+
3257+
// Note we could also infer the tree relop's value from similar relops higher in the dom tree.
3258+
// For example, (x >= 0) dominating (x > 0), or (x < 0) dominating (x > 0).
3259+
//
3260+
// That is left as a future enhancement.
3261+
//
3262+
if (domCmpVN == tree->GetVN(VNK_Conservative))
3263+
{
3264+
// Thes compare in "tree" is redundant.
3265+
// Is there a unique path from the dominating compare?
3266+
JITDUMP(" Redundant compare; current relop:\n");
3267+
DISPTREE(tree);
3268+
JITDUMP(" dominating relop in " FMT_BB " with same VN:\n", domBlock->bbNum);
3269+
DISPTREE(domCmpTree);
3270+
3271+
BasicBlock* trueSuccessor = domBlock->bbJumpDest;
3272+
BasicBlock* falseSuccessor = domBlock->bbNext;
3273+
3274+
const bool trueReaches = fgReachable(trueSuccessor, compCurBB);
3275+
const bool falseReaches = fgReachable(falseSuccessor, compCurBB);
3276+
3277+
if (trueReaches && falseReaches)
3278+
{
3279+
// Both dominating compare outcomes reach the current block so we can't infer the
3280+
// value of the relop.
3281+
//
3282+
// If the dominating compare is close to the current compare, this may be a missed
3283+
// opportunity to tail duplicate.
3284+
//
3285+
JITDUMP("Both successors of " FMT_BB " reach, can't optimize\n", domBlock->bbNum);
3286+
3287+
if ((trueSuccessor->GetUniqueSucc() == compCurBB) ||
3288+
(falseSuccessor->GetUniqueSucc() == compCurBB))
3289+
{
3290+
JITDUMP("Perhaps we should have tail duplicated " FMT_BB "\n", compCurBB->bbNum);
3291+
}
3292+
}
3293+
else if (trueReaches)
3294+
{
3295+
// Taken jump in dominator reaches, fall through doesn't; relop must be true.
3296+
//
3297+
JITDUMP("Jump successor " FMT_BB " of " FMT_BB " reaches, relop must be true\n",
3298+
domBlock->bbJumpDest->bbNum, domBlock->bbNum);
3299+
relopValue = 1;
3300+
break;
3301+
}
3302+
else if (falseReaches)
3303+
{
3304+
// Fall through from dominator reaches, taken jump doesn't; relop must be false.
3305+
//
3306+
JITDUMP("Fall through successor " FMT_BB " of " FMT_BB " reaches, relop must be false\n",
3307+
domBlock->bbNext->bbNum, domBlock->bbNum);
3308+
relopValue = 0;
3309+
break;
3310+
}
3311+
else
3312+
{
3313+
// No apparent path from the dominating BB.
3314+
//
3315+
// If domBlock or compCurBB is in an EH handler we may fail to find a path.
3316+
// Just ignore those cases.
3317+
//
3318+
// No point in looking further up the tree.
3319+
//
3320+
break;
3321+
}
3322+
}
3323+
}
3324+
}
3325+
3326+
// Keep looking higher up in the tree
3327+
//
3328+
prevBlock = domBlock;
3329+
domBlock = domBlock->bbIDom;
3330+
}
3331+
3332+
// Did we determine the relop value via dominance checks? If so, optimize.
3333+
//
3334+
if (relopValue == -1)
3335+
{
3336+
JITDUMP("Failed to find a suitable dominating compare, so we won't optimize\n");
3337+
}
3338+
else
3339+
{
3340+
// Bail out if tree is has certain side effects
3341+
//
3342+
// Note we really shouldn't get here if the tree has non-exception effects,
3343+
// as they should have impacted the value number.
3344+
//
3345+
if ((tree->gtFlags & GTF_SIDE_EFFECT) != 0)
3346+
{
3347+
// Bail if there is a non-exception effect.
3348+
//
3349+
if ((tree->gtFlags & GTF_SIDE_EFFECT) != GTF_EXCEPT)
3350+
{
3351+
JITDUMP("Current relop has non-exception side effects, so we won't optimize\n");
3352+
return nullptr;
3353+
}
3354+
3355+
// Be conservative if there is an exception effect and we're in an EH region
3356+
// as we might not model the full extent of EH flow.
3357+
//
3358+
if (compCurBB->hasTryIndex())
3359+
{
3360+
JITDUMP("Current relop has exception side effect and is in a try, so we won't optimize\n");
3361+
return nullptr;
3362+
}
3363+
}
3364+
3365+
JITDUMP("\nVN relop based redundant branch opt in " FMT_BB ":\n", compCurBB->bbNum);
3366+
3367+
tree->ChangeOperConst(GT_CNS_INT);
3368+
tree->AsIntCon()->gtIconVal = relopValue;
3369+
3370+
newTree = fgMorphTree(tree);
3371+
DISPTREE(newTree);
3372+
return optAssertionProp_Update(newTree, tree, stmt);
3373+
}
3374+
32183375
// Look for assertions of the form (tree EQ/NE 0)
32193376
AssertionIndex index = optGlobalAssertionIsEqualOrNotEqualZero(assertions, tree);
32203377

0 commit comments

Comments
 (0)