-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
[NFC][AsmPrinter] Refactor FrameIndexExprs as a std::set #66433
[NFC][AsmPrinter] Refactor FrameIndexExprs as a std::set #66433
Conversation
@llvm/pr-subscribers-debuginfo ChangesThis avoids the need for a mutable member to implement deferred sorting, and some bespoke code to maintain a SmallVector as a set.The performance impact seems to be negligible in some small tests, and so seems acceptable to greatly simplify the code. An old FIXME and accompanying workaround are dropped. It is ostensibly dead-code within the current codebase.Full diff: https://github.com/llvm/llvm-project/pull/66433.diff 2 Files Affected:
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 1cb65a8a9a659f3..1039c5955e905d7 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -257,6 +257,19 @@ static DbgValueLoc getDebugLocValue(const MachineInstr *MI) { return DbgValueLoc(Expr, DbgValueLocEntries, IsVariadic); } +static uint64_t getFragmentOffsetInBits(const DIExpression &Expr) { + std::optional<DIExpression::FragmentInfo> Fragment = Expr.getFragmentInfo(); + return Fragment ? Fragment->OffsetInBits : 0; +} + +bool FrameIndexExpr::operator<(const FrameIndexExpr &Other) const { + return getFragmentOffsetInBits(*Expr) < getFragmentOffsetInBits(*Other.Expr); +} + +bool EntryValueInfo::operator<(const EntryValueInfo &Other) const { + return getFragmentOffsetInBits(Expr) < getFragmentOffsetInBits(Other.Expr); +} + Loc::Single::Single(DbgValueLoc ValueLoc) : ValueLoc(std::make_unique<DbgValueLoc>(ValueLoc)), Expr(ValueLoc.getExpression()) { @@ -267,42 +280,15 @@ Loc::Single::Single(DbgValueLoc ValueLoc) Loc::Single::Single(const MachineInstr *DbgValue) : Single(getDebugLocValue(DbgValue)) {} -ArrayRef<FrameIndexExpr> Loc::MMI::getFrameIndexExprs() const { - if (FrameIndexExprs.size() == 1) - return FrameIndexExprs; - - assert(llvm::all_of( - FrameIndexExprs, - [](const FrameIndexExpr &A) { return A.Expr->isFragment(); }) && - "multiple FI expressions without DW_OP_LLVM_fragment"); - llvm::sort(FrameIndexExprs, - [](const FrameIndexExpr &A, const FrameIndexExpr &B) -> bool { - return A.Expr->getFragmentInfo()->OffsetInBits < - B.Expr->getFragmentInfo()->OffsetInBits; - }); - +const std::set<FrameIndexExpr> &Loc::MMI::getFrameIndexExprs() const { return FrameIndexExprs; } void Loc::MMI::addFrameIndexExpr(const DIExpression *Expr, int FI) { - // FIXME: This logic should not be necessary anymore, as we now have proper - // deduplication. However, without it, we currently run into the assertion - // below, which means that we are likely dealing with broken input, i.e. two - // non-fragment entries for the same variable at different frame indices. - if (FrameIndexExprs.size()) { - auto *Expr = FrameIndexExprs.back().Expr; - if (!Expr || !Expr->isFragment()) - return; - } - - if (llvm::none_of(FrameIndexExprs, [&](const FrameIndexExpr &Other) { - return FI == Other.FI && Expr == Other.Expr; - })) - FrameIndexExprs.push_back({FI, Expr}); - + FrameIndexExprs.insert({FI, Expr}); assert((FrameIndexExprs.size() == 1 || llvm::all_of(FrameIndexExprs, - [](FrameIndexExpr &FIE) { + [](const FrameIndexExpr &FIE) { return FIE.Expr && FIE.Expr->isFragment(); })) && "conflicting locations for variable"); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h index e8b0f3178939dc8..a60f0816798f336 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -107,6 +107,9 @@ class DbgVariable; struct FrameIndexExpr { int FI; const DIExpression *Expr; + + /// Operator enabling sorting based on fragment offset. + bool operator<(const FrameIndexExpr &Other) const; }; /// Represents an entry-value location, or a fragment of one. @@ -115,15 +118,7 @@ struct EntryValueInfo { const DIExpression &Expr; /// Operator enabling sorting based on fragment offset. - bool operator<(const EntryValueInfo &Other) const { - return getFragmentOffsetInBits() < Other.getFragmentOffsetInBits(); - } - -private: - uint64_t getFragmentOffsetInBits() const { - std::optional<DIExpression::FragmentInfo> Fragment = Expr.getFragmentInfo(); - return Fragment ? Fragment->OffsetInBits : 0; - } + bool operator<(const EntryValueInfo &Other) const; }; // Namespace for alternatives of a DbgVariable. @@ -158,7 +153,7 @@ class Multi { }; /// Single location defined by (potentially multiple) MMI entries. struct MMI { - mutable SmallVector<FrameIndexExpr, 1> FrameIndexExprs; + std::set<FrameIndexExpr> FrameIndexExprs; public: explicit MMI(const DIExpression *E, int FI) : FrameIndexExprs({{FI, E}}) { @@ -167,7 +162,7 @@ struct MMI { } void addFrameIndexExpr(const DIExpression *Expr, int FI); /// Get the FI entries, sorted by fragment offset. - ArrayRef<FrameIndexExpr> getFrameIndexExprs() const; + const std::set<FrameIndexExpr> &getFrameIndexExprs() const; }; /// Single location defined by (potentially multiple) EntryValueInfo. struct EntryValue { |
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.
Definitely looks nicer with std::set than the mutable; if compile times are a concern, you can also try using the LLVM compile time tracker - you could get set up to use it to test commits pre-merge, but you can also just see if your patch causes any large changes post-merge (which is fine imo given the numbers you posted on the earlier patch).
@@ -107,6 +107,9 @@ class DbgVariable; | |||
struct FrameIndexExpr { | |||
int FI; | |||
const DIExpression *Expr; | |||
|
|||
/// Operator enabling sorting based on fragment offset. | |||
bool operator<(const FrameIndexExpr &Other) const; |
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.
Usually it's preferable to implement any operator overload that can be a non-member, as a non-member (to allow equal conversions on both the LHS and RHS) - could you do that here? (& elsewhere)
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.
Sounds good! I rolled the change to the other type here into this PR as it seems trivial and the PR process in GH doesn't let me "stack" it easily. Let me know if anyone prefers it go in separately!
@@ -158,7 +153,7 @@ class Multi { | |||
}; | |||
/// Single location defined by (potentially multiple) MMI entries. | |||
struct MMI { | |||
mutable SmallVector<FrameIndexExpr, 1> FrameIndexExprs; | |||
std::set<FrameIndexExpr> FrameIndexExprs; |
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.
Another possibilty would be a SetVector
? (though then it's insertion ordered, rather than <
ordered - not sure if that's sufficiently stable for the needs? perhaps not)
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 think we don't need the extra functionality provided by the SetVector
here: our sorting keys (fragment offsets) are stable without the need for insertion-order-tracking.
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.
IIUC the DWARF emitter also wants the fragments ordered by offset? I'm not sure what would happen if we were to emit DWARF fragment expressions out of order 🤔
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.
IIUC the DWARF emitter also wants the fragments ordered by offset? I'm not sure what would happen if we were to emit DWARF fragment expressions out of order 🤔
Ah, yeah - DWARF does require the fragments be in order (essentially they don't say where they are in the structure - so you have to emit the first byte first, second byte second, etc)
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.
LGTM! Glad to see this change.
(also, sorry for the delay... I still haven't sorted my github email filters)
Thank you for the pointer! Nikita graciously added my fork and I tried it out on this branch. The worst benchmark for instructions:u is |
It seems like I ran into the issue mentioned in https://discourse.llvm.org/t/how-to-rerun-buildkite-github-pull-requests/73402/4 with the windows build-bot I'm going to force-push to the branch to kick off a new build |
This avoids the need for a mutable member to implement deferred sorting, and some bespoke code to maintain a SmallVector as a set. The performance impact seems to be negligible in some small tests, and so seems acceptable to greatly simplify the code. An old FIXME and accompanying workaround are dropped. It is ostensibly dead-code within the current codebase.
a3f4517
to
7e65050
Compare
This avoids the need for a mutable member to implement deferred sorting, and some bespoke code to maintain a SmallVector as a set.
The performance impact seems to be negligible in some small tests, and so seems acceptable to greatly simplify the code.
An old FIXME and accompanying workaround are dropped. It is ostensibly dead-code within the current codebase.