[llvm] Add a pass to calculate machine function's cfg hash to detect whether… (PR #84145)

via llvm-commits llvm-commits at lists.llvm.org
Wed Mar 6 01:42:09 PST 2024


https://github.com/lifengxiang1025 created https://github.com/llvm/llvm-project/pull/84145

… Propeller's profile is out-dated [1/2]

>From 7f9eca85ebef223c564eb71f496e8c46644f3d84 Mon Sep 17 00:00:00 2001
From: lifengxiang <lifengxiang.1025 at bytedance.com>
Date: Wed, 6 Mar 2024 17:39:37 +0800
Subject: [PATCH] Add a pass to calculate machine function's cfg hash to detect
 whether Propeller's profile is out-dated [1/2]

---
 .../CodeGen/BasicBlockSectionsProfileReader.h |  6 ++
 .../llvm/CodeGen/MachineFunctionHashBuilder.h | 57 +++++++++++++
 llvm/include/llvm/CodeGen/Passes.h            |  5 ++
 llvm/include/llvm/InitializePasses.h          |  2 +-
 llvm/lib/CodeGen/BasicBlockPathCloning.cpp    | 11 +++
 llvm/lib/CodeGen/BasicBlockSections.cpp       | 30 ++++---
 .../BasicBlockSectionsProfileReader.cpp       | 48 ++++++++---
 llvm/lib/CodeGen/CMakeLists.txt               |  1 +
 llvm/lib/CodeGen/CodeGen.cpp                  |  1 +
 .../CodeGen/MachineFunctionHashBuilder.cpp    | 79 ++++++++++++++++++
 llvm/lib/CodeGen/TargetPassConfig.cpp         |  8 ++
 .../CodeGen/X86/machine-function-cfg-hash.ll  | 81 +++++++++++++++++++
 12 files changed, 308 insertions(+), 21 deletions(-)
 create mode 100644 llvm/include/llvm/CodeGen/MachineFunctionHashBuilder.h
 create mode 100644 llvm/lib/CodeGen/MachineFunctionHashBuilder.cpp
 create mode 100644 llvm/test/CodeGen/X86/machine-function-cfg-hash.ll

diff --git a/llvm/include/llvm/CodeGen/BasicBlockSectionsProfileReader.h b/llvm/include/llvm/CodeGen/BasicBlockSectionsProfileReader.h
index bba675f1d3eb7d..8707925f0afbaa 100644
--- a/llvm/include/llvm/CodeGen/BasicBlockSectionsProfileReader.h
+++ b/llvm/include/llvm/CodeGen/BasicBlockSectionsProfileReader.h
@@ -100,6 +100,8 @@ class BasicBlockSectionsProfileReader {
   SmallVector<SmallVector<unsigned>>
   getClonePathsForFunction(StringRef FuncName) const;
 
+  uint64_t getCFGHashForFunction(StringRef FuncName) const;
+
 private:
   StringRef getAliasName(StringRef FuncName) const {
     auto R = FuncAliasMap.find(FuncName);
@@ -151,6 +153,8 @@ class BasicBlockSectionsProfileReader {
   // Some functions have alias names. We use this map to find the main alias
   // name which appears in ProgramPathAndClusterInfo as a key.
   StringMap<StringRef> FuncAliasMap;
+
+  StringMap<uint64_t> FuncHashMap;
 };
 
 // Creates a BasicBlockSectionsProfileReader pass to parse the basic block
@@ -206,6 +210,8 @@ class BasicBlockSectionsProfileReaderWrapperPass : public ImmutablePass {
   SmallVector<SmallVector<unsigned>>
   getClonePathsForFunction(StringRef FuncName) const;
 
+  uint64_t getCFGHashForFunction(StringRef FuncName) 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/include/llvm/CodeGen/MachineFunctionHashBuilder.h b/llvm/include/llvm/CodeGen/MachineFunctionHashBuilder.h
new file mode 100644
index 00000000000000..85fd43e19762a6
--- /dev/null
+++ b/llvm/include/llvm/CodeGen/MachineFunctionHashBuilder.h
@@ -0,0 +1,57 @@
+//===-- MachineFunctionHashBuilder.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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the implementation of pass about calculating machine
+/// function hash.
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_MACHINE_FUNCTION_HASH_BUILDER_H
+#define LLVM_MACHINE_FUNCTION_HASH_BUILDER_H
+
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/InitializePasses.h"
+
+namespace llvm {
+
+class MachineFunctionHashBuilder : public MachineFunctionPass {
+public:
+  static char ID;
+
+  MachineFunctionHashBuilder() : MachineFunctionPass(ID) {
+    initializeMachineFunctionHashBuilderPass(*PassRegistry::getPassRegistry());
+  }
+
+  StringRef getPassName() const override {
+    return "Calculate machine function hash.";
+  }
+
+  bool runOnMachineFunction(MachineFunction &MF) override;
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    AU.setPreservesAll();
+    MachineFunctionPass::getAnalysisUsage(AU);
+  }
+
+  uint64_t getCFGHash(StringRef Name) {
+    if (!CFGHash.count(Name)) {
+      return 0;
+    }
+    return CFGHash[Name];
+  }
+
+private:
+  void setCFGHash(StringRef Name, uint64_t Hash) { CFGHash[Name] = Hash; }
+  StringMap<uint64_t> CFGHash;
+};
+
+} // namespace llvm
+#endif
\ No newline at end of file
diff --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h
index f850767270a4fd..ab25ec59e0a54c 100644
--- a/llvm/include/llvm/CodeGen/Passes.h
+++ b/llvm/include/llvm/CodeGen/Passes.h
@@ -605,6 +605,11 @@ namespace llvm {
 
   /// Lowers KCFI operand bundles for indirect calls.
   FunctionPass *createKCFIPass();
+
+  /// Calculate machine function hash.
+  extern char &MachineFunctionHashBuilderID;
+
+  MachineFunctionPass *createMachineFunctionHashBuilderPass();
 } // End llvm namespace
 
 #endif
diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h
index e4bf3868d00069..c2f5146c7c36c3 100644
--- a/llvm/include/llvm/InitializePasses.h
+++ b/llvm/include/llvm/InitializePasses.h
@@ -191,6 +191,7 @@ void initializeMachineCycleInfoPrinterPassPass(PassRegistry &);
 void initializeMachineCycleInfoWrapperPassPass(PassRegistry &);
 void initializeMachineDominanceFrontierPass(PassRegistry&);
 void initializeMachineDominatorTreePass(PassRegistry&);
+void initializeMachineFunctionHashBuilderPass(PassRegistry &);
 void initializeMachineFunctionPrinterPassPass(PassRegistry&);
 void initializeMachineFunctionSplitterPass(PassRegistry &);
 void initializeMachineLateInstrsCleanupPass(PassRegistry&);
@@ -313,7 +314,6 @@ void initializeWasmEHPreparePass(PassRegistry&);
 void initializeWinEHPreparePass(PassRegistry&);
 void initializeWriteBitcodePassPass(PassRegistry&);
 void initializeXRayInstrumentationPass(PassRegistry&);
-
 } // end namespace llvm
 
 #endif // LLVM_INITIALIZEPASSES_H
diff --git a/llvm/lib/CodeGen/BasicBlockPathCloning.cpp b/llvm/lib/CodeGen/BasicBlockPathCloning.cpp
index 901542e8507bdf..0bcc3117bacd7f 100644
--- a/llvm/lib/CodeGen/BasicBlockPathCloning.cpp
+++ b/llvm/lib/CodeGen/BasicBlockPathCloning.cpp
@@ -37,6 +37,7 @@
 #include "llvm/CodeGen/BasicBlockSectionUtils.h"
 #include "llvm/CodeGen/BasicBlockSectionsProfileReader.h"
 #include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineFunctionHashBuilder.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
 #include "llvm/CodeGen/Passes.h"
 #include "llvm/CodeGen/TargetInstrInfo.h"
@@ -219,6 +220,7 @@ INITIALIZE_PASS_BEGIN(
     "Applies path clonings for the -basic-block-sections=list option", false,
     false)
 INITIALIZE_PASS_DEPENDENCY(BasicBlockSectionsProfileReaderWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(MachineFunctionHashBuilder)
 INITIALIZE_PASS_END(
     BasicBlockPathCloning, "bb-path-cloning",
     "Applies path clonings for the -basic-block-sections=list option", false,
@@ -229,6 +231,14 @@ bool BasicBlockPathCloning::runOnMachineFunction(MachineFunction &MF) {
          "BB Sections list not enabled!");
   if (hasInstrProfHashMismatch(MF))
     return false;
+  // Check for cfg drift.
+  if (auto *MFHB = getAnalysisIfAvailable<MachineFunctionHashBuilder>()) {
+    auto &BBSPRWP = getAnalysis<BasicBlockSectionsProfileReaderWrapperPass>();
+    if (MFHB->getCFGHash(MF.getName()) !=
+        BBSPRWP.getCFGHashForFunction(MF.getName())) {
+      return false;
+    }
+  }
 
   return ApplyCloning(MF,
                       getAnalysis<BasicBlockSectionsProfileReaderWrapperPass>()
@@ -238,6 +248,7 @@ bool BasicBlockPathCloning::runOnMachineFunction(MachineFunction &MF) {
 void BasicBlockPathCloning::getAnalysisUsage(AnalysisUsage &AU) const {
   AU.setPreservesAll();
   AU.addRequired<BasicBlockSectionsProfileReaderWrapperPass>();
+  AU.addUsedIfAvailable<MachineFunctionHashBuilder>();
   MachineFunctionPass::getAnalysisUsage(AU);
 }
 
diff --git a/llvm/lib/CodeGen/BasicBlockSections.cpp b/llvm/lib/CodeGen/BasicBlockSections.cpp
index 09e45ea5794b76..5cc3ec22a3b132 100644
--- a/llvm/lib/CodeGen/BasicBlockSections.cpp
+++ b/llvm/lib/CodeGen/BasicBlockSections.cpp
@@ -73,6 +73,7 @@
 #include "llvm/CodeGen/BasicBlockSectionUtils.h"
 #include "llvm/CodeGen/BasicBlockSectionsProfileReader.h"
 #include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineFunctionHashBuilder.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
 #include "llvm/CodeGen/Passes.h"
 #include "llvm/CodeGen/TargetInstrInfo.h"
@@ -133,6 +134,7 @@ INITIALIZE_PASS_BEGIN(
     "into clusters of basic blocks.",
     false, false)
 INITIALIZE_PASS_DEPENDENCY(BasicBlockSectionsProfileReaderWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(MachineFunctionHashBuilder)
 INITIALIZE_PASS_END(BasicBlockSections, "bbsections-prepare",
                     "Prepares for basic block sections, by splitting functions "
                     "into clusters of basic blocks.",
@@ -296,15 +298,24 @@ bool BasicBlockSections::handleBBSections(MachineFunction &MF) {
   if (BBSectionsType == BasicBlockSection::None)
     return false;
 
-  // Check for source drift. If the source has changed since the profiles
-  // were obtained, optimizing basic blocks might be sub-optimal.
-  // This only applies to BasicBlockSection::List as it creates
-  // clusters of basic blocks using basic block ids. Source drift can
-  // invalidate these groupings leading to sub-optimal code generation with
-  // regards to performance.
-  if (BBSectionsType == BasicBlockSection::List &&
-      hasInstrProfHashMismatch(MF))
-    return false;
+  if (BBSectionsType == BasicBlockSection::List) {
+    //  Check for source drift. If the source has changed since the profiles
+    //  were obtained, optimizing basic blocks might be sub-optimal.
+    //  This only applies to BasicBlockSection::List as it creates
+    //  clusters of basic blocks using basic block ids. Source drift can
+    //  invalidate these groupings leading to sub-optimal code generation with
+    //  regards to performance.
+    if (hasInstrProfHashMismatch(MF))
+      return false;
+    // Check for cfg drift.
+    if (auto *MFHB = getAnalysisIfAvailable<MachineFunctionHashBuilder>()) {
+      auto &BBSPRWP = getAnalysis<BasicBlockSectionsProfileReaderWrapperPass>();
+      if (MFHB->getCFGHash(MF.getName()) !=
+          BBSPRWP.getCFGHashForFunction(MF.getName())) {
+        return false;
+      }
+    }
+  }
   // Renumber blocks before sorting them. This is useful for accessing the
   // original layout positions and finding the original fallthroughs.
   MF.RenumberBlocks();
@@ -399,6 +410,7 @@ bool BasicBlockSections::runOnMachineFunction(MachineFunction &MF) {
 void BasicBlockSections::getAnalysisUsage(AnalysisUsage &AU) const {
   AU.setPreservesAll();
   AU.addRequired<BasicBlockSectionsProfileReaderWrapperPass>();
+  AU.addUsedIfAvailable<MachineFunctionHashBuilder>();
   MachineFunctionPass::getAnalysisUsage(AU);
 }
 
diff --git a/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp b/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp
index 6eef5d2c50a2f9..ab5b49367fc7ac 100644
--- a/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp
+++ b/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp
@@ -75,10 +75,16 @@ BasicBlockSectionsProfileReader::getClonePathsForFunction(
   return ProgramPathAndClusterInfo.lookup(getAliasName(FuncName)).ClonePaths;
 }
 
+uint64_t BasicBlockSectionsProfileReader::getCFGHashForFunction(
+    StringRef FuncName) const {
+  auto R = FuncHashMap.find(getAliasName(FuncName));
+  return R != FuncHashMap.end() ? R->second : 0;
+}
 // Reads the version 1 basic block sections profile. Profile for each function
 // is encoded as follows:
 //   m <module_name>
 //   f <function_name_1> <function_name_2> ...
+//   h <hash>
 //   c <bb_id_1> <bb_id_2> <bb_id_3>
 //   c <bb_id_4> <bb_id_5>
 //   ...
@@ -86,17 +92,17 @@ BasicBlockSectionsProfileReader::getClonePathsForFunction(
 // distinguishing profile for internal-linkage functions with the same name. If
 // not specified, it will apply to any function with the same name. Function
 // name specifier (starting with 'f') can specify multiple function name
-// aliases. Basic block clusters are specified by 'c' and specify the cluster of
-// basic blocks, and the internal order in which they must be placed in the same
-// section.
-// This profile can also specify cloning paths which instruct the compiler to
-// clone basic blocks along a path. The cloned blocks are then specified in the
-// cluster information.
-// The following profile lists two cloning paths (starting with 'p') for
-// function bar and places the total 9 blocks within two clusters. The first two
-// blocks of a cloning path specify the edge along which the path is cloned. For
-// instance, path 1 (1 -> 3 -> 4) instructs that 3 and 4 must be cloned along
-// the edge 1->3. Within the given clusters, each cloned block is identified by
+// aliases. Function hash are specified by 'h' to detect whether profile is
+// out-dated. Basic block clusters are specified by 'c' and specify the cluster
+// of basic blocks, and the internal order in which they must be placed in the
+// same section. This profile can also specify cloning paths which instruct the
+// compiler to clone basic blocks along a path. The cloned blocks are then
+// specified in the cluster information. The following profile lists two cloning
+// paths (starting with 'p') for function bar and places the total 9 blocks
+// within two clusters. The first two blocks of a cloning path specify the edge
+// along which the path is cloned. For instance, path 1 (1 -> 3 -> 4) instructs
+// that 3 and 4 must be cloned along the edge 1->3. Within the given clusters,
+// each cloned block is identified by
 // "<original block id>.<clone id>". For instance, 3.1 represents the first
 // clone of block 3. Original blocks are specified just with their block ids. A
 // block cloned multiple times appears with distinct clone ids. The CFG for bar
@@ -198,6 +204,21 @@ Error BasicBlockSectionsProfileReader::ReadV1Profile() {
       DIFilename = "";
       continue;
     }
+    case 'h': { // Machine function cfg hash
+      if (Values.size() != 1) {
+        return createProfileParseError(Twine("invalid hash value: '") + S +
+                                       "'");
+      }
+      if (FI == ProgramPathAndClusterInfo.end())
+        continue;
+      unsigned long long Hash = 0;
+      if (getAsUnsignedInteger(Values.front(), 10, Hash))
+        return createProfileParseError(
+            Twine("unable to parse function hash: '" + Values.front()) +
+            "': unsigned integer expected");
+      FuncHashMap[FI->first()] = static_cast<uint64_t>(Hash);
+      continue;
+    }
     case 'c': // Basic block cluster specifier.
       // Skip the profile when we the profile iterator (FI) refers to the
       // past-the-end element.
@@ -444,6 +465,11 @@ BasicBlockSectionsProfileReaderWrapperPass::getBBSPR() {
   return BBSPR;
 }
 
+uint64_t BasicBlockSectionsProfileReaderWrapperPass::getCFGHashForFunction(
+    StringRef FuncName) const {
+  return BBSPR.getCFGHashForFunction(FuncName);
+}
+
 ImmutablePass *llvm::createBasicBlockSectionsProfileReaderWrapperPass(
     const MemoryBuffer *Buf) {
   return new BasicBlockSectionsProfileReaderWrapperPass(Buf);
diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt
index e02c1d6417e077..250db791597124 100644
--- a/llvm/lib/CodeGen/CMakeLists.txt
+++ b/llvm/lib/CodeGen/CMakeLists.txt
@@ -119,6 +119,7 @@ add_llvm_component_library(LLVMCodeGen
   MachineDominators.cpp
   MachineFrameInfo.cpp
   MachineFunction.cpp
+  MachineFunctionHashBuilder.cpp
   MachineFunctionPass.cpp
   MachineFunctionPrinterPass.cpp
   MachineFunctionSplitter.cpp
diff --git a/llvm/lib/CodeGen/CodeGen.cpp b/llvm/lib/CodeGen/CodeGen.cpp
index 544f1b7f593531..967aaf1276882e 100644
--- a/llvm/lib/CodeGen/CodeGen.cpp
+++ b/llvm/lib/CodeGen/CodeGen.cpp
@@ -142,4 +142,5 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
   initializeWasmEHPreparePass(Registry);
   initializeWinEHPreparePass(Registry);
   initializeXRayInstrumentationPass(Registry);
+  initializeMachineFunctionHashBuilderPass(Registry);
 }
diff --git a/llvm/lib/CodeGen/MachineFunctionHashBuilder.cpp b/llvm/lib/CodeGen/MachineFunctionHashBuilder.cpp
new file mode 100644
index 00000000000000..d7cf06d439b5bc
--- /dev/null
+++ b/llvm/lib/CodeGen/MachineFunctionHashBuilder.cpp
@@ -0,0 +1,79 @@
+//===-- MachineFunctionHashBuilder.cpp ----------------------------------*-
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the implementation of pass about calculating machine
+/// function hash.
+//===----------------------------------------------------------------------===//
+#include "llvm/CodeGen/MachineFunctionHashBuilder.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/MD5.h"
+#include "llvm/Support/raw_ostream.h"
+#include <queue>
+#include <unordered_map>
+#include <unordered_set>
+
+using namespace llvm;
+static cl::opt<bool>
+    MFCFGHashDump("mf-cfg-hash-dump",
+                  cl::desc("Dump machine function's control flow grpah hash"),
+                  cl::init(false), cl::Hidden);
+
+// Calculate machine function hash in level order traversal.
+// For each machine basic block, using its mbb's BaseID,
+// size of successors and  successors' mbb's BaseID to update hash.
+// These informations can make graph unique.
+static uint64_t calculateMBBCFGHash(MachineFunction &MF) {
+  std::unordered_set<MachineBasicBlock *> Visited;
+  MD5 Hash;
+  std::queue<MachineBasicBlock *> Q;
+  if (!MF.empty()) {
+    Q.push(&*MF.begin());
+  }
+  while (!Q.empty()) {
+    MachineBasicBlock *Now = Q.front();
+    Q.pop();
+    using namespace llvm::support;
+    uint32_t Value = endian::byte_swap<uint32_t, llvm::endianness::little>(
+        Now->getBBID()->BaseID);
+    uint32_t Size =
+        endian::byte_swap<uint32_t, llvm::endianness::little>(Now->succ_size());
+    Hash.update(llvm::ArrayRef((uint8_t *)&Value, sizeof(Value)));
+    Hash.update(llvm::ArrayRef((uint8_t *)&Size, sizeof(Size)));
+    if (Visited.count(Now)) {
+      continue;
+    }
+    Visited.insert(Now);
+    for (MachineBasicBlock *Succ : Now->successors()) {
+      Q.push(Succ);
+    }
+  }
+  llvm::MD5::MD5Result Result;
+  Hash.final(Result);
+  return Result.low();
+}
+
+bool MachineFunctionHashBuilder::runOnMachineFunction(MachineFunction &MF) {
+  setCFGHash(MF.getName(), calculateMBBCFGHash(MF));
+  if (MFCFGHashDump) {
+    llvm::outs() << "Function name: " << MF.getName().str()
+                 << " Hash: " << getCFGHash(MF.getName()) << "\n";
+  }
+  return true;
+}
+
+char MachineFunctionHashBuilder::ID = 0;
+INITIALIZE_PASS(MachineFunctionHashBuilder, "machine-function-hash",
+                "Calculate machine function hash", false, false)
+char &llvm::MachineFunctionHashBuilderID = MachineFunctionHashBuilder::ID;
+MachineFunctionPass *llvm::createMachineFunctionHashBuilderPass() {
+  return new MachineFunctionHashBuilder();
+}
diff --git a/llvm/lib/CodeGen/TargetPassConfig.cpp b/llvm/lib/CodeGen/TargetPassConfig.cpp
index cf068ece8d4cab..6d65fed80be2ad 100644
--- a/llvm/lib/CodeGen/TargetPassConfig.cpp
+++ b/llvm/lib/CodeGen/TargetPassConfig.cpp
@@ -254,6 +254,11 @@ static cl::opt<bool>
     GCEmptyBlocks("gc-empty-basic-blocks", cl::init(false), cl::Hidden,
                   cl::desc("Enable garbage-collecting empty basic blocks"));
 
+/// Enable calculating machine function's cfg hash.
+static cl::opt<bool> UseMachineFunctionCFGHash(
+    "mf-cfg-hash", cl::init(false), cl::Hidden,
+    cl::desc("Enable calculating machine function's cfg hash."));
+
 /// Allow standard passes to be disabled by command line options. This supports
 /// simple binary flags that either suppress the pass or do nothing.
 /// i.e. -disable-mypass=false has no effect.
@@ -1247,6 +1252,9 @@ void TargetPassConfig::addMachinePasses() {
   // We run the BasicBlockSections pass if either we need BB sections or BB
   // address map (or both).
   if (NeedsBBSections || TM->Options.BBAddrMap) {
+    if (UseMachineFunctionCFGHash) {
+      addPass(llvm::createMachineFunctionHashBuilderPass());
+    }
     if (TM->getBBSectionsType() == llvm::BasicBlockSection::List) {
       addPass(llvm::createBasicBlockSectionsProfileReaderWrapperPass(
           TM->getBBSectionsFuncListBuf()));
diff --git a/llvm/test/CodeGen/X86/machine-function-cfg-hash.ll b/llvm/test/CodeGen/X86/machine-function-cfg-hash.ll
new file mode 100644
index 00000000000000..180a15cab432b8
--- /dev/null
+++ b/llvm/test/CodeGen/X86/machine-function-cfg-hash.ll
@@ -0,0 +1,81 @@
+; RUN: llc < %s -O0 -mtriple=x86_64-pc-linux -function-sections -basic-block-sections=labels \
+; RUN: -mf-cfg-hash=true -mf-cfg-hash-dump=true | FileCheck %s -check-prefix=HASH
+
+;; Foo's cfg is:
+;; 0->2->3
+;;  ->1->3 
+;; Hash is calculated by order: 0 2 2 1 1 1 3 0 3 0.
+; HASH: Function name: _Z3fooi Hash: 4924244626749595063
+
+;; Profile for version 1:
+; RUN: echo 'v1' > %t1
+; RUN: echo 'f _Z3fooi' >> %t1
+; RUN: echo 'h 4924244626749595063' >> %t1
+; RUN: echo 'c 0 2' >> %t1
+; RUN: echo 'c 1' >> %t1
+; RUN: llc < %s -O0 -mtriple=x86_64-pc-linux -function-sections -basic-block-sections=%t1 \
+; RUN: -mf-cfg-hash=true | FileCheck %s -check-prefix=MATCH
+
+;; Profile for version 1:
+; RUN: echo 'v1' > %t2
+; RUN: echo 'f _Z3fooi' >> %t2
+; RUN: echo 'h 0' >> %t2
+; RUN: echo 'c 0 2' >> %t2
+; RUN: echo 'c 1' >> %t2
+; RUN: llc < %s -O0 -mtriple=x86_64-pc-linux -function-sections -basic-block-sections=%t2 \
+; RUN: -mf-cfg-hash=true | FileCheck %s -check-prefix=DISMATCH
+; RUN: llc < %s -O0 -mtriple=x86_64-pc-linux -function-sections -basic-block-sections=%t2 \
+; RUN: | FileCheck %s -check-prefix=MATCH
+
+; MATCH: _Z3fooi.cold
+; DISMATCH-NOT: _Z3fooi.cold
+
+; ModuleID = 'foo.cc'
+source_filename = "foo.cc"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: mustprogress noinline optnone uwtable
+define dso_local noundef i32 @_Z3fooi(i32 noundef %a) #0 {
+entry:
+  %retval = alloca i32, align 4
+  %a.addr = alloca i32, align 4
+  store i32 %a, ptr %a.addr, align 4
+  %0 = load i32, ptr %a.addr, align 4
+  %and = and i32 %0, 1
+  %tobool = icmp ne i32 %and, 0
+  br i1 %tobool, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  %1 = load i32, ptr %a.addr, align 4
+  %call = call noundef i32 @_Z3bari(i32 noundef %1)
+  store i32 %call, ptr %retval, align 4
+  br label %return
+
+if.end:                                           ; preds = %entry
+  %2 = load i32, ptr %a.addr, align 4
+  %call1 = call noundef i32 @_Z3bazi(i32 noundef %2)
+  store i32 %call1, ptr %retval, align 4
+  br label %return
+
+return:                                           ; preds = %if.end, %if.then
+  %3 = load i32, ptr %retval, align 4
+  ret i32 %3
+}
+
+declare noundef i32 @_Z3bari(i32 noundef) #1
+
+declare noundef i32 @_Z3bazi(i32 noundef) #1
+
+attributes #0 = { mustprogress noinline optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4}
+!llvm.ident = !{!5}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 8, !"PIC Level", i32 2}
+!2 = !{i32 7, !"PIE Level", i32 2}
+!3 = !{i32 7, !"uwtable", i32 2}
+!4 = !{i32 7, !"frame-pointer", i32 2}
+!5 = !{!"clang version 18.0.0"}
\ No newline at end of file



More information about the llvm-commits mailing list