[llvm] ee71af4 - [llvm-exegesis] [AArch64] Reland Resolving "not all operands are initialized by snippet generator" (#156423)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 3 06:02:36 PDT 2025
Author: Lakshay Kumar
Date: 2025-09-03T14:02:30+01:00
New Revision: ee71af4fc7e62981da3d73a917ef1919e6d4c2d8
URL: https://github.com/llvm/llvm-project/commit/ee71af4fc7e62981da3d73a917ef1919e6d4c2d8
DIFF: https://github.com/llvm/llvm-project/commit/ee71af4fc7e62981da3d73a917ef1919e6d4c2d8.diff
LOG: [llvm-exegesis] [AArch64] Reland Resolving "not all operands are initialized by snippet generator" (#156423)
### Reland #142529 (Resolving "not all operands are initialized by
snippet generator")
Introduced changes in implementation of `randomizeTargetMCOperand()` for
AArch64 that omitting `OPERAND_SHIFT_MSL`, `OPERAND_PCREL` to an
immediate value of 264 and 8 respectively.
PS: Omitting
`MCOI::OPERAND_FIRST_TARGET/llvm:AArch64:OPERAND_IMPLICIT_IMM_0`
similarly, to value 0. It was low hanging change thus added in this PR
only.
For any future operand type of AArch64 if not initialised will exit with
error "`Unimplemented operand type: MCOI::OperandType:<#Number>`".
#### [Reland Updates]
Updated `tools/llvm-exegesis/AArch64/error-resolution.s` which caused
problem.
Test case was failing when there is uninitialised operands error coming
from secondary/consumer instruction used by exegesis in latency mode
required to chain up the assembly to ensure serial execution.
i.e. We get error message like `UMOVvi16_idx0: Not all operands were
initialized by the snippet generator for <<<any opcode other than
UMOVvi16_idx0>>> opcode.` but test case want to check like
`# UMOVvi16_idx0_latency: ---`. Thus the testcase fails.
```+ /llvm-project/build/bin/FileCheck /llvm-project/llvm/test/tools/llvm-exegesis/AArch64/error-resolution.s --check-prefix=UMOVvi16_idx0_latency
/llvm-project/llvm/test/tools/llvm-exegesis/AArch64/error-resolution.s:65:26: error: UMOVvi16_idx0_latency: expected string not found in input
# UMOVvi16_idx0_latency: ---
^
<stdin>:1:1: note: scanning from here
UMOVvi16_idx0: Not all operands were initialized by the snippet generator for LD1W_D_IMM opcode.
^
Input file: <stdin>
Check file: /llvm-project/llvm/test/tools/llvm-exegesis/AArch64/error-resolution.s
-dump-input=help explains the following input dump.
Input was:
<<<<<<
1: UMOVvi16_idx0: Not all operands were initialized by the snippet generator for LD1W_D_IMM opcode.
check:65 X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: no match found
>>>>>>
--
********************
********************
Failed Tests (1):
LLVM :: tools/llvm-exegesis/AArch64/error-resolution.s
```
#### [Why it fails (only sometimes)]
Exegesis in latency mode require the generated assembly to be chained to
ensure serial execution,
For this exegesis add an additional consumer instruction for some
instruction, which is chosen via a random seed.
Thus, it randomly fails whenever there is secondary consumer instruction
(which is unsupported/throws error) added in generated assembly.
Added:
llvm/test/tools/llvm-exegesis/AArch64/error-resolution.s
Modified:
llvm/lib/Target/AArch64/AArch64InstrFormats.td
llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.h
llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp
llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index feff59061aa16..8958ad129269c 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -1327,6 +1327,8 @@ def move_vec_shift : Operand<i32> {
let PrintMethod = "printShifter";
let EncoderMethod = "getMoveVecShifterOpValue";
let ParserMatchClass = MoveVecShifterOperand;
+ let OperandType = "OPERAND_SHIFT_MSL";
+ let OperandNamespace = "AArch64";
}
let DiagnosticType = "AddSubSecondSource" in {
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.h b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.h
index 91bdc880998b2..7774d07a214bf 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.h
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.h
@@ -65,15 +65,16 @@ void initLLVMToCVRegMapping(MCRegisterInfo *MRI);
bool isHForm(const MCInst &MI, const MCInstrInfo *MCII);
bool isQForm(const MCInst &MI, const MCInstrInfo *MCII);
bool isFpOrNEON(const MCInst &MI, const MCInstrInfo *MCII);
-}
+} // namespace AArch64_MC
namespace AArch64 {
enum OperandType {
OPERAND_IMPLICIT_IMM_0 = MCOI::OPERAND_FIRST_TARGET,
+ OPERAND_SHIFT_MSL,
};
} // namespace AArch64
-} // End llvm namespace
+} // namespace llvm
// Defines symbolic names for AArch64 registers. This defines a mapping from
// register name to register number.
diff --git a/llvm/test/tools/llvm-exegesis/AArch64/error-resolution.s b/llvm/test/tools/llvm-exegesis/AArch64/error-resolution.s
new file mode 100644
index 0000000000000..66ca6fb31d78f
--- /dev/null
+++ b/llvm/test/tools/llvm-exegesis/AArch64/error-resolution.s
@@ -0,0 +1,72 @@
+# REQUIRES: aarch64-registered-target
+
+
+
+// Test for omitting OperandType::OPERAND_SHIFT_MSL
+
+// MOVIv2s_msl: MOVI vd, #imm{, shift}
+# RUN: llvm-exegesis --mtriple=aarch64 --mcpu=neoverse-v2 --mode=latency --benchmark-phase=prepare-and-assemble-snippet --opcode-name=MOVIv4s_msl 2>&1 | FileCheck %s --check-prefix=MOVIv4s_msl_latency
+# RUN: llvm-exegesis --mtriple=aarch64 --mcpu=neoverse-v2 --mode=inverse_throughput --benchmark-phase=prepare-and-assemble-snippet --opcode-name=MOVIv4s_msl 2>&1 | FileCheck %s --check-prefix=MOVIv4s_msl_throughput
+# MOVIv4s_msl_latency-NOT: Not all operands were initialized by the snippet generator for MOVIv4s_msl opcode
+
+// TODO: Add test to check if the immediate value is correct when serial execution strategy is added for MOVIv4s_msl
+
+
+# MOVIv4s_msl_throughput-NOT: Not all operands were initialized by the snippet generator for MOVIv4s_msl opcode
+# MOVIv4s_msl_throughput: ---
+# MOVIv4s_msl_throughput-NEXT: mode: inverse_throughput
+# MOVIv4s_msl_throughput-NEXT: key:
+# MOVIv4s_msl_throughput-NEXT: instructions:
+# MOVIv4s_msl_throughput-NEXT: MOVIv4s_msl [[REG1:Q[0-9]+|LR]] i_0x1 i_0x108
+# MOVIv4s_msl_throughput: ...
+
+// MOVIv2s_msl: MOVI vd, #imm{, shift}
+# RUN: llvm-exegesis --mtriple=aarch64 --mcpu=neoverse-v2 --mode=latency --benchmark-phase=prepare-and-assemble-snippet --opcode-name=MOVIv2s_msl 2>&1 | FileCheck %s --check-prefix=MOVIv2s_msl_latency
+# RUN: llvm-exegesis --mtriple=aarch64 --mcpu=neoverse-v2 --mode=inverse_throughput --benchmark-phase=prepare-and-assemble-snippet --opcode-name=MOVIv2s_msl 2>&1 | FileCheck %s --check-prefix=MOVIv2s_msl_throughput
+# MOVIv2s_msl_latency-NOT: Not all operands were initialized by the snippet generator for MOVIv2s_msl opcode
+
+// TODO: Add test to check if the immediate value is correct when serial execution strategy is added for MOVIv2s_msl
+
+
+# MOVIv2s_msl_throughput-NOT: Not all operands were initialized by the snippet generator for MOVIv2s_msl opcode
+# MOVIv2s_msl_throughput: ---
+# MOVIv2s_msl_throughput-NEXT: mode: inverse_throughput
+# MOVIv2s_msl_throughput-NEXT: key:
+# MOVIv2s_msl_throughput-NEXT: instructions:
+# MOVIv2s_msl_throughput-NEXT: MOVIv2s_msl [[REG1:D[0-9]+|LR]] i_0x1 i_0x108
+# MOVIv2s_msl_throughput: ...
+
+
+
+// Test for omitting OperandType::OPERAND_PCREL
+// LDRDl: LDRD ldr1, ldr2, [pc, #imm]
+# RUN: llvm-exegesis --mtriple=aarch64 --mcpu=neoverse-v2 --mode=latency --benchmark-phase=prepare-and-assemble-snippet --opcode-name=LDRDl 2>&1 | FileCheck %s --check-prefix=LDRDl_latency
+# RUN: llvm-exegesis --mtriple=aarch64 --mcpu=neoverse-v2 --mode=inverse_throughput --benchmark-phase=prepare-and-assemble-snippet --opcode-name=LDRDl 2>&1 | FileCheck %s --check-prefix=LDRDl_throughput
+
+# LDRDl_latency-NOT: Not all operands were initialized by the snippet generator for LDRDl opcodes
+# LDRDl_throughput-NOT: Not all operands were initialized by the snippet generator for LDRDl opcodes
+
+# LDRDl_throughput: ---
+# LDRDl_throughput-NEXT: mode: inverse_throughput
+# LDRDl_throughput-NEXT: key:
+# LDRDl_throughput-NEXT: instructions:
+# LDRDl_throughput-NEXT: LDRDl [[REG1:D[0-9]+|LR]] i_0x8
+# LDRDl_throughput: ...
+
+
+
+// Test for omitting OperandType::OPERAND_IMPLICIT_IMM_0
+
+// UMOVvi16_idx0: UMOV wd, vn.h[index]
+# RUN: llvm-exegesis --mtriple=aarch64 --mcpu=neoverse-v2 --mode=latency --benchmark-phase=prepare-and-assemble-snippet --opcode-name=UMOVvi16_idx0 2>&1 | FileCheck %s --check-prefix=UMOVvi16_idx0_latency
+# RUN: llvm-exegesis --mtriple=aarch64 --mcpu=neoverse-v2 --mode=inverse_throughput --benchmark-phase=prepare-and-assemble-snippet --opcode-name=UMOVvi16_idx0 2>&1 | FileCheck %s --check-prefix=UMOVvi16_idx0_throughput
+
+# UMOVvi16_idx0_latency-NOT: UMOVvi16_idx0: Not all operands were initialized by the snippet generator for UMOVvi16_idx0 opcode.
+
+# UMOVvi16_idx0_throughput-NOT: UMOVvi16_idx0: Not all operands were initialized by the snippet generator for UMOVvi16_idx0 opcode.
+# UMOVvi16_idx0_throughput: ---
+# UMOVvi16_idx0_throughput-NEXT: mode: inverse_throughput
+# UMOVvi16_idx0_throughput-NEXT: key:
+# UMOVvi16_idx0_throughput-NEXT: instructions:
+# UMOVvi16_idx0_throughput-NEXT: UMOVvi16_idx0 [[REG1:W[0-9]+|LR]] [[REG2:Q[0-9]+|LR]] i_0x0
+# UMOVvi16_idx0_throughput: ...
diff --git a/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp b/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp
index c4ad9ae201d4e..2c13dd514a744 100644
--- a/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp
+++ b/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp
@@ -119,6 +119,10 @@ class ExegesisAArch64Target : public ExegesisTarget {
ExegesisAArch64Target()
: ExegesisTarget(AArch64CpuPfmCounters, AArch64_MC::isOpcodeAvailable) {}
+ Error randomizeTargetMCOperand(const Instruction &Instr, const Variable &Var,
+ MCOperand &AssignedValue,
+ const BitVector &ForbiddenRegs) const override;
+
private:
std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, MCRegister Reg,
const APInt &Value) const override {
@@ -182,6 +186,56 @@ class ExegesisAArch64Target : public ExegesisTarget {
}
};
+Error ExegesisAArch64Target::randomizeTargetMCOperand(
+ const Instruction &Instr, const Variable &Var, MCOperand &AssignedValue,
+ const BitVector &ForbiddenRegs) const {
+ const Operand &Op = Instr.getPrimaryOperand(Var);
+ const auto OperandType = Op.getExplicitOperandInfo().OperandType;
+ // NOTE: To resolve "Not all operands were initialized by snippet generator"
+ // Requires OperandType to be defined for such opcode's operands in AArch64
+ // tablegen files. And omit introduced OperandType(s).
+
+ // Hacky Fix: Defaulting all OPERAND_UNKNOWN to immediate value 0 works with a
+ // limitation that it introduces illegal instruction error for system
+ // instructions. System instructions will need to be omitted with OperandType
+ // or opcode specific values to avoid generating invalid encodings or
+ // unreliable benchmark results for these system-level instructions.
+ // Implement opcode-specific immediate value handling for system instrs:
+ // - MRS/MSR: Use valid system register encodings (e.g., NZCV, FPCR, FPSR)
+ // - MSRpstatesvcrImm1: Use valid PSTATE field encodings (e.g., SPSel,
+ // DAIFSet)
+ // - SYSLxt/SYSxt: Use valid system instruction encodings with proper
+ // CRn/CRm/op values
+ // - UDF: Use valid undefined instruction immediate ranges (0-65535)
+
+ switch (OperandType) {
+ // MSL (Masking Shift Left) imm operand for 32-bit splatted SIMD constants
+ // Correspond to AArch64InstructionSelector::tryAdvSIMDModImm321s()
+ case llvm::AArch64::OPERAND_SHIFT_MSL: {
+ // There are two valid encodings:
+ // - Type 7: imm at [15:8], [47:40], shift = 264 (0x108) → msl #8
+ // - Type 8: imm at [23:16], [55:48], shift = 272 (0x110) → msl #16
+ // Corresponds AArch64_AM::encodeAdvSIMDModImmType7()
+ // But, v2s_msl and v4s_msl instructions accept either form,
+ // Thus, Arbitrarily chosing 264 (msl #8) for simplicity.
+ AssignedValue = MCOperand::createImm(264);
+ return Error::success();
+ }
+ case llvm::AArch64::OPERAND_IMPLICIT_IMM_0:
+ AssignedValue = MCOperand::createImm(0);
+ return Error::success();
+ case MCOI::OperandType::OPERAND_PCREL:
+ AssignedValue = MCOperand::createImm(8);
+ return Error::success();
+ default:
+ break;
+ }
+
+ return make_error<Failure>(
+ Twine("Unimplemented operand type: MCOI::OperandType:")
+ .concat(Twine(static_cast<int>(OperandType))));
+}
+
} // namespace
static ExegesisTarget *getTheExegesisAArch64Target() {
diff --git a/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp b/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp
index 04064ae1d8441..7023f1bfae193 100644
--- a/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp
+++ b/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp
@@ -276,6 +276,10 @@ static Error randomizeMCOperand(const LLVMState &State,
AssignedValue = MCOperand::createReg(randomBit(AllowedRegs));
break;
}
+ /// Omit pc-relative operands to imm value based on the instruction
+ case MCOI::OperandType::OPERAND_PCREL:
+ return State.getExegesisTarget().randomizeTargetMCOperand(
+ Instr, Var, AssignedValue, ForbiddenRegs);
default:
break;
}
More information about the llvm-commits
mailing list