-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[codegen] Emit missing cleanups when an expression contains a branch #80698
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 14 commits
28d9071
442809c
eeabfa2
4125808
3543711
d23cdb3
dc3659a
ddf7c24
a58284b
cf5024c
db43f02
034ebda
b902c61
12706f2
ed016d6
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 |
---|---|---|
|
@@ -627,9 +627,11 @@ CodeGenFunction::getJumpDestForLabel(const LabelDecl *D) { | |
if (Dest.isValid()) return Dest; | ||
|
||
// Create, but don't insert, the new block. | ||
// FIXME: We do not know `BranchInExprDepth` for the destination and currently | ||
// emit *all* the BranchInExpr cleanups. | ||
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. Can you briefly describe what you expect the fix for this to look like, if you have some idea? 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. I think we should remember/copy the entire (This would not work if the goto destination is inside a different stmt-expr. In this case, the code is invalid anyways.) Probably need to rethink how BranchInExpr is emitted to avoid copying the complete stack each time. |
||
Dest = JumpDest(createBasicBlock(D->getName()), | ||
EHScopeStack::stable_iterator::invalid(), | ||
NextCleanupDestIndex++); | ||
/*BranchInExprDepth=*/0, NextCleanupDestIndex++); | ||
return Dest; | ||
} | ||
|
||
|
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.
Any thoughts on pushing a cleanup for each array element, vs. using a single cleanup which iterates over the elements, like we do for exceptions?
Is there any chance an ArrayFiller needs a branch cleanup? Off the top of my head, I don't think it's possible because branches exits can only happen in code explicitly written in the current function, but that's a subtle invariant.
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.
I had considered using
IrregularPartialArrayDestroy
instead of element-wise destroy. The catch is that this cleanup expects allocatedarray.init.end
to store the current end pointer. This is updated as we iterate over and create the elements.I do not think we should add these "stores" overhead, especially with
-fno-exceptions
when there are no branches in expr (the simple cases).What we could be doing instead is just considering the current array index and using that for the array end address.
But that seems to be warned against in the comments:
I do not understand the "complex" flows where this could go wrong.
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.
The complexity here is basically that we'd have to reimplement mem2reg to compute the correct number of cleanups along every control-flow path. Instead, we store to an alloca, and just let the mem2reg optimization clean it up.
On a similar note, because mem2reg cleans up the stores, their overhead is minimal.
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.
Can you please tell me how to verify that mem2reg will clear these stores.
If we can use this cleanup as-is, then we should be able to reuse the
EH-only
cleanups without introducing another cleanup stack (as also pointed out by @jyknight).(I was not able to remove the stores by
bin/opt -S -passes=mem2reg
. I am new to Codegen so I might be missing something.)It is important that we do not introduce these stores with exceptions disabled. But from the looks of it, it should be a easy optimisation pass as the store would never be read in normal circumstances.
This is the only blocker in the reusing EH-only cleanups.
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.
Are you sure you generated the IR correctly? Note that clang marks everything optnone at -O0 by default.
That said, I guess -O0 codegen is a potential issue; I don't think we run any passes that would clean up the dead stores in that case. I'd only be concerned about the case where we don't actually emit the cleanup; trying to minimize the codesize of the cleanup code isn't important at -O0.
To address the case of no cleanups, maybe we could generate the stores lazily? Basically, save where the stores should be, but don't generate them until we know the cleanup is actually used. Or equivalently, emit the stores, then erase them if the cleanup isn't emitted.