-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[Utils] Consolidate LockstepReverseIterator into own header (NFC)
#116657
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 2 commits
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 | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,155 @@ | ||||||||
| //===- LockstepReverseIterator.h ------------------------------*- C++ -*---===// | ||||||||
| // | ||||||||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||||||||
| // See https://llvm.org/LICENSE.txt for license information. | ||||||||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||||||
| // | ||||||||
| //===----------------------------------------------------------------------===// | ||||||||
|
|
||||||||
| #ifndef LLVM_TRANSFORMS_UTILS_LOCKSTEPREVERSEITERATOR_H | ||||||||
| #define LLVM_TRANSFORMS_UTILS_LOCKSTEPREVERSEITERATOR_H | ||||||||
|
|
||||||||
| #include "llvm/ADT/ArrayRef.h" | ||||||||
| #include "llvm/ADT/SetVector.h" | ||||||||
| #include "llvm/ADT/SmallVector.h" | ||||||||
| #include "llvm/IR/BasicBlock.h" | ||||||||
| #include "llvm/IR/Instruction.h" | ||||||||
|
|
||||||||
| namespace llvm { | ||||||||
|
|
||||||||
| struct NoActiveBlocksOption {}; | ||||||||
|
|
||||||||
| struct ActiveBlocksOption { | ||||||||
| protected: | ||||||||
| SmallSetVector<BasicBlock *, 4> ActiveBlocks; | ||||||||
|
|
||||||||
| public: | ||||||||
| ActiveBlocksOption() = default; | ||||||||
| }; | ||||||||
|
|
||||||||
| /// Iterates through instructions in a set of blocks in reverse order from the | ||||||||
| /// first non-terminator. For example (assume all blocks have size n): | ||||||||
| /// LockstepReverseIterator I([B1, B2, B3]); | ||||||||
| /// *I-- = [B1[n], B2[n], B3[n]]; | ||||||||
| /// *I-- = [B1[n-1], B2[n-1], B3[n-1]]; | ||||||||
| /// *I-- = [B1[n-2], B2[n-2], B3[n-2]]; | ||||||||
| /// ... | ||||||||
| /// | ||||||||
| /// The iterator continues processing until all blocks have been exhausted if \p | ||||||||
| /// EarlyFailure is explicitly set to \c false. Use \c getActiveBlocks() to | ||||||||
| /// determine which blocks are still going and the order they appear in the list | ||||||||
| /// returned by operator*. | ||||||||
| template <bool EarlyFailure = true> | ||||||||
| class LockstepReverseIterator | ||||||||
| : public std::conditional_t<EarlyFailure, NoActiveBlocksOption, | ||||||||
| ActiveBlocksOption> { | ||||||||
|
||||||||
| private: | ||||||||
| ArrayRef<BasicBlock *> Blocks; | ||||||||
| SmallVector<Instruction *, 4> Insts; | ||||||||
| bool Fail; | ||||||||
|
|
||||||||
| public: | ||||||||
| LockstepReverseIterator(ArrayRef<BasicBlock *> Blocks) : Blocks(Blocks) { | ||||||||
| reset(); | ||||||||
| } | ||||||||
|
|
||||||||
| void reset() { | ||||||||
| Fail = false; | ||||||||
| if constexpr (!EarlyFailure) { | ||||||||
| this->ActiveBlocks.clear(); | ||||||||
| for (BasicBlock *BB : Blocks) | ||||||||
| this->ActiveBlocks.insert(BB); | ||||||||
| } | ||||||||
| Insts.clear(); | ||||||||
| for (BasicBlock *BB : Blocks) { | ||||||||
| Instruction *Prev = BB->getTerminator()->getPrevNonDebugInstruction(); | ||||||||
| if (!Prev) { | ||||||||
| // Block wasn't big enough - only contained a terminator. | ||||||||
| if constexpr (EarlyFailure) { | ||||||||
| Fail = true; | ||||||||
| return; | ||||||||
| } else { | ||||||||
| this->ActiveBlocks.remove(BB); | ||||||||
| continue; | ||||||||
| } | ||||||||
| } | ||||||||
| Insts.push_back(Prev); | ||||||||
| } | ||||||||
| if (Insts.empty()) | ||||||||
| Fail = true; | ||||||||
| } | ||||||||
|
|
||||||||
| bool isValid() const { return !Fail; } | ||||||||
| ArrayRef<Instruction *> operator*() const { return Insts; } | ||||||||
|
|
||||||||
| // Note: This needs to return a SmallSetVector as the elements of | ||||||||
| // ActiveBlocks will be later copied to Blocks using std::copy. The | ||||||||
| // resultant order of elements in Blocks needs to be deterministic. | ||||||||
| // Using SmallPtrSet instead causes non-deterministic order while | ||||||||
| // copying. And we cannot simply sort Blocks as they need to match the | ||||||||
| // corresponding Values. | ||||||||
| SmallSetVector<BasicBlock *, 4> &getActiveBlocks() { | ||||||||
| static_assert(!EarlyFailure, "Unknown method"); | ||||||||
| return this->ActiveBlocks; | ||||||||
| } | ||||||||
|
|
||||||||
|
Collaborator
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. Could this be a member of the active blocks base, so it's just totally not defined on the inactive version? (then there'd be no need for the static assert, and maybe it'd be better for compiler diagnostics?)
Contributor
Author
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. Makes sense, though we still need to expose getActiveBlocks in the derived as well, as the base one is now constrained by private inheritance. |
||||||||
| void restrictToBlocks(SmallSetVector<BasicBlock *, 4> &Blocks) { | ||||||||
| static_assert(!EarlyFailure, "Unknown method"); | ||||||||
| for (auto It = Insts.begin(); It != Insts.end();) { | ||||||||
| if (!Blocks.contains((*It)->getParent())) { | ||||||||
| this->ActiveBlocks.remove((*It)->getParent()); | ||||||||
| It = Insts.erase(It); | ||||||||
| } else { | ||||||||
| ++It; | ||||||||
| } | ||||||||
| } | ||||||||
| } | ||||||||
|
|
||||||||
| void operator--() { | ||||||||
|
||||||||
| if (Fail) | ||||||||
| return; | ||||||||
| SmallVector<Instruction *, 4> NewInsts; | ||||||||
| for (Instruction *Inst : Insts) { | ||||||||
| Instruction *Prev = Inst->getPrevNonDebugInstruction(); | ||||||||
| if (!Prev) { | ||||||||
| if constexpr (!EarlyFailure) { | ||||||||
| this->ActiveBlocks.remove(Inst->getParent()); | ||||||||
| } else { | ||||||||
| Fail = true; | ||||||||
| return; | ||||||||
| } | ||||||||
| } else { | ||||||||
| NewInsts.push_back(Prev); | ||||||||
| } | ||||||||
| } | ||||||||
| if (NewInsts.empty()) { | ||||||||
| Fail = true; | ||||||||
| return; | ||||||||
| } | ||||||||
| Insts = NewInsts; | ||||||||
| } | ||||||||
|
|
||||||||
| void operator++() { | ||||||||
|
||||||||
| void operator++() { | |
| void operator++() { | |
| static_assert(!EarlyFailure, "Unknown method"); |
This method does not maintain the set of active blocks.
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.
Use
class.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'd rather favour
structfor consistency, as we keep the default constructor private forNoActiveBlocksOption, unless it's a strong concern.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.
FWIW https://llvm.org/docs/CodingStandards.html#use-of-class-and-struct-keywords says to use struct when all members are public, which isn't the case here