[llvm] [IR] Add per-function numbers to basic blocks (PR #101052)

Alexis Engelke via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 30 08:48:41 PDT 2024


https://github.com/aengelke updated https://github.com/llvm/llvm-project/pull/101052

>From bff9e567fe51220de00e8049e72e3037794ab542 Mon Sep 17 00:00:00 2001
From: Alexis Engelke <engelke at in.tum.de>
Date: Mon, 29 Jul 2024 17:00:38 +0000
Subject: [PATCH 1/4] [IR] Add per-function numbers to basic blocks

Every basic block that is linked into a function now has a unique
number, which can be queried using getNumber(). Numbers are densely
allocated, but not re-assigned on block removal for stability. Block
numbers are intended to be fairly stable and only be updated when
removing a several basic blocks to make sure the numbering doesn't
become too sparse.

To reduce holes in the numbering, renumberBlocks() can be called to
re-assign numbers in block order.
---
 llvm/include/llvm/IR/BasicBlock.h  | 10 +++++
 llvm/include/llvm/IR/Function.h    | 22 +++++++++
 llvm/lib/IR/BasicBlock.cpp         |  2 +
 llvm/lib/IR/Function.cpp           | 25 +++++++++++
 llvm/unittests/IR/FunctionTest.cpp | 72 ++++++++++++++++++++++++++++++
 5 files changed, 131 insertions(+)

diff --git a/llvm/include/llvm/IR/BasicBlock.h b/llvm/include/llvm/IR/BasicBlock.h
index 12571d957da60..c7913e60cea08 100644
--- a/llvm/include/llvm/IR/BasicBlock.h
+++ b/llvm/include/llvm/IR/BasicBlock.h
@@ -67,6 +67,11 @@ class BasicBlock final : public Value, // Basic blocks are data objects also
   bool IsNewDbgInfoFormat;
 
 private:
+  // Allow Function to renumber blocks.
+  friend class Function;
+  /// Per-function unique number.
+  unsigned Number = -1u;
+
   friend class BlockAddress;
   friend class SymbolTableListTraits<BasicBlock>;
 
@@ -96,6 +101,11 @@ class BasicBlock final : public Value, // Basic blocks are data objects also
   void setIsNewDbgInfoFormat(bool NewFlag);
   void setNewDbgInfoFormatFlag(bool NewFlag);
 
+  unsigned getNumber() const {
+    assert(getParent() && "only basic blocks in functions have valid numbers");
+    return Number;
+  }
+
   /// Record that the collection of DbgRecords in \p M "trails" after the last
   /// instruction of this block. These are equivalent to dbg.value intrinsics
   /// that exist at the end of a basic block with no terminator (a transient
diff --git a/llvm/include/llvm/IR/Function.h b/llvm/include/llvm/IR/Function.h
index fd7a6aa46eea0..a2514bf5229dc 100644
--- a/llvm/include/llvm/IR/Function.h
+++ b/llvm/include/llvm/IR/Function.h
@@ -75,6 +75,22 @@ class LLVM_EXTERNAL_VISIBILITY Function : public GlobalObject,
 private:
   // Important things that make up a function!
   BasicBlockListType BasicBlocks;         ///< The basic blocks
+
+  // Basic blocks need to get their number when added to a function.
+  friend void BasicBlock::setParent(Function *);
+  unsigned NextBlockNum = 0;
+
+public:
+  /// Renumber basic blocks into a dense value range starting from 0. Be aware
+  /// that other data structures and analyses (e.g., DominatorTree) may depend
+  /// on the value numbers and need to be updated or invalidated.
+  void renumberBlocks();
+
+  /// Assert that all blocks have unique numbers within 0..NextBlockNum. This
+  /// has O(n) runtime complexity.
+  void validateBlockNumbers() const;
+
+private:
   mutable Argument *Arguments = nullptr;  ///< The formal arguments
   size_t NumArgs;
   std::unique_ptr<ValueSymbolTable>
@@ -996,6 +1012,12 @@ class LLVM_EXTERNAL_VISIBILITY Function : public GlobalObject,
   void setValueSubclassDataBit(unsigned Bit, bool On);
 };
 
+#ifdef NDEBUG
+/// In release builds, this is a no-op. For !NDEBUG builds, the checks are
+/// implemented in the .cpp file.
+inline void Function::validateBlockNumbers() const {}
+#endif
+
 /// Check whether null pointer dereferencing is considered undefined behavior
 /// for a given function or an address space.
 /// Null pointer access in non-zero address space is not considered undefined.
diff --git a/llvm/lib/IR/BasicBlock.cpp b/llvm/lib/IR/BasicBlock.cpp
index bf19934da047c..a797602c73f30 100644
--- a/llvm/lib/IR/BasicBlock.cpp
+++ b/llvm/lib/IR/BasicBlock.cpp
@@ -240,6 +240,8 @@ BasicBlock::~BasicBlock() {
 
 void BasicBlock::setParent(Function *parent) {
   // Set Parent=parent, updating instruction symtab entries as appropriate.
+  if (Parent != parent)
+    Number = parent ? parent->NextBlockNum++ : -1u;
   InstList.setSymTabObject(&Parent, parent);
 }
 
diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp
index 20871982afb06..bef2f935c4ba3 100644
--- a/llvm/lib/IR/Function.cpp
+++ b/llvm/lib/IR/Function.cpp
@@ -13,6 +13,7 @@
 #include "llvm/IR/Function.h"
 #include "SymbolTableListTraitsImpl.h"
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitVector.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallString.h"
@@ -85,6 +86,28 @@ static cl::opt<int> NonGlobalValueMaxNameSize(
 
 extern cl::opt<bool> UseNewDbgInfoFormat;
 
+void Function::renumberBlocks() {
+  validateBlockNumbers();
+
+  NextBlockNum = 0;
+  for (auto &BB : *this)
+    BB.Number = NextBlockNum++;
+}
+
+#ifndef NDEBUG
+/// In asserts builds, this checks the numbering. In non-asserts builds, it
+/// is defined as a no-op inline function in Function.h
+void Function::validateBlockNumbers() const {
+  BitVector Numbers(NextBlockNum);
+  for (const auto &BB : *this) {
+    unsigned Num = BB.getNumber();
+    assert(Num < NextBlockNum && "out of range block number");
+    assert(!Numbers[Num] && "duplicate block numbers");
+    Numbers.set(Num);
+  }
+}
+#endif
+
 void Function::convertToNewDbgValues() {
   IsNewDbgInfoFormat = true;
   for (auto &BB : *this) {
@@ -509,6 +532,8 @@ Function::Function(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace,
 }
 
 Function::~Function() {
+  validateBlockNumbers();
+
   dropAllReferences();    // After this it is safe to delete instructions.
 
   // Delete all of the method arguments and unlink from symbol table...
diff --git a/llvm/unittests/IR/FunctionTest.cpp b/llvm/unittests/IR/FunctionTest.cpp
index 9aaff3ea33830..18edbbaf76561 100644
--- a/llvm/unittests/IR/FunctionTest.cpp
+++ b/llvm/unittests/IR/FunctionTest.cpp
@@ -487,6 +487,78 @@ TEST(FunctionTest, EraseBBs) {
   EXPECT_EQ(F->size(), 0u);
 }
 
+TEST(FunctionTest, BasicBlockNumbers) {
+  LLVMContext Context;
+  Type *VoidType(Type::getVoidTy(Context));
+  FunctionType *FuncType(FunctionType::get(VoidType, false));
+  std::unique_ptr<Function> Func(
+      Function::Create(FuncType, GlobalValue::ExternalLinkage));
+
+  BasicBlock *BB1 = BasicBlock::Create(Context, "bb1", Func.get());
+  EXPECT_EQ(BB1->getNumber(), 0u);
+  BasicBlock *BB2 = BasicBlock::Create(Context, "bb2", Func.get());
+  EXPECT_EQ(BB2->getNumber(), 1u);
+  BasicBlock *BB3 = BasicBlock::Create(Context, "bb3", Func.get());
+  EXPECT_EQ(BB3->getNumber(), 2u);
+
+  BB2->eraseFromParent();
+  // Erasing doesn't trigger renumbering
+  EXPECT_EQ(BB1->getNumber(), 0u);
+  EXPECT_EQ(BB3->getNumber(), 2u);
+  // ... and number are assigned monotonically increasing
+  BasicBlock *BB4 = BasicBlock::Create(Context, "bb4", Func.get());
+  EXPECT_EQ(BB4->getNumber(), 3u);
+  // ... even if inserted not at the end
+  BasicBlock *BB5 = BasicBlock::Create(Context, "bb5", Func.get(), BB1);
+  EXPECT_EQ(BB5->getNumber(), 4u);
+
+  // Func is now: bb5, bb1, bb3, bb4
+  // Renumbering assigns numbers in their order in the function
+  Func->renumberBlocks();
+  EXPECT_EQ(BB5->getNumber(), 0u);
+  EXPECT_EQ(BB1->getNumber(), 1u);
+  EXPECT_EQ(BB3->getNumber(), 2u);
+  EXPECT_EQ(BB4->getNumber(), 3u);
+
+  // Moving a block inside the function doesn't change numbers
+  BB1->moveBefore(BB5);
+  EXPECT_EQ(BB5->getNumber(), 0u);
+  EXPECT_EQ(BB1->getNumber(), 1u);
+  EXPECT_EQ(BB3->getNumber(), 2u);
+  EXPECT_EQ(BB4->getNumber(), 3u);
+
+  // Removing a block and adding it back assigns a new number, because the
+  // block was temporarily without a parent.
+  BB4->removeFromParent();
+  BB4->insertInto(Func.get());
+  EXPECT_EQ(BB5->getNumber(), 0u);
+  EXPECT_EQ(BB1->getNumber(), 1u);
+  EXPECT_EQ(BB3->getNumber(), 2u);
+  EXPECT_EQ(BB4->getNumber(), 4u);
+
+  std::unique_ptr<Function> Func2(
+      Function::Create(FuncType, GlobalValue::ExternalLinkage));
+  BasicBlock *BB6 = BasicBlock::Create(Context, "bb6", Func2.get());
+  EXPECT_EQ(BB6->getNumber(), 0u);
+  // Moving a block to a different function assigns a new number
+  BB3->removeFromParent();
+  BB3->insertInto(Func2.get(), BB6);
+  EXPECT_EQ(BB3->getParent(), Func2.get());
+  EXPECT_EQ(BB3->getNumber(), 1u);
+
+  Func2->renumberBlocks();
+  EXPECT_EQ(BB3->getNumber(), 0u);
+  EXPECT_EQ(BB6->getNumber(), 1u);
+
+  // splice works as expected and assigns new numbers
+  Func->splice(Func->end(), Func2.get());
+  EXPECT_EQ(BB5->getNumber(), 0u);
+  EXPECT_EQ(BB1->getNumber(), 1u);
+  EXPECT_EQ(BB4->getNumber(), 4u);
+  EXPECT_EQ(BB3->getNumber(), 5u);
+  EXPECT_EQ(BB6->getNumber(), 6u);
+}
+
 TEST(FunctionTest, UWTable) {
   LLVMContext Ctx;
   std::unique_ptr<Module> M = parseIR(Ctx, R"(

>From 64053557ee540ab7911e5cbc29f4ae4c27219e4f Mon Sep 17 00:00:00 2001
From: Alexis Engelke <engelke at in.tum.de>
Date: Tue, 30 Jul 2024 09:42:15 +0000
Subject: [PATCH 2/4] Address comments

---
 llvm/include/llvm/IR/Function.h    | 8 +-------
 llvm/lib/IR/Function.cpp           | 6 ++----
 llvm/unittests/IR/FunctionTest.cpp | 4 ++--
 3 files changed, 5 insertions(+), 13 deletions(-)

diff --git a/llvm/include/llvm/IR/Function.h b/llvm/include/llvm/IR/Function.h
index a2514bf5229dc..9c10a67d2382e 100644
--- a/llvm/include/llvm/IR/Function.h
+++ b/llvm/include/llvm/IR/Function.h
@@ -86,11 +86,11 @@ class LLVM_EXTERNAL_VISIBILITY Function : public GlobalObject,
   /// on the value numbers and need to be updated or invalidated.
   void renumberBlocks();
 
+private:
   /// Assert that all blocks have unique numbers within 0..NextBlockNum. This
   /// has O(n) runtime complexity.
   void validateBlockNumbers() const;
 
-private:
   mutable Argument *Arguments = nullptr;  ///< The formal arguments
   size_t NumArgs;
   std::unique_ptr<ValueSymbolTable>
@@ -1012,12 +1012,6 @@ class LLVM_EXTERNAL_VISIBILITY Function : public GlobalObject,
   void setValueSubclassDataBit(unsigned Bit, bool On);
 };
 
-#ifdef NDEBUG
-/// In release builds, this is a no-op. For !NDEBUG builds, the checks are
-/// implemented in the .cpp file.
-inline void Function::validateBlockNumbers() const {}
-#endif
-
 /// Check whether null pointer dereferencing is considered undefined behavior
 /// for a given function or an address space.
 /// Null pointer access in non-zero address space is not considered undefined.
diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp
index bef2f935c4ba3..80783fdd8e7ed 100644
--- a/llvm/lib/IR/Function.cpp
+++ b/llvm/lib/IR/Function.cpp
@@ -94,10 +94,8 @@ void Function::renumberBlocks() {
     BB.Number = NextBlockNum++;
 }
 
-#ifndef NDEBUG
-/// In asserts builds, this checks the numbering. In non-asserts builds, it
-/// is defined as a no-op inline function in Function.h
 void Function::validateBlockNumbers() const {
+#ifndef NDEBUG
   BitVector Numbers(NextBlockNum);
   for (const auto &BB : *this) {
     unsigned Num = BB.getNumber();
@@ -105,8 +103,8 @@ void Function::validateBlockNumbers() const {
     assert(!Numbers[Num] && "duplicate block numbers");
     Numbers.set(Num);
   }
-}
 #endif
+}
 
 void Function::convertToNewDbgValues() {
   IsNewDbgInfoFormat = true;
diff --git a/llvm/unittests/IR/FunctionTest.cpp b/llvm/unittests/IR/FunctionTest.cpp
index 18edbbaf76561..7f4715db513d3 100644
--- a/llvm/unittests/IR/FunctionTest.cpp
+++ b/llvm/unittests/IR/FunctionTest.cpp
@@ -489,8 +489,8 @@ TEST(FunctionTest, EraseBBs) {
 
 TEST(FunctionTest, BasicBlockNumbers) {
   LLVMContext Context;
-  Type *VoidType(Type::getVoidTy(Context));
-  FunctionType *FuncType(FunctionType::get(VoidType, false));
+  Type *VoidType = Type::getVoidTy(Context);
+  FunctionType *FuncType = FunctionType::get(VoidType, false);
   std::unique_ptr<Function> Func(
       Function::Create(FuncType, GlobalValue::ExternalLinkage));
 

>From 7f911e9b384016bc2e7a94675d214e9d912fc052 Mon Sep 17 00:00:00 2001
From: Alexis Engelke <engelke at in.tum.de>
Date: Tue, 30 Jul 2024 10:06:57 +0000
Subject: [PATCH 3/4] Add getMaxBlockNumber() and getBlockNumberEpoch()

---
 llvm/include/llvm/IR/Function.h    | 16 ++++++++++++++++
 llvm/lib/IR/Function.cpp           |  1 +
 llvm/unittests/IR/FunctionTest.cpp | 20 ++++++++++++++++++++
 3 files changed, 37 insertions(+)

diff --git a/llvm/include/llvm/IR/Function.h b/llvm/include/llvm/IR/Function.h
index 9c10a67d2382e..6a8b50db329d2 100644
--- a/llvm/include/llvm/IR/Function.h
+++ b/llvm/include/llvm/IR/Function.h
@@ -79,13 +79,29 @@ class LLVM_EXTERNAL_VISIBILITY Function : public GlobalObject,
   // Basic blocks need to get their number when added to a function.
   friend void BasicBlock::setParent(Function *);
   unsigned NextBlockNum = 0;
+  /// Epoch of block numbers. (Could be shrinked to uint8_t if required.)
+  unsigned BlockNumEpoch = 0;
 
 public:
+  /// Return a value larger than the largest block number. Intended to allocate
+  /// a vector that is sufficiently large to hold all blocks indexed by their
+  /// number.
+  unsigned getMaxBlockNumber() const { return NextBlockNum; }
+
   /// Renumber basic blocks into a dense value range starting from 0. Be aware
   /// that other data structures and analyses (e.g., DominatorTree) may depend
   /// on the value numbers and need to be updated or invalidated.
   void renumberBlocks();
 
+  /// Return the "epoch" of current block numbers. This will return a different
+  /// value after every renumbering. The intention is: if something (e.g., an
+  /// analysis) uses block numbers, it also stores the number epoch and then
+  /// can assert later on that the epoch didn't change (indicating that the
+  /// numbering is still valid). If the epoch changed, blocks might have been
+  /// assigned new numbers and previous uses of the numbers needs to be
+  /// invalidated. This is solely intended as a debugging feature.
+  unsigned getBlockNumberEpoch() const { return BlockNumEpoch; }
+
 private:
   /// Assert that all blocks have unique numbers within 0..NextBlockNum. This
   /// has O(n) runtime complexity.
diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp
index 80783fdd8e7ed..1fe4f4991b002 100644
--- a/llvm/lib/IR/Function.cpp
+++ b/llvm/lib/IR/Function.cpp
@@ -92,6 +92,7 @@ void Function::renumberBlocks() {
   NextBlockNum = 0;
   for (auto &BB : *this)
     BB.Number = NextBlockNum++;
+  BlockNumEpoch++;
 }
 
 void Function::validateBlockNumbers() const {
diff --git a/llvm/unittests/IR/FunctionTest.cpp b/llvm/unittests/IR/FunctionTest.cpp
index 7f4715db513d3..402667931fbc5 100644
--- a/llvm/unittests/IR/FunctionTest.cpp
+++ b/llvm/unittests/IR/FunctionTest.cpp
@@ -494,31 +494,43 @@ TEST(FunctionTest, BasicBlockNumbers) {
   std::unique_ptr<Function> Func(
       Function::Create(FuncType, GlobalValue::ExternalLinkage));
 
+  EXPECT_EQ(Func->getBlockNumberEpoch(), 0u);
+  EXPECT_EQ(Func->getMaxBlockNumber(), 0u);
+
   BasicBlock *BB1 = BasicBlock::Create(Context, "bb1", Func.get());
   EXPECT_EQ(BB1->getNumber(), 0u);
+  EXPECT_EQ(Func->getMaxBlockNumber(), 1u);
   BasicBlock *BB2 = BasicBlock::Create(Context, "bb2", Func.get());
   EXPECT_EQ(BB2->getNumber(), 1u);
+  EXPECT_EQ(Func->getMaxBlockNumber(), 2u);
   BasicBlock *BB3 = BasicBlock::Create(Context, "bb3", Func.get());
   EXPECT_EQ(BB3->getNumber(), 2u);
+  EXPECT_EQ(Func->getMaxBlockNumber(), 3u);
 
   BB2->eraseFromParent();
   // Erasing doesn't trigger renumbering
   EXPECT_EQ(BB1->getNumber(), 0u);
   EXPECT_EQ(BB3->getNumber(), 2u);
+  EXPECT_EQ(Func->getMaxBlockNumber(), 3u);
   // ... and number are assigned monotonically increasing
   BasicBlock *BB4 = BasicBlock::Create(Context, "bb4", Func.get());
   EXPECT_EQ(BB4->getNumber(), 3u);
+  EXPECT_EQ(Func->getMaxBlockNumber(), 4u);
   // ... even if inserted not at the end
   BasicBlock *BB5 = BasicBlock::Create(Context, "bb5", Func.get(), BB1);
   EXPECT_EQ(BB5->getNumber(), 4u);
+  EXPECT_EQ(Func->getMaxBlockNumber(), 5u);
 
   // Func is now: bb5, bb1, bb3, bb4
   // Renumbering assigns numbers in their order in the function
+  EXPECT_EQ(Func->getBlockNumberEpoch(), 0u);
   Func->renumberBlocks();
+  EXPECT_EQ(Func->getBlockNumberEpoch(), 1u);
   EXPECT_EQ(BB5->getNumber(), 0u);
   EXPECT_EQ(BB1->getNumber(), 1u);
   EXPECT_EQ(BB3->getNumber(), 2u);
   EXPECT_EQ(BB4->getNumber(), 3u);
+  EXPECT_EQ(Func->getMaxBlockNumber(), 4u);
 
   // Moving a block inside the function doesn't change numbers
   BB1->moveBefore(BB5);
@@ -526,6 +538,7 @@ TEST(FunctionTest, BasicBlockNumbers) {
   EXPECT_EQ(BB1->getNumber(), 1u);
   EXPECT_EQ(BB3->getNumber(), 2u);
   EXPECT_EQ(BB4->getNumber(), 3u);
+  EXPECT_EQ(Func->getMaxBlockNumber(), 4u);
 
   // Removing a block and adding it back assigns a new number, because the
   // block was temporarily without a parent.
@@ -535,20 +548,26 @@ TEST(FunctionTest, BasicBlockNumbers) {
   EXPECT_EQ(BB1->getNumber(), 1u);
   EXPECT_EQ(BB3->getNumber(), 2u);
   EXPECT_EQ(BB4->getNumber(), 4u);
+  EXPECT_EQ(Func->getMaxBlockNumber(), 5u);
 
   std::unique_ptr<Function> Func2(
       Function::Create(FuncType, GlobalValue::ExternalLinkage));
   BasicBlock *BB6 = BasicBlock::Create(Context, "bb6", Func2.get());
   EXPECT_EQ(BB6->getNumber(), 0u);
+  EXPECT_EQ(Func2->getMaxBlockNumber(), 1u);
   // Moving a block to a different function assigns a new number
   BB3->removeFromParent();
   BB3->insertInto(Func2.get(), BB6);
   EXPECT_EQ(BB3->getParent(), Func2.get());
   EXPECT_EQ(BB3->getNumber(), 1u);
+  EXPECT_EQ(Func2->getMaxBlockNumber(), 2u);
 
+  EXPECT_EQ(Func2->getBlockNumberEpoch(), 0u);
   Func2->renumberBlocks();
+  EXPECT_EQ(Func2->getBlockNumberEpoch(), 1u);
   EXPECT_EQ(BB3->getNumber(), 0u);
   EXPECT_EQ(BB6->getNumber(), 1u);
+  EXPECT_EQ(Func2->getMaxBlockNumber(), 2u);
 
   // splice works as expected and assigns new numbers
   Func->splice(Func->end(), Func2.get());
@@ -557,6 +576,7 @@ TEST(FunctionTest, BasicBlockNumbers) {
   EXPECT_EQ(BB4->getNumber(), 4u);
   EXPECT_EQ(BB3->getNumber(), 5u);
   EXPECT_EQ(BB6->getNumber(), 6u);
+  EXPECT_EQ(Func->getMaxBlockNumber(), 7u);
 }
 
 TEST(FunctionTest, UWTable) {

>From 71a23f543040bd15f7649a2cb44f1a94d4ddcc02 Mon Sep 17 00:00:00 2001
From: Alexis Engelke <engelke at in.tum.de>
Date: Tue, 30 Jul 2024 15:46:38 +0000
Subject: [PATCH 4/4] Move block number functions to block-related functions

---
 llvm/include/llvm/IR/Function.h | 53 +++++++++++++++++----------------
 1 file changed, 28 insertions(+), 25 deletions(-)

diff --git a/llvm/include/llvm/IR/Function.h b/llvm/include/llvm/IR/Function.h
index 6a8b50db329d2..4abf978687d9d 100644
--- a/llvm/include/llvm/IR/Function.h
+++ b/llvm/include/llvm/IR/Function.h
@@ -82,31 +82,6 @@ class LLVM_EXTERNAL_VISIBILITY Function : public GlobalObject,
   /// Epoch of block numbers. (Could be shrinked to uint8_t if required.)
   unsigned BlockNumEpoch = 0;
 
-public:
-  /// Return a value larger than the largest block number. Intended to allocate
-  /// a vector that is sufficiently large to hold all blocks indexed by their
-  /// number.
-  unsigned getMaxBlockNumber() const { return NextBlockNum; }
-
-  /// Renumber basic blocks into a dense value range starting from 0. Be aware
-  /// that other data structures and analyses (e.g., DominatorTree) may depend
-  /// on the value numbers and need to be updated or invalidated.
-  void renumberBlocks();
-
-  /// Return the "epoch" of current block numbers. This will return a different
-  /// value after every renumbering. The intention is: if something (e.g., an
-  /// analysis) uses block numbers, it also stores the number epoch and then
-  /// can assert later on that the epoch didn't change (indicating that the
-  /// numbering is still valid). If the epoch changed, blocks might have been
-  /// assigned new numbers and previous uses of the numbers needs to be
-  /// invalidated. This is solely intended as a debugging feature.
-  unsigned getBlockNumberEpoch() const { return BlockNumEpoch; }
-
-private:
-  /// Assert that all blocks have unique numbers within 0..NextBlockNum. This
-  /// has O(n) runtime complexity.
-  void validateBlockNumbers() const;
-
   mutable Argument *Arguments = nullptr;  ///< The formal arguments
   size_t NumArgs;
   std::unique_ptr<ValueSymbolTable>
@@ -842,6 +817,34 @@ class LLVM_EXTERNAL_VISIBILITY Function : public GlobalObject,
     return SymTab.get();
   }
 
+  //===--------------------------------------------------------------------===//
+  // Block number functions
+
+  /// Return a value larger than the largest block number. Intended to allocate
+  /// a vector that is sufficiently large to hold all blocks indexed by their
+  /// number.
+  unsigned getMaxBlockNumber() const { return NextBlockNum; }
+
+  /// Renumber basic blocks into a dense value range starting from 0. Be aware
+  /// that other data structures and analyses (e.g., DominatorTree) may depend
+  /// on the value numbers and need to be updated or invalidated.
+  void renumberBlocks();
+
+  /// Return the "epoch" of current block numbers. This will return a different
+  /// value after every renumbering. The intention is: if something (e.g., an
+  /// analysis) uses block numbers, it also stores the number epoch and then
+  /// can assert later on that the epoch didn't change (indicating that the
+  /// numbering is still valid). If the epoch changed, blocks might have been
+  /// assigned new numbers and previous uses of the numbers needs to be
+  /// invalidated. This is solely intended as a debugging feature.
+  unsigned getBlockNumberEpoch() const { return BlockNumEpoch; }
+
+private:
+  /// Assert that all blocks have unique numbers within 0..NextBlockNum. This
+  /// has O(n) runtime complexity.
+  void validateBlockNumbers() const;
+
+public:
   //===--------------------------------------------------------------------===//
   // BasicBlock iterator forwarding functions
   //



More information about the llvm-commits mailing list