Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JIT: Merge fgRemoveConditionalJump and fgOptimizeBranchToNext #97456

Merged
merged 1 commit into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -5966,8 +5966,6 @@ class Compiler

bool fgOptimizeSwitchBranches(BasicBlock* block);

bool fgOptimizeBranchToNext(BasicBlock* block, BasicBlock* bNext, BasicBlock* bPrev);

bool fgOptimizeSwitchJumps();
#ifdef DEBUG
void fgPrintEdgeWeights();
Expand Down
152 changes: 26 additions & 126 deletions src/coreclr/jit/fgopt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1442,109 +1442,6 @@ void Compiler::fgUnreachableBlock(BasicBlock* block)
fgRemoveBlockAsPred(block);
}

//-------------------------------------------------------------
// fgRemoveConditionalJump: Remove or morph a jump when we jump to the same
// block when both the condition is true or false. Remove the branch condition,
// but leave any required side effects.
//
// Arguments:
// block - block with conditional branch
//
void Compiler::fgRemoveConditionalJump(BasicBlock* block)
{
noway_assert(block->KindIs(BBJ_COND) && block->TrueTargetIs(block->GetFalseTarget()));
assert(compRationalIRForm == block->IsLIR());

FlowEdge* flow = fgGetPredForBlock(block->GetFalseTarget(), block);
noway_assert(flow->getDupCount() == 2);

// Change the BBJ_COND to BBJ_ALWAYS, and adjust the refCount and dupCount.
--block->GetFalseTarget()->bbRefs;
block->SetKind(BBJ_ALWAYS);
block->SetFlags(BBF_NONE_QUIRK);
flow->decrementDupCount();

#ifdef DEBUG
if (verbose)
{
printf("Block " FMT_BB " becoming a BBJ_ALWAYS to " FMT_BB " (jump target is the same whether the condition"
" is true or false)\n",
block->bbNum, block->GetTarget()->bbNum);
}
#endif

// Remove the block jump condition

if (block->IsLIR())
{
LIR::Range& blockRange = LIR::AsRange(block);

GenTree* test = blockRange.LastNode();
assert(test->OperIsConditionalJump());

bool isClosed;
unsigned sideEffects;
LIR::ReadOnlyRange testRange = blockRange.GetTreeRange(test, &isClosed, &sideEffects);

// TODO-LIR: this should really be checking GTF_ALL_EFFECT, but that produces unacceptable
// diffs compared to the existing backend.
if (isClosed && ((sideEffects & GTF_SIDE_EFFECT) == 0))
{
// If the jump and its operands form a contiguous, side-effect-free range,
// remove them.
blockRange.Delete(this, block, std::move(testRange));
}
else
{
// Otherwise, just remove the jump node itself.
blockRange.Remove(test, true);
}
}
else
{
Statement* test = block->lastStmt();
GenTree* tree = test->GetRootNode();

noway_assert(tree->gtOper == GT_JTRUE);

GenTree* sideEffList = nullptr;

if (tree->gtFlags & GTF_SIDE_EFFECT)
{
gtExtractSideEffList(tree, &sideEffList);

if (sideEffList)
{
noway_assert(sideEffList->gtFlags & GTF_SIDE_EFFECT);
#ifdef DEBUG
if (verbose)
{
printf("Extracted side effects list from condition...\n");
gtDispTree(sideEffList);
printf("\n");
}
#endif
}
}

// Delete the cond test or replace it with the side effect tree
if (sideEffList == nullptr)
{
fgRemoveStmt(block, test);
}
else
{
test->SetRootNode(sideEffList);

if (fgNodeThreading != NodeThreading::None)
{
gtSetStmtInfo(test);
fgSetStmtSeq(test);
}
}
}
}

//-------------------------------------------------------------
// fgOptimizeBranchToEmptyUnconditional:
// Optimize a jump to an empty block which ends in an unconditional branch.
Expand Down Expand Up @@ -2610,27 +2507,25 @@ bool Compiler::fgOptimizeUncondBranchToSimpleCond(BasicBlock* block, BasicBlock*
}

//-------------------------------------------------------------
// fgOptimizeBranchToNext:
// Optimize a block which has a branch to the following block
// fgRemoveConditionalJump:
// Optimize a BBJ_COND block that unconditionally jumps to the same target
//
// Arguments:
// block - block with a BBJ_COND jump kind
// bNext - target that block jumps to regardless of its condition
// bPrev - block which is prior to the first block
// block - BBJ_COND block with identical true/false targets
//
// Returns: true if changes were made
//
bool Compiler::fgOptimizeBranchToNext(BasicBlock* block, BasicBlock* bNext, BasicBlock* bPrev)
void Compiler::fgRemoveConditionalJump(BasicBlock* block)
{
assert(block->KindIs(BBJ_COND));
assert(block->TrueTargetIs(bNext));
assert(block->FalseTargetIs(bNext));
assert(block->PrevIs(bPrev));
assert(block->TrueTargetIs(block->GetFalseTarget()));

BasicBlock* target = block->GetTrueTarget();

#ifdef DEBUG
if (verbose)
{
printf("\nRemoving conditional jump to next block (" FMT_BB " -> " FMT_BB ")\n", block->bbNum, bNext->bbNum);
printf("Block " FMT_BB " becoming a BBJ_ALWAYS to " FMT_BB " (jump target is the same whether the condition"
" is true or false)\n",
block->bbNum, target->bbNum);
}
#endif // DEBUG

Expand Down Expand Up @@ -2729,17 +2624,19 @@ bool Compiler::fgOptimizeBranchToNext(BasicBlock* block, BasicBlock* bNext, Basi
}
}

/* Conditional is gone - always jump to the next block */
/* Conditional is gone - always jump to target */

block->SetKind(BBJ_ALWAYS);
assert(block->TargetIs(target));

// TODO-NoFallThrough: Set BBF_NONE_QUIRK only when false target is the next block
block->SetFlags(BBF_NONE_QUIRK);

/* Update bbRefs and bbNum - Conditional predecessors to the same
* block are counted twice so we have to remove one of them */

noway_assert(bNext->countOfInEdges() > 1);
fgRemoveRefPred(bNext, block);

return true;
noway_assert(target->countOfInEdges() > 1);
fgRemoveRefPred(target, block);
}

//-------------------------------------------------------------
Expand Down Expand Up @@ -4928,12 +4825,15 @@ bool Compiler::fgUpdateFlowGraph(bool doTailDuplication, bool isPhase)
{
// TODO-NoFallThrough: Fix above condition once bbFalseTarget can diverge from bbNext
assert(block->FalseTargetIs(bNext));
if (fgOptimizeBranchToNext(block, bNext, bPrev))
{
change = true;
modified = true;
bDest = nullptr;
}
fgRemoveConditionalJump(block);

assert(block->KindIs(BBJ_ALWAYS));
assert(block->TargetIs(bNext));
change = true;
modified = true;

// Skip jump optimizations, and try to compact block and bNext later
bDest = nullptr;
}
}

Expand Down