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

[RemoveDIs] Update DIBuilder to conditionally insert DbgRecords #84739

Merged
merged 36 commits into from Mar 12, 2024

Conversation

OCHyams
Copy link
Contributor

@OCHyams OCHyams commented Mar 11, 2024

Have DIBuilder conditionally insert either debug intrinsics or DbgRecord depending on the module's IsNewDbgInfoFormat flag. The insertion methods now return a DbgInstPtr (a PointerUnion<Instruction *, DbgRecord *>).

Add a unittest for both modes (I couldn't find an existing test testing insertion behaviours specifically).

Update the DIBuilder C API. I went a different direction for this, rather than returning a union, I've added an additional set of functions.

LLVMDIBuilderInsertDeclareBefore            # Changed - Inserts a non-instruction debug record.
LLVMDIBuilderInsertDeclareAtEnd             # Changed - Inserts a non-instruction debug record.
LLVMDIBuilderInsertDbgValueBefore           # Changed - Inserts a non-instruction debug record.
LLVMDIBuilderInsertDbgValueAtEnd            # Changed - Inserts a non-instruction debug record.

LLVMIsNewDbgInfoFormat                      # New - Returns true if the module is in the new non-instruction mode.  Will be deprecated in future.
LLVMDIBuilderInsertDeclareIntrinsicBefore   # New - Old behaviour of the changed functions above, i.e., insert a dbg intrinsic call. Will be deprecated in future.
LLVMDIBuilderInsertDeclareIntrinsicAtEnd    # New - Old behaviour of the changed functions above, i.e., insert a dbg intrinsic call. Will be deprecated in future.
LLVMDIBuilderInsertDbgValueIntrinsicBefore  # New - Old behaviour of the changed functions above, i.e., insert a dbg intrinsic call. Will be deprecated in future.
LLVMDIBuilderInsertDbgValueIntrinsicAtEnd   # New - Old behaviour of the changed functions above, i.e., insert a dbg intrinsic call. Will be deprecated in future.

I figured this would minimise disruption to the C API, because we'll be removing debug intrinsics entirely at some point. However, if anyone strongly feels the approach should match the DIBuilder returning-a-union interface I can change it, I'm not particularly attached to either method.

This patch changes the existing assumption that DbgRecords are only ever inserted if there's an instruction to insert-before because clang currently inserts debug intrinsics while CodeGening (like any other instruction) meaning it'll try inserting to the end of a block without a terminator. We already have machinery in place to maintain the DbgRecords when a terminator is removed - these become "trailing DbgRecords" which are re-attached when a new instruction is inserted. All I've done is allow this state to occur while inserting DbgRecords too, i.e., it's not only removing terminators that causes this valid transient state, but inserting DbgRecords into incomplete blocks too.

Note: this doesn't mean clang is emitting DbgRecords yet, because the modules it creates are still always in the old debug mode. That will come in a future patch.

Copy link
Contributor

@SLTozer SLTozer left a comment

Choose a reason for hiding this comment

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

Is it possible that the C-interface changes could be split into a separate patch? My concern is that it's going to be a very disruptive patch, and so the commit that breaks everyone using the llvm-c interface should be as small and specific as possible.

@OCHyams
Copy link
Contributor Author

OCHyams commented Mar 11, 2024

Is it possible that the C-interface changes could be split into a separate patch? My concern is that it's going to be a very disruptive patch, and so the commit that breaks everyone using the llvm-c interface should be as small and specific as possible.

SGTM. We could even consider leaving the C interface in an "old-format-only-mode" until we completely remove the "old format". The only thing that'd need to change in the C API at that point would be the return type of those functions. Looking at usages of DIBuilder in LLVM and Clang, the return type isn't used very often, so applying that update to a codebase using the builder API in a similar fashion would be trivial (there may be no work to do in a lot of cases). wdyt?

@OCHyams
Copy link
Contributor Author

OCHyams commented Mar 11, 2024

Rebased, removed C-API changes as mentioned above.

@SLTozer
Copy link
Contributor

SLTozer commented Mar 11, 2024

SGTM. We could even consider leaving the C interface in an "old-format-only-mode" until we completely remove the "old format".

That might work - though since the work is already done, perhaps the right order would be to have a patch that adds the RemoveDI-version of the C interface and an intrinsic-focused version, then in another patch change the original function to be the RemoveDIs version - that way the downstream consumers get a nudge, but have an immediate fix if needed (change instances of the existing function to the intrinsic version), then eventually we can delete the extra versions. Does that sound reasonable?

Copy link
Contributor

@SLTozer SLTozer left a comment

Choose a reason for hiding this comment

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

Largely looks good, some comments inline.

Comment on lines -755 to -756
assert(Dest != end() &&
"Transferring trailing DPValues to another trailing position");
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this something that we see happen when building BBs in clang?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is hit by test OpenMP/cancel_codegen.cpp

assert(Where->getParent() == this);
if (!Where->DbgMarker)
createMarker(Where);
assert(Where == end() || Where->getParent() == this);
Copy link
Contributor

Choose a reason for hiding this comment

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

Is the first condition in this assert meant to be inverted? I would have thought that if Where == end(), then Where->getParent() == this would be trivially true!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If Where == end() then we can't dereference Where to check the parent matches. It's checking either Where is end() or, if it's not then the parent should match this bb.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, so this is changing the condition here to account for insertions at end() (as for the OpenMP test above), while also preventing the error you just described. Got it!

InsertBB->insertDPValueBefore(DPL, InsertBefore->getIterator());
else if (InsertBB)
InsertBB->insertDPValueBefore(DPL, InsertBB->end());
// FIXME: Use smart pointers for DbgRecord ownership management.
Copy link
Contributor

Choose a reason for hiding this comment

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

What would we need smart pointers for here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah that was a leftover comment to myself. Not needed here, was just musing on whether introducing smart pointers to type-ify DbgRecod ownership might be beneficial in the future. Deleted the comment!

Dest,
DIExpression::get(Expr->getContext(), std::nullopt),
DbgAssign->getDebugLoc())
.template get<decltype(DbgInstType)>());
Copy link
Contributor

Choose a reason for hiding this comment

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

C++20 can't come soon enough. That being said, instead of passing the extra DbgInstType to this class, you could create an overloaded function just above this function body:

DPValue *UnwrapDbgInstPtr(DbgInstPtr P, DPValue *) { return static_cast<DPValue*>(cast<DbgRecord*>(P)); }
`DPValue *UnwrapDbgInstPtr(DbgInstPtr P, DbgAssignIntrinsic *) { return static_cast<DbgAssignIntrinsic*>(cast<Instruction*>(P)); }

And then you could just call UnwrapDbgInstPtr(DIB.insertDbgAssign(...), DbgAssign) here. YMMV on this though!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

SGTM, that moves some of the ugliness out of this lambda, which is desirable. Done.


// Test in new-debug mode.
// Reset the test then call convertToNewDbgValues to flip the flag
// on the test's Module, Funciton and BasicBlock.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// on the test's Module, Funciton and BasicBlock.
// on the test's Module, Function and BasicBlock.

// on the test's Module, Funciton and BasicBlock.
TearDown();
SetUp();
M->convertToNewDbgValues();
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to convert M back afterwards? In some of the unit tests we do this (restore the previous state), but I'm not sure if these ones require it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good question but no not needed here. The module is deleted and recreated automatically for each test with TearDown and SetUp.

Copy link
Contributor Author

@OCHyams OCHyams left a comment

Choose a reason for hiding this comment

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

Does that sound reasonable?

SGTM

Comment on lines -755 to -756
assert(Dest != end() &&
"Transferring trailing DPValues to another trailing position");
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is hit by test OpenMP/cancel_codegen.cpp

InsertBB->insertDPValueBefore(DPL, InsertBefore->getIterator());
else if (InsertBB)
InsertBB->insertDPValueBefore(DPL, InsertBB->end());
// FIXME: Use smart pointers for DbgRecord ownership management.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah that was a leftover comment to myself. Not needed here, was just musing on whether introducing smart pointers to type-ify DbgRecod ownership might be beneficial in the future. Deleted the comment!

// on the test's Module, Funciton and BasicBlock.
TearDown();
SetUp();
M->convertToNewDbgValues();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good question but no not needed here. The module is deleted and recreated automatically for each test with TearDown and SetUp.

Dest,
DIExpression::get(Expr->getContext(), std::nullopt),
DbgAssign->getDebugLoc())
.template get<decltype(DbgInstType)>());
Copy link
Contributor Author

Choose a reason for hiding this comment

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

SGTM, that moves some of the ugliness out of this lambda, which is desirable. Done.

assert(Where->getParent() == this);
if (!Where->DbgMarker)
createMarker(Where);
assert(Where == end() || Where->getParent() == this);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

If Where == end() then we can't dereference Where to check the parent matches. It's checking either Where is end() or, if it's not then the parent should match this bb.

@OCHyams
Copy link
Contributor Author

OCHyams commented Mar 12, 2024

Thanks for the review!

@OCHyams OCHyams merged commit 9997e03 into llvm:main Mar 12, 2024
3 of 4 checks passed
OCHyams added a commit that referenced this pull request Mar 18, 2024
This patch fixes problems that pop up when clang emits DbgRecords
instead of debug intrinsics.

Note: this doesn't mean clang is emitting DbgRecords yet, because the
modules it creates are still always in the old debug mode. That will
come in a future patch.

Depends on #84739
OCHyams added a commit that referenced this pull request Mar 18, 2024
This patch fixes problems that pop up when clang emits DbgRecords
instead of debug intrinsics.

Note: this doesn't mean clang is emitting DbgRecords yet, because the
modules it creates are still always in the old debug mode. That will
come in a future patch.

Depends on #84739
OCHyams added a commit that referenced this pull request Mar 18, 2024
…4915)

Follow on from #84739, which updates the DIBuilder class.

All the functions that have been added are temporary and will be
deprecated in the future. The intention is that they'll help downstream
projects adapt during the transition period.

```
New functions (all to be deprecated)
------------------------------------
LLVMIsNewDbgInfoFormat                      # Returns true if the module is in the new non-instruction mode.
LLVMSetIsNewDbgInfoFormat                   # Convert to the requested debug info format.

LLVMDIBuilderInsertDeclareIntrinsicBefore   # Insert a debug intrinsic (old debug info format). 
LLVMDIBuilderInsertDeclareIntrinsicAtEnd    # Same as above.
LLVMDIBuilderInsertDbgValueIntrinsicBefore  # Same as above.
LLVMDIBuilderInsertDbgValueIntrinsicAtEnd   # Same as above.

LLVMDIBuilderInsertDeclareRecordBefore      # Insert a debug record (new debug info format). 
LLVMDIBuilderInsertDeclareRecordAtEnd       # Same as above.
LLVMDIBuilderInsertDbgValueRecordBefore     # Same as above.
LLVMDIBuilderInsertDbgValueRecordAtEnd      # Same as above.
```

The existing `LLVMDIBuilderInsert...` functions call through to the
intrinsic versions (old debug info format) currently.

In the next patch, I'll swap them to call the debug records versions
(new debug info format). Downstream users of this API can query and
change the current format using the first two functions above, or can
instead opt to temporarily use intrinsics or records explicitly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants