[llvm] 255870d - [JITLink] Update splitBlock to support splitting into multiple blocks.

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Sat Sep 21 16:52:17 PDT 2024


Author: Lang Hames
Date: 2024-09-22T09:52:08+10:00
New Revision: 255870d7b5c474b1ea0b61f165d11930ada2e2ef

URL: https://github.com/llvm/llvm-project/commit/255870d7b5c474b1ea0b61f165d11930ada2e2ef
DIFF: https://github.com/llvm/llvm-project/commit/255870d7b5c474b1ea0b61f165d11930ada2e2ef.diff

LOG: [JITLink] Update splitBlock to support splitting into multiple blocks.

LinkGraph::splitBlock used to take a single split-point to split a Block into
two. In the common case where a block needs to be split repeatedly (e.g. in
eh-frame and compact-unwind sections), iterative calls to splitBlock could
lead to poor performance as symbols and edges are repeatedly shuffled to new
blocks.

This commit updates LinkGraph::splitBlock to take a sequence of split offsets,
allowing a block to be split into an arbitrary number of new blocks. Internally,
Symbols and Edges only need to be moved once (directly to whichever new block
they will be associated with), leading to better performance.

On some large MachO object files in an out of tree project this change improved
the performance of splitBlock by several orders of magnitude.

rdar://135820493

Added: 
    

Modified: 
    llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
    llvm/lib/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.cpp
    llvm/lib/ExecutionEngine/JITLink/JITLink.cpp
    llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp
    llvm/test/ExecutionEngine/JITLink/AArch64/ELF_ehframe.s
    llvm/test/ExecutionEngine/JITLink/AArch64/MachO_ehframe.s
    llvm/test/ExecutionEngine/JITLink/LoongArch/ELF_loongarch64_ehframe.s
    llvm/test/ExecutionEngine/JITLink/RISCV/ELF_ehframe.s
    llvm/test/ExecutionEngine/JITLink/ppc64/ELF_ppc64_ehframe.s
    llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
index 8fe53760a852d7..e8a971bbfd2cb6 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
@@ -231,6 +231,12 @@ class Block : public Addressable {
   /// Returns the size of this defined addressable.
   size_t getSize() const { return Size; }
 
+  /// Turns this block into a zero-fill block of the given size.
+  void setZeroFillSize(size_t Size) {
+    Data = nullptr;
+    this->Size = Size;
+  }
+
   /// Returns the address range of this defined addressable.
   orc::ExecutorAddrRange getRange() const {
     return orc::ExecutorAddrRange(getAddress(), getSize());
@@ -1166,17 +1172,22 @@ class LinkGraph {
   /// Cache type for the splitBlock function.
   using SplitBlockCache = std::optional<SmallVector<Symbol *, 8>>;
 
-  /// Splits block B at the given index which must be greater than zero.
-  /// If SplitIndex == B.getSize() then this function is a no-op and returns B.
-  /// If SplitIndex < B.getSize() then this function returns a new block
-  /// covering the range [ 0, SplitIndex ), and B is modified to cover the range
-  /// [ SplitIndex, B.size() ).
+  /// Splits block B into a sequence of smaller blocks.
+  ///
+  /// SplitOffsets should be a sequence of ascending offsets in B. The starting
+  /// offset should be greater than zero, and the final offset less than
+  /// B.getSize() - 1.
+  ///
+  /// The resulting seqeunce of blocks will start with the original block B
+  /// (truncated to end at the first split offset) followed by newly introduced
+  /// blocks starting at the subsequent split points.
   ///
   /// The optional Cache parameter can be used to speed up repeated calls to
-  /// splitBlock for a single block. If the value is None the cache will be
-  /// treated as uninitialized and splitBlock will populate it. Otherwise it
-  /// is assumed to contain the list of Symbols pointing at B, sorted in
-  /// descending order of offset.
+  /// splitBlock for blocks within a single Section. If the value is None then
+  /// the cache will be treated as uninitialized and splitBlock will populate
+  /// it. Otherwise it is assumed to contain the list of Symbols pointing at B,
+  /// sorted in descending order of offset.
+  ///
   ///
   /// Notes:
   ///
@@ -1189,18 +1200,56 @@ class LinkGraph {
   ///    LinkGraph does not have. Clients are responsible for ensuring that
   ///    splitBlock is not used in a way that invalidates edges.
   ///
-  /// 2. The newly introduced block will have a new ordinal which will be
-  ///    higher than any other ordinals in the section. Clients are responsible
-  ///    for re-assigning block ordinals to restore a compatible order if
-  ///    needed.
+  /// 2. The newly introduced blocks will have new ordinals that will be higher
+  ///    than any other ordinals in the section. Clients are responsible for
+  ///    re-assigning block ordinals to restore a compatible order if needed.
   ///
   /// 3. The cache is not automatically updated if new symbols are introduced
   ///    between calls to splitBlock. Any newly introduced symbols may be
   ///    added to the cache manually (descending offset order must be
   ///    preserved), or the cache can be set to None and rebuilt by
   ///    splitBlock on the next call.
-  Block &splitBlock(Block &B, size_t SplitIndex,
-                    SplitBlockCache *Cache = nullptr);
+  template <typename SplitOffsetRange>
+  std::vector<Block *> splitBlock(Block &B, SplitOffsetRange &&SplitOffsets,
+                                  LinkGraph::SplitBlockCache *Cache = nullptr) {
+    std::vector<Block *> Blocks;
+    Blocks.push_back(&B);
+
+    if (std::empty(SplitOffsets))
+      return Blocks;
+
+    // Special case zero-fill:
+    if (B.isZeroFill()) {
+      size_t OrigSize = B.getSize();
+      for (Edge::OffsetT Offset : SplitOffsets) {
+        assert(Offset > 0 && Offset < B.getSize() &&
+               "Split offset must be inside block content");
+        Blocks.back()->setZeroFillSize(
+            Offset - (Blocks.back()->getAddress() - B.getAddress()));
+        Blocks.push_back(&createZeroFillBlock(
+            B.getSection(), B.getSize(), B.getAddress() + Offset,
+            B.getAlignment(),
+            (B.getAlignmentOffset() + Offset) % B.getAlignment()));
+      }
+      Blocks.back()->setZeroFillSize(
+          OrigSize - (Blocks.back()->getAddress() - B.getAddress()));
+      return Blocks;
+    }
+
+    // Handle content blocks. We'll just create the blocks with their starting
+    // address and no content here. The bulk of the work is deferred to
+    // splitBlockImpl.
+    for (Edge::OffsetT Offset : SplitOffsets) {
+      assert(Offset > 0 && Offset < B.getSize() &&
+             "Split offset must be inside block content");
+      Blocks.push_back(&createContentBlock(
+          B.getSection(), ArrayRef<char>(), B.getAddress() + Offset,
+          B.getAlignment(),
+          (B.getAlignmentOffset() + Offset) % B.getAlignment()));
+    }
+
+    return splitBlockImpl(std::move(Blocks), Cache);
+  }
 
   /// Add an external symbol.
   /// Some formats (e.g. ELF) allow Symbols to have sizes. For Symbols whose
@@ -1534,6 +1583,9 @@ class LinkGraph {
   void dump(raw_ostream &OS);
 
 private:
+  std::vector<Block *> splitBlockImpl(std::vector<Block *> Blocks,
+                                      SplitBlockCache *Cache);
+
   // Put the BumpPtrAllocator first so that we don't free any of the underlying
   // memory until the Symbol/Addressable destructors have been run.
   BumpPtrAllocator Allocator;

diff  --git a/llvm/lib/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.cpp b/llvm/lib/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.cpp
index 2a60d8206f6306..2bfbda9aa07e39 100644
--- a/llvm/lib/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.cpp
@@ -78,12 +78,11 @@ Error DWARFRecordSectionSplitter::processBlock(
       StringRef(B.getContent().data(), B.getContent().size()),
       G.getEndianness());
 
+  std::vector<Edge::OffsetT> SplitOffsets;
   while (true) {
-    uint64_t RecordStartOffset = BlockReader.getOffset();
-
     LLVM_DEBUG({
       dbgs() << "    Processing CFI record at "
-             << formatv("{0:x16}", B.getAddress()) << "\n";
+             << (B.getAddress() + BlockReader.getOffset()) << "\n";
     });
 
     uint32_t Length;
@@ -100,17 +99,16 @@ Error DWARFRecordSectionSplitter::processBlock(
         return Err;
     }
 
-    // If this was the last block then there's nothing to split
-    if (BlockReader.empty()) {
-      LLVM_DEBUG(dbgs() << "      Extracted " << B << "\n");
-      return Error::success();
-    }
+    // If this was the last block then there's nothing more to split
+    if (BlockReader.empty())
+      break;
 
-    uint64_t BlockSize = BlockReader.getOffset() - RecordStartOffset;
-    auto &NewBlock = G.splitBlock(B, BlockSize, &Cache);
-    (void)NewBlock;
-    LLVM_DEBUG(dbgs() << "      Extracted " << NewBlock << "\n");
+    SplitOffsets.push_back(BlockReader.getOffset());
   }
+
+  G.splitBlock(B, SplitOffsets);
+
+  return Error::success();
 }
 
 } // namespace jitlink

diff  --git a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp
index b103a9ca98e189..45ae70113aa26c 100644
--- a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp
@@ -167,84 +167,103 @@ Section::~Section() {
     B->~Block();
 }
 
-Block &LinkGraph::splitBlock(Block &B, size_t SplitIndex,
-                             SplitBlockCache *Cache) {
-
-  assert(SplitIndex > 0 && "splitBlock can not be called with SplitIndex == 0");
-
-  // If the split point covers all of B then just return B.
-  if (SplitIndex == B.getSize())
-    return B;
-
-  assert(SplitIndex < B.getSize() && "SplitIndex out of range");
-
-  // Create the new block covering [ 0, SplitIndex ).
-  auto &NewBlock =
-      B.isZeroFill()
-          ? createZeroFillBlock(B.getSection(), SplitIndex, B.getAddress(),
-                                B.getAlignment(), B.getAlignmentOffset())
-          : createContentBlock(
-                B.getSection(), B.getContent().slice(0, SplitIndex),
-                B.getAddress(), B.getAlignment(), B.getAlignmentOffset());
-
-  // Modify B to cover [ SplitIndex, B.size() ).
-  B.setAddress(B.getAddress() + SplitIndex);
-  B.setContent(B.getContent().slice(SplitIndex));
-  B.setAlignmentOffset((B.getAlignmentOffset() + SplitIndex) %
-                       B.getAlignment());
-
-  // Handle edge transfer/update.
-  {
-    // Copy edges to NewBlock (recording their iterators so that we can remove
-    // them from B), and update of Edges remaining on B.
-    std::vector<Block::edge_iterator> EdgesToRemove;
-    for (auto I = B.edges().begin(); I != B.edges().end();) {
-      if (I->getOffset() < SplitIndex) {
-        NewBlock.addEdge(*I);
-        I = B.removeEdge(I);
-      } else {
-        I->setOffset(I->getOffset() - SplitIndex);
-        ++I;
-      }
-    }
+std::vector<Block *> LinkGraph::splitBlockImpl(std::vector<Block *> Blocks,
+                                               SplitBlockCache *Cache) {
+  assert(!Blocks.empty() && "Blocks must at least contain the original block");
+
+  // Fix up content of all blocks.
+  ArrayRef<char> Content = Blocks.front()->getContent();
+  for (size_t I = 0; I != Blocks.size() - 1; ++I) {
+    Blocks[I]->setContent(
+        Content.slice(Blocks[I]->getAddress() - Blocks[0]->getAddress(),
+                      Blocks[I + 1]->getAddress() - Blocks[I]->getAddress()));
   }
+  Blocks.back()->setContent(
+      Content.slice(Blocks.back()->getAddress() - Blocks[0]->getAddress()));
+  bool IsMutable = Blocks[0]->ContentMutable;
+  for (auto *B : Blocks)
+    B->ContentMutable = IsMutable;
 
-  // Handle symbol transfer/update.
+  // Transfer symbols.
   {
-    // Initialize the symbols cache if necessary.
     SplitBlockCache LocalBlockSymbolsCache;
     if (!Cache)
       Cache = &LocalBlockSymbolsCache;
+
+    // Build cache if required.
     if (*Cache == std::nullopt) {
       *Cache = SplitBlockCache::value_type();
-      for (auto *Sym : B.getSection().symbols())
-        if (&Sym->getBlock() == &B)
-          (*Cache)->push_back(Sym);
 
+      for (auto *Sym : Blocks[0]->getSection().symbols())
+        if (&Sym->getBlock() == Blocks[0])
+          (*Cache)->push_back(Sym);
       llvm::sort(**Cache, [](const Symbol *LHS, const Symbol *RHS) {
-        return LHS->getOffset() > RHS->getOffset();
+        return LHS->getAddress() > RHS->getAddress();
       });
     }
-    auto &BlockSymbols = **Cache;
-
-    // Transfer all symbols with offset less than SplitIndex to NewBlock.
-    while (!BlockSymbols.empty() &&
-           BlockSymbols.back()->getOffset() < SplitIndex) {
-      auto *Sym = BlockSymbols.back();
-      // If the symbol extends beyond the split, update the size to be within
-      // the new block.
-      if (Sym->getOffset() + Sym->getSize() > SplitIndex)
-        Sym->setSize(SplitIndex - Sym->getOffset());
-      Sym->setBlock(NewBlock);
-      BlockSymbols.pop_back();
+
+    auto TransferSymbol = [](Symbol &Sym, Block &B) {
+      Sym.setOffset(Sym.getAddress() - B.getAddress());
+      if (Sym.getSize() > B.getSize())
+        Sym.setSize(B.getSize() - Sym.getOffset());
+      Sym.setBlock(B);
+    };
+
+    // Transfer symbols to all blocks except the last one.
+    for (size_t I = 0; I != Blocks.size() - 1; ++I) {
+      if ((*Cache)->empty())
+        break;
+      while (!(*Cache)->empty() &&
+             (*Cache)->back()->getAddress() < Blocks[I + 1]->getAddress()) {
+        TransferSymbol(*(*Cache)->back(), *Blocks[I]);
+        (*Cache)->pop_back();
+      }
+    }
+    // Transfer symbols to the last block, checking that all are in-range.
+    while (!(*Cache)->empty()) {
+      auto &Sym = *(*Cache)->back();
+      (*Cache)->pop_back();
+      assert(Sym.getAddress() >= Blocks.back()->getAddress() &&
+             "Symbol address preceeds block");
+      assert(Sym.getAddress() <= Blocks.back()->getRange().End &&
+             "Symbol address starts past end of block");
+      TransferSymbol(Sym, *Blocks.back());
+    }
+  }
+
+  // Transfer edges.
+  auto &Edges = Blocks[0]->Edges;
+  llvm::sort(Edges, [](const Edge &LHS, const Edge &RHS) {
+    return LHS.getOffset() < RHS.getOffset();
+  });
+
+  for (size_t I = Blocks.size() - 1; I != 0; --I) {
+
+    // If all edges have been transferred then bail out.
+    if (Edges.empty())
+      break;
+
+    Edge::OffsetT Delta = Blocks[I]->getAddress() - Blocks[0]->getAddress();
+
+    // If no edges to move for this block then move to the next one.
+    if (Edges.back().getOffset() < Delta)
+      continue;
+
+    size_t EI = Edges.size() - 1;
+    while (EI != 0 && Edges[EI - 1].getOffset() >= Delta)
+      --EI;
+
+    for (size_t J = EI; J != Edges.size(); ++J) {
+      Blocks[I]->Edges.push_back(std::move(Edges[J]));
+      Blocks[I]->Edges.back().setOffset(Blocks[I]->Edges.back().getOffset() -
+                                        Delta);
     }
 
-    // Update offsets for all remaining symbols in B.
-    for (auto *Sym : BlockSymbols)
-      Sym->setOffset(Sym->getOffset() - SplitIndex);
+    while (Edges.size() > EI)
+      Edges.pop_back();
   }
 
-  return NewBlock;
+  return Blocks;
 }
 
 void LinkGraph::dump(raw_ostream &OS) {

diff  --git a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp
index 260999b4fb4548..15d679bcbb5df8 100644
--- a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp
@@ -11,6 +11,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "MachOLinkGraphBuilder.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Sequence.h"
 #include <optional>
 
 #define DEBUG_TYPE "jitlink"
@@ -796,10 +798,11 @@ Error CompactUnwindSplitter::operator()(LinkGraph &G) {
       continue;
     }
 
+    unsigned NumBlocks = B->getSize() / CURecordSize;
+
     LLVM_DEBUG({
       dbgs() << "  Splitting block at " << formatv("{0:x16}", B->getAddress())
-             << " into " << (B->getSize() / CURecordSize)
-             << " compact unwind record(s)\n";
+             << " into " << NumBlocks << " compact unwind record(s)\n";
     });
 
     if (B->getSize() % CURecordSize)
@@ -810,49 +813,50 @@ Error CompactUnwindSplitter::operator()(LinkGraph &G) {
           " (not a multiple of CU record size of " +
           formatv("{0:x}", CURecordSize) + ")");
 
-    unsigned NumBlocks = B->getSize() / CURecordSize;
-    LinkGraph::SplitBlockCache C;
+    auto Blocks =
+        G.splitBlock(*B, map_range(seq(1U, NumBlocks), [=](Edge::OffsetT Idx) {
+          return Idx * CURecordSize;
+        }));
 
-    for (unsigned I = 0; I != NumBlocks; ++I) {
-      auto &CURec = G.splitBlock(*B, CURecordSize, &C);
+    for (auto *CURec : Blocks) {
       bool AddedKeepAlive = false;
 
-      for (auto &E : CURec.edges()) {
+      for (auto &E : CURec->edges()) {
         if (E.getOffset() == 0) {
           LLVM_DEBUG({
             dbgs() << "    Updating compact unwind record at "
-                   << formatv("{0:x16}", CURec.getAddress()) << " to point to "
+                   << CURec->getAddress() << " to point to "
                    << (E.getTarget().hasName() ? E.getTarget().getName()
                                                : StringRef())
-                   << " (at " << formatv("{0:x16}", E.getTarget().getAddress())
-                   << ")\n";
+                   << " (at " << E.getTarget().getAddress() << ")\n";
           });
 
           if (E.getTarget().isExternal())
             return make_error<JITLinkError>(
                 "Error adding keep-alive edge for compact unwind record at " +
-                formatv("{0:x}", CURec.getAddress()) + ": target " +
+                formatv("{0:x}", CURec->getAddress()) + ": target " +
                 E.getTarget().getName() + " is an external symbol");
           auto &TgtBlock = E.getTarget().getBlock();
           auto &CURecSym =
-              G.addAnonymousSymbol(CURec, 0, CURecordSize, false, false);
+              G.addAnonymousSymbol(*CURec, 0, CURecordSize, false, false);
           TgtBlock.addEdge(Edge::KeepAlive, 0, CURecSym, 0);
           AddedKeepAlive = true;
         } else if (E.getOffset() != PersonalityEdgeOffset &&
                    E.getOffset() != LSDAEdgeOffset)
-          return make_error<JITLinkError>("Unexpected edge at offset " +
-                                          formatv("{0:x}", E.getOffset()) +
-                                          " in compact unwind record at " +
-                                          formatv("{0:x}", CURec.getAddress()));
+          return make_error<JITLinkError>(
+              "Unexpected edge at offset " + formatv("{0:x}", E.getOffset()) +
+              " in compact unwind record at " +
+              formatv("{0:x}", CURec->getAddress()));
       }
 
       if (!AddedKeepAlive)
         return make_error<JITLinkError>(
             "Error adding keep-alive edge for compact unwind record at " +
-            formatv("{0:x}", CURec.getAddress()) +
+            formatv("{0:x}", CURec->getAddress()) +
             ": no outgoing target edge at offset 0");
     }
   }
+
   return Error::success();
 }
 

diff  --git a/llvm/test/ExecutionEngine/JITLink/AArch64/ELF_ehframe.s b/llvm/test/ExecutionEngine/JITLink/AArch64/ELF_ehframe.s
index 716c4e5abd3fb9..151a041e7bcda5 100644
--- a/llvm/test/ExecutionEngine/JITLink/AArch64/ELF_ehframe.s
+++ b/llvm/test/ExecutionEngine/JITLink/AArch64/ELF_ehframe.s
@@ -8,9 +8,7 @@
 # CHECK: DWARFRecordSectionSplitter: Processing .eh_frame...
 # CHECK:  Processing block at
 # CHECK:    Processing CFI record at
-# CHECK:      Extracted {{.*}} section = .eh_frame
 # CHECK:    Processing CFI record at
-# CHECK:      Extracted {{.*}} section = .eh_frame
 # CHECK: EHFrameEdgeFixer: Processing .eh_frame in "{{.*}}"...
 # CHECK:   Processing block at
 # CHECK:     Record is CIE

diff  --git a/llvm/test/ExecutionEngine/JITLink/AArch64/MachO_ehframe.s b/llvm/test/ExecutionEngine/JITLink/AArch64/MachO_ehframe.s
index 4bc006a9a7a2a9..8d43b0f975f69c 100644
--- a/llvm/test/ExecutionEngine/JITLink/AArch64/MachO_ehframe.s
+++ b/llvm/test/ExecutionEngine/JITLink/AArch64/MachO_ehframe.s
@@ -8,9 +8,7 @@
 # CHECK: DWARFRecordSectionSplitter: Processing __TEXT,__eh_frame...
 # CHECK:  Processing block at
 # CHECK:    Processing CFI record at
-# CHECK:      Extracted {{.*}} section = __TEXT,__eh_frame
 # CHECK:    Processing CFI record at
-# CHECK:      Extracted {{.*}} section = __TEXT,__eh_frame
 # CHECK: EHFrameEdgeFixer: Processing __TEXT,__eh_frame in "{{.*}}"...
 # CHECK:   Processing block at
 # CHECK:     Record is CIE

diff  --git a/llvm/test/ExecutionEngine/JITLink/LoongArch/ELF_loongarch64_ehframe.s b/llvm/test/ExecutionEngine/JITLink/LoongArch/ELF_loongarch64_ehframe.s
index 3eb3cba11da262..cc545853f3278b 100644
--- a/llvm/test/ExecutionEngine/JITLink/LoongArch/ELF_loongarch64_ehframe.s
+++ b/llvm/test/ExecutionEngine/JITLink/LoongArch/ELF_loongarch64_ehframe.s
@@ -8,9 +8,7 @@
 # CHECK: DWARFRecordSectionSplitter: Processing .eh_frame...
 # CHECK:  Processing block at
 # CHECK:    Processing CFI record at
-# CHECK:      Extracted {{.*}} section = .eh_frame
 # CHECK:    Processing CFI record at
-# CHECK:      Extracted {{.*}} section = .eh_frame
 # CHECK: EHFrameEdgeFixer: Processing .eh_frame in "{{.*}}"...
 # CHECK:   Processing block at
 # CHECK:     Record is CIE

diff  --git a/llvm/test/ExecutionEngine/JITLink/RISCV/ELF_ehframe.s b/llvm/test/ExecutionEngine/JITLink/RISCV/ELF_ehframe.s
index 9173bf7c3d95e4..2458a755587928 100644
--- a/llvm/test/ExecutionEngine/JITLink/RISCV/ELF_ehframe.s
+++ b/llvm/test/ExecutionEngine/JITLink/RISCV/ELF_ehframe.s
@@ -13,9 +13,7 @@
 # CHECK: DWARFRecordSectionSplitter: Processing .eh_frame...
 # CHECK:  Processing block at
 # CHECK:    Processing CFI record at
-# CHECK:      Extracted {{.*}} section = .eh_frame
 # CHECK:    Processing CFI record at
-# CHECK:      Extracted {{.*}} section = .eh_frame
 # CHECK: EHFrameEdgeFixer: Processing .eh_frame in "{{.*}}"...
 # CHECK:   Processing block at
 # CHECK:     Record is CIE

diff  --git a/llvm/test/ExecutionEngine/JITLink/ppc64/ELF_ppc64_ehframe.s b/llvm/test/ExecutionEngine/JITLink/ppc64/ELF_ppc64_ehframe.s
index 13e9006b7a8a81..9e9b340c5d8d22 100644
--- a/llvm/test/ExecutionEngine/JITLink/ppc64/ELF_ppc64_ehframe.s
+++ b/llvm/test/ExecutionEngine/JITLink/ppc64/ELF_ppc64_ehframe.s
@@ -11,9 +11,7 @@
 # CHECK: DWARFRecordSectionSplitter: Processing .eh_frame...
 # CHECK:   Processing block at
 # CHECK:     Processing CFI record at
-# CHECK:       Extracted {{.*}} section = .eh_frame
 # CHECK:     Processing CFI record at
-# CHECK:       Extracted {{.*}} section = .eh_frame
 # CHECK: EHFrameEdgeFixer: Processing .eh_frame in "{{.*}}"...
 # CHECK:   Processing block at
 # CHECK:     Record is CIE

diff  --git a/llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp b/llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp
index 20eed05b14ae8e..5eea2118461952 100644
--- a/llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp
+++ b/llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp
@@ -685,37 +685,44 @@ TEST(LinkGraphTest, SplitBlock) {
   B1.addEdge(Edge::FirstRelocation, 12, ES4, 0);
 
   // Split B1.
-  auto &B2 = G.splitBlock(B1, 8);
+  auto Blocks = G.splitBlock(B1, ArrayRef<int>({8}));
 
-  // Check that the block addresses and content matches what we would expect.
-  EXPECT_EQ(B1.getAddress(), B1Addr + 8);
-  EXPECT_EQ(B1.getContent(), BlockContent.slice(8));
-
-  EXPECT_EQ(B2.getAddress(), B1Addr);
-  EXPECT_EQ(B2.getContent(), BlockContent.slice(0, 8));
+  EXPECT_EQ(Blocks.size(), 2U);
+  EXPECT_EQ(Blocks[0], &B1);
+  auto &B2 = *Blocks[1];
 
-  // Check that symbols in B1 were transferred as expected:
-  // We expect S1 and S2 to have been transferred to B2, and S3 and S4 to have
-  // remained attached to B1. Symbols S3 and S4 should have had their offsets
-  // slid to account for the change in address of B2.
-  EXPECT_EQ(&S1.getBlock(), &B2);
+  // Check that the block addresses and content matches what we would expect.
+  EXPECT_EQ(B1.getAddress(), B1Addr);
+  EXPECT_EQ(B1.getContent(), BlockContent.slice(0, 8));
+  EXPECT_EQ(B1.edges_size(), 2U);
+
+  EXPECT_EQ(B2.getAddress(), B1Addr + 8);
+  EXPECT_EQ(B2.getContent(), BlockContent.slice(8));
+  EXPECT_EQ(B2.edges_size(), 2U);
+
+  // Check that symbols in B2 were transferred as expected:
+  // We expect S1 and S2 to have been transferred to B1, and S3 and S4 to have
+  // remained attached to B2. Symbols S3 and S4 should have had their offsets
+  // slid to account for the change in address of B1.
+  EXPECT_EQ(&S1.getBlock(), &B1);
   EXPECT_EQ(S1.getOffset(), 0U);
 
-  EXPECT_EQ(&S2.getBlock(), &B2);
+  EXPECT_EQ(&S2.getBlock(), &B1);
   EXPECT_EQ(S2.getOffset(), 4U);
 
-  EXPECT_EQ(&S3.getBlock(), &B1);
+  EXPECT_EQ(&S3.getBlock(), &B2);
   EXPECT_EQ(S3.getOffset(), 0U);
 
-  EXPECT_EQ(&S4.getBlock(), &B1);
+  EXPECT_EQ(&S4.getBlock(), &B2);
   EXPECT_EQ(S4.getOffset(), 4U);
 
-  EXPECT_EQ(&S5.getBlock(), &B2);
+  EXPECT_EQ(&S5.getBlock(), &B1);
   EXPECT_EQ(S5.getOffset(), 0U);
+
   // Size shrinks to fit.
   EXPECT_EQ(S5.getSize(), 8U);
 
-  // Check that edges in B1 have been transferred as expected:
+  // Check that edges in B2 have been transferred as expected:
   // Both blocks should now have two edges each at offsets 0 and 4.
   EXPECT_EQ(llvm::size(B1.edges()), 2);
   if (size(B1.edges()) == 2) {


        


More information about the llvm-commits mailing list