[llvm] [llvm-exegesis] Process memory operands with unsuitable register class (PR #190342)

via llvm-commits llvm-commits at lists.llvm.org
Fri Apr 3 06:02:05 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-tools-llvm-exegesis

Author: Timur Baidusenov (bai-tim)

<details>
<summary>Changes</summary>

This patch generalizes the handling of registers that do not fit into the required register class. This can now happen when the scratch register is inserted in C_(L|S)(W|D)SP instruction.

---

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


12 Files Affected:

- (added) llvm/test/tools/llvm-exegesis/RISCV/mem-register-sp.s (+41) 
- (modified) llvm/tools/llvm-exegesis/lib/Assembler.cpp (+2) 
- (modified) llvm/tools/llvm-exegesis/lib/BenchmarkResult.h (+2) 
- (modified) llvm/tools/llvm-exegesis/lib/CodeTemplate.cpp (+12) 
- (modified) llvm/tools/llvm-exegesis/lib/CodeTemplate.h (+3) 
- (modified) llvm/tools/llvm-exegesis/lib/ParallelSnippetGenerator.cpp (+25-9) 
- (modified) llvm/tools/llvm-exegesis/lib/ParallelSnippetGenerator.h (+3-2) 
- (modified) llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp (+30-20) 
- (modified) llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp (+26-22) 
- (modified) llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp (+66-1) 
- (modified) llvm/tools/llvm-exegesis/lib/SnippetGenerator.h (+6) 
- (modified) llvm/tools/llvm-exegesis/lib/Target.h (+8) 


``````````diff
diff --git a/llvm/test/tools/llvm-exegesis/RISCV/mem-register-sp.s b/llvm/test/tools/llvm-exegesis/RISCV/mem-register-sp.s
new file mode 100644
index 0000000000000..3205e2c296711
--- /dev/null
+++ b/llvm/test/tools/llvm-exegesis/RISCV/mem-register-sp.s
@@ -0,0 +1,41 @@
+# RUN: llvm-exegesis -mode=latency --benchmark-phase=assemble-measured-code -opcode-name=C_LWSP --min-instructions=100000 \
+# RUN:   --dump-object-to-disk=%d -mtriple=riscv32-unknown-linux-gnu --mcpu=generic --repetition-mode=loop --min-instructions=100000 --loop-body-size=100 \
+# RUN:   -mattr=+m,+c,+f,+a,+zba,+zbb,+zbc,+zbs
+# RUN: llvm-objdump -M numeric -d %d > %t.s
+# RUN: FileCheck %s --input-file=%t.s --check-prefix=CHECK-LOAD-ASM
+
+# RUN: llvm-exegesis -mode=latency --benchmark-phase=assemble-measured-code -opcode-name=C_LWSP --min-instructions=100000 \
+# RUN:   --dump-object-to-disk=%d -mtriple=riscv32-unknown-linux-gnu --mcpu=generic --repetition-mode=loop --loop-body-size=100 \
+# RUN:   -mattr=+m,+c,+f,+a,+zba,+zbb,+zbc,+zbs --mode=inverse_throughput
+# RUN: llvm-objdump -M numeric -d %d > %t.s
+# RUN: FileCheck %s --input-file=%t.s --check-prefix=CHECK-LOAD-ASM
+
+# RUN: llvm-exegesis -mode=latency --benchmark-phase=assemble-measured-code -opcode-name=C_LWSP --min-instructions=100000 \
+# RUN:   --dump-object-to-disk=%d -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --repetition-mode=loop --loop-body-size=100 \
+# RUN:   -mattr=+m,+c,+f,+a,+zba,+zbb,+zbc,+zbs
+# RUN: llvm-objdump -M numeric -d %d > %t.s
+# RUN: FileCheck %s --input-file=%t.s --check-prefix=CHECK-LOAD-ASM
+
+# RUN: llvm-exegesis -mode=latency --benchmark-phase=assemble-measured-code -opcode-name=C_LDSP --min-instructions=100000 \
+# RUN:   --dump-object-to-disk=%d -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --repetition-mode=loop --loop-body-size=100 \
+# RUN:   -mattr=+m,+c,+f,+a,+zba,+zbb,+zbc,+zbs
+# RUN: llvm-objdump -M numeric -d %d > %t.s
+# RUN: FileCheck %s --input-file=%t.s --check-prefix=CHECK-LOAD-ASM
+
+# RUN: llvm-exegesis -mode=latency --benchmark-phase=assemble-measured-code -opcode-name=C_SWSP --min-instructions=100000 \
+# RUN:   --dump-object-to-disk=%d -mtriple=riscv32-unknown-linux-gnu --mcpu=generic --repetition-mode=loop --loop-body-size=100 \
+# RUN:   -mattr=+m,+c,+f,+a,+zba,+zbb,+zbc,+zbs --mode=inverse_throughput
+# RUN: llvm-objdump -M numeric -d %d > %t.s
+# RUN: FileCheck %s --input-file=%t.s --check-prefix=CHECK-STORE-ASM
+
+# RUN: llvm-exegesis -mode=latency --benchmark-phase=assemble-measured-code -opcode-name=C_SDSP --min-instructions=100000 \
+# RUN:   --dump-object-to-disk=%d -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --repetition-mode=loop --loop-body-size=100 \
+# RUN:   -mattr=+m,+c,+f,+a,+zba,+zbb,+zbc,+zbs --mode=inverse_throughput
+# RUN: llvm-objdump -M numeric -d %d > %t.s
+# RUN: FileCheck %s --input-file=%t.s --check-prefix=CHECK-STORE-ASM
+
+CHECK-LOAD-ASM: mv x2, x10
+CHECK-LOAD-ASM-COUNT-100: l{{[wd]}} x{{[0-9]+}}, 0x0(x2)
+
+CHECK-STORE-ASM: mv x2, x10
+CHECK-STORE-ASM-COUNT-100: s{{[wd]}} x{{[0-9]+}}, 0x0(x2)
diff --git a/llvm/tools/llvm-exegesis/lib/Assembler.cpp b/llvm/tools/llvm-exegesis/lib/Assembler.cpp
index 7191e49c6dccd..c6ddf7dcd5e87 100644
--- a/llvm/tools/llvm-exegesis/lib/Assembler.cpp
+++ b/llvm/tools/llvm-exegesis/lib/Assembler.cpp
@@ -300,6 +300,8 @@ Error assembleToStream(const ExegesisTarget &ET,
   if (!IsSnippetSetupComplete)
     Properties.resetTracksLiveness();
 
+  Entry.addInstructions(Key.PrologueInstructions);
+
   Fill(Sink);
 
   // prologue/epilogue pass needs the reserved registers to be frozen, this
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h
index 7984c8805cadc..c737ccd2f5b7d 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h
@@ -76,6 +76,8 @@ struct BenchmarkKey {
   uintptr_t SnippetAddress = 0;
   // The register that should be used to hold the loop counter.
   MCRegister LoopRegister;
+  // Instructions for inserting into entry.
+  std::vector<MCInst> PrologueInstructions;
 };
 
 struct BenchmarkMeasure {
diff --git a/llvm/tools/llvm-exegesis/lib/CodeTemplate.cpp b/llvm/tools/llvm-exegesis/lib/CodeTemplate.cpp
index fd156ee01e7ce..72080f117b336 100644
--- a/llvm/tools/llvm-exegesis/lib/CodeTemplate.cpp
+++ b/llvm/tools/llvm-exegesis/lib/CodeTemplate.cpp
@@ -63,6 +63,18 @@ bool InstructionTemplate::hasImmediateVariables() const {
   });
 }
 
+Operand InstructionTemplate::getMemOpReg() const {
+  auto &I = getInstr();
+  auto MemOpIt =
+      find_if(I.Operands, [](const Operand &Op) { return Op.isMemory(); });
+  assert(MemOpIt != I.Operands.end() &&
+         "Instruction must have memory operands");
+
+  const Operand &MemOp = *MemOpIt;
+  assert(MemOp.isReg() && "Memory operand expected to be register");
+  return MemOp;
+}
+
 MCInst InstructionTemplate::build() const {
   MCInst Result;
   Result.setOpcode(Instr->Description.Opcode);
diff --git a/llvm/tools/llvm-exegesis/lib/CodeTemplate.h b/llvm/tools/llvm-exegesis/lib/CodeTemplate.h
index a65015b45b786..d1a3d2faa3bca 100644
--- a/llvm/tools/llvm-exegesis/lib/CodeTemplate.h
+++ b/llvm/tools/llvm-exegesis/lib/CodeTemplate.h
@@ -38,6 +38,7 @@ struct InstructionTemplate {
   bool hasImmediateVariables() const;
   const Instruction &getInstr() const { return *Instr; }
   ArrayRef<MCOperand> getVariableValues() const { return VariableValues; }
+  Operand getMemOpReg() const;
   void setVariableValues(ArrayRef<MCOperand> NewVariableValues) {
     assert(VariableValues.size() == NewVariableValues.size() &&
            "Value count mismatch");
@@ -133,6 +134,8 @@ struct CodeTemplate {
   // the pointer to this memory is passed in to the function.
   MCRegister ScratchSpacePointerInReg;
 
+  std::vector<MCInst> Prologue;
+
 #if defined(__GNUC__) && (defined(__clang__) || LLVM_GNUC_PREREQ(8, 0, 0))
   // FIXME: GCC7 bug workaround. Drop #if after GCC7 no longer supported.
 private:
diff --git a/llvm/tools/llvm-exegesis/lib/ParallelSnippetGenerator.cpp b/llvm/tools/llvm-exegesis/lib/ParallelSnippetGenerator.cpp
index aa409138ae71b..2333fb2d2131d 100644
--- a/llvm/tools/llvm-exegesis/lib/ParallelSnippetGenerator.cpp
+++ b/llvm/tools/llvm-exegesis/lib/ParallelSnippetGenerator.cpp
@@ -88,28 +88,36 @@ static bool hasVariablesWithTiedOperands(const Instruction &Instr) {
 
 ParallelSnippetGenerator::~ParallelSnippetGenerator() = default;
 
-void ParallelSnippetGenerator::instantiateMemoryOperands(
+Error ParallelSnippetGenerator::callInstantiateMemoryOperands(
     const MCRegister ScratchSpacePointerInReg,
-    std::vector<InstructionTemplate> &Instructions) const {
+    std::vector<InstructionTemplate> &Instructions,
+    std::vector<MCInst> &Prologue, const BitVector &ForbiddenRegisters) const {
   if (!ScratchSpacePointerInReg)
-    return; // no memory operands.
+    return Error::success(); // no memory operands.
   const auto &ET = State.getExegesisTarget();
   const unsigned MemStep = ET.getMaxMemoryAccessSize();
   const size_t OriginalInstructionsSize = Instructions.size();
   size_t I = 0;
   for (InstructionTemplate &IT : Instructions) {
-    ET.fillMemoryOperands(IT, ScratchSpacePointerInReg, I * MemStep);
+    if (auto Err = instantiateMemoryOperands(
+            State, IT, ScratchSpacePointerInReg, I * MemStep, Prologue,
+            ForbiddenRegisters))
+      return Err;
     ++I;
   }
 
   while (Instructions.size() < kMinNumDifferentAddresses) {
     InstructionTemplate IT = Instructions[I % OriginalInstructionsSize];
-    ET.fillMemoryOperands(IT, ScratchSpacePointerInReg, I * MemStep);
+    if (auto Err = instantiateMemoryOperands(
+            State, IT, ScratchSpacePointerInReg, I * MemStep, Prologue,
+            ForbiddenRegisters))
+      return Err;
     ++I;
     Instructions.push_back(std::move(IT));
   }
   assert(I * MemStep < BenchmarkRunner::ScratchSpace::kSize &&
          "not enough scratch space");
+  return Error::success();
 }
 
 enum class RegRandomizationStrategy : uint8_t {
@@ -304,13 +312,19 @@ ParallelSnippetGenerator::generateCodeTemplates(
   if (SelfAliasing.empty()) {
     CT.Info = "instruction is parallel, repeating a random one.";
     CT.Instructions.push_back(std::move(Variant));
-    instantiateMemoryOperands(CT.ScratchSpacePointerInReg, CT.Instructions);
+    if (auto Err = callInstantiateMemoryOperands(CT.ScratchSpacePointerInReg,
+                                                 CT.Instructions, CT.Prologue,
+                                                 ForbiddenRegisters))
+      return std::move(Err);
     return getSingleton(std::move(CT));
   }
   if (SelfAliasing.hasImplicitAliasing()) {
     CT.Info = "instruction is serial, repeating a random one.";
     CT.Instructions.push_back(std::move(Variant));
-    instantiateMemoryOperands(CT.ScratchSpacePointerInReg, CT.Instructions);
+    if (auto Err = callInstantiateMemoryOperands(CT.ScratchSpacePointerInReg,
+                                                 CT.Instructions, CT.Prologue,
+                                                 ForbiddenRegisters))
+      return std::move(Err);
     return getSingleton(std::move(CT));
   }
   std::vector<CodeTemplate> Result;
@@ -343,8 +357,10 @@ ParallelSnippetGenerator::generateCodeTemplates(
       return make_error<StringError>(
           Twine("Failed to produce any snippet via: ").concat(CurrCT.Info),
           inconvertibleErrorCode());
-    instantiateMemoryOperands(CurrCT.ScratchSpacePointerInReg,
-                              CurrCT.Instructions);
+    if (auto Err = callInstantiateMemoryOperands(
+            CurrCT.ScratchSpacePointerInReg, CurrCT.Instructions,
+            CurrCT.Prologue, ForbiddenRegisters))
+      return std::move(Err);
     Result.push_back(std::move(CurrCT));
   }
   return Result;
diff --git a/llvm/tools/llvm-exegesis/lib/ParallelSnippetGenerator.h b/llvm/tools/llvm-exegesis/lib/ParallelSnippetGenerator.h
index d3c85c0c303a2..4609c2397d47e 100644
--- a/llvm/tools/llvm-exegesis/lib/ParallelSnippetGenerator.h
+++ b/llvm/tools/llvm-exegesis/lib/ParallelSnippetGenerator.h
@@ -54,9 +54,10 @@ class ParallelSnippetGenerator : public SnippetGenerator {
   //   mov eax, [rdi + 128]
   //   add eax, [rdi + 192]
   //   mov eax, [rdi + 256]
-  void instantiateMemoryOperands(
+  Error callInstantiateMemoryOperands(
       MCRegister ScratchSpaceReg,
-      std::vector<InstructionTemplate> &SnippetTemplate) const;
+      std::vector<InstructionTemplate> &SnippetTemplate,
+      std::vector<MCInst> &Prologue, const BitVector &ForbiddenRegisters) const;
 };
 
 } // namespace exegesis
diff --git a/llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp b/llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp
index 887df7ac7b393..14c720a5d8c7a 100644
--- a/llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp
+++ b/llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp
@@ -736,6 +736,10 @@ class ExegesisRISCVTarget : public ExegesisTarget {
   generateInstructionVariants(const Instruction &Instr,
                               unsigned MaxConfigsPerOpcode) const override;
 
+  virtual std::optional<MCInst>
+  createCopyInstruction(MCRegister Src, MCRegister Dst) const override;
+  void processInstructionReservedRegs(InstructionTemplate &IT) const override;
+
   void addTargetSpecificPasses(PassManagerBase &PM) const override {
     // Turn AVL operand of physical registers into virtual registers.
     PM.add(exegesis::createRISCVPreprocessingPass());
@@ -808,29 +812,18 @@ void ExegesisRISCVTarget::fillMemoryOperands(InstructionTemplate &IT,
                                              unsigned Offset) const {
   // TODO: for now we ignore Offset because have no way
   // to detect it in instruction.
-  auto &I = IT.getInstr();
-
-  auto MemOpIt =
-      find_if(I.Operands, [](const Operand &Op) { return Op.isMemory(); });
-  assert(MemOpIt != I.Operands.end() &&
-         "Instruction must have memory operands");
-
-  const Operand &MemOp = *MemOpIt;
-
-  assert(MemOp.isReg() && "Memory operand expected to be register");
-
-  unsigned Opcode = I.getOpcode();
-  if (Opcode == RISCV::C_LDSP || Opcode == RISCV::C_LWSP ||
-      Opcode == RISCV::C_SDSP || Opcode == RISCV::C_SWSP) {
-    IT.getValueFor(I.Operands[0]) = MCOperand::createReg(RISCV::X2);
-    // Force base register to SP (X2)
-    IT.getValueFor(MemOp) = MCOperand::createReg(RISCV::X2);
-    return;
-  }
-
+  const Operand &MemOp = IT.getMemOpReg();
   IT.getValueFor(MemOp) = MCOperand::createReg(Reg);
 }
 
+std::optional<MCInst>
+ExegesisRISCVTarget::createCopyInstruction(MCRegister Src,
+                                           MCRegister Dst) const {
+  if (!RISCV::GPRRegClass.contains(Src) || !RISCV::GPRRegClass.contains(Dst))
+    return std::nullopt;
+  return MCInstBuilder(RISCV::ADDI).addReg(Dst).addReg(Src).addImm(0);
+}
+
 const MCPhysReg UnavailableRegisters[4] = {RISCV::X0, DefaultLoopCounterReg,
                                            ScratchIntReg, ScratchMemoryReg};
 
@@ -890,6 +883,23 @@ ExegesisRISCVTarget::generateInstructionVariants(
   return {IT};
 }
 
+// Process instructions that used reserved registers.
+void ExegesisRISCVTarget::processInstructionReservedRegs(
+    InstructionTemplate &IT) const {
+  MCOperand &AssignedValue = IT.getValueFor(IT.getMemOpReg());
+
+  switch (IT.getOpcode()) {
+  case RISCV::C_LWSP:
+  case RISCV::C_LDSP:
+  case RISCV::C_SWSP:
+  case RISCV::C_SDSP:
+    AssignedValue = MCOperand::createReg(RISCV::X2);
+    break;
+  default:
+    break;
+  }
+}
+
 } // anonymous namespace
 
 static ExegesisTarget *getTheRISCVExegesisTarget() {
diff --git a/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp b/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp
index 71b2d71e084e1..911331a97ec28 100644
--- a/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp
+++ b/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp
@@ -89,12 +89,13 @@ static ExecutionMode getExecutionModes(const Instruction &Instr,
   return EM;
 }
 
-static void appendCodeTemplates(const LLVMState &State,
-                                InstructionTemplate Variant,
-                                const BitVector &ForbiddenRegisters,
-                                ExecutionMode ExecutionModeBit,
-                                StringRef ExecutionClassDescription,
-                                std::vector<CodeTemplate> &CodeTemplates) {
+static Error appendCodeTemplates(const LLVMState &State,
+                                 const SerialSnippetGenerator &Generator,
+                                 InstructionTemplate Variant,
+                                 const BitVector &ForbiddenRegisters,
+                                 ExecutionMode ExecutionModeBit,
+                                 StringRef ExecutionClassDescription,
+                                 std::vector<CodeTemplate> &CodeTemplates) {
   assert(isEnumValue(ExecutionModeBit) && "Bit must be a power of two");
   switch (ExecutionModeBit) {
   case ExecutionMode::ALWAYS_SERIAL_IMPLICIT_REGS_ALIAS:
@@ -108,7 +109,7 @@ static void appendCodeTemplates(const LLVMState &State,
     CT.Info = std::string(ExecutionClassDescription);
     CT.Instructions.push_back(std::move(Variant));
     CodeTemplates.push_back(std::move(CT));
-    return;
+    return Error::success();
   }
   case ExecutionMode::SERIAL_VIA_MEMORY_INSTR: {
     // Select back-to-back memory instruction.
@@ -126,7 +127,7 @@ static void appendCodeTemplates(const LLVMState &State,
       });
 
       if (DefOpIt == I.Operands.end())
-        return;
+        return Error::success();
 
       const Operand &DefOp = *DefOpIt;
       const ExegesisTarget &ET = State.getExegesisTarget();
@@ -139,17 +140,17 @@ static void appendCodeTemplates(const LLVMState &State,
       // Register classes of def operand and memory operand must be the same
       // to perform aliasing.
       if (!RegClass.contains(ScratchMemoryRegister))
-        return;
-
-      ET.fillMemoryOperands(Variant, ScratchMemoryRegister, 0);
-
-      // Only force the def register to ScratchMemoryRegister if the target
-      // hasn't assigned a value yet.
-      MCOperand &DefVal = Variant.getValueFor(DefOp);
-      if (!DefVal.isValid())
-        DefVal = MCOperand::createReg(ScratchMemoryRegister);
+        return Error::success();
 
       CodeTemplate CT;
+      const Operand &MemOp = Variant.getMemOpReg();
+      if (auto Err = Generator.instantiateMemoryOperands(
+              State, Variant, ScratchMemoryRegister, 0, CT.Prologue,
+              ForbiddenRegisters))
+        return Err;
+      MCOperand MemOpVal = Variant.getValueFor(MemOp);
+      Variant.getValueFor(DefOp) = MCOperand::createReg(MemOpVal.getReg());
+
       CT.Execution = ExecutionModeBit;
       CT.ScratchSpacePointerInReg = ScratchMemoryRegister;
 
@@ -159,7 +160,7 @@ static void appendCodeTemplates(const LLVMState &State,
     }
 
     // TODO: implement more cases
-    return;
+    return Error::success();
   }
   case ExecutionMode::SERIAL_VIA_EXPLICIT_REGS: {
     // Making the execution of this instruction serial by selecting one def
@@ -176,7 +177,7 @@ static void appendCodeTemplates(const LLVMState &State,
     CT.Info = std::string(ExecutionClassDescription);
     CT.Instructions.push_back(std::move(Variant));
     CodeTemplates.push_back(std::move(CT));
-    return;
+    return Error::success();
   }
   case ExecutionMode::SERIAL_VIA_NON_MEMORY_INSTR: {
     const Instruction &Instr = Variant.getInstr();
@@ -199,11 +200,12 @@ static void appendCodeTemplates(const LLVMState &State,
       CT.Instructions.push_back(std::move(OtherIT));
       CodeTemplates.push_back(std::move(CT));
     }
-    return;
+    return Error::success();
   }
   default:
     llvm_unreachable("Unhandled enum value");
   }
+  return Error::success();
 }
 
 SerialSnippetGenerator::~SerialSnippetGenerator() = default;
@@ -216,8 +218,10 @@ SerialSnippetGenerator::generateCodeTemplates(
       getExecutionModes(Variant.getInstr(), ForbiddenRegisters);
   for (const auto EC : kExecutionClasses) {
     for (const auto ExecutionModeBit : getExecutionModeBits(EM & EC.Mask))
-      appendCodeTemplates(State, Variant, ForbiddenRegisters, ExecutionModeBit,
-                          EC.Description, Results);
+      if (auto Err =
+              appendCodeTemplates(State, *this, Variant, ForbiddenRegisters,
+                                  ExecutionModeBit, EC.Description, Results))
+        return std::move(Err);
     if (!Results.empty())
       break;
   }
diff --git a/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp b/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp
index 86d4e197b6063..75623826dab3f 100644
--- a/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp
+++ b/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp
@@ -63,7 +63,6 @@ Error SnippetGenerator::generateConfigurations(
     const auto &ScratchRegAliases =
         State.getRATC().getRegister(ScratchSpacePointerInReg).aliasedBits();
     // If the instruction implicitly writes to ScratchSpacePointerInReg , abort.
-    // FIXME: We could make a copy of the scratch register.
     for (const auto &Op : Variant.getInstr().Operands) {
       if (Op.isDef() && Op.isImplicitReg() &&
           ScratchRegAliases.test(Op.getImplicitReg().id()))
@@ -95,6 +94,9 @@ Error SnippetGenerator::generateConfigurations(
             return Error;
           BC.Key.Instructions.push_back(Inst);
         }
+
+        BC.Key.PrologueInstructions = CT.Prologue;
+
         if (CT.ScratchSpacePointerInReg)
           BC.LiveIns.push_back(CT.ScratchSpacePointerInReg);
         BC.Key.RegisterInitialValues =
@@ -160,6 +162,69 @@ std::vector<RegisterValue> SnippetGenerator::computeRegisterInitialValues(
   return RIV;
 }
 
+// Instantiates memory operands for the given instruction template, ensuring
+// that the register used in the memory operand belongs to the required
+// register class.
+//
+// This function handles cases where the provided register (e.g., from a
+// forced scratch register insertion) may not be compatible with the memory
+// operand's register class. It attempts to:
+//   1. Use the provided register if it is already in the required class.
+//   2. Otherwise, reuse an existing register from the instruction template's
+//      memory operand if it is valid.
+//   3. As a fallback, allocate a free register from the required class and
+/...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/190342


More information about the llvm-commits mailing list