[llvm] [Utils] Consolidate `LockstepReverseIterator` into own header (NFC) (PR #116657)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Fri Dec 13 03:18:42 PST 2024


================
@@ -0,0 +1,160 @@
+//===- 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 {
+  template <typename... Args> NoActiveBlocksOption(Args...) {}
+};
+
+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:
+  using BasicBlockT = BasicBlock;
+  using InstructionT = Instruction;
+
+  ArrayRef<BasicBlockT *> Blocks;
+  SmallVector<InstructionT *, 4> Insts;
+  bool Fail;
+
+public:
+  LockstepReverseIterator(ArrayRef<BasicBlockT *> Blocks) : Blocks(Blocks) {
+    reset();
+  }
+
+  void reset() {
+    Fail = false;
+    if constexpr (!EarlyFailure) {
+      this->ActiveBlocks.clear();
+      for (BasicBlockT *BB : Blocks)
+        this->ActiveBlocks.insert(BB);
+    }
+    Insts.clear();
+    for (BasicBlockT *BB : Blocks) {
+      InstructionT *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<InstructionT *> 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.
+  template <bool C = EarlyFailure, std::enable_if_t<!C, int> = 0>
----------------
dtcxzyw wrote:

You can use `static_assert(!EarlyFailure)` instead of the SFINAE trick.

https://github.com/llvm/llvm-project/pull/116657


More information about the llvm-commits mailing list