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: Handle QMARK properly for LCL_ADDR propagation #103909

Merged
merged 4 commits into from
Jun 26, 2024
Merged
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
101 changes: 90 additions & 11 deletions src/coreclr/jit/lclmorph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,10 +225,11 @@ class LocalEqualsLocalAddrAssertions
AssertionToIndexMap m_map;
uint64_t* m_lclAssertions;
uint64_t* m_outgoingAssertions;
uint64_t m_currentAssertions = 0;
BitVec m_localsToExpose;

public:
uint64_t CurrentAssertions = 0;

LocalEqualsLocalAddrAssertions(Compiler* comp)
: m_comp(comp)
, m_assertions(comp->getAllocator(CMK_LocalAddressVisitor))
Expand Down Expand Up @@ -285,28 +286,28 @@ class LocalEqualsLocalAddrAssertions
{
if ((m_assertions.Height() == 0) || (block->bbPreds == nullptr) || m_comp->bbIsHandlerBeg(block))
{
m_currentAssertions = 0;
CurrentAssertions = 0;
return;
}

m_currentAssertions = UINT64_MAX;
CurrentAssertions = UINT64_MAX;
for (BasicBlock* pred : block->PredBlocks())
{
assert(m_comp->m_dfsTree->Contains(pred));
if (pred->bbPostorderNum <= block->bbPostorderNum)
{
m_currentAssertions = 0;
CurrentAssertions = 0;
break;
}

m_currentAssertions &= m_outgoingAssertions[pred->bbPostorderNum];
CurrentAssertions &= m_outgoingAssertions[pred->bbPostorderNum];
}

#ifdef DEBUG
if (m_currentAssertions != 0)
if (CurrentAssertions != 0)
{
JITDUMP(FMT_BB " incoming assertions:\n", block->bbNum);
uint64_t assertions = m_currentAssertions;
uint64_t assertions = CurrentAssertions;
do
{
uint32_t index = BitOperations::BitScanForward(assertions);
Expand All @@ -328,7 +329,7 @@ class LocalEqualsLocalAddrAssertions
//
void EndBlock(BasicBlock* block)
{
m_outgoingAssertions[block->bbPostorderNum] = m_currentAssertions;
m_outgoingAssertions[block->bbPostorderNum] = CurrentAssertions;
}

//-------------------------------------------------------------------
Expand Down Expand Up @@ -389,7 +390,7 @@ class LocalEqualsLocalAddrAssertions
}
}

m_currentAssertions |= uint64_t(1) << index;
CurrentAssertions |= uint64_t(1) << index;
}

//-------------------------------------------------------------------
Expand All @@ -400,7 +401,7 @@ class LocalEqualsLocalAddrAssertions
//
void Clear(unsigned dstLclNum)
{
m_currentAssertions &= ~m_lclAssertions[dstLclNum];
CurrentAssertions &= ~m_lclAssertions[dstLclNum];
}

//-----------------------------------------------------------------------------------
Expand All @@ -415,7 +416,7 @@ class LocalEqualsLocalAddrAssertions
//
const LocalEqualsLocalAddrAssertion* GetCurrentAssertion(unsigned lclNum)
{
uint64_t curAssertion = m_currentAssertions & m_lclAssertions[lclNum];
uint64_t curAssertion = CurrentAssertions & m_lclAssertions[lclNum];
assert(genMaxOneBit(curAssertion));
if (curAssertion == 0)
{
Expand Down Expand Up @@ -797,6 +798,9 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
}
break;

case GT_QMARK:
return HandleQMarkSubTree(use);

default:
break;
}
Expand Down Expand Up @@ -1038,6 +1042,81 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
}

private:
//------------------------------------------------------------------------
// HandleQMarkSubTree: Process a sub-tree rooted at a GT_QMARK.
//
// Arguments:
// use - the use of the qmark
//
// Returns:
// The walk result.
//
// Remarks:
// GT_QMARK needs special handling due to the conditional nature of it.
// Particularly when we are optimizing and propagating LCL_ADDRs we need
// to take care that assertions created inside the conditionally executed
// parts are handled appropriately. This function inlines the pre and
// post-order visit logic here to make that handling work.
//
fgWalkResult HandleQMarkSubTree(GenTree** use)
{
assert((*use)->OperIs(GT_QMARK));
GenTreeQmark* qmark = (*use)->AsQmark();

// We have to inline the pre/postorder visit here to handle
// assertions properly.
assert(!qmark->IsReverseOp());
if (WalkTree(&qmark->gtOp1, qmark) == Compiler::WALK_ABORT)
{
return Compiler::WALK_ABORT;
}

if (m_lclAddrAssertions != nullptr)
{
uint64_t origAssertions = m_lclAddrAssertions->CurrentAssertions;

if (WalkTree(&qmark->gtOp2->AsOp()->gtOp1, qmark->gtOp2) == Compiler::WALK_ABORT)
{
return Compiler::WALK_ABORT;
}

uint64_t op1Assertions = m_lclAddrAssertions->CurrentAssertions;
m_lclAddrAssertions->CurrentAssertions = origAssertions;

if (WalkTree(&qmark->gtOp2->AsOp()->gtOp2, qmark->gtOp2) == Compiler::WALK_ABORT)
{
return Compiler::WALK_ABORT;
}

uint64_t op2Assertions = m_lclAddrAssertions->CurrentAssertions;
m_lclAddrAssertions->CurrentAssertions = op1Assertions & op2Assertions;
}
else
{
if ((WalkTree(&qmark->gtOp2->AsOp()->gtOp1, qmark->gtOp2) == Compiler::WALK_ABORT) ||
(WalkTree(&qmark->gtOp2->AsOp()->gtOp2, qmark->gtOp2) == Compiler::WALK_ABORT))
{
return Compiler::WALK_ABORT;
}
}

assert(TopValue(0).Node() == qmark->gtGetOp2()->gtGetOp2());
assert(TopValue(1).Node() == qmark->gtGetOp2()->gtGetOp1());
assert(TopValue(2).Node() == qmark->gtGetOp1());

EscapeValue(TopValue(0), qmark->gtGetOp2());
PopValue();

EscapeValue(TopValue(0), qmark->gtGetOp2());
PopValue();

EscapeValue(TopValue(0), qmark);
PopValue();

PushValue(use);
return Compiler::WALK_SKIP_SUBTREES;
}

void PushValue(GenTree** use)
{
m_valueStack.Push(use);
Expand Down
Loading