This is an archive of the discontinued LLVM Phabricator instance.

[IR] Add Instruction::getInsertionPointAfterDef()
ClosedPublic

Authored by nikic on Jul 13 2022, 9:40 AM.

Details

Summary

Transforms occasionally want to insert an instruction directly after the definition point of a value. This involves quite a few different edge cases, e.g. for phi nodes the next insertion point is not the next instruction, and for invokes and callbrs its not even in the next block. Additionally, the insertion point may not exist at all if catchswitch is involved.

We currently reimplement this logic in a few places, and usually get it wrong in one way or another. I've added two tests to demonstrate issues.

This adds a general Instruction::getInsertionPointAfterDef() API to reuse the (hopefully correct) logic.

Diff Detail

Event Timeline

nikic created this revision.Jul 13 2022, 9:40 AM
Herald added a project: Restricted Project. · View Herald TranscriptJul 13 2022, 9:40 AM
Herald added a subscriber: hiraditya. · View Herald Transcript
nikic requested review of this revision.Jul 13 2022, 9:40 AM
Herald added a project: Restricted Project. · View Herald TranscriptJul 13 2022, 9:40 AM
nikic added inline comments.Jul 13 2022, 9:44 AM
llvm/lib/Transforms/Coroutines/CoroFrame.cpp
2647

I'm wondering if it makes sense to move this API to Value instead, to handle this case as well. It's needed here and in the InstCombine freeze transform.

reames added inline comments.Jul 13 2022, 10:54 AM
llvm/lib/IR/Instruction.cpp
135

Please add a comment explaining this case. It's non obvious, and without your wording about catchswitch in the commit message, I'd not have figured this out.

Structure wise, I think I'd prefer:
if (phi node) {
} else if (terminator) {

if (invoke) {}
else if (callbr) {}
else { assert(catchswitch) }

} else {
}

Not a strong preference, so please treat that as a suggestion, nothing more.

barannikov88 added inline comments.
llvm/lib/Transforms/Coroutines/CoroFrame.cpp
2647

There are other Values apart from Argument and Instruction for which the term "point [within a basic block] after the value is defined" does not make sense (e.g. Constant), . It of course could be asserted, but still, Value seems too low-level and too fundamental class for this kind of interface.
I'm not even sure the Instruction is a good place for this method either. The method always returns a location within some basic block, so putting this method into a BasicBlock might seem like a good idea. However, the method should be made static, which would just overload the class with rarely used method with no real benefit.
Considering all of this, I would suggest to turn this method into a standalone utility function with a template argument which is statically asserted to be an Instruction or an Argument.
llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h might be a good place.

Excuse my English

barannikov88 added inline comments.Jul 13 2022, 11:17 AM
llvm/lib/Transforms/Coroutines/CoroFrame.cpp
2647

or llvm/include/llvm/Transforms/Utils/Local.h or ...

nikic added inline comments.Jul 13 2022, 12:05 PM
llvm/lib/Transforms/Coroutines/CoroFrame.cpp
2647

The variant on Value would accept a Function *, which would allow handling constants as well (for them, the insertion point is the same as for arguments: the start of the function).

I don't think this has any particular relation to basic blocks, so adding to BasicBlock or BasicBlockUtils does not seem appropriate to me.

barannikov88 added inline comments.Jul 13 2022, 12:22 PM
llvm/lib/Transforms/Coroutines/CoroFrame.cpp
2647

Well, polluting Value with an interface which is used in exactly four places it not a solution either. That's why I'm suggesting to make this a standalone function, not a member of any particular class. Where to put it is a separate question, but since it is used in transformation passes it may make sense to put it somewhere under include/llvm/Transforms/.
Please consider my comments as a suggestion only.

nikic updated this revision to Diff 444539.Jul 14 2022, 12:25 AM

Additional comments and assertions.

nikic added inline comments.Jul 14 2022, 12:26 AM
llvm/lib/IR/Instruction.cpp
135

I've kept the general code structure, but added an assertion that no terminators fall through to the last cast, so we notice if additional value-returning terminators are introduced.

I would strongly prefer to see this split into a NFC change (even if that means preserving a bug), and functional changes to fix each bug in turn.

In fact, LGTM if you want to land the API with a non-functional change user. But only in that case.

I sort of wonder if we could handle the Argument case by having this be a utility on Function, but we can explore that in a future revision if that patterns turns out to be common.

llvm/include/llvm/IR/Instruction.h
157

Can you change this to getInsertionPointAfterDef? That reads more clearly to me.

llvm/lib/Transforms/Coroutines/CoroFrame.cpp
2648

I think you should assert InsertPt here. Otherwise, we have to figure out what to do with DVI in the catch switch case which the existing code didn't handle.

efriedma added inline comments.
llvm/lib/IR/Instruction.cpp
131

I think for CallBrInst, we're considering modifying the dominance rules to allow the produced value to be used in all destinations? In which case there wouldn't be one unique location after the definition.

llvm/lib/IR/Instruction.cpp
131

I think for CallBrInst, we're considering modifying the dominance rules to allow the produced value to be used in all destinations?

Yes; GCC implemented asm goto w/ outputs this way; we should update our implementation, too. @morbo and I were just discussing this on Tuesday.

https://github.com/llvm/llvm-project/issues/53562

131

@void I meant.

nikic added a comment.Aug 29 2022, 5:42 AM

This would have prevented D132105...

llvm/lib/IR/Instruction.cpp
131

But shouldn't we still implement the current semantics for now? Allowing callbr result to be used on all successors will need more changes, in particular to dominance.

reames added inline comments.Aug 29 2022, 7:28 AM
llvm/lib/IR/Instruction.cpp
131

Agreed. In particular, my LGTM still stands with this concern raised.

nikic updated this revision to Diff 456339.Aug 29 2022, 7:33 AM
nikic marked an inline comment as done.
nikic retitled this revision from [IR] Add Instruction::getAfterDefInsertionPoint() to [IR] Add Instruction::getInsertionPointAfterDef().
nikic edited the summary of this revision. (Show Details)

Rename method and rebase patch.

nikic added inline comments.Aug 29 2022, 7:39 AM
llvm/lib/Transforms/Coroutines/CoroFrame.cpp
2648

I believe this code just performs the move for cosmetic reasons (dbg.declare is not control dependent, it does not matter where in the function it occurs) -- so I think just doing nothing if no insertion point is found would be the right thing to do here (though I have no idea whether this can occur in practice in the context where this function is used).

This revision was not accepted when it landed; it landed in state Needs Review.Aug 31 2022, 1:50 AM
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.