[llvm] [MCA] Enable customization of individual instructions (PR #155420)

Roman Belenov via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 12 03:38:34 PDT 2025


https://github.com/r-belenov updated https://github.com/llvm/llvm-project/pull/155420

>From b1a67b7972a83cd1bc4a8bbede1e117d013c667b Mon Sep 17 00:00:00 2001
From: Roman Belenov <103195329+r-belenov at users.noreply.github.com>
Date: Tue, 26 Aug 2025 17:00:10 +0300
Subject: [PATCH 01/24] Added interface to customize individual instructions
 and possibility to change latency via special comments

* Added customizations to header

* Added customization to implementation

* Use default small vector size for custom instructions

* Typo fixed

* Use std::vector for custom descriptors

* Revert to SmallVector

* Erroneous dereference removed

* Introduced annotated instructions

* Updated getter method

* Updated getter usage

* Fixed type usage

* Revert to MCInst for regions

* Keep annotations in separate map

* Removed usage of annotated instruction

* Use std::optional

* Add setter/getter for explicit latency

* Set instruction latency according to annotation

* Simplify default return

* Revert to explicit default value

* Add missing brace

* Added missing field name

* Typo fixed

* Added missing namespace tags

* Whitespace removed

* Index annotations by smloc

* Search latency by SMLoc

* Use pointer as a map key

* Missing const added

* Added optional annotation to MCStreamerWrapper

* Added interface to annotate instructions

* Move annotations to CodeRegons

* Get explicit latency from Regions

* Erroneous dereference removed

* Add interface to pass latency to MCStreamerWrapper

* Fixed incorrect code placement

* Make Streamer available to CommentConsumer

* Move MCStreamerWrapper definition to make it visible in comment consumers

* Parse latency comment

* Fix drop_front usage

* Fix whitespace skipping on latency annotation

* Added test for latency annotation

* Additional test for latency annotations

* Use load in test instruction

* Use load in test instruction

* Added instruction builder customization

* Added customized instruction creation

* Pass builder to custom creation functor

* Added header with InstrBuilder declaration

* Typo fixed

* Added base for instruction customizations test

* Added missing result object

* Hardcode name for summary view

* Explicitly model single instruction

* Add actual custom latency test

* Typo fixed

* Pass latency to lambda body

* Adding missing const

* Specify lambda return type

* Erroneous argument removed

* Removed unnecessary lambda return type

* Code cleanup

* Code cleanup
---
 llvm/include/llvm/MCA/InstrBuilder.h          | 11 ++-
 llvm/lib/MCA/InstrBuilder.cpp                 | 15 +++-
 .../tools/llvm-mca/X86/llvm-mca-markers-13.s  | 10 +++
 .../tools/llvm-mca/X86/llvm-mca-markers-14.s  | 10 +++
 llvm/tools/llvm-mca/CodeRegion.h              | 18 ++++
 llvm/tools/llvm-mca/CodeRegionGenerator.cpp   | 12 +++
 llvm/tools/llvm-mca/CodeRegionGenerator.h     | 85 +++++++++++--------
 llvm/tools/llvm-mca/llvm-mca.cpp              |  6 +-
 llvm/unittests/tools/llvm-mca/MCATestBase.cpp |  5 +-
 llvm/unittests/tools/llvm-mca/MCATestBase.h   |  7 +-
 .../tools/llvm-mca/X86/TestIncrementalMCA.cpp | 26 ++++++
 11 files changed, 159 insertions(+), 46 deletions(-)
 create mode 100644 llvm/test/tools/llvm-mca/X86/llvm-mca-markers-13.s
 create mode 100644 llvm/test/tools/llvm-mca/X86/llvm-mca-markers-14.s

diff --git a/llvm/include/llvm/MCA/InstrBuilder.h b/llvm/include/llvm/MCA/InstrBuilder.h
index e0949d975fa99..9bb8c5b28fdad 100644
--- a/llvm/include/llvm/MCA/InstrBuilder.h
+++ b/llvm/include/llvm/MCA/InstrBuilder.h
@@ -25,6 +25,7 @@
 #include "llvm/MCA/Support.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/Error.h"
+#include <functional>
 
 namespace llvm {
 namespace mca {
@@ -78,6 +79,10 @@ class InstrBuilder {
   DenseMap<std::pair<hash_code, unsigned>, std::unique_ptr<const InstrDesc>>
       VariantDescriptors;
 
+  // These descriptors are customized for particular instructions and cannot
+  // be reused
+  SmallVector<std::unique_ptr<const InstrDesc>> CustomDescriptors;
+
   bool FirstCallInst;
   bool FirstReturnInst;
   unsigned CallLatency;
@@ -87,7 +92,8 @@ class InstrBuilder {
 
   Expected<unsigned> getVariantSchedClassID(const MCInst &MCI, unsigned SchedClassID);
   Expected<const InstrDesc &>
-  createInstrDescImpl(const MCInst &MCI, const SmallVector<Instrument *> &IVec);
+  createInstrDescImpl(const MCInst &MCI, const SmallVector<Instrument *> &IVec,
+                      std::function<void(InstrDesc&)> Customizer = {});
   Expected<const InstrDesc &>
   getOrCreateInstrDesc(const MCInst &MCI,
                        const SmallVector<Instrument *> &IVec);
@@ -116,7 +122,8 @@ class InstrBuilder {
   void setInstRecycleCallback(InstRecycleCallback CB) { InstRecycleCB = CB; }
 
   LLVM_ABI Expected<std::unique_ptr<Instruction>>
-  createInstruction(const MCInst &MCI, const SmallVector<Instrument *> &IVec);
+  createInstruction(const MCInst &MCI, const SmallVector<Instrument *> &IVec,
+                    std::function<void(InstrDesc&)> Customizer = {});
 };
 } // namespace mca
 } // namespace llvm
diff --git a/llvm/lib/MCA/InstrBuilder.cpp b/llvm/lib/MCA/InstrBuilder.cpp
index cad25a6ddd3f5..4a0f09c4160d9 100644
--- a/llvm/lib/MCA/InstrBuilder.cpp
+++ b/llvm/lib/MCA/InstrBuilder.cpp
@@ -558,7 +558,8 @@ Expected<unsigned> InstrBuilder::getVariantSchedClassID(const MCInst &MCI,
 
 Expected<const InstrDesc &>
 InstrBuilder::createInstrDescImpl(const MCInst &MCI,
-                                  const SmallVector<Instrument *> &IVec) {
+                                  const SmallVector<Instrument *> &IVec,
+                                  std::function<void(InstrDesc&)> Customizer) {
   assert(STI.getSchedModel().hasInstrSchedModel() &&
          "Itineraries are not yet supported!");
 
@@ -632,6 +633,12 @@ InstrBuilder::createInstrDescImpl(const MCInst &MCI,
     return std::move(Err);
 
   // Now add the new descriptor.
+
+  if (Customizer) {
+    Customizer(*ID);
+    return *CustomDescriptors.emplace_back(std::move(ID));
+  }
+  
   bool IsVariadic = MCDesc.isVariadic();
   if ((ID->IsRecyclable = !IsVariadic && !IsVariant)) {
     auto DKey = std::make_pair(MCI.getOpcode(), SchedClassID);
@@ -675,8 +682,10 @@ STATISTIC(NumVariantInst, "Number of MCInsts that doesn't have static Desc");
 
 Expected<std::unique_ptr<Instruction>>
 InstrBuilder::createInstruction(const MCInst &MCI,
-                                const SmallVector<Instrument *> &IVec) {
-  Expected<const InstrDesc &> DescOrErr = getOrCreateInstrDesc(MCI, IVec);
+                                const SmallVector<Instrument *> &IVec,
+                                std::function<void(InstrDesc&)> Customizer) {
+  Expected<const InstrDesc &> DescOrErr = Customizer? createInstrDescImpl(MCI, IVec, Customizer) :
+      getOrCreateInstrDesc(MCI, IVec);
   if (!DescOrErr)
     return DescOrErr.takeError();
   const InstrDesc &D = *DescOrErr;
diff --git a/llvm/test/tools/llvm-mca/X86/llvm-mca-markers-13.s b/llvm/test/tools/llvm-mca/X86/llvm-mca-markers-13.s
new file mode 100644
index 0000000000000..9115ffadbdaee
--- /dev/null
+++ b/llvm/test/tools/llvm-mca/X86/llvm-mca-markers-13.s
@@ -0,0 +1,10 @@
+# NOTE: Assertions have been autogenerated by utils/update_mca_test_checks.py
+# RUN: llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=btver2 -iterations=10 %s 2>&1 | FileCheck %s
+
+add (%eax), %eax // LLVM-MCA-LATENCY : 100
+mov %eax, (%ebx)
+
+# CHECK:      Iterations:        10
+# CHECK-NEXT: Instructions:      20
+# CHECK-NEXT: Total Cycles:      1004
+# CHECK-NEXT: Total uOps:        20
diff --git a/llvm/test/tools/llvm-mca/X86/llvm-mca-markers-14.s b/llvm/test/tools/llvm-mca/X86/llvm-mca-markers-14.s
new file mode 100644
index 0000000000000..41da9f4b4cef1
--- /dev/null
+++ b/llvm/test/tools/llvm-mca/X86/llvm-mca-markers-14.s
@@ -0,0 +1,10 @@
+# NOTE: Assertions have been autogenerated by utils/update_mca_test_checks.py
+# RUN: llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=btver2 -iterations=10 %s 2>&1 | FileCheck %s
+
+add (%eax), %eax // LLVM-MCA-LATENCY : 100
+mov %eax, (%ebx) // LLVM-MCA-LATENCY : 100
+
+# CHECK:      Iterations:        10
+# CHECK-NEXT: Instructions:      20
+# CHECK-NEXT: Total Cycles:      1103
+# CHECK-NEXT: Total uOps:        20
diff --git a/llvm/tools/llvm-mca/CodeRegion.h b/llvm/tools/llvm-mca/CodeRegion.h
index c04ea51169cfb..d16f976fe101e 100644
--- a/llvm/tools/llvm-mca/CodeRegion.h
+++ b/llvm/tools/llvm-mca/CodeRegion.h
@@ -69,10 +69,15 @@
 #include "llvm/Support/SMLoc.h"
 #include "llvm/Support/SourceMgr.h"
 #include <vector>
+#include <utility>
 
 namespace llvm {
 namespace mca {
 
+struct InstAnnotation {
+  std::optional<unsigned> Latency;
+};
+
 /// A region of assembly code.
 ///
 /// It identifies a sequence of machine instructions.
@@ -155,6 +160,9 @@ class CodeRegions {
   llvm::StringMap<unsigned> ActiveRegions;
   bool FoundErrors;
 
+  // Annotations specified in comments, indexed by SMLoc value
+  llvm::DenseMap<const char*, InstAnnotation> Annotations;
+
 public:
   CodeRegions(llvm::SourceMgr &S) : SM(S), FoundErrors(false) {}
   virtual ~CodeRegions() = default;
@@ -170,6 +178,16 @@ class CodeRegions {
   void addInstruction(const llvm::MCInst &Instruction);
   llvm::SourceMgr &getSourceMgr() const { return SM; }
 
+  void Annotate(llvm::SMLoc Loc, const InstAnnotation& A) { Annotations[Loc.getPointer()] = A; }
+  std::optional<unsigned> getExplicitLatency(llvm::SMLoc Loc) const {
+    const auto It = Annotations.find(Loc.getPointer());
+    if (It != Annotations.end()) {
+      return It->second.Latency;
+    } else {
+      return {};
+    }
+  }
+
   llvm::ArrayRef<llvm::MCInst> getInstructionSequence(unsigned Idx) const {
     return Regions[Idx]->getInstructions();
   }
diff --git a/llvm/tools/llvm-mca/CodeRegionGenerator.cpp b/llvm/tools/llvm-mca/CodeRegionGenerator.cpp
index f7f929e49ead9..767f92bf6f935 100644
--- a/llvm/tools/llvm-mca/CodeRegionGenerator.cpp
+++ b/llvm/tools/llvm-mca/CodeRegionGenerator.cpp
@@ -95,6 +95,18 @@ void AnalysisRegionCommentConsumer::HandleComment(SMLoc Loc,
     return;
 
   Comment = Comment.drop_front(Position);
+  if (Comment.starts_with("LLVM-MCA-LATENCY")) {
+      auto Parts = Comment.split(':');
+      Position = Parts.second.find_first_not_of(" \t");
+      if (Position >= Parts.second.size())
+        return;
+      auto LatStr = Parts.second.drop_front(Position);
+      unsigned Latency = 0;
+      if (!LatStr.getAsInteger(10, Latency))
+        Streamer.AddLatencyAnnotation(Latency);
+      return;
+  }
+
   if (Comment.consume_front("LLVM-MCA-END")) {
     // Skip spaces and tabs.
     Position = Comment.find_first_not_of(" \t");
diff --git a/llvm/tools/llvm-mca/CodeRegionGenerator.h b/llvm/tools/llvm-mca/CodeRegionGenerator.h
index a48c67a22f27b..2c632be5e7f53 100644
--- a/llvm/tools/llvm-mca/CodeRegionGenerator.h
+++ b/llvm/tools/llvm-mca/CodeRegionGenerator.h
@@ -31,6 +31,50 @@
 namespace llvm {
 namespace mca {
 
+// This class provides the callbacks that occur when parsing input assembly.
+class MCStreamerWrapper : public MCStreamer {
+protected:
+  CodeRegions &Regions;
+  std::optional<InstAnnotation> CurrentAnnotation;
+
+public:
+  MCStreamerWrapper(MCContext &Context, mca::CodeRegions &R)
+      : MCStreamer(Context), Regions(R) {}
+
+  // We only want to intercept the emission of new instructions.
+  void emitInstruction(const MCInst &Inst,
+                       const MCSubtargetInfo & /* unused */) override {
+    Regions.addInstruction(Inst);
+    if (CurrentAnnotation) {
+      Regions.Annotate(Inst.getLoc(), *CurrentAnnotation);
+      CurrentAnnotation = {};
+    }
+  }
+
+  void AddLatencyAnnotation(unsigned Lat) {
+    if (!CurrentAnnotation) CurrentAnnotation = InstAnnotation();
+    CurrentAnnotation->Latency = Lat;
+  }
+
+  bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
+    return true;
+  }
+
+  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+                        Align ByteAlignment) override {}
+  void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
+                    uint64_t Size = 0, Align ByteAlignment = Align(1),
+                    SMLoc Loc = SMLoc()) override {}
+  void beginCOFFSymbolDef(const MCSymbol *Symbol) override {}
+  void emitCOFFSymbolStorageClass(int StorageClass) override {}
+  void emitCOFFSymbolType(int Type) override {}
+  void endCOFFSymbolDef() override {}
+
+  ArrayRef<MCInst> GetInstructionSequence(unsigned Index) const {
+    return Regions.getInstructionSequence(Index);
+  }
+};
+
 class MCACommentConsumer : public AsmCommentConsumer {
 protected:
   bool FoundError = false;
@@ -44,9 +88,10 @@ class MCACommentConsumer : public AsmCommentConsumer {
 /// A comment consumer that parses strings.  The only valid tokens are strings.
 class AnalysisRegionCommentConsumer : public MCACommentConsumer {
   AnalysisRegions &Regions;
+  MCStreamerWrapper &Streamer;
 
 public:
-  AnalysisRegionCommentConsumer(AnalysisRegions &R) : Regions(R) {}
+  AnalysisRegionCommentConsumer(AnalysisRegions &R, MCStreamerWrapper &S) : Regions(R), Streamer(S) {}
 
   /// Parses a comment. It begins a new region if it is of the form
   /// LLVM-MCA-BEGIN. It ends a region if it is of the form LLVM-MCA-END.
@@ -82,40 +127,6 @@ class InstrumentRegionCommentConsumer : public MCACommentConsumer {
   InstrumentManager &getInstrumentManager() { return IM; }
 };
 
-// This class provides the callbacks that occur when parsing input assembly.
-class MCStreamerWrapper : public MCStreamer {
-protected:
-  CodeRegions &Regions;
-
-public:
-  MCStreamerWrapper(MCContext &Context, mca::CodeRegions &R)
-      : MCStreamer(Context), Regions(R) {}
-
-  // We only want to intercept the emission of new instructions.
-  void emitInstruction(const MCInst &Inst,
-                       const MCSubtargetInfo & /* unused */) override {
-    Regions.addInstruction(Inst);
-  }
-
-  bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
-    return true;
-  }
-
-  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                        Align ByteAlignment) override {}
-  void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
-                    uint64_t Size = 0, Align ByteAlignment = Align(1),
-                    SMLoc Loc = SMLoc()) override {}
-  void beginCOFFSymbolDef(const MCSymbol *Symbol) override {}
-  void emitCOFFSymbolStorageClass(int StorageClass) override {}
-  void emitCOFFSymbolType(int Type) override {}
-  void endCOFFSymbolDef() override {}
-
-  ArrayRef<MCInst> GetInstructionSequence(unsigned Index) const {
-    return Regions.getInstructionSequence(Index);
-  }
-};
-
 class InstrumentMCStreamer : public MCStreamerWrapper {
   InstrumentManager &IM;
 
@@ -210,15 +221,15 @@ class AsmCodeRegionGenerator : public virtual CodeRegionGenerator {
 
 class AsmAnalysisRegionGenerator final : public AnalysisRegionGenerator,
                                          public AsmCodeRegionGenerator {
-  AnalysisRegionCommentConsumer CC;
   MCStreamerWrapper Streamer;
+  AnalysisRegionCommentConsumer CC;
 
 public:
   AsmAnalysisRegionGenerator(const Target &T, llvm::SourceMgr &SM, MCContext &C,
                              const MCAsmInfo &A, const MCSubtargetInfo &S,
                              const MCInstrInfo &I)
       : AnalysisRegionGenerator(SM), AsmCodeRegionGenerator(T, C, A, S, I),
-        CC(Regions), Streamer(Ctx, Regions) {}
+        Streamer(Ctx, Regions), CC(Regions, Streamer) {}
 
   MCACommentConsumer *getCommentConsumer() override { return &CC; };
   CodeRegions &getRegions() override { return Regions; };
diff --git a/llvm/tools/llvm-mca/llvm-mca.cpp b/llvm/tools/llvm-mca/llvm-mca.cpp
index 4b0611186d21f..5f653ffcd83ed 100644
--- a/llvm/tools/llvm-mca/llvm-mca.cpp
+++ b/llvm/tools/llvm-mca/llvm-mca.cpp
@@ -633,7 +633,11 @@ int main(int argc, char **argv) {
       const SmallVector<mca::Instrument *> Instruments =
           InstrumentRegions.getActiveInstruments(Loc);
 
-      Expected<std::unique_ptr<mca::Instruction>> Inst =
+      auto Latency = Regions.getExplicitLatency(Loc);
+      Expected<std::unique_ptr<mca::Instruction>> Inst = Latency ?
+          IB.createInstruction(MCI, Instruments, [=](llvm::mca::InstrDesc& ID) {
+            for (auto& W : ID.Writes) W.Latency = *Latency;
+            ID.MaxLatency = *Latency; }) :
           IB.createInstruction(MCI, Instruments);
       if (!Inst) {
         if (auto NewE = handleErrors(
diff --git a/llvm/unittests/tools/llvm-mca/MCATestBase.cpp b/llvm/unittests/tools/llvm-mca/MCATestBase.cpp
index cd3258ef96d64..96413168b8f5e 100644
--- a/llvm/unittests/tools/llvm-mca/MCATestBase.cpp
+++ b/llvm/unittests/tools/llvm-mca/MCATestBase.cpp
@@ -61,7 +61,8 @@ void MCATestBase::SetUp() {
 
 Error MCATestBase::runBaselineMCA(json::Object &Result, ArrayRef<MCInst> Insts,
                                   ArrayRef<mca::View *> Views,
-                                  const mca::PipelineOptions *PO) {
+                                  const mca::PipelineOptions *PO,
+                                  Builder B) {
   mca::Context MCA(*MRI, *STI);
 
   // Default InstrumentManager
@@ -72,7 +73,7 @@ Error MCATestBase::runBaselineMCA(json::Object &Result, ArrayRef<MCInst> Insts,
   SmallVector<std::unique_ptr<mca::Instruction>> LoweredInsts;
   for (const auto &MCI : Insts) {
     Expected<std::unique_ptr<mca::Instruction>> Inst =
-        IB.createInstruction(MCI, Instruments);
+        B ? B(IB, MCI, Instruments) : IB.createInstruction(MCI, Instruments);
     if (!Inst) {
       if (auto NewE =
               handleErrors(Inst.takeError(),
diff --git a/llvm/unittests/tools/llvm-mca/MCATestBase.h b/llvm/unittests/tools/llvm-mca/MCATestBase.h
index 66e20a45c96ce..399a8e892bc28 100644
--- a/llvm/unittests/tools/llvm-mca/MCATestBase.h
+++ b/llvm/unittests/tools/llvm-mca/MCATestBase.h
@@ -24,6 +24,7 @@
 #include "llvm/MC/MCTargetOptions.h"
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/MCA/Context.h"
+#include "llvm/MCA/InstrBuilder.h"
 #include "llvm/TargetParser/SubtargetFeature.h"
 #include "llvm/TargetParser/Triple.h"
 
@@ -70,12 +71,16 @@ class MCATestBase : public ::testing::Test {
 
   void SetUp() override;
 
+  using Builder = std::function<Expected<std::unique_ptr<mca::Instruction>>
+      (mca::InstrBuilder&, const MCInst&, const SmallVector<mca::Instrument *>&)>;
+
   /// Utility function to run MCA with (nearly) the same configuration as the
   /// `llvm-mca` tool to verify result correctness.
   /// This function only displays on SummaryView by default.
   virtual Error runBaselineMCA(json::Object &Result, ArrayRef<MCInst> Insts,
                                ArrayRef<mca::View *> Views = {},
-                               const mca::PipelineOptions *PO = nullptr);
+                               const mca::PipelineOptions *PO = nullptr,
+                               Builder B = {});
 };
 
 } // end namespace mca
diff --git a/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp b/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp
index 1a14c687295ca..cf66460b11fc8 100644
--- a/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp
+++ b/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp
@@ -234,3 +234,29 @@ TEST_F(X86TestBase, TestVariantInstructionsSameAddress) {
   Expected<unsigned> Cycles = P->run();
   ASSERT_TRUE(static_cast<bool>(Cycles));
 }
+
+TEST_F(X86TestBase, TestInstructionCustomization) {
+  const unsigned ExplicitLatency = 100;  
+  SmallVector<MCInst> MCIs;
+  MCInst InstructionToAdd = MCInstBuilder(X86::XOR64rr)
+                                .addReg(X86::RAX)
+                                .addReg(X86::RAX)
+                                .addReg(X86::RAX);
+  MCIs.push_back(InstructionToAdd);
+
+  // Run the baseline.
+  json::Object BaselineResult;
+  auto E = runBaselineMCA(BaselineResult, MCIs, {}, nullptr,
+      [=](InstrBuilder& IB, const MCInst& MCI, const SmallVector<Instrument*>& Instruments) {
+        return IB.createInstruction(MCI, Instruments,
+          [=](InstrDesc& ID) {
+            for (auto& W : ID.Writes) W.Latency = ExplicitLatency;
+            ID.MaxLatency = ExplicitLatency;
+          });
+      });
+  auto *BaselineObj = BaselineResult.getObject("SummaryView");
+  auto V = BaselineObj->getInteger("TotalCycles");
+  ASSERT_TRUE(V);
+  // Additional 3 cycles for Dispatch, Executed and Retired states
+  ASSERT_EQ(unsigned(*V), ExplicitLatency + 3) << "Total cycles do not match";
+}

>From 4abee0f229ed6859ed9f0f86662a75f34d788664 Mon Sep 17 00:00:00 2001
From: Roman Belenov <103195329+r-belenov at users.noreply.github.com>
Date: Tue, 26 Aug 2025 17:28:21 +0300
Subject: [PATCH 02/24] Fix formatting

---
 llvm/include/llvm/MCA/InstrBuilder.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/include/llvm/MCA/InstrBuilder.h b/llvm/include/llvm/MCA/InstrBuilder.h
index 9bb8c5b28fdad..7b2fbde2c4a0e 100644
--- a/llvm/include/llvm/MCA/InstrBuilder.h
+++ b/llvm/include/llvm/MCA/InstrBuilder.h
@@ -93,7 +93,7 @@ class InstrBuilder {
   Expected<unsigned> getVariantSchedClassID(const MCInst &MCI, unsigned SchedClassID);
   Expected<const InstrDesc &>
   createInstrDescImpl(const MCInst &MCI, const SmallVector<Instrument *> &IVec,
-                      std::function<void(InstrDesc&)> Customizer = {});
+                      std::function<void(InstrDesc &)> Customizer = {});
   Expected<const InstrDesc &>
   getOrCreateInstrDesc(const MCInst &MCI,
                        const SmallVector<Instrument *> &IVec);
@@ -123,7 +123,7 @@ class InstrBuilder {
 
   LLVM_ABI Expected<std::unique_ptr<Instruction>>
   createInstruction(const MCInst &MCI, const SmallVector<Instrument *> &IVec,
-                    std::function<void(InstrDesc&)> Customizer = {});
+                    std::function<void(InstrDesc &)> Customizer = {});
 };
 } // namespace mca
 } // namespace llvm

>From 1298dd3391061b66c57bd69b58a44894f001f4fe Mon Sep 17 00:00:00 2001
From: Roman Belenov <103195329+r-belenov at users.noreply.github.com>
Date: Tue, 26 Aug 2025 17:31:59 +0300
Subject: [PATCH 03/24] Fix formatting

---
 llvm/lib/MCA/InstrBuilder.cpp | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/MCA/InstrBuilder.cpp b/llvm/lib/MCA/InstrBuilder.cpp
index 4a0f09c4160d9..8b3e52a871f71 100644
--- a/llvm/lib/MCA/InstrBuilder.cpp
+++ b/llvm/lib/MCA/InstrBuilder.cpp
@@ -559,7 +559,7 @@ Expected<unsigned> InstrBuilder::getVariantSchedClassID(const MCInst &MCI,
 Expected<const InstrDesc &>
 InstrBuilder::createInstrDescImpl(const MCInst &MCI,
                                   const SmallVector<Instrument *> &IVec,
-                                  std::function<void(InstrDesc&)> Customizer) {
+                                  std::function<void(InstrDesc &)> Customizer) {
   assert(STI.getSchedModel().hasInstrSchedModel() &&
          "Itineraries are not yet supported!");
 
@@ -638,7 +638,7 @@ InstrBuilder::createInstrDescImpl(const MCInst &MCI,
     Customizer(*ID);
     return *CustomDescriptors.emplace_back(std::move(ID));
   }
-  
+
   bool IsVariadic = MCDesc.isVariadic();
   if ((ID->IsRecyclable = !IsVariadic && !IsVariant)) {
     auto DKey = std::make_pair(MCI.getOpcode(), SchedClassID);
@@ -683,9 +683,10 @@ STATISTIC(NumVariantInst, "Number of MCInsts that doesn't have static Desc");
 Expected<std::unique_ptr<Instruction>>
 InstrBuilder::createInstruction(const MCInst &MCI,
                                 const SmallVector<Instrument *> &IVec,
-                                std::function<void(InstrDesc&)> Customizer) {
-  Expected<const InstrDesc &> DescOrErr = Customizer? createInstrDescImpl(MCI, IVec, Customizer) :
-      getOrCreateInstrDesc(MCI, IVec);
+                                std::function<void(InstrDesc &)> Customizer) {
+  Expected<const InstrDesc &> DescOrErr =
+      Customizer ? createInstrDescImpl(MCI, IVec, Customizer)
+                 : getOrCreateInstrDesc(MCI, IVec);
   if (!DescOrErr)
     return DescOrErr.takeError();
   const InstrDesc &D = *DescOrErr;

>From b5c3b952f9295d3ed4e493d2d3d2dd6c88a5adf2 Mon Sep 17 00:00:00 2001
From: Roman Belenov <103195329+r-belenov at users.noreply.github.com>
Date: Tue, 26 Aug 2025 17:35:46 +0300
Subject: [PATCH 04/24] Fix formatting

---
 llvm/tools/llvm-mca/CodeRegion.h | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/llvm/tools/llvm-mca/CodeRegion.h b/llvm/tools/llvm-mca/CodeRegion.h
index d16f976fe101e..0b5385a6d7ad1 100644
--- a/llvm/tools/llvm-mca/CodeRegion.h
+++ b/llvm/tools/llvm-mca/CodeRegion.h
@@ -68,8 +68,8 @@
 #include "llvm/Support/Error.h"
 #include "llvm/Support/SMLoc.h"
 #include "llvm/Support/SourceMgr.h"
-#include <vector>
 #include <utility>
+#include <vector>
 
 namespace llvm {
 namespace mca {
@@ -161,7 +161,7 @@ class CodeRegions {
   bool FoundErrors;
 
   // Annotations specified in comments, indexed by SMLoc value
-  llvm::DenseMap<const char*, InstAnnotation> Annotations;
+  llvm::DenseMap<const char *, InstAnnotation> Annotations;
 
 public:
   CodeRegions(llvm::SourceMgr &S) : SM(S), FoundErrors(false) {}
@@ -178,7 +178,9 @@ class CodeRegions {
   void addInstruction(const llvm::MCInst &Instruction);
   llvm::SourceMgr &getSourceMgr() const { return SM; }
 
-  void Annotate(llvm::SMLoc Loc, const InstAnnotation& A) { Annotations[Loc.getPointer()] = A; }
+  void Annotate(llvm::SMLoc Loc, const InstAnnotation& A) {
+    Annotations[Loc.getPointer()] = A;
+  }
   std::optional<unsigned> getExplicitLatency(llvm::SMLoc Loc) const {
     const auto It = Annotations.find(Loc.getPointer());
     if (It != Annotations.end()) {

>From 302b994407840ae4a4039ce5cbb25de7edf7d2f5 Mon Sep 17 00:00:00 2001
From: Roman Belenov <103195329+r-belenov at users.noreply.github.com>
Date: Tue, 26 Aug 2025 17:37:17 +0300
Subject: [PATCH 05/24] Fix formatting

---
 llvm/tools/llvm-mca/CodeRegionGenerator.cpp | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/llvm/tools/llvm-mca/CodeRegionGenerator.cpp b/llvm/tools/llvm-mca/CodeRegionGenerator.cpp
index 767f92bf6f935..0d400760f17e1 100644
--- a/llvm/tools/llvm-mca/CodeRegionGenerator.cpp
+++ b/llvm/tools/llvm-mca/CodeRegionGenerator.cpp
@@ -96,15 +96,15 @@ void AnalysisRegionCommentConsumer::HandleComment(SMLoc Loc,
 
   Comment = Comment.drop_front(Position);
   if (Comment.starts_with("LLVM-MCA-LATENCY")) {
-      auto Parts = Comment.split(':');
-      Position = Parts.second.find_first_not_of(" \t");
-      if (Position >= Parts.second.size())
-        return;
-      auto LatStr = Parts.second.drop_front(Position);
-      unsigned Latency = 0;
-      if (!LatStr.getAsInteger(10, Latency))
-        Streamer.AddLatencyAnnotation(Latency);
+    auto Parts = Comment.split(':');
+    Position = Parts.second.find_first_not_of(" \t");
+    if (Position >= Parts.second.size())
       return;
+    auto LatStr = Parts.second.drop_front(Position);
+    unsigned Latency = 0;
+    if (!LatStr.getAsInteger(10, Latency))
+      Streamer.AddLatencyAnnotation(Latency);
+    return;
   }
 
   if (Comment.consume_front("LLVM-MCA-END")) {

>From 23389785357f8cf7a11ce7050cf8904eb4915db2 Mon Sep 17 00:00:00 2001
From: Roman Belenov <103195329+r-belenov at users.noreply.github.com>
Date: Tue, 26 Aug 2025 17:39:13 +0300
Subject: [PATCH 06/24] Fix formatting

---
 llvm/tools/llvm-mca/CodeRegionGenerator.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/llvm/tools/llvm-mca/CodeRegionGenerator.h b/llvm/tools/llvm-mca/CodeRegionGenerator.h
index 2c632be5e7f53..1f43a8b26c471 100644
--- a/llvm/tools/llvm-mca/CodeRegionGenerator.h
+++ b/llvm/tools/llvm-mca/CodeRegionGenerator.h
@@ -52,7 +52,8 @@ class MCStreamerWrapper : public MCStreamer {
   }
 
   void AddLatencyAnnotation(unsigned Lat) {
-    if (!CurrentAnnotation) CurrentAnnotation = InstAnnotation();
+    if (!CurrentAnnotation)
+      CurrentAnnotation = InstAnnotation();
     CurrentAnnotation->Latency = Lat;
   }
 
@@ -91,7 +92,8 @@ class AnalysisRegionCommentConsumer : public MCACommentConsumer {
   MCStreamerWrapper &Streamer;
 
 public:
-  AnalysisRegionCommentConsumer(AnalysisRegions &R, MCStreamerWrapper &S) : Regions(R), Streamer(S) {}
+  AnalysisRegionCommentConsumer(AnalysisRegions &R, MCStreamerWrapper &S)
+      : Regions(R), Streamer(S) {}
 
   /// Parses a comment. It begins a new region if it is of the form
   /// LLVM-MCA-BEGIN. It ends a region if it is of the form LLVM-MCA-END.

>From 0be9fbf1719caf78d8db77d3c26249ee30dc2e3a Mon Sep 17 00:00:00 2001
From: Roman Belenov <103195329+r-belenov at users.noreply.github.com>
Date: Tue, 26 Aug 2025 17:41:47 +0300
Subject: [PATCH 07/24] Fix formatting

---
 llvm/tools/llvm-mca/llvm-mca.cpp | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/llvm/tools/llvm-mca/llvm-mca.cpp b/llvm/tools/llvm-mca/llvm-mca.cpp
index 5f653ffcd83ed..902a603a8e7dc 100644
--- a/llvm/tools/llvm-mca/llvm-mca.cpp
+++ b/llvm/tools/llvm-mca/llvm-mca.cpp
@@ -634,11 +634,14 @@ int main(int argc, char **argv) {
           InstrumentRegions.getActiveInstruments(Loc);
 
       auto Latency = Regions.getExplicitLatency(Loc);
-      Expected<std::unique_ptr<mca::Instruction>> Inst = Latency ?
-          IB.createInstruction(MCI, Instruments, [=](llvm::mca::InstrDesc& ID) {
-            for (auto& W : ID.Writes) W.Latency = *Latency;
-            ID.MaxLatency = *Latency; }) :
-          IB.createInstruction(MCI, Instruments);
+      Expected<std::unique_ptr<mca::Instruction>> Inst =
+          Latency ? IB.createInstruction(MCI, Instruments,
+                                         [=](llvm::mca::InstrDesc& ID) {
+                                           for (auto& W : ID.Writes)
+                                             W.Latency = *Latency;
+                                           ID.MaxLatency = *Latency;
+                                         })
+                  : IB.createInstruction(MCI, Instruments);
       if (!Inst) {
         if (auto NewE = handleErrors(
                 Inst.takeError(),

>From f1ad060d678b53d1bdd4a6c0659bbfb0764d9cfb Mon Sep 17 00:00:00 2001
From: Roman Belenov <103195329+r-belenov at users.noreply.github.com>
Date: Tue, 26 Aug 2025 17:43:15 +0300
Subject: [PATCH 08/24] Fix formatting

---
 llvm/unittests/tools/llvm-mca/MCATestBase.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/unittests/tools/llvm-mca/MCATestBase.cpp b/llvm/unittests/tools/llvm-mca/MCATestBase.cpp
index 96413168b8f5e..e2ff1dbe73a49 100644
--- a/llvm/unittests/tools/llvm-mca/MCATestBase.cpp
+++ b/llvm/unittests/tools/llvm-mca/MCATestBase.cpp
@@ -61,8 +61,7 @@ void MCATestBase::SetUp() {
 
 Error MCATestBase::runBaselineMCA(json::Object &Result, ArrayRef<MCInst> Insts,
                                   ArrayRef<mca::View *> Views,
-                                  const mca::PipelineOptions *PO,
-                                  Builder B) {
+                                  const mca::PipelineOptions *PO, Builder B) {
   mca::Context MCA(*MRI, *STI);
 
   // Default InstrumentManager

>From 757fec3e279200fe3d7a9abdded8b412fbec9ac5 Mon Sep 17 00:00:00 2001
From: Roman Belenov <103195329+r-belenov at users.noreply.github.com>
Date: Tue, 26 Aug 2025 17:44:43 +0300
Subject: [PATCH 09/24] Fix formatting

---
 llvm/unittests/tools/llvm-mca/MCATestBase.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/llvm/unittests/tools/llvm-mca/MCATestBase.h b/llvm/unittests/tools/llvm-mca/MCATestBase.h
index 399a8e892bc28..557da7b3d0d05 100644
--- a/llvm/unittests/tools/llvm-mca/MCATestBase.h
+++ b/llvm/unittests/tools/llvm-mca/MCATestBase.h
@@ -71,8 +71,9 @@ class MCATestBase : public ::testing::Test {
 
   void SetUp() override;
 
-  using Builder = std::function<Expected<std::unique_ptr<mca::Instruction>>
-      (mca::InstrBuilder&, const MCInst&, const SmallVector<mca::Instrument *>&)>;
+  using Builder = std::function<Expected<std::unique_ptr<mca::Instruction>>(
+      mca::InstrBuilder&, const MCInst&,
+      const SmallVector<mca::Instrument *> &)>;
 
   /// Utility function to run MCA with (nearly) the same configuration as the
   /// `llvm-mca` tool to verify result correctness.

>From 452bb402949d7c427417d88d96c5ed220237a300 Mon Sep 17 00:00:00 2001
From: Roman Belenov <103195329+r-belenov at users.noreply.github.com>
Date: Tue, 26 Aug 2025 17:47:02 +0300
Subject: [PATCH 10/24] Fix formatting

---
 .../tools/llvm-mca/X86/TestIncrementalMCA.cpp  | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp b/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp
index cf66460b11fc8..8aa879b3e053d 100644
--- a/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp
+++ b/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp
@@ -236,7 +236,7 @@ TEST_F(X86TestBase, TestVariantInstructionsSameAddress) {
 }
 
 TEST_F(X86TestBase, TestInstructionCustomization) {
-  const unsigned ExplicitLatency = 100;  
+  const unsigned ExplicitLatency = 100;
   SmallVector<MCInst> MCIs;
   MCInst InstructionToAdd = MCInstBuilder(X86::XOR64rr)
                                 .addReg(X86::RAX)
@@ -247,13 +247,15 @@ TEST_F(X86TestBase, TestInstructionCustomization) {
   // Run the baseline.
   json::Object BaselineResult;
   auto E = runBaselineMCA(BaselineResult, MCIs, {}, nullptr,
-      [=](InstrBuilder& IB, const MCInst& MCI, const SmallVector<Instrument*>& Instruments) {
-        return IB.createInstruction(MCI, Instruments,
-          [=](InstrDesc& ID) {
-            for (auto& W : ID.Writes) W.Latency = ExplicitLatency;
-            ID.MaxLatency = ExplicitLatency;
-          });
-      });
+                          [=](InstrBuilder &IB, const MCInst &MCI,
+                              const SmallVector<Instrument *> &Instruments) {
+                            return IB.createInstruction(
+                                MCI, Instruments, [=](InstrDesc &ID) {
+                                  for (auto &W : ID.Writes)
+                                    W.Latency = ExplicitLatency;
+                                  ID.MaxLatency = ExplicitLatency;
+                                });
+                          });
   auto *BaselineObj = BaselineResult.getObject("SummaryView");
   auto V = BaselineObj->getInteger("TotalCycles");
   ASSERT_TRUE(V);

>From 4d655f875362cbae9fc17febfa78fc874a168c86 Mon Sep 17 00:00:00 2001
From: Roman Belenov <rbelenov at gmail.com>
Date: Tue, 26 Aug 2025 17:51:49 +0300
Subject: [PATCH 11/24] Fix formatting

---
 llvm/tools/llvm-mca/CodeRegion.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/tools/llvm-mca/CodeRegion.h b/llvm/tools/llvm-mca/CodeRegion.h
index 0b5385a6d7ad1..52c0854779be6 100644
--- a/llvm/tools/llvm-mca/CodeRegion.h
+++ b/llvm/tools/llvm-mca/CodeRegion.h
@@ -178,7 +178,7 @@ class CodeRegions {
   void addInstruction(const llvm::MCInst &Instruction);
   llvm::SourceMgr &getSourceMgr() const { return SM; }
 
-  void Annotate(llvm::SMLoc Loc, const InstAnnotation& A) {
+  void Annotate(llvm::SMLoc Loc, const InstAnnotation &A) {
     Annotations[Loc.getPointer()] = A;
   }
   std::optional<unsigned> getExplicitLatency(llvm::SMLoc Loc) const {

>From ef2a0f0106358ee44d1a036e8b6cf2ab6fc50179 Mon Sep 17 00:00:00 2001
From: Roman Belenov <rbelenov at gmail.com>
Date: Tue, 26 Aug 2025 17:52:56 +0300
Subject: [PATCH 12/24] Fix formatting

---
 llvm/tools/llvm-mca/llvm-mca.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/tools/llvm-mca/llvm-mca.cpp b/llvm/tools/llvm-mca/llvm-mca.cpp
index 902a603a8e7dc..73ac11794154f 100644
--- a/llvm/tools/llvm-mca/llvm-mca.cpp
+++ b/llvm/tools/llvm-mca/llvm-mca.cpp
@@ -636,8 +636,8 @@ int main(int argc, char **argv) {
       auto Latency = Regions.getExplicitLatency(Loc);
       Expected<std::unique_ptr<mca::Instruction>> Inst =
           Latency ? IB.createInstruction(MCI, Instruments,
-                                         [=](llvm::mca::InstrDesc& ID) {
-                                           for (auto& W : ID.Writes)
+                                         [=](llvm::mca::InstrDesc &ID) {
+                                           for (auto &W : ID.Writes)
                                              W.Latency = *Latency;
                                            ID.MaxLatency = *Latency;
                                          })

>From 77eefdbeefd5f004d9b7c304e963fe44d65549b4 Mon Sep 17 00:00:00 2001
From: Roman Belenov <rbelenov at gmail.com>
Date: Tue, 26 Aug 2025 17:54:25 +0300
Subject: [PATCH 13/24] Fix formatting

---
 llvm/unittests/tools/llvm-mca/MCATestBase.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/unittests/tools/llvm-mca/MCATestBase.h b/llvm/unittests/tools/llvm-mca/MCATestBase.h
index 557da7b3d0d05..e991252cd3efd 100644
--- a/llvm/unittests/tools/llvm-mca/MCATestBase.h
+++ b/llvm/unittests/tools/llvm-mca/MCATestBase.h
@@ -72,7 +72,7 @@ class MCATestBase : public ::testing::Test {
   void SetUp() override;
 
   using Builder = std::function<Expected<std::unique_ptr<mca::Instruction>>(
-      mca::InstrBuilder&, const MCInst&,
+      mca::InstrBuilder &, const MCInst &,
       const SmallVector<mca::Instrument *> &)>;
 
   /// Utility function to run MCA with (nearly) the same configuration as the

>From 6e0d12b6aa58c9608b677da571781157e07bb4af Mon Sep 17 00:00:00 2001
From: Roman Belenov <rbelenov at gmail.com>
Date: Wed, 27 Aug 2025 07:59:05 +0300
Subject: [PATCH 14/24] Using function_ref to pass function arguments

* Switch to function_ref

* Switch to function_ref

* Check pipeline execution status

* Switch to function_ref
---
 llvm/include/llvm/MCA/InstrBuilder.h                     | 4 ++--
 llvm/lib/MCA/InstrBuilder.cpp                            | 4 ++--
 llvm/unittests/tools/llvm-mca/MCATestBase.h              | 2 +-
 llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp | 1 +
 4 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/llvm/include/llvm/MCA/InstrBuilder.h b/llvm/include/llvm/MCA/InstrBuilder.h
index 7b2fbde2c4a0e..6779d27dcca3a 100644
--- a/llvm/include/llvm/MCA/InstrBuilder.h
+++ b/llvm/include/llvm/MCA/InstrBuilder.h
@@ -93,7 +93,7 @@ class InstrBuilder {
   Expected<unsigned> getVariantSchedClassID(const MCInst &MCI, unsigned SchedClassID);
   Expected<const InstrDesc &>
   createInstrDescImpl(const MCInst &MCI, const SmallVector<Instrument *> &IVec,
-                      std::function<void(InstrDesc &)> Customizer = {});
+                      function_ref<void(InstrDesc &)> Customizer = {});
   Expected<const InstrDesc &>
   getOrCreateInstrDesc(const MCInst &MCI,
                        const SmallVector<Instrument *> &IVec);
@@ -123,7 +123,7 @@ class InstrBuilder {
 
   LLVM_ABI Expected<std::unique_ptr<Instruction>>
   createInstruction(const MCInst &MCI, const SmallVector<Instrument *> &IVec,
-                    std::function<void(InstrDesc &)> Customizer = {});
+                    function_ref<void(InstrDesc &)> Customizer = {});
 };
 } // namespace mca
 } // namespace llvm
diff --git a/llvm/lib/MCA/InstrBuilder.cpp b/llvm/lib/MCA/InstrBuilder.cpp
index 8b3e52a871f71..f65145b4203c0 100644
--- a/llvm/lib/MCA/InstrBuilder.cpp
+++ b/llvm/lib/MCA/InstrBuilder.cpp
@@ -559,7 +559,7 @@ Expected<unsigned> InstrBuilder::getVariantSchedClassID(const MCInst &MCI,
 Expected<const InstrDesc &>
 InstrBuilder::createInstrDescImpl(const MCInst &MCI,
                                   const SmallVector<Instrument *> &IVec,
-                                  std::function<void(InstrDesc &)> Customizer) {
+                                  function_ref<void(InstrDesc &)> Customizer) {
   assert(STI.getSchedModel().hasInstrSchedModel() &&
          "Itineraries are not yet supported!");
 
@@ -683,7 +683,7 @@ STATISTIC(NumVariantInst, "Number of MCInsts that doesn't have static Desc");
 Expected<std::unique_ptr<Instruction>>
 InstrBuilder::createInstruction(const MCInst &MCI,
                                 const SmallVector<Instrument *> &IVec,
-                                std::function<void(InstrDesc &)> Customizer) {
+                                function_ref<void(InstrDesc &)> Customizer) {
   Expected<const InstrDesc &> DescOrErr =
       Customizer ? createInstrDescImpl(MCI, IVec, Customizer)
                  : getOrCreateInstrDesc(MCI, IVec);
diff --git a/llvm/unittests/tools/llvm-mca/MCATestBase.h b/llvm/unittests/tools/llvm-mca/MCATestBase.h
index e991252cd3efd..c741d1f90c7f0 100644
--- a/llvm/unittests/tools/llvm-mca/MCATestBase.h
+++ b/llvm/unittests/tools/llvm-mca/MCATestBase.h
@@ -71,7 +71,7 @@ class MCATestBase : public ::testing::Test {
 
   void SetUp() override;
 
-  using Builder = std::function<Expected<std::unique_ptr<mca::Instruction>>(
+  using Builder = function_ref<Expected<std::unique_ptr<mca::Instruction>>(
       mca::InstrBuilder &, const MCInst &,
       const SmallVector<mca::Instrument *> &)>;
 
diff --git a/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp b/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp
index 8aa879b3e053d..668afd1a8d6be 100644
--- a/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp
+++ b/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp
@@ -256,6 +256,7 @@ TEST_F(X86TestBase, TestInstructionCustomization) {
                                   ID.MaxLatency = ExplicitLatency;
                                 });
                           });
+  ASSERT_FALSE(bool(E)) << "Failed to run baseline";
   auto *BaselineObj = BaselineResult.getObject("SummaryView");
   auto V = BaselineObj->getInteger("TotalCycles");
   ASSERT_TRUE(V);

>From 08cc266db1c57e7d06d7a3f3374d52239e0c1f73 Mon Sep 17 00:00:00 2001
From: Roman Belenov <rbelenov at gmail.com>
Date: Wed, 27 Aug 2025 16:59:23 +0300
Subject: [PATCH 15/24] Use InstrumentManager to customize instructions

Extended InstrumentManager to allow InstrDesc modification with instruments; added common instrument that can modify instruction latencies.
---
 llvm/include/llvm/MCA/CustomBehaviour.h       | 25 +++++-
 llvm/include/llvm/MCA/InstrBuilder.h          |  6 +-
 llvm/lib/MCA/CustomBehaviour.cpp              | 72 +++++++++++++++
 llvm/lib/MCA/InstrBuilder.cpp                 | 12 ++-
 .../tools/llvm-mca/X86/llvm-mca-markers-13.s  |  4 +-
 .../tools/llvm-mca/X86/llvm-mca-markers-14.s  |  5 +-
 llvm/tools/llvm-mca/CodeRegion.h              | 20 -----
 llvm/tools/llvm-mca/CodeRegionGenerator.cpp   | 12 ---
 llvm/tools/llvm-mca/CodeRegionGenerator.h     | 87 ++++++++-----------
 llvm/tools/llvm-mca/llvm-mca.cpp              | 18 ++--
 llvm/unittests/tools/llvm-mca/MCATestBase.cpp | 17 ++--
 llvm/unittests/tools/llvm-mca/MCATestBase.h   |  6 +-
 .../tools/llvm-mca/X86/TestIncrementalMCA.cpp | 14 +--
 13 files changed, 166 insertions(+), 132 deletions(-)

diff --git a/llvm/include/llvm/MCA/CustomBehaviour.h b/llvm/include/llvm/MCA/CustomBehaviour.h
index 0bf86ce688f44..f73be65d7af5e 100644
--- a/llvm/include/llvm/MCA/CustomBehaviour.h
+++ b/llvm/include/llvm/MCA/CustomBehaviour.h
@@ -130,6 +130,9 @@ class Instrument {
 
   virtual ~Instrument() = default;
 
+  virtual bool canCustomize() const { return false; }
+  virtual void customize(InstrDesc &) const {}
+
   StringRef getDesc() const { return Desc; }
   StringRef getData() const { return Data; }
 };
@@ -143,19 +146,26 @@ class LLVM_ABI InstrumentManager {
 protected:
   const MCSubtargetInfo &STI;
   const MCInstrInfo &MCII;
+  bool EnableDefaults;
+  std::unique_ptr<InstrumentManager> TargetIM;
 
 public:
-  InstrumentManager(const MCSubtargetInfo &STI, const MCInstrInfo &MCII)
-      : STI(STI), MCII(MCII) {}
+  InstrumentManager(const MCSubtargetInfo &STI, const MCInstrInfo &MCII,
+                    bool EnableDefaults = false,
+                    std::unique_ptr<InstrumentManager> TargetIM = {})
+      : STI(STI), MCII(MCII), EnableDefaults(EnableDefaults),
+        TargetIM(std::move(TargetIM)) {}
 
   virtual ~InstrumentManager() = default;
 
   /// Returns true if llvm-mca should ignore instruments.
-  virtual bool shouldIgnoreInstruments() const { return true; }
+  virtual bool shouldIgnoreInstruments() const {
+    return !EnableDefaults &&
+           (!TargetIM || TargetIM->shouldIgnoreInstruments()); }
 
   // Returns true if this supports processing Instrument with
   // Instrument.Desc equal to Type
-  virtual bool supportsInstrumentType(StringRef Type) const { return false; }
+  virtual bool supportsInstrumentType(StringRef Type) const;
 
   /// Allocate an Instrument, and return a unique pointer to it. This function
   /// may be useful to create instruments coming from comments in the assembly.
@@ -175,6 +185,13 @@ class LLVM_ABI InstrumentManager {
   /// it returns the SchedClassID that belongs to MCI.
   virtual unsigned getSchedClassID(const MCInstrInfo &MCII, const MCInst &MCI,
                                    const SmallVector<Instrument *> &IVec) const;
+
+  // Return true if instruments can modify instruction description
+  virtual bool canCustomize(const SmallVector<Instrument *> &IVec) const;
+
+  // Customize instruction description
+  virtual void customize(const SmallVector<Instrument *> &IVec,
+                         llvm::mca::InstrDesc &Desc) const;
 };
 
 } // namespace mca
diff --git a/llvm/include/llvm/MCA/InstrBuilder.h b/llvm/include/llvm/MCA/InstrBuilder.h
index 6779d27dcca3a..32923deb3e096 100644
--- a/llvm/include/llvm/MCA/InstrBuilder.h
+++ b/llvm/include/llvm/MCA/InstrBuilder.h
@@ -92,8 +92,7 @@ class InstrBuilder {
 
   Expected<unsigned> getVariantSchedClassID(const MCInst &MCI, unsigned SchedClassID);
   Expected<const InstrDesc &>
-  createInstrDescImpl(const MCInst &MCI, const SmallVector<Instrument *> &IVec,
-                      function_ref<void(InstrDesc &)> Customizer = {});
+  createInstrDescImpl(const MCInst &MCI, const SmallVector<Instrument *> &IVec);
   Expected<const InstrDesc &>
   getOrCreateInstrDesc(const MCInst &MCI,
                        const SmallVector<Instrument *> &IVec);
@@ -122,8 +121,7 @@ class InstrBuilder {
   void setInstRecycleCallback(InstRecycleCallback CB) { InstRecycleCB = CB; }
 
   LLVM_ABI Expected<std::unique_ptr<Instruction>>
-  createInstruction(const MCInst &MCI, const SmallVector<Instrument *> &IVec,
-                    function_ref<void(InstrDesc &)> Customizer = {});
+  createInstruction(const MCInst &MCI, const SmallVector<Instrument *> &IVec);
 };
 } // namespace mca
 } // namespace llvm
diff --git a/llvm/lib/MCA/CustomBehaviour.cpp b/llvm/lib/MCA/CustomBehaviour.cpp
index 1aa266e0a1e43..d196afeefba25 100644
--- a/llvm/lib/MCA/CustomBehaviour.cpp
+++ b/llvm/lib/MCA/CustomBehaviour.cpp
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/MCA/CustomBehaviour.h"
+#include "llvm/MCA/Instruction.h"
 
 namespace llvm {
 namespace mca {
@@ -42,19 +43,90 @@ CustomBehaviour::getEndViews(llvm::MCInstPrinter &IP,
   return std::vector<std::unique_ptr<View>>();
 }
 
+class CustomInstrument : public Instrument {
+  std::optional<unsigned> Latency;
+public:
+  static const llvm::StringRef DESC_NAME;
+  explicit CustomInstrument(StringRef Data) : Instrument(DESC_NAME, Data) {
+    // Skip spaces and tabs.
+    unsigned Position = Data.find_first_not_of(" \t");
+    if (Position >= Data.size())
+      // We reached the end of the comment. Bail out.
+      return;
+    Data = Data.drop_front(Position);
+    auto [Name, Value] = Data.split(':');
+    if (Name.upper() == "LATENCY") {
+      Position = Value.find_first_not_of(" \t");
+      if (Position >= Value.size())
+        return;
+      auto Stripped = Value.drop_front(Position);
+      unsigned L = 0;
+      if (!Stripped.getAsInteger(10, L))
+        Latency = L;
+    }
+  }
+
+  bool canCustomize() const override {
+    return bool(Latency);
+  }
+
+  void customize(InstrDesc& ID) const override {
+    if (Latency) {
+      for (auto &W : ID.Writes)
+        W.Latency = *Latency;
+      ID.MaxLatency = *Latency;
+    }
+  }
+};
+
+const llvm::StringRef CustomInstrument::DESC_NAME = "CUSTOMIZE";
+
+bool InstrumentManager::supportsInstrumentType(StringRef Type) const {
+  if (EnableDefaults && Type == CustomInstrument::DESC_NAME)
+    return true;
+  if (TargetIM)
+    return TargetIM->supportsInstrumentType(Type);
+  return false;
+}
+
+bool InstrumentManager::canCustomize(const llvm::SmallVector<Instrument *> &IVec) const {
+  for (const auto I : IVec) {
+    if (I->canCustomize())
+      return true;
+  }
+  return false;
+}
+
+void InstrumentManager::customize(const llvm::SmallVector<Instrument *> &IVec, InstrDesc &ID) const {
+  for (const auto I : IVec) {
+    if (I->canCustomize())
+      I->customize(ID);
+  }
+}
+
 UniqueInstrument InstrumentManager::createInstrument(llvm::StringRef Desc,
                                                      llvm::StringRef Data) {
+  if (!EnableDefaults)
+    return std::make_unique<Instrument>(Desc, Data);
+  if (Desc == CustomInstrument::DESC_NAME)
+    return std::make_unique<CustomInstrument>(Data);
+  if (TargetIM && TargetIM->supportsInstrumentType(Desc))
+    return TargetIM->createInstrument(Desc, Data);
   return std::make_unique<Instrument>(Desc, Data);
 }
 
 SmallVector<UniqueInstrument>
 InstrumentManager::createInstruments(const MCInst &Inst) {
+  if (TargetIM)
+    return TargetIM->createInstruments(Inst);
   return SmallVector<UniqueInstrument>();
 }
 
 unsigned InstrumentManager::getSchedClassID(
     const MCInstrInfo &MCII, const MCInst &MCI,
     const llvm::SmallVector<Instrument *> &IVec) const {
+  if (TargetIM)
+    return TargetIM->getSchedClassID(MCII, MCI, IVec);
   return MCII.get(MCI.getOpcode()).getSchedClass();
 }
 
diff --git a/llvm/lib/MCA/InstrBuilder.cpp b/llvm/lib/MCA/InstrBuilder.cpp
index f65145b4203c0..1625677ce3e15 100644
--- a/llvm/lib/MCA/InstrBuilder.cpp
+++ b/llvm/lib/MCA/InstrBuilder.cpp
@@ -558,8 +558,7 @@ Expected<unsigned> InstrBuilder::getVariantSchedClassID(const MCInst &MCI,
 
 Expected<const InstrDesc &>
 InstrBuilder::createInstrDescImpl(const MCInst &MCI,
-                                  const SmallVector<Instrument *> &IVec,
-                                  function_ref<void(InstrDesc &)> Customizer) {
+                                  const SmallVector<Instrument *> &IVec) {
   assert(STI.getSchedModel().hasInstrSchedModel() &&
          "Itineraries are not yet supported!");
 
@@ -634,8 +633,8 @@ InstrBuilder::createInstrDescImpl(const MCInst &MCI,
 
   // Now add the new descriptor.
 
-  if (Customizer) {
-    Customizer(*ID);
+  if (IM.canCustomize(IVec)) {
+    IM.customize(IVec, *ID);
     return *CustomDescriptors.emplace_back(std::move(ID));
   }
 
@@ -682,10 +681,9 @@ STATISTIC(NumVariantInst, "Number of MCInsts that doesn't have static Desc");
 
 Expected<std::unique_ptr<Instruction>>
 InstrBuilder::createInstruction(const MCInst &MCI,
-                                const SmallVector<Instrument *> &IVec,
-                                function_ref<void(InstrDesc &)> Customizer) {
+                                const SmallVector<Instrument *> &IVec) {
   Expected<const InstrDesc &> DescOrErr =
-      Customizer ? createInstrDescImpl(MCI, IVec, Customizer)
+      IM.canCustomize(IVec) ? createInstrDescImpl(MCI, IVec)
                  : getOrCreateInstrDesc(MCI, IVec);
   if (!DescOrErr)
     return DescOrErr.takeError();
diff --git a/llvm/test/tools/llvm-mca/X86/llvm-mca-markers-13.s b/llvm/test/tools/llvm-mca/X86/llvm-mca-markers-13.s
index 9115ffadbdaee..1c39a667e0733 100644
--- a/llvm/test/tools/llvm-mca/X86/llvm-mca-markers-13.s
+++ b/llvm/test/tools/llvm-mca/X86/llvm-mca-markers-13.s
@@ -1,7 +1,9 @@
 # NOTE: Assertions have been autogenerated by utils/update_mca_test_checks.py
 # RUN: llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=btver2 -iterations=10 %s 2>&1 | FileCheck %s
 
-add (%eax), %eax // LLVM-MCA-LATENCY : 100
+# LLVM-MCA-CUSTOMIZE Latency:100
+add (%eax), %eax
+# LLVM-MCA-CUSTOMIZE
 mov %eax, (%ebx)
 
 # CHECK:      Iterations:        10
diff --git a/llvm/test/tools/llvm-mca/X86/llvm-mca-markers-14.s b/llvm/test/tools/llvm-mca/X86/llvm-mca-markers-14.s
index 41da9f4b4cef1..b887cc3002a73 100644
--- a/llvm/test/tools/llvm-mca/X86/llvm-mca-markers-14.s
+++ b/llvm/test/tools/llvm-mca/X86/llvm-mca-markers-14.s
@@ -1,8 +1,9 @@
 # NOTE: Assertions have been autogenerated by utils/update_mca_test_checks.py
 # RUN: llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=btver2 -iterations=10 %s 2>&1 | FileCheck %s
 
-add (%eax), %eax // LLVM-MCA-LATENCY : 100
-mov %eax, (%ebx) // LLVM-MCA-LATENCY : 100
+# LLVM-MCA-CUSTOMIZE Latency:100
+add (%eax), %eax
+mov %eax, (%ebx)
 
 # CHECK:      Iterations:        10
 # CHECK-NEXT: Instructions:      20
diff --git a/llvm/tools/llvm-mca/CodeRegion.h b/llvm/tools/llvm-mca/CodeRegion.h
index 52c0854779be6..c04ea51169cfb 100644
--- a/llvm/tools/llvm-mca/CodeRegion.h
+++ b/llvm/tools/llvm-mca/CodeRegion.h
@@ -68,16 +68,11 @@
 #include "llvm/Support/Error.h"
 #include "llvm/Support/SMLoc.h"
 #include "llvm/Support/SourceMgr.h"
-#include <utility>
 #include <vector>
 
 namespace llvm {
 namespace mca {
 
-struct InstAnnotation {
-  std::optional<unsigned> Latency;
-};
-
 /// A region of assembly code.
 ///
 /// It identifies a sequence of machine instructions.
@@ -160,9 +155,6 @@ class CodeRegions {
   llvm::StringMap<unsigned> ActiveRegions;
   bool FoundErrors;
 
-  // Annotations specified in comments, indexed by SMLoc value
-  llvm::DenseMap<const char *, InstAnnotation> Annotations;
-
 public:
   CodeRegions(llvm::SourceMgr &S) : SM(S), FoundErrors(false) {}
   virtual ~CodeRegions() = default;
@@ -178,18 +170,6 @@ class CodeRegions {
   void addInstruction(const llvm::MCInst &Instruction);
   llvm::SourceMgr &getSourceMgr() const { return SM; }
 
-  void Annotate(llvm::SMLoc Loc, const InstAnnotation &A) {
-    Annotations[Loc.getPointer()] = A;
-  }
-  std::optional<unsigned> getExplicitLatency(llvm::SMLoc Loc) const {
-    const auto It = Annotations.find(Loc.getPointer());
-    if (It != Annotations.end()) {
-      return It->second.Latency;
-    } else {
-      return {};
-    }
-  }
-
   llvm::ArrayRef<llvm::MCInst> getInstructionSequence(unsigned Idx) const {
     return Regions[Idx]->getInstructions();
   }
diff --git a/llvm/tools/llvm-mca/CodeRegionGenerator.cpp b/llvm/tools/llvm-mca/CodeRegionGenerator.cpp
index 0d400760f17e1..f7f929e49ead9 100644
--- a/llvm/tools/llvm-mca/CodeRegionGenerator.cpp
+++ b/llvm/tools/llvm-mca/CodeRegionGenerator.cpp
@@ -95,18 +95,6 @@ void AnalysisRegionCommentConsumer::HandleComment(SMLoc Loc,
     return;
 
   Comment = Comment.drop_front(Position);
-  if (Comment.starts_with("LLVM-MCA-LATENCY")) {
-    auto Parts = Comment.split(':');
-    Position = Parts.second.find_first_not_of(" \t");
-    if (Position >= Parts.second.size())
-      return;
-    auto LatStr = Parts.second.drop_front(Position);
-    unsigned Latency = 0;
-    if (!LatStr.getAsInteger(10, Latency))
-      Streamer.AddLatencyAnnotation(Latency);
-    return;
-  }
-
   if (Comment.consume_front("LLVM-MCA-END")) {
     // Skip spaces and tabs.
     Position = Comment.find_first_not_of(" \t");
diff --git a/llvm/tools/llvm-mca/CodeRegionGenerator.h b/llvm/tools/llvm-mca/CodeRegionGenerator.h
index 1f43a8b26c471..a48c67a22f27b 100644
--- a/llvm/tools/llvm-mca/CodeRegionGenerator.h
+++ b/llvm/tools/llvm-mca/CodeRegionGenerator.h
@@ -31,51 +31,6 @@
 namespace llvm {
 namespace mca {
 
-// This class provides the callbacks that occur when parsing input assembly.
-class MCStreamerWrapper : public MCStreamer {
-protected:
-  CodeRegions &Regions;
-  std::optional<InstAnnotation> CurrentAnnotation;
-
-public:
-  MCStreamerWrapper(MCContext &Context, mca::CodeRegions &R)
-      : MCStreamer(Context), Regions(R) {}
-
-  // We only want to intercept the emission of new instructions.
-  void emitInstruction(const MCInst &Inst,
-                       const MCSubtargetInfo & /* unused */) override {
-    Regions.addInstruction(Inst);
-    if (CurrentAnnotation) {
-      Regions.Annotate(Inst.getLoc(), *CurrentAnnotation);
-      CurrentAnnotation = {};
-    }
-  }
-
-  void AddLatencyAnnotation(unsigned Lat) {
-    if (!CurrentAnnotation)
-      CurrentAnnotation = InstAnnotation();
-    CurrentAnnotation->Latency = Lat;
-  }
-
-  bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
-    return true;
-  }
-
-  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                        Align ByteAlignment) override {}
-  void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
-                    uint64_t Size = 0, Align ByteAlignment = Align(1),
-                    SMLoc Loc = SMLoc()) override {}
-  void beginCOFFSymbolDef(const MCSymbol *Symbol) override {}
-  void emitCOFFSymbolStorageClass(int StorageClass) override {}
-  void emitCOFFSymbolType(int Type) override {}
-  void endCOFFSymbolDef() override {}
-
-  ArrayRef<MCInst> GetInstructionSequence(unsigned Index) const {
-    return Regions.getInstructionSequence(Index);
-  }
-};
-
 class MCACommentConsumer : public AsmCommentConsumer {
 protected:
   bool FoundError = false;
@@ -89,11 +44,9 @@ class MCACommentConsumer : public AsmCommentConsumer {
 /// A comment consumer that parses strings.  The only valid tokens are strings.
 class AnalysisRegionCommentConsumer : public MCACommentConsumer {
   AnalysisRegions &Regions;
-  MCStreamerWrapper &Streamer;
 
 public:
-  AnalysisRegionCommentConsumer(AnalysisRegions &R, MCStreamerWrapper &S)
-      : Regions(R), Streamer(S) {}
+  AnalysisRegionCommentConsumer(AnalysisRegions &R) : Regions(R) {}
 
   /// Parses a comment. It begins a new region if it is of the form
   /// LLVM-MCA-BEGIN. It ends a region if it is of the form LLVM-MCA-END.
@@ -129,6 +82,40 @@ class InstrumentRegionCommentConsumer : public MCACommentConsumer {
   InstrumentManager &getInstrumentManager() { return IM; }
 };
 
+// This class provides the callbacks that occur when parsing input assembly.
+class MCStreamerWrapper : public MCStreamer {
+protected:
+  CodeRegions &Regions;
+
+public:
+  MCStreamerWrapper(MCContext &Context, mca::CodeRegions &R)
+      : MCStreamer(Context), Regions(R) {}
+
+  // We only want to intercept the emission of new instructions.
+  void emitInstruction(const MCInst &Inst,
+                       const MCSubtargetInfo & /* unused */) override {
+    Regions.addInstruction(Inst);
+  }
+
+  bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
+    return true;
+  }
+
+  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+                        Align ByteAlignment) override {}
+  void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
+                    uint64_t Size = 0, Align ByteAlignment = Align(1),
+                    SMLoc Loc = SMLoc()) override {}
+  void beginCOFFSymbolDef(const MCSymbol *Symbol) override {}
+  void emitCOFFSymbolStorageClass(int StorageClass) override {}
+  void emitCOFFSymbolType(int Type) override {}
+  void endCOFFSymbolDef() override {}
+
+  ArrayRef<MCInst> GetInstructionSequence(unsigned Index) const {
+    return Regions.getInstructionSequence(Index);
+  }
+};
+
 class InstrumentMCStreamer : public MCStreamerWrapper {
   InstrumentManager &IM;
 
@@ -223,15 +210,15 @@ class AsmCodeRegionGenerator : public virtual CodeRegionGenerator {
 
 class AsmAnalysisRegionGenerator final : public AnalysisRegionGenerator,
                                          public AsmCodeRegionGenerator {
-  MCStreamerWrapper Streamer;
   AnalysisRegionCommentConsumer CC;
+  MCStreamerWrapper Streamer;
 
 public:
   AsmAnalysisRegionGenerator(const Target &T, llvm::SourceMgr &SM, MCContext &C,
                              const MCAsmInfo &A, const MCSubtargetInfo &S,
                              const MCInstrInfo &I)
       : AnalysisRegionGenerator(SM), AsmCodeRegionGenerator(T, C, A, S, I),
-        Streamer(Ctx, Regions), CC(Regions, Streamer) {}
+        CC(Regions), Streamer(Ctx, Regions) {}
 
   MCACommentConsumer *getCommentConsumer() override { return &CC; };
   CodeRegions &getRegions() override { return Regions; };
diff --git a/llvm/tools/llvm-mca/llvm-mca.cpp b/llvm/tools/llvm-mca/llvm-mca.cpp
index 73ac11794154f..019c5a0db86aa 100644
--- a/llvm/tools/llvm-mca/llvm-mca.cpp
+++ b/llvm/tools/llvm-mca/llvm-mca.cpp
@@ -511,12 +511,13 @@ int main(int argc, char **argv) {
 
   std::unique_ptr<mca::InstrumentManager> IM;
   if (!DisableInstrumentManager) {
-    IM = std::unique_ptr<mca::InstrumentManager>(
-        TheTarget->createInstrumentManager(*STI, *MCII));
+    std::unique_ptr<mca::InstrumentManager> TargetIM =
+      std::unique_ptr<mca::InstrumentManager>(TheTarget->createInstrumentManager(*STI, *MCII));
+    IM = std::make_unique<mca::InstrumentManager>(*STI, *MCII, true, std::move(TargetIM));
   }
   if (!IM) {
-    // If the target doesn't have its own IM implemented (or the -disable-cb
-    // flag is set) then we use the base class (which does nothing).
+    // If -disable-cb flag is set then we use the base class with default behavior
+    // (which does nothing).
     IM = std::make_unique<mca::InstrumentManager>(*STI, *MCII);
   }
 
@@ -633,15 +634,8 @@ int main(int argc, char **argv) {
       const SmallVector<mca::Instrument *> Instruments =
           InstrumentRegions.getActiveInstruments(Loc);
 
-      auto Latency = Regions.getExplicitLatency(Loc);
       Expected<std::unique_ptr<mca::Instruction>> Inst =
-          Latency ? IB.createInstruction(MCI, Instruments,
-                                         [=](llvm::mca::InstrDesc &ID) {
-                                           for (auto &W : ID.Writes)
-                                             W.Latency = *Latency;
-                                           ID.MaxLatency = *Latency;
-                                         })
-                  : IB.createInstruction(MCI, Instruments);
+        IB.createInstruction(MCI, Instruments);
       if (!Inst) {
         if (auto NewE = handleErrors(
                 Inst.takeError(),
diff --git a/llvm/unittests/tools/llvm-mca/MCATestBase.cpp b/llvm/unittests/tools/llvm-mca/MCATestBase.cpp
index e2ff1dbe73a49..98ebd96fd0005 100644
--- a/llvm/unittests/tools/llvm-mca/MCATestBase.cpp
+++ b/llvm/unittests/tools/llvm-mca/MCATestBase.cpp
@@ -61,18 +61,25 @@ void MCATestBase::SetUp() {
 
 Error MCATestBase::runBaselineMCA(json::Object &Result, ArrayRef<MCInst> Insts,
                                   ArrayRef<mca::View *> Views,
-                                  const mca::PipelineOptions *PO, Builder B) {
+                                  const mca::PipelineOptions *PO,
+                                  SmallVector<std::pair<StringRef, StringRef>> Descs) {
   mca::Context MCA(*MRI, *STI);
 
-  // Default InstrumentManager
-  auto IM = std::make_unique<mca::InstrumentManager>(*STI, *MCII);
+  // Enable instruments when descriptions are provided
+  auto IM = std::make_unique<mca::InstrumentManager>(*STI, *MCII, !Descs.empty());
   mca::InstrBuilder IB(*STI, *MCII, *MRI, MCIA.get(), *IM, /*CallLatency=*/100);
 
-  const SmallVector<mca::Instrument *> Instruments;
+  SmallVector<mca::Instrument *> Instruments;
+  SmallVector<mca::UniqueInstrument> InstrumentsOwner;
+  for (const auto& Desc : Descs) {
+    auto I = IM->createInstrument(Desc.first, Desc.second);
+    Instruments.push_back(I.get());
+    InstrumentsOwner.push_back(std::move(I));
+  }
   SmallVector<std::unique_ptr<mca::Instruction>> LoweredInsts;
   for (const auto &MCI : Insts) {
     Expected<std::unique_ptr<mca::Instruction>> Inst =
-        B ? B(IB, MCI, Instruments) : IB.createInstruction(MCI, Instruments);
+        IB.createInstruction(MCI, Instruments);
     if (!Inst) {
       if (auto NewE =
               handleErrors(Inst.takeError(),
diff --git a/llvm/unittests/tools/llvm-mca/MCATestBase.h b/llvm/unittests/tools/llvm-mca/MCATestBase.h
index c741d1f90c7f0..71de00f1e457b 100644
--- a/llvm/unittests/tools/llvm-mca/MCATestBase.h
+++ b/llvm/unittests/tools/llvm-mca/MCATestBase.h
@@ -71,17 +71,13 @@ class MCATestBase : public ::testing::Test {
 
   void SetUp() override;
 
-  using Builder = function_ref<Expected<std::unique_ptr<mca::Instruction>>(
-      mca::InstrBuilder &, const MCInst &,
-      const SmallVector<mca::Instrument *> &)>;
-
   /// Utility function to run MCA with (nearly) the same configuration as the
   /// `llvm-mca` tool to verify result correctness.
   /// This function only displays on SummaryView by default.
   virtual Error runBaselineMCA(json::Object &Result, ArrayRef<MCInst> Insts,
                                ArrayRef<mca::View *> Views = {},
                                const mca::PipelineOptions *PO = nullptr,
-                               Builder B = {});
+                               SmallVector<std::pair<StringRef, StringRef>> Descs = {});
 };
 
 } // end namespace mca
diff --git a/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp b/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp
index 668afd1a8d6be..390697c2dd987 100644
--- a/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp
+++ b/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp
@@ -243,19 +243,13 @@ TEST_F(X86TestBase, TestInstructionCustomization) {
                                 .addReg(X86::RAX)
                                 .addReg(X86::RAX);
   MCIs.push_back(InstructionToAdd);
+  SmallVector<std::pair<StringRef, StringRef>> InstrDescs;
+  InstrDescs.push_back(std::make_pair(StringRef("CUSTOMIZE"),
+      StringRef("Latency:100")));
 
   // Run the baseline.
   json::Object BaselineResult;
-  auto E = runBaselineMCA(BaselineResult, MCIs, {}, nullptr,
-                          [=](InstrBuilder &IB, const MCInst &MCI,
-                              const SmallVector<Instrument *> &Instruments) {
-                            return IB.createInstruction(
-                                MCI, Instruments, [=](InstrDesc &ID) {
-                                  for (auto &W : ID.Writes)
-                                    W.Latency = ExplicitLatency;
-                                  ID.MaxLatency = ExplicitLatency;
-                                });
-                          });
+  auto E = runBaselineMCA(BaselineResult, MCIs, {}, nullptr, InstrDescs);
   ASSERT_FALSE(bool(E)) << "Failed to run baseline";
   auto *BaselineObj = BaselineResult.getObject("SummaryView");
   auto V = BaselineObj->getInteger("TotalCycles");

>From 1282e706e5a08b3933930a4a50e5d47e9ad8ee3f Mon Sep 17 00:00:00 2001
From: Roman Belenov <rbelenov at gmail.com>
Date: Wed, 27 Aug 2025 17:34:33 +0300
Subject: [PATCH 16/24] Fix formatting

Fixed formatting issues
---
 llvm/include/llvm/MCA/CustomBehaviour.h            |  3 ++-
 llvm/lib/MCA/CustomBehaviour.cpp                   | 13 +++++++------
 llvm/lib/MCA/InstrBuilder.cpp                      |  6 +++---
 llvm/tools/llvm-mca/llvm-mca.cpp                   | 12 +++++++-----
 llvm/unittests/tools/llvm-mca/MCATestBase.cpp      | 14 ++++++++------
 llvm/unittests/tools/llvm-mca/MCATestBase.h        |  9 +++++----
 .../tools/llvm-mca/X86/TestIncrementalMCA.cpp      |  4 ++--
 7 files changed, 34 insertions(+), 27 deletions(-)

diff --git a/llvm/include/llvm/MCA/CustomBehaviour.h b/llvm/include/llvm/MCA/CustomBehaviour.h
index f73be65d7af5e..63331518f76ab 100644
--- a/llvm/include/llvm/MCA/CustomBehaviour.h
+++ b/llvm/include/llvm/MCA/CustomBehaviour.h
@@ -161,7 +161,8 @@ class LLVM_ABI InstrumentManager {
   /// Returns true if llvm-mca should ignore instruments.
   virtual bool shouldIgnoreInstruments() const {
     return !EnableDefaults &&
-           (!TargetIM || TargetIM->shouldIgnoreInstruments()); }
+           (!TargetIM || TargetIM->shouldIgnoreInstruments());
+  }
 
   // Returns true if this supports processing Instrument with
   // Instrument.Desc equal to Type
diff --git a/llvm/lib/MCA/CustomBehaviour.cpp b/llvm/lib/MCA/CustomBehaviour.cpp
index d196afeefba25..d22117af29025 100644
--- a/llvm/lib/MCA/CustomBehaviour.cpp
+++ b/llvm/lib/MCA/CustomBehaviour.cpp
@@ -45,6 +45,7 @@ CustomBehaviour::getEndViews(llvm::MCInstPrinter &IP,
 
 class CustomInstrument : public Instrument {
   std::optional<unsigned> Latency;
+
 public:
   static const llvm::StringRef DESC_NAME;
   explicit CustomInstrument(StringRef Data) : Instrument(DESC_NAME, Data) {
@@ -66,11 +67,9 @@ class CustomInstrument : public Instrument {
     }
   }
 
-  bool canCustomize() const override {
-    return bool(Latency);
-  }
+  bool canCustomize() const override { return bool(Latency); }
 
-  void customize(InstrDesc& ID) const override {
+  void customize(InstrDesc &ID) const override {
     if (Latency) {
       for (auto &W : ID.Writes)
         W.Latency = *Latency;
@@ -89,7 +88,8 @@ bool InstrumentManager::supportsInstrumentType(StringRef Type) const {
   return false;
 }
 
-bool InstrumentManager::canCustomize(const llvm::SmallVector<Instrument *> &IVec) const {
+bool InstrumentManager::canCustomize(
+    const llvm::SmallVector<Instrument *> &IVec) const {
   for (const auto I : IVec) {
     if (I->canCustomize())
       return true;
@@ -97,7 +97,8 @@ bool InstrumentManager::canCustomize(const llvm::SmallVector<Instrument *> &IVec
   return false;
 }
 
-void InstrumentManager::customize(const llvm::SmallVector<Instrument *> &IVec, InstrDesc &ID) const {
+void InstrumentManager::customize(const llvm::SmallVector<Instrument *> &IVec,
+                                  InstrDesc &ID) const {
   for (const auto I : IVec) {
     if (I->canCustomize())
       I->customize(ID);
diff --git a/llvm/lib/MCA/InstrBuilder.cpp b/llvm/lib/MCA/InstrBuilder.cpp
index 1625677ce3e15..ffd6a8d5c14a8 100644
--- a/llvm/lib/MCA/InstrBuilder.cpp
+++ b/llvm/lib/MCA/InstrBuilder.cpp
@@ -682,9 +682,9 @@ STATISTIC(NumVariantInst, "Number of MCInsts that doesn't have static Desc");
 Expected<std::unique_ptr<Instruction>>
 InstrBuilder::createInstruction(const MCInst &MCI,
                                 const SmallVector<Instrument *> &IVec) {
-  Expected<const InstrDesc &> DescOrErr =
-      IM.canCustomize(IVec) ? createInstrDescImpl(MCI, IVec)
-                 : getOrCreateInstrDesc(MCI, IVec);
+  Expected<const InstrDesc &> DescOrErr = IM.canCustomize(IVec)
+                                              ? createInstrDescImpl(MCI, IVec)
+                                              : getOrCreateInstrDesc(MCI, IVec);
   if (!DescOrErr)
     return DescOrErr.takeError();
   const InstrDesc &D = *DescOrErr;
diff --git a/llvm/tools/llvm-mca/llvm-mca.cpp b/llvm/tools/llvm-mca/llvm-mca.cpp
index 019c5a0db86aa..6d937d1de9441 100644
--- a/llvm/tools/llvm-mca/llvm-mca.cpp
+++ b/llvm/tools/llvm-mca/llvm-mca.cpp
@@ -512,12 +512,14 @@ int main(int argc, char **argv) {
   std::unique_ptr<mca::InstrumentManager> IM;
   if (!DisableInstrumentManager) {
     std::unique_ptr<mca::InstrumentManager> TargetIM =
-      std::unique_ptr<mca::InstrumentManager>(TheTarget->createInstrumentManager(*STI, *MCII));
-    IM = std::make_unique<mca::InstrumentManager>(*STI, *MCII, true, std::move(TargetIM));
+        std::unique_ptr<mca::InstrumentManager>(
+            TheTarget->createInstrumentManager(*STI, *MCII));
+    IM = std::make_unique<mca::InstrumentManager>(*STI, *MCII, true,
+                                                  std::move(TargetIM));
   }
   if (!IM) {
-    // If -disable-cb flag is set then we use the base class with default behavior
-    // (which does nothing).
+    // If -disable-cb flag is set then we use the base class with default
+    // behavior (which does nothing).
     IM = std::make_unique<mca::InstrumentManager>(*STI, *MCII);
   }
 
@@ -635,7 +637,7 @@ int main(int argc, char **argv) {
           InstrumentRegions.getActiveInstruments(Loc);
 
       Expected<std::unique_ptr<mca::Instruction>> Inst =
-        IB.createInstruction(MCI, Instruments);
+          IB.createInstruction(MCI, Instruments);
       if (!Inst) {
         if (auto NewE = handleErrors(
                 Inst.takeError(),
diff --git a/llvm/unittests/tools/llvm-mca/MCATestBase.cpp b/llvm/unittests/tools/llvm-mca/MCATestBase.cpp
index 98ebd96fd0005..22f91a7acbc0a 100644
--- a/llvm/unittests/tools/llvm-mca/MCATestBase.cpp
+++ b/llvm/unittests/tools/llvm-mca/MCATestBase.cpp
@@ -59,19 +59,21 @@ void MCATestBase::SetUp() {
   ASSERT_TRUE(IP);
 }
 
-Error MCATestBase::runBaselineMCA(json::Object &Result, ArrayRef<MCInst> Insts,
-                                  ArrayRef<mca::View *> Views,
-                                  const mca::PipelineOptions *PO,
-                                  SmallVector<std::pair<StringRef, StringRef>> Descs) {
+Error MCATestBase::runBaselineMCA(
+    json::Object &Result, ArrayRef<MCInst> Insts,
+    ArrayRef<mca::View *> Views,
+    const mca::PipelineOptions *PO,
+    SmallVector<std::pair<StringRef, StringRef>> Descs) {
   mca::Context MCA(*MRI, *STI);
 
   // Enable instruments when descriptions are provided
-  auto IM = std::make_unique<mca::InstrumentManager>(*STI, *MCII, !Descs.empty());
+  auto IM =
+      std::make_unique<mca::InstrumentManager>(*STI, *MCII, !Descs.empty());
   mca::InstrBuilder IB(*STI, *MCII, *MRI, MCIA.get(), *IM, /*CallLatency=*/100);
 
   SmallVector<mca::Instrument *> Instruments;
   SmallVector<mca::UniqueInstrument> InstrumentsOwner;
-  for (const auto& Desc : Descs) {
+  for (const auto &Desc : Descs) {
     auto I = IM->createInstrument(Desc.first, Desc.second);
     Instruments.push_back(I.get());
     InstrumentsOwner.push_back(std::move(I));
diff --git a/llvm/unittests/tools/llvm-mca/MCATestBase.h b/llvm/unittests/tools/llvm-mca/MCATestBase.h
index 71de00f1e457b..1d88bc36ac0fa 100644
--- a/llvm/unittests/tools/llvm-mca/MCATestBase.h
+++ b/llvm/unittests/tools/llvm-mca/MCATestBase.h
@@ -74,10 +74,11 @@ class MCATestBase : public ::testing::Test {
   /// Utility function to run MCA with (nearly) the same configuration as the
   /// `llvm-mca` tool to verify result correctness.
   /// This function only displays on SummaryView by default.
-  virtual Error runBaselineMCA(json::Object &Result, ArrayRef<MCInst> Insts,
-                               ArrayRef<mca::View *> Views = {},
-                               const mca::PipelineOptions *PO = nullptr,
-                               SmallVector<std::pair<StringRef, StringRef>> Descs = {});
+  virtual Error
+  runBaselineMCA(json::Object &Result, ArrayRef<MCInst> Insts,
+                 ArrayRef<mca::View *> Views = {},
+                 const mca::PipelineOptions *PO = nullptr,
+                 SmallVector<std::pair<StringRef, StringRef>> Descs = {});
 };
 
 } // end namespace mca
diff --git a/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp b/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp
index 390697c2dd987..4ab9fcd7f71da 100644
--- a/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp
+++ b/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp
@@ -244,8 +244,8 @@ TEST_F(X86TestBase, TestInstructionCustomization) {
                                 .addReg(X86::RAX);
   MCIs.push_back(InstructionToAdd);
   SmallVector<std::pair<StringRef, StringRef>> InstrDescs;
-  InstrDescs.push_back(std::make_pair(StringRef("CUSTOMIZE"),
-      StringRef("Latency:100")));
+  InstrDescs.push_back(
+      std::make_pair(StringRef("CUSTOMIZE"), StringRef("Latency:100")));
 
   // Run the baseline.
   json::Object BaselineResult;

>From 71403fbbe04cdb39f06bfa4c8a6cd07c720fc28a Mon Sep 17 00:00:00 2001
From: Roman Belenov <rbelenov at gmail.com>
Date: Thu, 28 Aug 2025 10:47:06 +0300
Subject: [PATCH 17/24] Move latency customization logic to base Instrument

---
 llvm/include/llvm/MCA/CustomBehaviour.h       | 31 +++++++++++--
 llvm/lib/MCA/CustomBehaviour.cpp              | 45 ++-----------------
 llvm/unittests/tools/llvm-mca/MCATestBase.cpp |  3 +-
 3 files changed, 33 insertions(+), 46 deletions(-)

diff --git a/llvm/include/llvm/MCA/CustomBehaviour.h b/llvm/include/llvm/MCA/CustomBehaviour.h
index 63331518f76ab..64c050f96d8c2 100644
--- a/llvm/include/llvm/MCA/CustomBehaviour.h
+++ b/llvm/include/llvm/MCA/CustomBehaviour.h
@@ -123,15 +123,40 @@ class Instrument {
   /// The instrumentation data
   const StringRef Data;
 
+  std::optional<unsigned> Latency;
+
 public:
-  Instrument(StringRef Desc, StringRef Data) : Desc(Desc), Data(Data) {}
+  Instrument(StringRef Desc, StringRef Data) : Desc(Desc), Data(Data) {
+    // Skip spaces and tabs.
+    unsigned Position = Data.find_first_not_of(" \t");
+    if (Position >= Data.size())
+      // We reached the end of the comment. Bail out.
+      return;
+    Data = Data.drop_front(Position);
+    auto [Name, Value] = Data.split(':');
+    if (Name.upper() == "LATENCY") {
+      Position = Value.find_first_not_of(" \t");
+      if (Position >= Value.size())
+        return;
+      auto Stripped = Value.drop_front(Position);
+      unsigned L = 0;
+      if (!Stripped.getAsInteger(10, L))
+        Latency = L;
+    }
+  }
 
   Instrument() : Instrument("", "") {}
 
   virtual ~Instrument() = default;
 
-  virtual bool canCustomize() const { return false; }
-  virtual void customize(InstrDesc &) const {}
+  virtual bool canCustomize() const { return bool(Latency); }
+  virtual void customize(InstrDesc &ID) const {
+    if (Latency) {
+      for (auto &W : ID.Writes)
+        W.Latency = *Latency;
+      ID.MaxLatency = *Latency;
+    }
+  }
 
   StringRef getDesc() const { return Desc; }
   StringRef getData() const { return Data; }
diff --git a/llvm/lib/MCA/CustomBehaviour.cpp b/llvm/lib/MCA/CustomBehaviour.cpp
index d22117af29025..ecbf58e33376e 100644
--- a/llvm/lib/MCA/CustomBehaviour.cpp
+++ b/llvm/lib/MCA/CustomBehaviour.cpp
@@ -43,45 +43,10 @@ CustomBehaviour::getEndViews(llvm::MCInstPrinter &IP,
   return std::vector<std::unique_ptr<View>>();
 }
 
-class CustomInstrument : public Instrument {
-  std::optional<unsigned> Latency;
-
-public:
-  static const llvm::StringRef DESC_NAME;
-  explicit CustomInstrument(StringRef Data) : Instrument(DESC_NAME, Data) {
-    // Skip spaces and tabs.
-    unsigned Position = Data.find_first_not_of(" \t");
-    if (Position >= Data.size())
-      // We reached the end of the comment. Bail out.
-      return;
-    Data = Data.drop_front(Position);
-    auto [Name, Value] = Data.split(':');
-    if (Name.upper() == "LATENCY") {
-      Position = Value.find_first_not_of(" \t");
-      if (Position >= Value.size())
-        return;
-      auto Stripped = Value.drop_front(Position);
-      unsigned L = 0;
-      if (!Stripped.getAsInteger(10, L))
-        Latency = L;
-    }
-  }
-
-  bool canCustomize() const override { return bool(Latency); }
-
-  void customize(InstrDesc &ID) const override {
-    if (Latency) {
-      for (auto &W : ID.Writes)
-        W.Latency = *Latency;
-      ID.MaxLatency = *Latency;
-    }
-  }
-};
-
-const llvm::StringRef CustomInstrument::DESC_NAME = "CUSTOMIZE";
+static const llvm::StringRef CustomInstrumentName = "CUSTOMIZE";
 
 bool InstrumentManager::supportsInstrumentType(StringRef Type) const {
-  if (EnableDefaults && Type == CustomInstrument::DESC_NAME)
+  if (EnableDefaults && Type == CustomInstrumentName)
     return true;
   if (TargetIM)
     return TargetIM->supportsInstrumentType(Type);
@@ -107,12 +72,10 @@ void InstrumentManager::customize(const llvm::SmallVector<Instrument *> &IVec,
 
 UniqueInstrument InstrumentManager::createInstrument(llvm::StringRef Desc,
                                                      llvm::StringRef Data) {
-  if (!EnableDefaults)
-    return std::make_unique<Instrument>(Desc, Data);
-  if (Desc == CustomInstrument::DESC_NAME)
-    return std::make_unique<CustomInstrument>(Data);
   if (TargetIM && TargetIM->supportsInstrumentType(Desc))
     return TargetIM->createInstrument(Desc, Data);
+  if (!EnableDefaults)
+    return std::make_unique<Instrument>(Desc, Data);
   return std::make_unique<Instrument>(Desc, Data);
 }
 
diff --git a/llvm/unittests/tools/llvm-mca/MCATestBase.cpp b/llvm/unittests/tools/llvm-mca/MCATestBase.cpp
index 22f91a7acbc0a..1be41d5c76598 100644
--- a/llvm/unittests/tools/llvm-mca/MCATestBase.cpp
+++ b/llvm/unittests/tools/llvm-mca/MCATestBase.cpp
@@ -60,8 +60,7 @@ void MCATestBase::SetUp() {
 }
 
 Error MCATestBase::runBaselineMCA(
-    json::Object &Result, ArrayRef<MCInst> Insts,
-    ArrayRef<mca::View *> Views,
+    json::Object &Result, ArrayRef<MCInst> Insts, ArrayRef<mca::View *> Views,
     const mca::PipelineOptions *PO,
     SmallVector<std::pair<StringRef, StringRef>> Descs) {
   mca::Context MCA(*MRI, *STI);

>From b805a3c083c3415553bfbba34f09397f74cf63a7 Mon Sep 17 00:00:00 2001
From: Roman Belenov <rbelenov at gmail.com>
Date: Thu, 28 Aug 2025 16:48:13 +0300
Subject: [PATCH 18/24] Simplify IM creation

---
 llvm/include/llvm/MCA/CustomBehaviour.h |  7 ++++---
 llvm/lib/MCA/CustomBehaviour.cpp        |  9 +++++++++
 llvm/tools/llvm-mca/llvm-mca.cpp        | 17 ++++-------------
 3 files changed, 17 insertions(+), 16 deletions(-)

diff --git a/llvm/include/llvm/MCA/CustomBehaviour.h b/llvm/include/llvm/MCA/CustomBehaviour.h
index 64c050f96d8c2..c9a67c542994f 100644
--- a/llvm/include/llvm/MCA/CustomBehaviour.h
+++ b/llvm/include/llvm/MCA/CustomBehaviour.h
@@ -27,6 +27,9 @@
 #include "llvm/Support/Compiler.h"
 
 namespace llvm {
+
+class Target;
+
 namespace mca {
 
 /// Class which can be overriden by targets to modify the
@@ -177,9 +180,7 @@ class LLVM_ABI InstrumentManager {
 public:
   InstrumentManager(const MCSubtargetInfo &STI, const MCInstrInfo &MCII,
                     bool EnableDefaults = false,
-                    std::unique_ptr<InstrumentManager> TargetIM = {})
-      : STI(STI), MCII(MCII), EnableDefaults(EnableDefaults),
-        TargetIM(std::move(TargetIM)) {}
+                    const Target* TheTarget = nullptr);
 
   virtual ~InstrumentManager() = default;
 
diff --git a/llvm/lib/MCA/CustomBehaviour.cpp b/llvm/lib/MCA/CustomBehaviour.cpp
index ecbf58e33376e..7b2817d277365 100644
--- a/llvm/lib/MCA/CustomBehaviour.cpp
+++ b/llvm/lib/MCA/CustomBehaviour.cpp
@@ -13,6 +13,7 @@
 
 #include "llvm/MCA/CustomBehaviour.h"
 #include "llvm/MCA/Instruction.h"
+#include "llvm/MC/TargetRegistry.h"
 
 namespace llvm {
 namespace mca {
@@ -45,6 +46,14 @@ CustomBehaviour::getEndViews(llvm::MCInstPrinter &IP,
 
 static const llvm::StringRef CustomInstrumentName = "CUSTOMIZE";
 
+InstrumentManager::InstrumentManager(const MCSubtargetInfo &STI, const MCInstrInfo &MCII,
+                                     bool EnableDefaults,const Target* TheTarget)
+    : STI(STI), MCII(MCII), EnableDefaults(EnableDefaults) {
+    if (TheTarget)
+      TargetIM = std::unique_ptr<InstrumentManager>(
+          TheTarget->createInstrumentManager(STI, MCII));
+}
+
 bool InstrumentManager::supportsInstrumentType(StringRef Type) const {
   if (EnableDefaults && Type == CustomInstrumentName)
     return true;
diff --git a/llvm/tools/llvm-mca/llvm-mca.cpp b/llvm/tools/llvm-mca/llvm-mca.cpp
index 6d937d1de9441..bbebdb94d33e3 100644
--- a/llvm/tools/llvm-mca/llvm-mca.cpp
+++ b/llvm/tools/llvm-mca/llvm-mca.cpp
@@ -509,19 +509,10 @@ int main(int argc, char **argv) {
     return 1;
   }
 
-  std::unique_ptr<mca::InstrumentManager> IM;
-  if (!DisableInstrumentManager) {
-    std::unique_ptr<mca::InstrumentManager> TargetIM =
-        std::unique_ptr<mca::InstrumentManager>(
-            TheTarget->createInstrumentManager(*STI, *MCII));
-    IM = std::make_unique<mca::InstrumentManager>(*STI, *MCII, true,
-                                                  std::move(TargetIM));
-  }
-  if (!IM) {
-    // If -disable-cb flag is set then we use the base class with default
-    // behavior (which does nothing).
-    IM = std::make_unique<mca::InstrumentManager>(*STI, *MCII);
-  }
+  std::unique_ptr<mca::InstrumentManager> IM = 
+      std::make_unique<mca::InstrumentManager>(*STI, *MCII, !DisableInstrumentManager,
+                                               DisableInstrumentManager ? nullptr :
+                                               TheTarget);
 
   // Parse the input and create InstrumentRegion that llvm-mca
   // can use to improve analysis.

>From 801b0da28b3a56ae2cbea62ac29aa1e2da51ff2d Mon Sep 17 00:00:00 2001
From: Roman Belenov <rbelenov at gmail.com>
Date: Thu, 28 Aug 2025 17:00:04 +0300
Subject: [PATCH 19/24] Fix formatting

---
 llvm/include/llvm/MCA/CustomBehaviour.h |  2 +-
 llvm/lib/MCA/CustomBehaviour.cpp        | 12 +++++++-----
 llvm/tools/llvm-mca/llvm-mca.cpp        |  8 ++++----
 3 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/llvm/include/llvm/MCA/CustomBehaviour.h b/llvm/include/llvm/MCA/CustomBehaviour.h
index c9a67c542994f..3f461e58c748c 100644
--- a/llvm/include/llvm/MCA/CustomBehaviour.h
+++ b/llvm/include/llvm/MCA/CustomBehaviour.h
@@ -180,7 +180,7 @@ class LLVM_ABI InstrumentManager {
 public:
   InstrumentManager(const MCSubtargetInfo &STI, const MCInstrInfo &MCII,
                     bool EnableDefaults = false,
-                    const Target* TheTarget = nullptr);
+                    const Target *TheTarget = nullptr);
 
   virtual ~InstrumentManager() = default;
 
diff --git a/llvm/lib/MCA/CustomBehaviour.cpp b/llvm/lib/MCA/CustomBehaviour.cpp
index 7b2817d277365..e89511e563e50 100644
--- a/llvm/lib/MCA/CustomBehaviour.cpp
+++ b/llvm/lib/MCA/CustomBehaviour.cpp
@@ -46,12 +46,14 @@ CustomBehaviour::getEndViews(llvm::MCInstPrinter &IP,
 
 static const llvm::StringRef CustomInstrumentName = "CUSTOMIZE";
 
-InstrumentManager::InstrumentManager(const MCSubtargetInfo &STI, const MCInstrInfo &MCII,
-                                     bool EnableDefaults,const Target* TheTarget)
+InstrumentManager::InstrumentManager(const MCSubtargetInfo &STI,
+                                     const MCInstrInfo &MCII,
+                                     bool EnableDefaults,
+                                     const Target* TheTarget)
     : STI(STI), MCII(MCII), EnableDefaults(EnableDefaults) {
-    if (TheTarget)
-      TargetIM = std::unique_ptr<InstrumentManager>(
-          TheTarget->createInstrumentManager(STI, MCII));
+  if (TheTarget)
+    TargetIM = std::unique_ptr<InstrumentManager>(
+        TheTarget->createInstrumentManager(STI, MCII));
 }
 
 bool InstrumentManager::supportsInstrumentType(StringRef Type) const {
diff --git a/llvm/tools/llvm-mca/llvm-mca.cpp b/llvm/tools/llvm-mca/llvm-mca.cpp
index bbebdb94d33e3..6fcb5a6ba85f1 100644
--- a/llvm/tools/llvm-mca/llvm-mca.cpp
+++ b/llvm/tools/llvm-mca/llvm-mca.cpp
@@ -509,10 +509,10 @@ int main(int argc, char **argv) {
     return 1;
   }
 
-  std::unique_ptr<mca::InstrumentManager> IM = 
-      std::make_unique<mca::InstrumentManager>(*STI, *MCII, !DisableInstrumentManager,
-                                               DisableInstrumentManager ? nullptr :
-                                               TheTarget);
+  std::unique_ptr<mca::InstrumentManager> IM =
+      std::make_unique<mca::InstrumentManager>(
+          *STI, *MCII, !DisableInstrumentManager,
+          DisableInstrumentManager ? nullptr : TheTarget);
 
   // Parse the input and create InstrumentRegion that llvm-mca
   // can use to improve analysis.

>From ed4e0bde8b0044b233d3fdfed39b582edfc93eb9 Mon Sep 17 00:00:00 2001
From: Roman Belenov <rbelenov at gmail.com>
Date: Fri, 29 Aug 2025 10:02:59 +0300
Subject: [PATCH 20/24] Remove target IM from base class

---
 llvm/include/llvm/MCA/CustomBehaviour.h | 15 ++++-----------
 llvm/lib/MCA/CustomBehaviour.cpp        | 24 +-----------------------
 llvm/tools/llvm-mca/llvm-mca.cpp        | 19 +++++++++++++++----
 3 files changed, 20 insertions(+), 38 deletions(-)

diff --git a/llvm/include/llvm/MCA/CustomBehaviour.h b/llvm/include/llvm/MCA/CustomBehaviour.h
index 3f461e58c748c..b69cee4564b3f 100644
--- a/llvm/include/llvm/MCA/CustomBehaviour.h
+++ b/llvm/include/llvm/MCA/CustomBehaviour.h
@@ -27,9 +27,6 @@
 #include "llvm/Support/Compiler.h"
 
 namespace llvm {
-
-class Target;
-
 namespace mca {
 
 /// Class which can be overriden by targets to modify the
@@ -174,21 +171,17 @@ class LLVM_ABI InstrumentManager {
 protected:
   const MCSubtargetInfo &STI;
   const MCInstrInfo &MCII;
-  bool EnableDefaults;
-  std::unique_ptr<InstrumentManager> TargetIM;
+  bool EnableInstruments;
 
 public:
   InstrumentManager(const MCSubtargetInfo &STI, const MCInstrInfo &MCII,
-                    bool EnableDefaults = false,
-                    const Target *TheTarget = nullptr);
+                    bool EnableInstruments = false) :
+      STI(STI), MCII(MCII), EnableInstruments(EnableInstruments) {};
 
   virtual ~InstrumentManager() = default;
 
   /// Returns true if llvm-mca should ignore instruments.
-  virtual bool shouldIgnoreInstruments() const {
-    return !EnableDefaults &&
-           (!TargetIM || TargetIM->shouldIgnoreInstruments());
-  }
+  virtual bool shouldIgnoreInstruments() const { return !EnableInstruments; }
 
   // Returns true if this supports processing Instrument with
   // Instrument.Desc equal to Type
diff --git a/llvm/lib/MCA/CustomBehaviour.cpp b/llvm/lib/MCA/CustomBehaviour.cpp
index e89511e563e50..2f48444cb0fbe 100644
--- a/llvm/lib/MCA/CustomBehaviour.cpp
+++ b/llvm/lib/MCA/CustomBehaviour.cpp
@@ -46,22 +46,8 @@ CustomBehaviour::getEndViews(llvm::MCInstPrinter &IP,
 
 static const llvm::StringRef CustomInstrumentName = "CUSTOMIZE";
 
-InstrumentManager::InstrumentManager(const MCSubtargetInfo &STI,
-                                     const MCInstrInfo &MCII,
-                                     bool EnableDefaults,
-                                     const Target* TheTarget)
-    : STI(STI), MCII(MCII), EnableDefaults(EnableDefaults) {
-  if (TheTarget)
-    TargetIM = std::unique_ptr<InstrumentManager>(
-        TheTarget->createInstrumentManager(STI, MCII));
-}
-
 bool InstrumentManager::supportsInstrumentType(StringRef Type) const {
-  if (EnableDefaults && Type == CustomInstrumentName)
-    return true;
-  if (TargetIM)
-    return TargetIM->supportsInstrumentType(Type);
-  return false;
+  return EnableInstruments && Type == CustomInstrumentName;
 }
 
 bool InstrumentManager::canCustomize(
@@ -83,25 +69,17 @@ void InstrumentManager::customize(const llvm::SmallVector<Instrument *> &IVec,
 
 UniqueInstrument InstrumentManager::createInstrument(llvm::StringRef Desc,
                                                      llvm::StringRef Data) {
-  if (TargetIM && TargetIM->supportsInstrumentType(Desc))
-    return TargetIM->createInstrument(Desc, Data);
-  if (!EnableDefaults)
-    return std::make_unique<Instrument>(Desc, Data);
   return std::make_unique<Instrument>(Desc, Data);
 }
 
 SmallVector<UniqueInstrument>
 InstrumentManager::createInstruments(const MCInst &Inst) {
-  if (TargetIM)
-    return TargetIM->createInstruments(Inst);
   return SmallVector<UniqueInstrument>();
 }
 
 unsigned InstrumentManager::getSchedClassID(
     const MCInstrInfo &MCII, const MCInst &MCI,
     const llvm::SmallVector<Instrument *> &IVec) const {
-  if (TargetIM)
-    return TargetIM->getSchedClassID(MCII, MCI, IVec);
   return MCII.get(MCI.getOpcode()).getSchedClass();
 }
 
diff --git a/llvm/tools/llvm-mca/llvm-mca.cpp b/llvm/tools/llvm-mca/llvm-mca.cpp
index 6fcb5a6ba85f1..a568db5aa458c 100644
--- a/llvm/tools/llvm-mca/llvm-mca.cpp
+++ b/llvm/tools/llvm-mca/llvm-mca.cpp
@@ -509,10 +509,21 @@ int main(int argc, char **argv) {
     return 1;
   }
 
-  std::unique_ptr<mca::InstrumentManager> IM =
-      std::make_unique<mca::InstrumentManager>(
-          *STI, *MCII, !DisableInstrumentManager,
-          DisableInstrumentManager ? nullptr : TheTarget);
+  std::unique_ptr<mca::InstrumentManager> IM;
+  if (!DisableInstrumentManager) {
+    IM = std::unique_ptr<mca::InstrumentManager>(
+        TheTarget->createInstrumentManager(*STI, *MCII));
+    if (!IM) {
+      // If the target doesn't have its own IM implemented we use base class with
+      // instruments enabled.
+      IM = std::make_unique<mca::InstrumentManager>(*STI, *MCII, true);
+    }
+  }
+  else {
+    // If the -disable-cb flag is set then we use the default base class
+    // implementation (which does nothing).
+    IM = std::make_unique<mca::InstrumentManager>(*STI, *MCII);
+  }
 
   // Parse the input and create InstrumentRegion that llvm-mca
   // can use to improve analysis.

>From 042b3baa21e058259451fabadf45e281cbc93edf Mon Sep 17 00:00:00 2001
From: Roman Belenov <rbelenov at gmail.com>
Date: Fri, 29 Aug 2025 10:12:53 +0300
Subject: [PATCH 21/24] Fix formatting

* Update CustomBehaviour.h

* Update CustomBehaviour.cpp

* Update llvm-mca.cpp
---
 llvm/include/llvm/MCA/CustomBehaviour.h | 4 ++--
 llvm/lib/MCA/CustomBehaviour.cpp        | 1 -
 llvm/tools/llvm-mca/llvm-mca.cpp        | 7 +++----
 3 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/llvm/include/llvm/MCA/CustomBehaviour.h b/llvm/include/llvm/MCA/CustomBehaviour.h
index b69cee4564b3f..3b3fd740651ff 100644
--- a/llvm/include/llvm/MCA/CustomBehaviour.h
+++ b/llvm/include/llvm/MCA/CustomBehaviour.h
@@ -175,8 +175,8 @@ class LLVM_ABI InstrumentManager {
 
 public:
   InstrumentManager(const MCSubtargetInfo &STI, const MCInstrInfo &MCII,
-                    bool EnableInstruments = false) :
-      STI(STI), MCII(MCII), EnableInstruments(EnableInstruments) {};
+                    bool EnableInstruments = false)
+      : STI(STI), MCII(MCII), EnableInstruments(EnableInstruments) {};
 
   virtual ~InstrumentManager() = default;
 
diff --git a/llvm/lib/MCA/CustomBehaviour.cpp b/llvm/lib/MCA/CustomBehaviour.cpp
index 2f48444cb0fbe..48fc9e5d2f4bf 100644
--- a/llvm/lib/MCA/CustomBehaviour.cpp
+++ b/llvm/lib/MCA/CustomBehaviour.cpp
@@ -13,7 +13,6 @@
 
 #include "llvm/MCA/CustomBehaviour.h"
 #include "llvm/MCA/Instruction.h"
-#include "llvm/MC/TargetRegistry.h"
 
 namespace llvm {
 namespace mca {
diff --git a/llvm/tools/llvm-mca/llvm-mca.cpp b/llvm/tools/llvm-mca/llvm-mca.cpp
index a568db5aa458c..7bcad9cd64355 100644
--- a/llvm/tools/llvm-mca/llvm-mca.cpp
+++ b/llvm/tools/llvm-mca/llvm-mca.cpp
@@ -514,12 +514,11 @@ int main(int argc, char **argv) {
     IM = std::unique_ptr<mca::InstrumentManager>(
         TheTarget->createInstrumentManager(*STI, *MCII));
     if (!IM) {
-      // If the target doesn't have its own IM implemented we use base class with
-      // instruments enabled.
+      // If the target doesn't have its own IM implemented we use base class
+      // with instruments enabled.
       IM = std::make_unique<mca::InstrumentManager>(*STI, *MCII, true);
     }
-  }
-  else {
+  } else {
     // If the -disable-cb flag is set then we use the default base class
     // implementation (which does nothing).
     IM = std::make_unique<mca::InstrumentManager>(*STI, *MCII);

>From 5fb0db741a2a372ab7fee92949298e6c0831c249 Mon Sep 17 00:00:00 2001
From: Roman Belenov <rbelenov at gmail.com>
Date: Fri, 12 Sep 2025 12:08:43 +0300
Subject: [PATCH 22/24] Use explicit latency instrument

Latency customization logic is moved to dedicated instrument.
---
 llvm/docs/CommandGuide/llvm-mca.rst           | 14 ++++++
 llvm/include/llvm/MCA/CustomBehaviour.h       | 44 ++++++++++---------
 llvm/lib/MCA/CustomBehaviour.cpp              |  8 +++-
 .../tools/llvm-mca/X86/llvm-mca-markers-13.s  |  4 +-
 .../tools/llvm-mca/X86/llvm-mca-markers-14.s  |  2 +-
 .../tools/llvm-mca/X86/TestIncrementalMCA.cpp |  3 +-
 6 files changed, 48 insertions(+), 27 deletions(-)

diff --git a/llvm/docs/CommandGuide/llvm-mca.rst b/llvm/docs/CommandGuide/llvm-mca.rst
index 1daae5d064aca..c7600834d262e 100644
--- a/llvm/docs/CommandGuide/llvm-mca.rst
+++ b/llvm/docs/CommandGuide/llvm-mca.rst
@@ -383,6 +383,20 @@ that do not start with `LLVM-MCA-` are ignored by :program:`llvm-mca`.
 An instruction (a MCInst) is added to an InstrumentRegion R only
 if its location is in range [R.RangeStart, R.RangeEnd].
 
+There is one instrument that can be used on all targets to explicitly
+set instruction latencies. It can be used, for example, to model the
+cache misses that impact load latencies. The syntax is like
+
+.. code-block:: none
+
+  # LLVM-MCA-LATENCY 100
+  mov (%edi), %eax
+  # LLVM-MCA-LATENCY
+
+It set the latency of mov instruction to 100. LLVM-MCA-LATENCY without
+argument ends the region with explicit latency, after it default target
+latencies are used.
+
 On RISCV targets, vector instructions have different behaviour depending
 on the LMUL. Code can be instrumented with a comment that takes the
 following form:
diff --git a/llvm/include/llvm/MCA/CustomBehaviour.h b/llvm/include/llvm/MCA/CustomBehaviour.h
index 3b3fd740651ff..c075d781ccef9 100644
--- a/llvm/include/llvm/MCA/CustomBehaviour.h
+++ b/llvm/include/llvm/MCA/CustomBehaviour.h
@@ -123,43 +123,45 @@ class Instrument {
   /// The instrumentation data
   const StringRef Data;
 
-  std::optional<unsigned> Latency;
+public:
+  Instrument(StringRef Desc, StringRef Data) : Desc(Desc), Data(Data) {}
+  
+  Instrument() : Instrument("", "") {}
+
+  virtual ~Instrument() = default;
+
+  virtual bool canCustomize() const { return false; }
+  virtual void customize(InstrDesc &) const {}
+
+  StringRef getDesc() const { return Desc; }
+  StringRef getData() const { return Data; }
+};
 
+class LatencyInstrument : public Instrument {
+  std::optional<unsigned> Latency;
 public:
-  Instrument(StringRef Desc, StringRef Data) : Desc(Desc), Data(Data) {
+  static const llvm::StringRef DESC_NAME;
+  LatencyInstrument(StringRef Data) : Instrument(DESC_NAME, Data) {
     // Skip spaces and tabs.
     unsigned Position = Data.find_first_not_of(" \t");
     if (Position >= Data.size())
       // We reached the end of the comment. Bail out.
       return;
     Data = Data.drop_front(Position);
-    auto [Name, Value] = Data.split(':');
-    if (Name.upper() == "LATENCY") {
-      Position = Value.find_first_not_of(" \t");
-      if (Position >= Value.size())
-        return;
-      auto Stripped = Value.drop_front(Position);
-      unsigned L = 0;
-      if (!Stripped.getAsInteger(10, L))
-        Latency = L;
-    }
+    unsigned L = 0;
+    if (!Data.getAsInteger(10, L))
+      Latency = L;
   }
 
-  Instrument() : Instrument("", "") {}
-
-  virtual ~Instrument() = default;
-
-  virtual bool canCustomize() const { return bool(Latency); }
-  virtual void customize(InstrDesc &ID) const {
+  bool canCustomize() const override { return bool(Latency); }
+  void customize(InstrDesc &ID) const override {
     if (Latency) {
+      // TODO Allow to customize a subset of ID.Writes
       for (auto &W : ID.Writes)
         W.Latency = *Latency;
       ID.MaxLatency = *Latency;
     }
   }
-
-  StringRef getDesc() const { return Desc; }
-  StringRef getData() const { return Data; }
 };
 
 using UniqueInstrument = std::unique_ptr<Instrument>;
diff --git a/llvm/lib/MCA/CustomBehaviour.cpp b/llvm/lib/MCA/CustomBehaviour.cpp
index 48fc9e5d2f4bf..da2aa973a5a87 100644
--- a/llvm/lib/MCA/CustomBehaviour.cpp
+++ b/llvm/lib/MCA/CustomBehaviour.cpp
@@ -43,10 +43,10 @@ CustomBehaviour::getEndViews(llvm::MCInstPrinter &IP,
   return std::vector<std::unique_ptr<View>>();
 }
 
-static const llvm::StringRef CustomInstrumentName = "CUSTOMIZE";
+const llvm::StringRef LatencyInstrument::DESC_NAME = "LATENCY";
 
 bool InstrumentManager::supportsInstrumentType(StringRef Type) const {
-  return EnableInstruments && Type == CustomInstrumentName;
+  return EnableInstruments && Type == LatencyInstrument::DESC_NAME;
 }
 
 bool InstrumentManager::canCustomize(
@@ -68,6 +68,10 @@ void InstrumentManager::customize(const llvm::SmallVector<Instrument *> &IVec,
 
 UniqueInstrument InstrumentManager::createInstrument(llvm::StringRef Desc,
                                                      llvm::StringRef Data) {
+  if (!EnableInstruments)
+    return std::make_unique<Instrument>(Desc, Data);
+  if (Desc == LatencyInstrument::DESC_NAME)
+    return std::make_unique<LatencyInstrument>(Data);
   return std::make_unique<Instrument>(Desc, Data);
 }
 
diff --git a/llvm/test/tools/llvm-mca/X86/llvm-mca-markers-13.s b/llvm/test/tools/llvm-mca/X86/llvm-mca-markers-13.s
index 1c39a667e0733..aa00ac4400820 100644
--- a/llvm/test/tools/llvm-mca/X86/llvm-mca-markers-13.s
+++ b/llvm/test/tools/llvm-mca/X86/llvm-mca-markers-13.s
@@ -1,9 +1,9 @@
 # NOTE: Assertions have been autogenerated by utils/update_mca_test_checks.py
 # RUN: llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=btver2 -iterations=10 %s 2>&1 | FileCheck %s
 
-# LLVM-MCA-CUSTOMIZE Latency:100
+# LLVM-MCA-LATENCY 100
 add (%eax), %eax
-# LLVM-MCA-CUSTOMIZE
+# LLVM-MCA-LATENCY
 mov %eax, (%ebx)
 
 # CHECK:      Iterations:        10
diff --git a/llvm/test/tools/llvm-mca/X86/llvm-mca-markers-14.s b/llvm/test/tools/llvm-mca/X86/llvm-mca-markers-14.s
index b887cc3002a73..f460f1df8a703 100644
--- a/llvm/test/tools/llvm-mca/X86/llvm-mca-markers-14.s
+++ b/llvm/test/tools/llvm-mca/X86/llvm-mca-markers-14.s
@@ -1,7 +1,7 @@
 # NOTE: Assertions have been autogenerated by utils/update_mca_test_checks.py
 # RUN: llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=btver2 -iterations=10 %s 2>&1 | FileCheck %s
 
-# LLVM-MCA-CUSTOMIZE Latency:100
+# LLVM-MCA-LATENCY 100
 add (%eax), %eax
 mov %eax, (%ebx)
 
diff --git a/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp b/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp
index 4ab9fcd7f71da..7bfbbd7b1ccdd 100644
--- a/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp
+++ b/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp
@@ -235,6 +235,7 @@ TEST_F(X86TestBase, TestVariantInstructionsSameAddress) {
   ASSERT_TRUE(static_cast<bool>(Cycles));
 }
 
+// Test customization of instruction latency with instruments
 TEST_F(X86TestBase, TestInstructionCustomization) {
   const unsigned ExplicitLatency = 100;
   SmallVector<MCInst> MCIs;
@@ -245,7 +246,7 @@ TEST_F(X86TestBase, TestInstructionCustomization) {
   MCIs.push_back(InstructionToAdd);
   SmallVector<std::pair<StringRef, StringRef>> InstrDescs;
   InstrDescs.push_back(
-      std::make_pair(StringRef("CUSTOMIZE"), StringRef("Latency:100")));
+      std::make_pair(StringRef("LATENCY"), StringRef("100")));
 
   // Run the baseline.
   json::Object BaselineResult;

>From e1244168f7d9d26ff8602a8aa8b9d1f0b3435f3c Mon Sep 17 00:00:00 2001
From: Roman Belenov <rbelenov at gmail.com>
Date: Fri, 12 Sep 2025 12:18:42 +0300
Subject: [PATCH 23/24] Fix formatting (#12)

* Update CustomBehaviour.h

* Update TestIncrementalMCA.cpp
---
 llvm/include/llvm/MCA/CustomBehaviour.h                  | 3 ++-
 llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp | 3 +--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/include/llvm/MCA/CustomBehaviour.h b/llvm/include/llvm/MCA/CustomBehaviour.h
index c075d781ccef9..39c5f23f10e29 100644
--- a/llvm/include/llvm/MCA/CustomBehaviour.h
+++ b/llvm/include/llvm/MCA/CustomBehaviour.h
@@ -125,7 +125,7 @@ class Instrument {
 
 public:
   Instrument(StringRef Desc, StringRef Data) : Desc(Desc), Data(Data) {}
-  
+
   Instrument() : Instrument("", "") {}
 
   virtual ~Instrument() = default;
@@ -139,6 +139,7 @@ class Instrument {
 
 class LatencyInstrument : public Instrument {
   std::optional<unsigned> Latency;
+
 public:
   static const llvm::StringRef DESC_NAME;
   LatencyInstrument(StringRef Data) : Instrument(DESC_NAME, Data) {
diff --git a/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp b/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp
index 7bfbbd7b1ccdd..0bbb565de94ad 100644
--- a/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp
+++ b/llvm/unittests/tools/llvm-mca/X86/TestIncrementalMCA.cpp
@@ -245,8 +245,7 @@ TEST_F(X86TestBase, TestInstructionCustomization) {
                                 .addReg(X86::RAX);
   MCIs.push_back(InstructionToAdd);
   SmallVector<std::pair<StringRef, StringRef>> InstrDescs;
-  InstrDescs.push_back(
-      std::make_pair(StringRef("LATENCY"), StringRef("100")));
+  InstrDescs.push_back(std::make_pair(StringRef("LATENCY"), StringRef("100")));
 
   // Run the baseline.
   json::Object BaselineResult;

>From 74482dd19ff6cb38defaf19ce3d5e6cb0feb9624 Mon Sep 17 00:00:00 2001
From: Roman Belenov <rbelenov at gmail.com>
Date: Fri, 12 Sep 2025 13:38:13 +0300
Subject: [PATCH 24/24] Removing redundant include

<functional> was required for initial approach with customization passed via std::function, now we use IM methods.
---
 llvm/include/llvm/MCA/InstrBuilder.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/include/llvm/MCA/InstrBuilder.h b/llvm/include/llvm/MCA/InstrBuilder.h
index 32923deb3e096..a5ce632b03634 100644
--- a/llvm/include/llvm/MCA/InstrBuilder.h
+++ b/llvm/include/llvm/MCA/InstrBuilder.h
@@ -25,7 +25,6 @@
 #include "llvm/MCA/Support.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/Error.h"
-#include <functional>
 
 namespace llvm {
 namespace mca {



More information about the llvm-commits mailing list