[llvm] [Propeller] Read the CFG profile from the propeller directive. (PR #160422)

Rahman Lavaee via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 23 17:54:28 PDT 2025


https://github.com/rlavaee updated https://github.com/llvm/llvm-project/pull/160422

>From d208cd0072c15a84a2305f8d953482e6a85ddb83 Mon Sep 17 00:00:00 2001
From: Rahman Lavaee <rahmanl at google.com>
Date: Tue, 23 Sep 2025 19:44:33 +0000
Subject: [PATCH 1/5] [Propeller] Ingest the CFG profile.

---
 .../CodeGen/BasicBlockSectionsProfileReader.h | 11 ++++
 .../BasicBlockSectionsProfileReader.cpp       | 54 +++++++++++++++++++
 2 files changed, 65 insertions(+)

diff --git a/llvm/include/llvm/CodeGen/BasicBlockSectionsProfileReader.h b/llvm/include/llvm/CodeGen/BasicBlockSectionsProfileReader.h
index f0cfa7663c5fa..f14d4104e332e 100644
--- a/llvm/include/llvm/CodeGen/BasicBlockSectionsProfileReader.h
+++ b/llvm/include/llvm/CodeGen/BasicBlockSectionsProfileReader.h
@@ -50,6 +50,10 @@ struct FunctionPathAndClusterInfo {
   // the edge a -> b (a is not cloned). The index of the path in this vector
   // determines the `UniqueBBID::CloneID` of the cloned blocks in that path.
   SmallVector<SmallVector<unsigned>> ClonePaths;
+  // Node counts for each basic block.
+  DenseMap<UniqueBBID, uint64_t> NodeCounts;
+  // Edge counts for each edge, stored as a nested map.
+  DenseMap<UniqueBBID, DenseMap<UniqueBBID, uint64_t>> EdgeCounts;
 };
 
 class BasicBlockSectionsProfileReader {
@@ -77,6 +81,11 @@ class BasicBlockSectionsProfileReader {
   SmallVector<SmallVector<unsigned>>
   getClonePathsForFunction(StringRef FuncName) const;
 
+  // Returns the profile count for the edge from `SrcBBID` to `SinkBBID` in
+  // function `FuncName` or zero if it does not exist.
+  uint64_t getEdgeCount(StringRef FuncName, const UniqueBBID &SrcBBID,
+                        const UniqueBBID &SinkBBID);
+
 private:
   StringRef getAliasName(StringRef FuncName) const {
     auto R = FuncAliasMap.find(FuncName);
@@ -183,6 +192,8 @@ class BasicBlockSectionsProfileReaderWrapperPass : public ImmutablePass {
   SmallVector<SmallVector<unsigned>>
   getClonePathsForFunction(StringRef FuncName) const;
 
+  uint64_t getEdgeCount(StringRef FuncName, const UniqueBBID &SrcBBID, const UniqueBBID &DestBBID) const;
+
   // Initializes the FunctionNameToDIFilename map for the current module and
   // then reads the profile for the matching functions.
   bool doInitialization(Module &M) override;
diff --git a/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp b/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp
index 7baeb3fd7bcee..ef04d7bb670b5 100644
--- a/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp
+++ b/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp
@@ -76,6 +76,22 @@ BasicBlockSectionsProfileReader::getClonePathsForFunction(
   return ProgramPathAndClusterInfo.lookup(getAliasName(FuncName)).ClonePaths;
 }
 
+  uint64_t BasicBlockSectionsProfileReader::getEdgeCount(StringRef FuncName, const UniqueBBID &SrcBBID,
+                        const UniqueBBID &SinkBBID) {
+        auto It = ProgramPathAndClusterInfo.find(getAliasName(FuncName));
+        if (It == ProgramPathAndClusterInfo.end())
+      return 0;
+    auto NodeIt = It->second.EdgeCounts.find(SrcBBID);
+    if (NodeIt == It->second.EdgeCounts.end())
+      return 0;
+    auto EdgeIt = NodeIt->second.find(DestBBID);
+    if (EdgeIt == NodeIt->second.end())
+      return 0;
+    return EdgeIt->second;
+  }
+
+
+
 // Reads the version 1 basic block sections profile. Profile for each function
 // is encoded as follows:
 //   m <module_name>
@@ -240,6 +256,38 @@ Error BasicBlockSectionsProfileReader::ReadV1Profile() {
       }
       continue;
     }
+    case 'g': { // CFG profile specifier.
+      // Skip the profile when we the profile iterator (FI) refers to the
+      // past-the-end element.
+      if (FI == ProgramPathAndClusterInfo.end())
+        continue;
+      // For each node, its CFG profile is encoded as
+      // <src>:<count>,<sink_1>:<count_1>,<sink_2>:<count_2>,...
+      for (auto BasicBlockEdgeProfile : Values) {
+        if (BasicBlockEdgeProfile.empty())
+          continue;
+        SmallVector<StringRef, 4> NodeEdgeCounts;
+        BasicBlockEdgeProfile.split(NodeEdgeCounts, ',');
+        UniqueBBID SrcBBID;
+        for (int i = 0; i < NodeEdgeCounts.size(); ++i) {
+          auto [BBIDStr, CountStr] = NodeEdgeCounts[i].split(':');
+          auto BBID = parseUniqueBBID(BBIDStr);
+          if (!BBID)
+            return BBID.takeError();
+          unsigned long long Count = 0;
+          if (getAsUnsignedInteger(CountStr, 10, Count))
+            return createProfileParseError(
+                Twine("unsigned integer expected: '") + CountStr + "'");
+          if (i == 0) {
+            // The first element represents the source and its total count.
+            FI->second.NodeCounts[SrcBBID = *BBID] = Count;
+            continue;
+          }
+          FI->second.EdgeCounts[SrcBBID][*BBID] = Count;
+        }
+      }
+      continue;
+    }
     default:
       return createProfileParseError(Twine("invalid specifier: '") +
                                      Twine(Specifier) + "'");
@@ -440,11 +488,17 @@ BasicBlockSectionsProfileReaderWrapperPass::getClonePathsForFunction(
   return BBSPR.getClonePathsForFunction(FuncName);
 }
 
+uint64_t BasicBlockSectionsProfileReaderWrapperPass::getEdgeCount(StringRef FuncName, const UniqueBBID &SrcBBID, const UniqueBBID &SinkBBID) const {
+  return BBSPR.getEdgeCount(FuncName, SrcBBID, SinkBBID);
+}
+
 BasicBlockSectionsProfileReader &
 BasicBlockSectionsProfileReaderWrapperPass::getBBSPR() {
   return BBSPR;
 }
 
+
+
 ImmutablePass *llvm::createBasicBlockSectionsProfileReaderWrapperPass(
     const MemoryBuffer *Buf) {
   return new BasicBlockSectionsProfileReaderWrapperPass(Buf);

>From 7cabfa569c52bec88b5151fdf767be9ecda494e7 Mon Sep 17 00:00:00 2001
From: Rahman Lavaee <rahmanl at google.com>
Date: Tue, 23 Sep 2025 19:44:51 +0000
Subject: [PATCH 2/5] clang-format.

---
 .../CodeGen/BasicBlockSectionsProfileReader.h |  3 +-
 .../BasicBlockSectionsProfileReader.cpp       | 34 +++++++++----------
 2 files changed, 18 insertions(+), 19 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/BasicBlockSectionsProfileReader.h b/llvm/include/llvm/CodeGen/BasicBlockSectionsProfileReader.h
index f14d4104e332e..c683ec6111513 100644
--- a/llvm/include/llvm/CodeGen/BasicBlockSectionsProfileReader.h
+++ b/llvm/include/llvm/CodeGen/BasicBlockSectionsProfileReader.h
@@ -192,7 +192,8 @@ class BasicBlockSectionsProfileReaderWrapperPass : public ImmutablePass {
   SmallVector<SmallVector<unsigned>>
   getClonePathsForFunction(StringRef FuncName) const;
 
-  uint64_t getEdgeCount(StringRef FuncName, const UniqueBBID &SrcBBID, const UniqueBBID &DestBBID) const;
+  uint64_t getEdgeCount(StringRef FuncName, const UniqueBBID &SrcBBID,
+                        const UniqueBBID &DestBBID) const;
 
   // Initializes the FunctionNameToDIFilename map for the current module and
   // then reads the profile for the matching functions.
diff --git a/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp b/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp
index ef04d7bb670b5..97d56ce8942e8 100644
--- a/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp
+++ b/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp
@@ -76,21 +76,19 @@ BasicBlockSectionsProfileReader::getClonePathsForFunction(
   return ProgramPathAndClusterInfo.lookup(getAliasName(FuncName)).ClonePaths;
 }
 
-  uint64_t BasicBlockSectionsProfileReader::getEdgeCount(StringRef FuncName, const UniqueBBID &SrcBBID,
-                        const UniqueBBID &SinkBBID) {
-        auto It = ProgramPathAndClusterInfo.find(getAliasName(FuncName));
-        if (It == ProgramPathAndClusterInfo.end())
-      return 0;
-    auto NodeIt = It->second.EdgeCounts.find(SrcBBID);
-    if (NodeIt == It->second.EdgeCounts.end())
-      return 0;
-    auto EdgeIt = NodeIt->second.find(DestBBID);
-    if (EdgeIt == NodeIt->second.end())
-      return 0;
-    return EdgeIt->second;
-  }
-
-
+uint64_t BasicBlockSectionsProfileReader::getEdgeCount(
+    StringRef FuncName, const UniqueBBID &SrcBBID, const UniqueBBID &SinkBBID) {
+  auto It = ProgramPathAndClusterInfo.find(getAliasName(FuncName));
+  if (It == ProgramPathAndClusterInfo.end())
+    return 0;
+  auto NodeIt = It->second.EdgeCounts.find(SrcBBID);
+  if (NodeIt == It->second.EdgeCounts.end())
+    return 0;
+  auto EdgeIt = NodeIt->second.find(DestBBID);
+  if (EdgeIt == NodeIt->second.end())
+    return 0;
+  return EdgeIt->second;
+}
 
 // Reads the version 1 basic block sections profile. Profile for each function
 // is encoded as follows:
@@ -488,7 +486,9 @@ BasicBlockSectionsProfileReaderWrapperPass::getClonePathsForFunction(
   return BBSPR.getClonePathsForFunction(FuncName);
 }
 
-uint64_t BasicBlockSectionsProfileReaderWrapperPass::getEdgeCount(StringRef FuncName, const UniqueBBID &SrcBBID, const UniqueBBID &SinkBBID) const {
+uint64_t BasicBlockSectionsProfileReaderWrapperPass::getEdgeCount(
+    StringRef FuncName, const UniqueBBID &SrcBBID,
+    const UniqueBBID &SinkBBID) const {
   return BBSPR.getEdgeCount(FuncName, SrcBBID, SinkBBID);
 }
 
@@ -497,8 +497,6 @@ BasicBlockSectionsProfileReaderWrapperPass::getBBSPR() {
   return BBSPR;
 }
 
-
-
 ImmutablePass *llvm::createBasicBlockSectionsProfileReaderWrapperPass(
     const MemoryBuffer *Buf) {
   return new BasicBlockSectionsProfileReaderWrapperPass(Buf);

>From 15bd1b161786a445cf8480757f0b7deefebe61ed Mon Sep 17 00:00:00 2001
From: Rahman Lavaee <rahmanl at google.com>
Date: Tue, 23 Sep 2025 20:32:10 +0000
Subject: [PATCH 3/5] Fix const.

---
 llvm/include/llvm/CodeGen/BasicBlockSectionsProfileReader.h | 2 +-
 llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp        | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/BasicBlockSectionsProfileReader.h b/llvm/include/llvm/CodeGen/BasicBlockSectionsProfileReader.h
index c683ec6111513..82dd5feb31dba 100644
--- a/llvm/include/llvm/CodeGen/BasicBlockSectionsProfileReader.h
+++ b/llvm/include/llvm/CodeGen/BasicBlockSectionsProfileReader.h
@@ -84,7 +84,7 @@ class BasicBlockSectionsProfileReader {
   // Returns the profile count for the edge from `SrcBBID` to `SinkBBID` in
   // function `FuncName` or zero if it does not exist.
   uint64_t getEdgeCount(StringRef FuncName, const UniqueBBID &SrcBBID,
-                        const UniqueBBID &SinkBBID);
+                        const UniqueBBID &SinkBBID) const;
 
 private:
   StringRef getAliasName(StringRef FuncName) const {
diff --git a/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp b/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp
index 97d56ce8942e8..912654b45aa7e 100644
--- a/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp
+++ b/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp
@@ -77,14 +77,14 @@ BasicBlockSectionsProfileReader::getClonePathsForFunction(
 }
 
 uint64_t BasicBlockSectionsProfileReader::getEdgeCount(
-    StringRef FuncName, const UniqueBBID &SrcBBID, const UniqueBBID &SinkBBID) {
+    StringRef FuncName, const UniqueBBID &SrcBBID, const UniqueBBID &SinkBBID) const {
   auto It = ProgramPathAndClusterInfo.find(getAliasName(FuncName));
   if (It == ProgramPathAndClusterInfo.end())
     return 0;
   auto NodeIt = It->second.EdgeCounts.find(SrcBBID);
   if (NodeIt == It->second.EdgeCounts.end())
     return 0;
-  auto EdgeIt = NodeIt->second.find(DestBBID);
+  auto EdgeIt = NodeIt->second.find(SinkBBID);
   if (EdgeIt == NodeIt->second.end())
     return 0;
   return EdgeIt->second;

>From 0ed45908c27e7167392985548a36f690d6ff5875 Mon Sep 17 00:00:00 2001
From: Rahman Lavaee <rahmanl at google.com>
Date: Wed, 24 Sep 2025 00:27:53 +0000
Subject: [PATCH 4/5] Add and update tests.

---
 .../X86/basic-block-sections-clusters-error.ll      | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/llvm/test/CodeGen/X86/basic-block-sections-clusters-error.ll b/llvm/test/CodeGen/X86/basic-block-sections-clusters-error.ll
index d6f3d5010b556..751ab76722c07 100644
--- a/llvm/test/CodeGen/X86/basic-block-sections-clusters-error.ll
+++ b/llvm/test/CodeGen/X86/basic-block-sections-clusters-error.ll
@@ -57,6 +57,19 @@
 ; RUN: echo 'p 1 2 3 2' >> %t13
 ; RUN: not --crash llc < %s -O0 -mtriple=x86_64 -function-sections -basic-block-sections=%t13 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR13
 ; CHECK-ERROR13: LLVM ERROR: invalid profile {{.*}} at line 4: duplicate cloned block in path: '2'
+; RUN: echo 'v1' > %t14
+; RUN: echo 'f dummy1' >> %t14
+; RUN: echo 'c 0 1' >> %t14
+; RUN: echo 'g 0,1:2' >> %t14
+; RUN: not --crash llc < %s -O0 -mtriple=x86_64 -function-sections -basic-block-sections=%t14 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR14
+; CHECK-ERROR14: LLVM ERROR: invalid profile {{.*}} at line 4: unsigned integer expected: ''
+; RUN: echo 'v1' > %t15
+; RUN: echo 'f dummy1' >> %t15
+; RUN: echo 'c 0 1' >> %t15
+; RUN: echo 'g 0:4,1:2:3' >> %t15
+; RUN: not --crash llc < %s -O0 -mtriple=x86_64 -function-sections -basic-block-sections=%t15 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR15
+; CHECK-ERROR15: LLVM ERROR: invalid profile {{.*}} at line 4: unsigned integer expected: '2:3'
+
 
 define i32 @dummy1(i32 %x, i32 %y, i32 %z) {
   entry:

>From 95552ccf9846693c34738ebc33e6995e1f320030 Mon Sep 17 00:00:00 2001
From: Rahman Lavaee <rahmanl at google.com>
Date: Wed, 24 Sep 2025 00:54:11 +0000
Subject: [PATCH 5/5] Add the cfg test.

---
 .../CodeGen/X86/basic-block-sections-cfg.ll   | 40 +++++++++++++++++++
 1 file changed, 40 insertions(+)
 create mode 100644 llvm/test/CodeGen/X86/basic-block-sections-cfg.ll

diff --git a/llvm/test/CodeGen/X86/basic-block-sections-cfg.ll b/llvm/test/CodeGen/X86/basic-block-sections-cfg.ll
new file mode 100644
index 0000000000000..b8eadc3cac36e
--- /dev/null
+++ b/llvm/test/CodeGen/X86/basic-block-sections-cfg.ll
@@ -0,0 +1,40 @@
+; BB section test with CFG.
+;
+;; Profile for version 1:
+; RUN: echo 'v1' > %t
+; RUN: echo 'f foo' >> %t
+; RUN: echo 'g 0:10,1:9,2:1 1:8,3:8 2:2,3:2 3:11' >> %t
+; RUN: echo 'c 0 2 3' >> %t
+;
+; RUN: llc < %s -O0 -mtriple=x86_64-pc-linux -function-sections -basic-block-sections=%t | FileCheck %s
+;
+define void @foo(i1 zeroext) nounwind {
+  %2 = alloca i8, align 1
+  %3 = zext i1 %0 to i8
+  store i8 %3, ptr %2, align 1
+  %4 = load i8, ptr %2, align 1
+  %5 = trunc i8 %4 to i1
+  br i1 %5, label %6, label %8
+
+6:                                                ; preds = %1
+  %7 = call i32 @bar()
+  br label %10
+
+8:                                                ; preds = %1
+  %9 = call i32 @baz()
+  br label %10
+
+10:                                               ; preds = %8, %6
+  ret void
+}
+
+declare i32 @bar() #1
+
+declare i32 @baz() #1
+
+; CHECK: .section	.text.foo,"ax", at progbits
+; CHECK: callq baz
+; CHECK: retq
+; CHECK: .section	.text.split.foo,"ax", at progbits
+; CHECK: callq bar
+



More information about the llvm-commits mailing list