Skip to content

Adding Matching and Inference Functionality to Propeller-Patch 1 #140886

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

wdx727
Copy link

@wdx727 wdx727 commented May 21, 2025

We would like to add the matching and inference functionality to Propeller to address the issue that Propeller has zero tolerance for changes in source code and compilation parameters. The complete RFC can be found at the following URL: https://discourse.llvm.org/t/rfc-adding-matching-and-inference-functionality-to-propeller/86238/1.

Due to the large number of files modified in the previous PR, we plan to split the PR into three parts for separate submission:

Patch 1: Add a pass to calculate the hash value of MachineBlock and write the hash into the bb_address_map section. Related test cases and tools will also be modified.
Patch 2: Introduce a new Propeller profile data format and add a pass to read the profile, storing the mapping between MachineBlock hash values and execution frequencies.
Patch 3: Introduce Matching and Inference techniques to obtain the execution frequencies of all MachineBlocks, generate cluster information for MachineFunction, and use the profile in lld to generate symbol sorting.

The PR is Patch1.

…hash into the bb_address_map section. Related test cases and tools will also be modified.
Copy link

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot
Copy link
Member

llvmbot commented May 21, 2025

@llvm/pr-subscribers-backend-loongarch
@llvm/pr-subscribers-backend-arm
@llvm/pr-subscribers-backend-powerpc
@llvm/pr-subscribers-objectyaml
@llvm/pr-subscribers-llvm-binary-utilities

@llvm/pr-subscribers-backend-x86

Author: None (wdx727)

Changes

We would like to add the matching and inference functionality to Propeller to address the issue that Propeller has zero tolerance for changes in source code and compilation parameters. The complete RFC can be found at the following URL: https://discourse.llvm.org/t/rfc-adding-matching-and-inference-functionality-to-propeller/86238/1.

Due to the large number of files modified in the previous PR, we plan to split the PR into three parts for separate submission:

Patch 1: Add a pass to calculate the hash value of MachineBlock and write the hash into the bb_address_map section. Related test cases and tools will also be modified.
Patch 2: Introduce a new Propeller profile data format and add a pass to read the profile, storing the mapping between MachineBlock hash values and execution frequencies.
Patch 3: Introduce Matching and Inference techniques to obtain the execution frequencies of all MachineBlocks, generate cluster information for MachineFunction, and use the profile in lld to generate symbol sorting.

The PR is Patch1.


Patch is 60.23 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/140886.diff

28 Files Affected:

  • (added) llvm/include/llvm/CodeGen/MachineBlockHashInfo.h (+108)
  • (modified) llvm/include/llvm/InitializePasses.h (+1)
  • (modified) llvm/include/llvm/Object/ELFTypes.h (+3-2)
  • (modified) llvm/include/llvm/ObjectYAML/ELFYAML.h (+1)
  • (modified) llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (+6)
  • (modified) llvm/lib/CodeGen/CMakeLists.txt (+1)
  • (modified) llvm/lib/CodeGen/CodeGen.cpp (+1)
  • (added) llvm/lib/CodeGen/MachineBlockHashInfo.cpp (+104)
  • (modified) llvm/lib/Object/ELF.cpp (+2-1)
  • (modified) llvm/lib/ObjectYAML/ELFEmitter.cpp (+1)
  • (modified) llvm/lib/ObjectYAML/ELFYAML.cpp (+1)
  • (modified) llvm/test/CodeGen/X86/basic-block-address-map-pgo-features.ll (+6)
  • (modified) llvm/test/CodeGen/X86/basic-block-address-map-with-basic-block-sections.ll (+4-1)
  • (modified) llvm/test/CodeGen/X86/basic-block-address-map-with-mfs.ll (+3)
  • (modified) llvm/test/CodeGen/X86/basic-block-address-map.ll (+6)
  • (modified) llvm/test/tools/llvm-objdump/X86/elf-bbaddrmap-disassemble-symbolize-operands.yaml (+18)
  • (modified) llvm/test/tools/llvm-objdump/X86/elf-bbaddrmap-symbolize-relocatable.yaml (+7-3)
  • (modified) llvm/test/tools/llvm-objdump/X86/elf-pgoanalysismap.yaml (+9)
  • (modified) llvm/test/tools/llvm-readobj/ELF/bb-addr-map-pgo-analysis-map.test (+13-3)
  • (modified) llvm/test/tools/llvm-readobj/ELF/bb-addr-map-relocatable.test (+10-1)
  • (modified) llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test (+11-1)
  • (modified) llvm/test/tools/obj2yaml/ELF/bb-addr-map-pgo-analysis-map.yaml (+10)
  • (modified) llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml (+10)
  • (modified) llvm/test/tools/yaml2obj/ELF/bb-addr-map-pgo-analysis-map.yaml (+6-3)
  • (modified) llvm/test/tools/yaml2obj/ELF/bb-addr-map.yaml (+6-3)
  • (modified) llvm/tools/llvm-readobj/ELFDumper.cpp (+1)
  • (modified) llvm/tools/obj2yaml/elf2yaml.cpp (+2-1)
  • (modified) llvm/unittests/Object/ELFObjectFileTest.cpp (+58-29)
diff --git a/llvm/include/llvm/CodeGen/MachineBlockHashInfo.h b/llvm/include/llvm/CodeGen/MachineBlockHashInfo.h
new file mode 100644
index 0000000000000..a943f71357e6e
--- /dev/null
+++ b/llvm/include/llvm/CodeGen/MachineBlockHashInfo.h
@@ -0,0 +1,108 @@
+#ifndef LLVM_CODEGEN_MACHINEBLOCKHASHINFO_H
+#define LLVM_CODEGEN_MACHINEBLOCKHASHINFO_H
+
+#include "llvm/CodeGen/MachineFunctionPass.h"
+
+namespace llvm {
+
+/// An object wrapping several components of a basic block hash. The combined
+/// (blended) hash is represented and stored as one uint64_t, while individual
+/// components are of smaller size (e.g., uint16_t or uint8_t).
+struct BlendedBlockHash {
+private:
+  static uint64_t combineHashes(uint16_t Hash1, uint16_t Hash2, uint16_t Hash3,
+                                uint16_t Hash4) {
+    uint64_t Hash = 0;
+
+    Hash |= uint64_t(Hash4);
+    Hash <<= 16;
+
+    Hash |= uint64_t(Hash3);
+    Hash <<= 16;
+
+    Hash |= uint64_t(Hash2);
+    Hash <<= 16;
+
+    Hash |= uint64_t(Hash1);
+
+    return Hash;
+  }
+
+  static void parseHashes(uint64_t Hash, uint16_t &Hash1, uint16_t &Hash2,
+                          uint16_t &Hash3, uint16_t &Hash4) {
+    Hash1 = Hash & 0xffff;
+    Hash >>= 16;
+
+    Hash2 = Hash & 0xffff;
+    Hash >>= 16;
+
+    Hash3 = Hash & 0xffff;
+    Hash >>= 16;
+
+    Hash4 = Hash & 0xffff;
+    Hash >>= 16;
+  }
+
+public:
+  explicit BlendedBlockHash() {}
+
+  explicit BlendedBlockHash(uint64_t CombinedHash) {
+    parseHashes(CombinedHash, Offset, OpcodeHash, InstrHash, NeighborHash);
+  }
+
+  /// Combine the blended hash into uint64_t.
+  uint64_t combine() const {
+    return combineHashes(Offset, OpcodeHash, InstrHash, NeighborHash);
+  }
+
+  /// Compute a distance between two given blended hashes. The smaller the
+  /// distance, the more similar two blocks are. For identical basic blocks,
+  /// the distance is zero.
+  uint64_t distance(const BlendedBlockHash &BBH) const {
+    assert(OpcodeHash == BBH.OpcodeHash &&
+           "incorrect blended hash distance computation");
+    uint64_t Dist = 0;
+    // Account for NeighborHash
+    Dist += NeighborHash == BBH.NeighborHash ? 0 : 1;
+    Dist <<= 16;
+    // Account for InstrHash
+    Dist += InstrHash == BBH.InstrHash ? 0 : 1;
+    Dist <<= 16;
+    // Account for Offset
+    Dist += (Offset >= BBH.Offset ? Offset - BBH.Offset : BBH.Offset - Offset);
+    return Dist;
+  }
+
+  /// The offset of the basic block from the function start.
+  uint16_t Offset{0};
+  /// (Loose) Hash of the basic block instructions, excluding operands.
+  uint16_t OpcodeHash{0};
+  /// (Strong) Hash of the basic block instructions, including opcodes and
+  /// operands.
+  uint16_t InstrHash{0};
+  /// Hash of the (loose) basic block together with (loose) hashes of its
+  /// successors and predecessors.
+  uint16_t NeighborHash{0};
+};
+
+class MachineBlockHashInfo : public MachineFunctionPass {
+  DenseMap<unsigned, uint64_t> MBBHashInfo;
+
+public:
+  static char ID;
+  MachineBlockHashInfo();
+
+  StringRef getPassName() const override {
+    return "Basic Block Hash Compute";
+  }
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override;
+
+  bool runOnMachineFunction(MachineFunction &F) override;
+
+  uint64_t getMBBHash(const MachineBasicBlock &MBB);
+};
+
+} // end namespace llvm
+
+#endif // LLVM_CODEGEN_MACHINEBLOCKHASHINFO_H
\ No newline at end of file
diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h
index 42610d505c2bd..8cb62d5baf235 100644
--- a/llvm/include/llvm/InitializePasses.h
+++ b/llvm/include/llvm/InitializePasses.h
@@ -187,6 +187,7 @@ void initializeMIRCanonicalizerPass(PassRegistry &);
 void initializeMIRNamerPass(PassRegistry &);
 void initializeMIRPrintingPassPass(PassRegistry &);
 void initializeMachineBlockFrequencyInfoWrapperPassPass(PassRegistry &);
+void initializeMachineBlockHashInfoPass(PassRegistry&);
 void initializeMachineBlockPlacementLegacyPass(PassRegistry &);
 void initializeMachineBlockPlacementStatsLegacyPass(PassRegistry &);
 void initializeMachineBranchProbabilityInfoWrapperPassPass(PassRegistry &);
diff --git a/llvm/include/llvm/Object/ELFTypes.h b/llvm/include/llvm/Object/ELFTypes.h
index 87e4dbe448091..8a0b257d2ca27 100644
--- a/llvm/include/llvm/Object/ELFTypes.h
+++ b/llvm/include/llvm/Object/ELFTypes.h
@@ -914,9 +914,10 @@ struct BBAddrMap {
     uint32_t Size = 0;   // Size of the basic block.
     Metadata MD = {false, false, false, false,
                    false}; // Metdata for this basic block.
+    uint64_t Hash = 0;     // Hash for this basic block.
 
-    BBEntry(uint32_t ID, uint32_t Offset, uint32_t Size, Metadata MD)
-        : ID(ID), Offset(Offset), Size(Size), MD(MD){};
+    BBEntry(uint32_t ID, uint32_t Offset, uint32_t Size, Metadata MD, uint64_t Hash)
+        : ID(ID), Offset(Offset), Size(Size), MD(MD), Hash(Hash){};
 
     bool operator==(const BBEntry &Other) const {
       return ID == Other.ID && Offset == Other.Offset && Size == Other.Size &&
diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h
index dfdfa055d65fa..9427042db4303 100644
--- a/llvm/include/llvm/ObjectYAML/ELFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h
@@ -162,6 +162,7 @@ struct BBAddrMapEntry {
     llvm::yaml::Hex64 AddressOffset;
     llvm::yaml::Hex64 Size;
     llvm::yaml::Hex64 Metadata;
+    llvm::yaml::Hex64 Hash;
   };
   uint8_t Version;
   llvm::yaml::Hex8 Feature;
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index fdb81b05d9490..2e1e191183557 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -40,6 +40,7 @@
 #include "llvm/CodeGen/GCMetadataPrinter.h"
 #include "llvm/CodeGen/LazyMachineBlockFrequencyInfo.h"
 #include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineBlockHashInfo.h"
 #include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
 #include "llvm/CodeGen/MachineConstantPool.h"
 #include "llvm/CodeGen/MachineDominators.h"
@@ -451,6 +452,7 @@ const MCSection *AsmPrinter::getCurrentSection() const {
 void AsmPrinter::getAnalysisUsage(AnalysisUsage &AU) const {
   AU.setPreservesAll();
   MachineFunctionPass::getAnalysisUsage(AU);
+  AU.addRequired<MachineBlockHashInfo>();
   AU.addRequired<MachineOptimizationRemarkEmitterPass>();
   AU.addRequired<GCModuleInfo>();
   AU.addRequired<LazyMachineBlockFrequencyInfoPass>();
@@ -1479,6 +1481,8 @@ void AsmPrinter::emitBBAddrMapSection(const MachineFunction &MF) {
       PrevMBBEndSymbol = MBBSymbol;
     }
 
+    auto MBHI = &getAnalysis<MachineBlockHashInfo>();
+
     if (!Features.OmitBBEntries) {
       // TODO: Remove this check when version 1 is deprecated.
       if (BBAddrMapVersion > 1) {
@@ -1498,6 +1502,8 @@ void AsmPrinter::emitBBAddrMapSection(const MachineFunction &MF) {
       emitLabelDifferenceAsULEB128(MBB.getEndSymbol(), MBBSymbol);
       // Emit the Metadata.
       OutStreamer->emitULEB128IntValue(getBBAddrMapMetadata(MBB));
+      // Emit the Hash.
+      OutStreamer->emitULEB128IntValue(MBHI->getMBBHash(MBB));
     }
 
     PrevMBBEndSymbol = MBB.getEndSymbol();
diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt
index 5dd6413431255..424f7b98e2c91 100644
--- a/llvm/lib/CodeGen/CMakeLists.txt
+++ b/llvm/lib/CodeGen/CMakeLists.txt
@@ -108,6 +108,7 @@ add_llvm_component_library(LLVMCodeGen
   LowerEmuTLS.cpp
   MachineBasicBlock.cpp
   MachineBlockFrequencyInfo.cpp
+  MachineBlockHashInfo.cpp
   MachineBlockPlacement.cpp
   MachineBranchProbabilityInfo.cpp
   MachineCFGPrinter.cpp
diff --git a/llvm/lib/CodeGen/CodeGen.cpp b/llvm/lib/CodeGen/CodeGen.cpp
index 5250534d8a4e4..f66b6af84e971 100644
--- a/llvm/lib/CodeGen/CodeGen.cpp
+++ b/llvm/lib/CodeGen/CodeGen.cpp
@@ -72,6 +72,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
   initializeMIRNamerPass(Registry);
   initializeMIRProfileLoaderPassPass(Registry);
   initializeMachineBlockFrequencyInfoWrapperPassPass(Registry);
+  initializeMachineBlockHashInfoPass(Registry);
   initializeMachineBlockPlacementLegacyPass(Registry);
   initializeMachineBlockPlacementStatsLegacyPass(Registry);
   initializeMachineCFGPrinterPass(Registry);
diff --git a/llvm/lib/CodeGen/MachineBlockHashInfo.cpp b/llvm/lib/CodeGen/MachineBlockHashInfo.cpp
new file mode 100644
index 0000000000000..1bf5466fae9b3
--- /dev/null
+++ b/llvm/lib/CodeGen/MachineBlockHashInfo.cpp
@@ -0,0 +1,104 @@
+#include "llvm/CodeGen/MachineBlockHashInfo.h"
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/InitializePasses.h"
+
+using namespace llvm;
+
+using OperandHashFuncTy = function_ref<uint64_t(uint64_t &, const MachineOperand &)>;
+
+uint64_t hashBlock(const MachineBasicBlock &MBB, OperandHashFuncTy OperandHashFunc) {
+  uint64_t Hash = 0;
+  for (const MachineInstr &MI : MBB) {
+    if (MI.isPseudo())
+      continue;
+    // Ignore unconditional jumps
+    if (MI.isUnconditionalBranch())
+      continue;
+    Hash = hashing::detail::hash_16_bytes(Hash, MI.getOpcode());
+    for (unsigned i = 0; i < MI.getNumOperands(); i++) {
+      Hash = OperandHashFunc(Hash, MI.getOperand(i));
+    }
+  }
+  return Hash;
+}
+
+/// Hashing a 64-bit integer to a 16-bit one.
+uint16_t hash_64_to_16(const uint64_t Hash) {
+  uint16_t Res = (uint16_t)(Hash & 0xFFFF);
+  Res ^= (uint16_t)((Hash >> 16) & 0xFFFF);
+  Res ^= (uint16_t)((Hash >> 32) & 0xFFFF);
+  Res ^= (uint16_t)((Hash >> 48) & 0xFFFF);
+  return Res;
+}
+
+uint64_t hashInstOperand(uint64_t &Hash, const MachineOperand &Operand) {
+  return hashing::detail::hash_16_bytes(Hash, hash_value(Operand));
+}
+
+INITIALIZE_PASS(MachineBlockHashInfo, "machine-block-hash",
+                      "Machine Block Hash Analysis", true, true)
+
+char MachineBlockHashInfo::ID = 0;
+
+MachineBlockHashInfo::MachineBlockHashInfo() : MachineFunctionPass(ID) {
+  initializeMachineBlockHashInfoPass(*PassRegistry::getPassRegistry());
+}
+
+void MachineBlockHashInfo::getAnalysisUsage(AnalysisUsage &AU) const {
+  AU.setPreservesAll();
+  MachineFunctionPass::getAnalysisUsage(AU);
+}
+
+bool MachineBlockHashInfo::runOnMachineFunction(MachineFunction &F) {
+  DenseMap<MachineBasicBlock *, BlendedBlockHash> BlendedHashes;
+  DenseMap<MachineBasicBlock *, uint64_t> OpcodeHashes;
+  uint16_t Offset = 0;
+  // Initialize hash components
+  for (MachineBasicBlock &MBB : F) {
+    BlendedBlockHash BlendedHash;
+    // offset of the machine basic block
+    BlendedHash.Offset = Offset;
+    Offset += MBB.size();
+    // Hashing opcodes
+    uint64_t OpcodeHash = hashBlock(MBB, [](uint64_t &Hash, const MachineOperand &Op) { return Hash; });
+    OpcodeHashes[&MBB] = OpcodeHash;
+    BlendedHash.OpcodeHash = hash_64_to_16(OpcodeHash);
+    // Hash complete instructions
+    uint64_t InstrHash = hashBlock(MBB, hashInstOperand);
+    BlendedHash.InstrHash = hash_64_to_16(InstrHash);
+    BlendedHashes[&MBB] = BlendedHash;
+  }
+
+  // Initialize neighbor hash
+  for (MachineBasicBlock &MBB : F) {
+    uint64_t Hash = OpcodeHashes[&MBB];
+    // Append hashes of successors
+    for (MachineBasicBlock *SuccMBB : MBB.successors()) {
+      uint64_t SuccHash = OpcodeHashes[SuccMBB];
+      Hash = hashing::detail::hash_16_bytes(Hash, SuccHash);
+    }
+    // Append hashes of predecessors
+    for (MachineBasicBlock *PredMBB : MBB.predecessors()) {
+      uint64_t PredHash = OpcodeHashes[PredMBB];
+      Hash = hashing::detail::hash_16_bytes(Hash, PredHash);
+    }
+    BlendedHashes[&MBB].NeighborHash = hash_64_to_16(Hash);
+  }
+
+  // Assign hashes
+  for (MachineBasicBlock &MBB : F) {
+    if (MBB.getBBID()) {
+      MBBHashInfo[MBB.getBBID()->BaseID] = BlendedHashes[&MBB].combine();
+    }
+  }
+
+  return false;
+}
+
+uint64_t MachineBlockHashInfo::getMBBHash(const MachineBasicBlock &MBB) {
+  if (MBB.getBBID()) {
+    return MBBHashInfo[MBB.getBBID()->BaseID];
+  }
+  return 0;
+}
\ No newline at end of file
diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp
index bf42c92a242a1..dd585011a13ae 100644
--- a/llvm/lib/Object/ELF.cpp
+++ b/llvm/lib/Object/ELF.cpp
@@ -873,6 +873,7 @@ decodeBBAddrMapImpl(const ELFFile<ELFT> &EF,
           uint32_t Offset = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
           uint32_t Size = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
           uint32_t MD = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
+          uint64_t Hash = readULEB128As<uint64_t>(Data, Cur, ULEBSizeErr);
           if (Version >= 1) {
             // Offset is calculated relative to the end of the previous BB.
             Offset += PrevBBEndOffset;
@@ -884,7 +885,7 @@ decodeBBAddrMapImpl(const ELFFile<ELFT> &EF,
             MetadataDecodeErr = MetadataOrErr.takeError();
             break;
           }
-          BBEntries.push_back({ID, Offset, Size, *MetadataOrErr});
+          BBEntries.push_back({ID, Offset, Size, *MetadataOrErr, Hash});
         }
         TotalNumBlocks += BBEntries.size();
       }
diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp
index 9ae76a71ede5e..a2542b63479ee 100644
--- a/llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -1502,6 +1502,7 @@ void ELFState<ELFT>::writeSectionContent(
         SHeader.sh_size += CBA.writeULEB128(BBE.AddressOffset);
         SHeader.sh_size += CBA.writeULEB128(BBE.Size);
         SHeader.sh_size += CBA.writeULEB128(BBE.Metadata);
+        SHeader.sh_size += CBA.writeULEB128(BBE.Hash);
       }
     }
     if (!PGOAnalyses)
diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp
index 520e956fdab9f..3c98beef16210 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -1882,6 +1882,7 @@ void MappingTraits<ELFYAML::BBAddrMapEntry::BBEntry>::mapping(
   IO.mapRequired("AddressOffset", E.AddressOffset);
   IO.mapRequired("Size", E.Size);
   IO.mapRequired("Metadata", E.Metadata);
+  IO.mapRequired("Hash", E.Hash);
 }
 
 void MappingTraits<ELFYAML::PGOAnalysisMapEntry>::mapping(
diff --git a/llvm/test/CodeGen/X86/basic-block-address-map-pgo-features.ll b/llvm/test/CodeGen/X86/basic-block-address-map-pgo-features.ll
index 63779727ec72c..dd97aecd57cf3 100644
--- a/llvm/test/CodeGen/X86/basic-block-address-map-pgo-features.ll
+++ b/llvm/test/CodeGen/X86/basic-block-address-map-pgo-features.ll
@@ -81,26 +81,32 @@ declare i32 @__gxx_personality_v0(...)
 ; CHECK-NEXT:	.uleb128 .Lfunc_begin0-.Lfunc_begin0
 ; CHECK-NEXT:	.uleb128 .LBB_END0_0-.Lfunc_begin0
 ; CHECK-NEXT:	.byte	8
+; CHECK-NEXT: .ascii "{{.*}}"
 ; CHECK-NEXT:	.byte	1		# BB id
 ; CHECK-NEXT:	.uleb128 .LBB0_1-.LBB_END0_0
 ; CHECK-NEXT:	.uleb128 .LBB_END0_1-.LBB0_1
 ; CHECK-NEXT:	.byte	8
+; CHECK-NEXT: .ascii "{{.*}}"
 ; CHECK-NEXT:	.byte	3		# BB id
 ; CHECK-NEXT:	.uleb128 .LBB0_2-.LBB_END0_1
 ; CHECK-NEXT:	.uleb128 .LBB_END0_2-.LBB0_2
 ; CHECK-NEXT:	.byte	8
+; CHECK-NEXT: .ascii "{{.*}}"
 ; CHECK-NEXT:	.byte	5		# BB id
 ; CHECK-NEXT:	.uleb128 .LBB0_3-.LBB_END0_2
 ; CHECK-NEXT:	.uleb128 .LBB_END0_3-.LBB0_3
 ; CHECK-NEXT:	.byte	1
+; CHECK-NEXT: .ascii "{{.*}}"
 ; CHECK-NEXT:	.byte	4		# BB id
 ; CHECK-NEXT:	.uleb128 .LBB0_4-.LBB_END0_3
 ; CHECK-NEXT:	.uleb128 .LBB_END0_4-.LBB0_4
 ; CHECK-NEXT:	.byte	16
+; CHECK-NEXT: .ascii "{{.*}}"
 ; CHECK-NEXT:	.byte	2		# BB id
 ; CHECK-NEXT:	.uleb128 .LBB0_5-.LBB_END0_4
 ; CHECK-NEXT:	.uleb128 .LBB_END0_5-.LBB0_5
 ; CHECK-NEXT:	.byte	4
+; CHECK-NEXT: .ascii "{{.*}}"
 
 ;; PGO Analysis Map
 ; PGO-NONE-NOT: .byte	100		# function entry count
diff --git a/llvm/test/CodeGen/X86/basic-block-address-map-with-basic-block-sections.ll b/llvm/test/CodeGen/X86/basic-block-address-map-with-basic-block-sections.ll
index b897cf4853cac..4f13ad46838ea 100644
--- a/llvm/test/CodeGen/X86/basic-block-address-map-with-basic-block-sections.ll
+++ b/llvm/test/CodeGen/X86/basic-block-address-map-with-basic-block-sections.ll
@@ -54,18 +54,21 @@ declare i32 @__gxx_personality_v0(...)
 ; CHECK-NEXT:	.uleb128 .Lfunc_begin0-.Lfunc_begin0
 ; CHECK-NEXT:	.uleb128 .LBB_END0_0-.Lfunc_begin0
 ; CHECK-NEXT:	.byte	0
+; CHECK-NEXT: .ascii "{{.*}}"
 ; CHECK-NEXT:	.byte	2               # BB id
 ; CHECK-NEXT:	.uleb128 .LBB0_1-.LBB_END0_0
 ; CHECK-NEXT:	.uleb128 .LBB_END0_1-.LBB0_1
 ; CHECK-NEXT:	.byte	5
+; CHECK-NEXT: .ascii "{{.*}}"
 ; CHECK-NEXT:	.quad	_Z3bazb.cold    # base address
 ; CHECK-NEXT:	.byte	2               # number of basic blocks
 ; CHECK-NEXT:	.byte	1               # BB id
 ; CHECK-NEXT:	.uleb128 _Z3bazb.cold-_Z3bazb.cold
 ; CHECK-NEXT:	.uleb128 .LBB_END0_2-_Z3bazb.cold
 ; CHECK-NEXT:	.byte	8
+; CHECK-NEXT: .ascii "{{.*}}"
 ; CHECK-NEXT:	.byte	3               # BB id
 ; CHECK-NEXT:	.uleb128 .LBB0_3-.LBB_END0_2
 ; CHECK-NEXT:	.uleb128 .LBB_END0_3-.LBB0_3
 ; CHECK-NEXT:	.byte	1
-
+; CHECK-NEXT: .ascii "{{.*}}"
\ No newline at end of file
diff --git a/llvm/test/CodeGen/X86/basic-block-address-map-with-mfs.ll b/llvm/test/CodeGen/X86/basic-block-address-map-with-mfs.ll
index 2565db23c0249..304233d0865f4 100644
--- a/llvm/test/CodeGen/X86/basic-block-address-map-with-mfs.ll
+++ b/llvm/test/CodeGen/X86/basic-block-address-map-with-mfs.ll
@@ -64,16 +64,19 @@ declare i32 @qux()
 ; CHECK-NEXT:   .uleb128 .Lfunc_begin0-.Lfunc_begin0
 ; CHECK-NEXT:   .uleb128 .LBB_END0_0-.Lfunc_begin0
 ; CHECK-NEXT:   .byte   8
+; CHECK-NEXT: .ascii "{{.*}}"
 ; CHECK-NEXT:   .byte   1               # BB id
 ; CHECK-NEXT:   .uleb128 .LBB0_1-.LBB_END0_0
 ; CHECK-NEXT:   .uleb128 .LBB_END0_1-.LBB0_1
 ; CHECK-NEXT:   .byte   3
+; CHECK-NEXT: .ascii "{{.*}}"
 ; CHECK-NEXT:   .quad   foo.cold    # base address
 ; CHECK-NEXT:   .byte   1               # number of basic blocks
 ; CHECK-NEXT:   .byte   2               # BB id
 ; CHECK-NEXT:   .uleb128 foo.cold-foo.cold
 ; CHECK-NEXT:   .uleb128 .LBB_END0_2-foo.cold
 ; CHECK-NEXT:   .byte   3
+; CHECK-NEXT: .ascii "{{.*}}"
 
 ;; PGO Analysis Map
 ; PGO:         .ascii  "\3306"                            # function entry count
diff --git a/llvm/test/CodeGen/X86/basic-block-address-map.ll b/llvm/test/CodeGen/X86/basic-block-address-map.ll
index 4f12258eeeea0..7563bf9621be3 100644
--- a/llvm/test/CodeGen/X86/basic-block-address-map.ll
+++ b/llvm/test/CodeGen/X86/basic-block-address-map.ll
@@ -58,23 +58,29 @@ declare i32 @__gxx_personality_v0(...)
 ; CHECK-NEXT:	.uleb128 .Lfunc_begin0-.Lfunc_begin0
 ; CHECK-NEXT:	.uleb128 .LBB_END0_0-.Lfunc_begin0
 ; CHECK-NEXT:	.byte	8
+; CHECK-NEXT: .ascii "{{.*}}"
 ; CHECK-NEXT:   .byte	1		# BB id
 ; CHECK-NEXT:	.uleb128 .LBB0_1-.LBB_END0_0
 ; CHECK-NEXT:	.uleb128 .LBB_END0_1-.LBB0_1
 ; CHECK-NEXT:	.byte	8
+; CHECK-NEXT: .ascii "{{.*}}"
 ; CHECK-NEXT:   .byte	3		# BB id
 ; CHECK-NEXT:	.uleb128 .LBB0_2-.LBB_END0_1
 ; CHECK-NEXT:	.uleb128 .LBB_END0_2-.LBB0_2
 ; CHECK-NEXT:	.byte	8
+; CHECK-NEXT: .ascii "{{.*}}"
 ; CHECK-NEXT:   .byte	4		# BB id
 ; CHECK-NEXT:	.uleb128 .LBB0_3-.LBB_END0_2
 ; CHECK-NEXT:	.uleb128 .LBB_END0_3-.LBB0_3
 ; CHECK-NEXT:	.byte	16
+; CHECK-NEXT: .ascii "{{.*}}"
 ; CHECK-NEXT:   .byte	5		# BB id
 ; CHECK-NEXT:	.uleb128 .LBB0_4-.LBB_END0_3
 ; CHECK-NEXT:	.uleb128 .LBB_END0_4-.LBB0_4
 ; CHECK-NEXT:	.byte	1
+; CHECK-NEXT: .ascii "{{.*}}"
 ; CHECK-NEXT:   .byte	2		# BB id
 ; CHECK-NEXT:	.uleb128 .LBB0_5-.LBB_END0_4
 ; CHECK-NEXT:	.uleb128 .LBB_END0_5-.LBB0_5
 ; CHECK-NEXT:	.byte	5
+; CHECK-NEXT: .ascii "{{.*}}"
diff --git a/llvm/test/tools/llvm-objdump/X86/elf-bbaddrmap-disassemble-symbolize-operands.yaml b/llvm/test/tools/llvm-objdump/X86/elf-bbaddrmap-disassemble-symbolize-operands.yaml
index cc7faea67bed2..48ebfec41d9b7 100644
--- a/llvm/test/tools/llvm-objdump/X86/elf-bbaddrmap-disassemble-symbolize-operands.yaml
+++ b/llvm/test/tools/llvm-objdump/X86/elf-bbaddrmap-disassemble-symbolize-operands.yaml
@@ -113,28 +113,34 @@ Sections:
                AddressOffset: 0x0
                Size:          0x1
                Metadata:      0x1
+               Hash:          0x1
              - ID:            1
                AddressOffset: 0x0
                Size:          0x6
                Metadata:      0x0
+               Hash:          0x2
              - ID:            2
                AddressOffset: 0x1
                Size:          0x4
                Metadata:      0x0
+               Hash:          0x3
              - ID:            4
                AddressOffset: 0x0
                Size:          0x6
                Metadata:      0x1
+   ...
[truncated]


} // end namespace llvm

#endif // LLVM_CODEGEN_MACHINEBLOCKHASHINFO_H
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#endif // LLVM_CODEGEN_MACHINEBLOCKHASHINFO_H
#endif // LLVM_CODEGEN_MACHINEBLOCKHASHINFO_H

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DONE

uint64_t hashBlock(const MachineBasicBlock &MBB, OperandHashFuncTy OperandHashFunc) {
uint64_t Hash = 0;
for (const MachineInstr &MI : MBB) {
if (MI.isPseudo())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You presumably want isMetaInstruction. isPseudo only tells you if it's an instruction with a final machine encoding or not

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Here, we want to hash all instructions that are actually executed by the machine, so I think using isPseudo is fine.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not fine, isPseudo is essentially a backend implementation detail flag that very little code should ever need to consider. It will most likely eventually expand to some real machine sequence

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For stale profile, the ordering of basic blocks is prone to changes. In the Matching and Inference technique, hashes of basic blocks are used to accurately match basic blocks even when their ordering changes. We disregard pseudo-instructions, nop instructions, and unconditional jumps, as these are frequently added or removed due to basic block reordering. For more detailed explanations, refer to Section 3.1 of the Matching and Inference paper (https://arxiv.org/abs/2401.17168).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isPseudo does not mean what you think it means, and I'm sure you want isMetaInstruction

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much for pointing out the issue. We carefully reviewed the isPseudo method of the MachineInstr class and realized we had previously misunderstood its meaning. We have made corrections to the code accordingly.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed isPseudo to isMetaInstruction, but several test cases failed. The error messages are as follows. Could you please help analyze the possible causes?
image

@lifengxiang1025 lifengxiang1025 requested review from rlavaee and tmsri May 22, 2025 07:43

uint64_t hashBlock(const MachineBasicBlock &MBB, OperandHashFuncTy OperandHashFunc) {
uint64_t Hash = 0;
for (const MachineInstr &MI : MBB) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you also hash the terminator instructions (branches at the end of the block)? They may be reversed across builds.

@@ -873,6 +873,7 @@ decodeBBAddrMapImpl(const ELFFile<ELFT> &EF,
uint32_t Offset = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
uint32_t Size = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
uint32_t MD = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
uint64_t Hash = readULEB128As<uint64_t>(Data, Cur, ULEBSizeErr);
if (Version >= 1) {
Copy link
Contributor

@rlavaee rlavaee May 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to define a new version number for this to support backward-compatibility.

/// components are of smaller size (e.g., uint16_t or uint8_t).
struct BlendedBlockHash {
private:
static uint64_t combineHashes(uint16_t Hash1, uint16_t Hash2, uint16_t Hash3,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A lot of the code in this file repeats the implementation in BOLT (which has actually been improved since the original commits), e.g., https://github.com/llvm/llvm-project/blob/main/bolt/lib/Profile/StaleProfileMatching.cpp

Do you think there is a way to unify the implementations? (totally understand if not, since there might be some specifics)

@rlavaee
Copy link
Contributor

rlavaee commented Jun 5, 2025

FYI https://github.com/google/llvm-propeller now accepts external PRs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants