This is an archive of the discontinued LLVM Phabricator instance.

[IR][NFC] Adds BasicBlock::splice().
ClosedPublic

Authored by vporpo on Nov 29 2022, 8:58 PM.

Details

Summary

Currently the only way to do this is to work with the instruction list directly.
This is part of a series of cleanup patches towards making BasicBlock::getInstList() private.

Diff Detail

Event Timeline

vporpo created this revision.Nov 29 2022, 8:58 PM
Herald added a project: Restricted Project. · View Herald TranscriptNov 29 2022, 8:58 PM
Herald added a subscriber: hiraditya. · View Herald Transcript
vporpo requested review of this revision.Nov 29 2022, 8:58 PM
Herald added a project: Restricted Project. · View Herald TranscriptNov 29 2022, 8:58 PM
aeubanks added inline comments.Nov 30 2022, 11:18 AM
llvm/include/llvm/IR/BasicBlock.h
466

should add a test for this, e.g. splice(I1, I2) where I1 is right before I2 in the same block

llvm/unittests/IR/BasicBlockTest.cpp
386

this name is confusing, not sure what it's referring to

415

perhaps also test when we splice more than one instruction this way? e.g. FromI1 instead

aeubanks added inline comments.Nov 30 2022, 11:19 AM
llvm/include/llvm/IR/BasicBlock.h
466

and does the actual implementation not handle this?

vporpo added inline comments.Nov 30 2022, 11:41 AM
llvm/include/llvm/IR/BasicBlock.h
466

I am not sure. Since I am basically calling splice() internally I was relying on it being well tested. But anyway, since this is part of the BB API now, I agree that it needs a test.

llvm/unittests/IR/BasicBlockTest.cpp
386

Yeah good point.
I think I will also rename the arguments of BasicBlock::splice because Last actually refers to the iterator after tha last one. So End is a better name for it.

415

Agreed

aeubanks added inline comments.Nov 30 2022, 1:35 PM
llvm/include/llvm/IR/BasicBlock.h
466

if getInstList().splice() already handles this, then I'd say no need for this early return. would be good to double check

vporpo added inline comments.Nov 30 2022, 1:48 PM
llvm/include/llvm/IR/BasicBlock.h
466

I just checked and it won't handle this, but I don't think we can handle this either. The current behavior is that it just crashes when the iterator goes out of bounds as it never finds the End iterator. I added a test that confirms the crash.

I don't think we can handle this any better. We could add a linear-time check to test whether BeginIt is before EndIt, but I am not sure it is worth it. What do you think?

vporpo updated this revision to Diff 479063.Nov 30 2022, 1:48 PM

Updated test names, splice() argument names and added test for EndIt before BeginIt.

aeubanks added inline comments.Nov 30 2022, 3:25 PM
llvm/include/llvm/IR/BasicBlock.h
466

I think adding an assert, even if it's linear time, would be good to help future users. can add it under expensive checks (and gate the death test too) if it's too expensive in assert builds

vporpo updated this revision to Diff 479088.Nov 30 2022, 3:50 PM

Added expensive check that tests whether FromBeginIt is before FromEndIt.

vporpo added inline comments.Nov 30 2022, 4:11 PM
llvm/include/llvm/IR/BasicBlock.h
466

Yes the ilist splice already early returns if the iterators are equal. I removed the check from BasicBlock::splice(). I will update the patch.

vporpo added inline comments.Nov 30 2022, 4:29 PM
llvm/include/llvm/IR/BasicBlock.h
466

Hmm turns out that not all ilist splice functions check this:

void splice(iterator where, iplist_impl &L2, iterator first) {
  iterator last = first; ++last;
  if (where == first || where == last) return; // No change                                                                                                                    
  transfer(where, L2, first, last);
}
void splice(iterator where, iplist_impl &L2, iterator first, iterator last) {
  if (first != last) transfer(where, L2, first, last);
}

I am calling the second one which does not check where == first or where == last and it crashes.
I can't think of a reason why the check should be missing. I will create a separate patch for this.

vporpo added inline comments.Nov 30 2022, 7:59 PM
llvm/include/llvm/IR/BasicBlock.h
466

There seems to be a discrepancy in the way ilist's splice() works. The single-element splice() accepts a destination that is equal to the source. There is even a test on this TEST(IListTest, SpliceOne) which checks it. The multi-element splice() will crash, even if it is transferring only one element. There seems to be a lot of code relying on that, so changing this behavior needs some extended cleanup.

I think we should try to maintain this functionality for BB splice(), so we should keep the early exit check`if (ToIt == FromIt || ToIt == FromItLast)` in BasicBlock's single-element splice().

vporpo updated this revision to Diff 479152.Nov 30 2022, 8:36 PM

Added the early-return check that I removed in a previous version.

aeubanks added inline comments.Dec 1 2022, 12:15 PM
llvm/include/llvm/IR/BasicBlock.h
466

in that case can't we just forward every call to getInstList().splice(..., From->getInstList(), ...) rather than going through the newly added 4 param BasicBlock::splice()? Or do you want to funnel then all through one method so you can keep track of all splice calls more easily?

vporpo added inline comments.Dec 1 2022, 12:26 PM
llvm/include/llvm/IR/BasicBlock.h
466

Yes, my intention was to funnel them into a single call. But either way is fine. Which one do you think is better?

aeubanks accepted this revision.Dec 1 2022, 12:29 PM
aeubanks added inline comments.
llvm/include/llvm/IR/BasicBlock.h
466

it depends on how much extra work it is to keep track of 3 splice methods, vs the (admittedly very minor) duplication here with the ilist splice calls. up to you, I'll lgtm this patch either way

This revision is now accepted and ready to land.Dec 1 2022, 12:29 PM
vporpo added inline comments.Dec 1 2022, 12:36 PM
llvm/include/llvm/IR/BasicBlock.h
466

OK let's keep it as it is then. Thanks for the review!

This revision was landed with ongoing or failed builds.Dec 1 2022, 1:54 PM
This revision was automatically updated to reflect the committed changes.