[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:41 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-x86
Author: None (lifengxiang1025)
<details>
<summary>Changes</summary>
… Propeller's profile is out-dated [1/2]
---
Patch is 22.85 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/84145.diff
12 Files Affected:
- (modified) llvm/include/llvm/CodeGen/BasicBlockSectionsProfileReader.h (+6)
- (added) llvm/include/llvm/CodeGen/MachineFunctionHashBuilder.h (+57)
- (modified) llvm/include/llvm/CodeGen/Passes.h (+5)
- (modified) llvm/include/llvm/InitializePasses.h (+1-1)
- (modified) llvm/lib/CodeGen/BasicBlockPathCloning.cpp (+11)
- (modified) llvm/lib/CodeGen/BasicBlockSections.cpp (+21-9)
- (modified) llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp (+37-11)
- (modified) llvm/lib/CodeGen/CMakeLists.txt (+1)
- (modified) llvm/lib/CodeGen/CodeGen.cpp (+1)
- (added) llvm/lib/CodeGen/MachineFunctionHashBuilder.cpp (+79)
- (modified) llvm/lib/CodeGen/TargetPassConfig.cpp (+8)
- (added) llvm/test/CodeGen/X86/machine-function-cfg-hash.ll (+81)
``````````diff
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 Has...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/84145
More information about the llvm-commits
mailing list