-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[DomTreeUpdater] Handle critical edge splitting #100856
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -105,6 +105,12 @@ class GenericDomTreeUpdater { | |
return PendUpdates.size() != PendPDTUpdateIndex; | ||
} | ||
|
||
bool hasPendingCriticalEdges() const { | ||
if (!PDT && !DT) | ||
return false; | ||
return !CriticalEdgesToSplit.empty(); | ||
} | ||
|
||
///@{ | ||
/// \name Mutation APIs | ||
/// | ||
|
@@ -146,8 +152,25 @@ class GenericDomTreeUpdater { | |
/// 2. It is illegal to submit any update that has already been submitted, | ||
/// i.e., you are supposed not to insert an existent edge or delete a | ||
/// nonexistent edge. | ||
/// 3. This kind updates are incompatible with critical edge splitting | ||
/// updates, call this method will apply all critical edge updates in | ||
/// lazy mode. It is not recommended to interleave applyUpdates and | ||
/// applyUpdatesForCriticalEdgeSplitting. | ||
void applyUpdates(ArrayRef<typename DomTreeT::UpdateType> Updates); | ||
|
||
/// Apply updates that the critical edge (FromBB, ToBB) has been | ||
/// split with NewBB. | ||
/// | ||
/// \note Do not use this method with regular edges. | ||
/// | ||
/// \note This kind updates are incompatible with generic updates, | ||
/// call this method will submit all generic updates in lazy mode. | ||
/// It is not recommended to interleave applyUpdates and | ||
/// applyUpdatesForCriticalEdgeSplitting. | ||
void applyUpdatesForCriticalEdgeSplitting(BasicBlockT *FromBB, | ||
BasicBlockT *ToBB, | ||
BasicBlockT *NewBB); | ||
|
||
/// Submit updates to all available trees. It will also | ||
/// 1. discard duplicated updates, | ||
/// 2. remove invalid updates. (Invalid updates means deletion of an edge that | ||
|
@@ -197,6 +220,7 @@ class GenericDomTreeUpdater { | |
applyDomTreeUpdates(); | ||
applyPostDomTreeUpdates(); | ||
dropOutOfDateUpdates(); | ||
applySplitCriticalEdges(); | ||
} | ||
|
||
///@} | ||
|
@@ -243,6 +267,35 @@ class GenericDomTreeUpdater { | |
/// Drop all updates applied by all available trees and delete BasicBlocks if | ||
/// all available trees are up-to-date. | ||
void dropOutOfDateUpdates(); | ||
|
||
private: | ||
/// Helper structure used to hold all the basic blocks | ||
/// involved in the split of a critical edge. | ||
struct CriticalEdge { | ||
BasicBlockT *FromBB; | ||
BasicBlockT *ToBB; | ||
BasicBlockT *NewBB; | ||
}; | ||
|
||
/// Pile up all the critical edges to be split. | ||
/// The splitting of a critical edge is local and thus, it is possible | ||
/// to apply several of those changes at the same time. | ||
SmallVector<CriticalEdge, 32> CriticalEdgesToSplit; | ||
Comment on lines
+280
to
+283
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this is local, what's the benefit of enqueuing critical edge updates vs. performing them eagerly?
Comment on lines
+280
to
+283
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How did you pick the small size of 32? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is copied from abea99f. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would you be able to compile a few representative programs (e.g., clang) and print the maximum and average size? Otherwise I'd stick to the default small size. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tested with bzip2: maximum: 92
average: 8.70909 Most will not exceed 7. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the due diligence! Then I'd stick to the default value |
||
|
||
/// Remember all the basic blocks that are inserted during | ||
/// edge splitting. | ||
/// Invariant: NewBBs == all the basic blocks contained in the NewBB | ||
/// field of all the elements of CriticalEdgesToSplit. | ||
/// I.e., forall elt in CriticalEdgesToSplit, it exists BB in NewBBs | ||
/// such as BB == elt.NewBB. | ||
SmallSet<BasicBlockT *, 32> NewBBs; | ||
|
||
/// Apply all the recorded critical edges to the DT. | ||
/// This updates the underlying DT information in a way that uses | ||
/// the fast query path of DT as much as possible. | ||
/// | ||
/// \post CriticalEdgesToSplit.empty(). | ||
void applySplitCriticalEdges(); | ||
}; | ||
|
||
} // namespace llvm | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't parse this sentence. Could you explain it in a bit more detail?
Specifically, it is not clear to me how to reconcile 'incompatible' with 'not recommended'. What happens if we do add edge splitting updates in eager and lazy mode?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for my poor expression.
In lazy mode
Because
cfg::Update
doesn't model the update kind for critical edge splitting.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about exposing a more general update type that captures both edge additions/deletions and critical edge splitting? Would that make sense? I'm trying to see if we can avoid adding new methods and, in turn, having to document intricacies like this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From user perspective a unified update method is better, i.e.
applyUpdates({{From1, To1, UpdateKind::Insert}, {From, To, New, UpdateKind::Split}...})
, thencfg::Update<NodePtrT>
is not enough.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you explain this part? I'm not sure which API we are talking about and what the limitations are.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently all update operations are based on
cfg::Update
. If we extendcfg::Update
directly e.g. add a new kindUpdateKind::Split
, then it is duplicated with two insertions and deletion, and causes some compiler warnings.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could update
cfg::Update
though and add one more node ref there. I still don't understand what the issue is here:There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A critical splitting update can be expressed as insert two new edges and delete old critical edge.
Current CFG codes rely on the dichotomy of
UpdateKind
, a new update kind makes old match not exhaustive.Some CFG related codes need to be updated, e.g.
LegalizeUpdates
which is not easy to update, because it assumescfg::Update
only has two pointer fields...