Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
13 changes: 6 additions & 7 deletions llvm/lib/Transforms/Vectorize/VPlan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1004,13 +1004,12 @@ static void replaceVPBBWithIRVPBB(VPBasicBlock *VPBB, BasicBlock *IRBB) {
assert(!R.isPhi() && "Tried to move phi recipe to end of block");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While we're here, worth adding in documentation above that VPBB, having a single predecessor, is expected to be free of phi recipes. A more informative error message may be "VPBB to be replaced by IRBB must be free of phi recipes".

Note that, in general, replacing a VPBB with an IRBB is a temporary solution, until the full skeleton is built in VPlan. Blocks would clearly be identified as IRBB's or not, from the outset.

R.moveBefore(*IRVPBB, IRVPBB->end());
}
VPBlockBase *PredVPBB = VPBB->getSinglePredecessor();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assert of having a single predecessor is now lost, yet still documented. The function traverses multiple predecessors, but probably works and tested for single predecessor only, as VPBB is still expected to be free of phi recipes? Better be clear, assert and test what is supported.

VPBlockUtils::disconnectBlocks(PredVPBB, VPBB);
VPBlockUtils::connectBlocks(PredVPBB, IRVPBB);
for (auto *Succ : to_vector(VPBB->getSuccessors())) {
VPBlockUtils::connectBlocks(IRVPBB, Succ);
VPBlockUtils::disconnectBlocks(VPBB, Succ);
}

VPBlockUtils::reassociateBlocks(VPBB, IRVPBB);
IRVPBB->setPredecessors(VPBB->getPredecessors());
IRVPBB->setSuccessors(VPBB->getSuccessors());

// Any successor/predecessor lists will be cleared on deletion.
delete VPBB;
}

Expand Down
29 changes: 29 additions & 0 deletions llvm/lib/Transforms/Vectorize/VPlan.h
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,26 @@ class VPBlockBase {
return getEnclosingBlockWithPredecessors()->getSinglePredecessor();
}

/// This function replaces one predecessor with another, useful when
/// trying to replace an old block in the CFG with a new one.
void replacePredecessor(VPBlockBase *Old, VPBlockBase *New) {
auto I = find(Predecessors, Old);
assert(I != Predecessors.end());
assert(Old->getParent() == New->getParent() &&
"replaced predecessor must have the same parent");
*I = New;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this may leaves Old in an invalid state, as we remove it from the list of predecessors here, but don't remove this from the Successors of Old. Can we also remove it from there? Otherwise the callers of the API must either remove the node itself or completely delete the block

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, but if we go down that route then surely we should also care about setting the successor of New to this as well so that we leave it in a valid state? I guess if this function was private then it wouldn't be part of the interface so it wouldn't matter as much. If we do the extra work here as you suggest, then this patch becomes less about efficiency and more about retaining ordering, which is fine but then I probably ought to change the title!

Copy link
Contributor Author

@david-arm david-arm Oct 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example, removePredecessor does not leave the Predecessor argument in a valid state either because this will still be a successor of Predecessor . How about I make the functions private and then we can behave like removePredecessor, unless you see value in these new interfaces being public?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, let me take a look tomorrow

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, no problem. I just added a new commit as I realised the the public reassociateBlocks interface was leaving Old and New in an invalid state. Hopefully, this now addresses your concern!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks this was what I was about to suggest, as this ensures that reassociateBlocks leaves the CFG in a valid state.

}

/// This function replaces one successor with another, useful when
/// trying to replace an old block in the CFG with a new one.
void replaceSuccessor(VPBlockBase *Old, VPBlockBase *New) {
auto I = find(Successors, Old);
assert(I != Successors.end());
assert(Old->getParent() == New->getParent() &&
"replaced successor must have the same parent");
*I = New;
}

/// Set a given VPBlockBase \p Successor as the single successor of this
/// VPBlockBase. This VPBlockBase is not added as predecessor of \p Successor.
/// This VPBlockBase must have no successors.
Expand Down Expand Up @@ -3862,6 +3882,15 @@ class VPBlockUtils {
To->removePredecessor(From);
}

/// Reassociate all the blocks connected to \p Old so that they now point to
/// \p New.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// \p New.
/// \p New instead.

static void reassociateBlocks(VPBlockBase *Old, VPBlockBase *New) {
for (auto *Pred : to_vector(Old->getPredecessors()))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this to_vector() needed, given that Old's predecessors remain intact?

Pred->replaceSuccessor(Old, New);
for (auto *Succ : to_vector(Old->getSuccessors()))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this to_vector() needed, given that Old's successors remain intact?

Succ->replacePredecessor(Old, New);
}

/// Return an iterator range over \p Range which only includes \p BlockTy
/// blocks. The accesses are casted to \p BlockTy.
template <typename BlockTy, typename T>
Expand Down
Loading