[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