[llvm] 2e8ecf7 - [llvm-exegesis] [AArch64] Resolving "not all operands are initialized by snippet generator" (#142529)

via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 1 02:47:19 PDT 2025


Author: Lakshay Kumar
Date: 2025-09-01T10:47:15+01:00
New Revision: 2e8ecf7d5fbb4e0d029b0baf94f57f8161b396be

URL: https://github.com/llvm/llvm-project/commit/2e8ecf7d5fbb4e0d029b0baf94f57f8161b396be
DIFF: https://github.com/llvm/llvm-project/commit/2e8ecf7d5fbb4e0d029b0baf94f57f8161b396be.diff

LOG: [llvm-exegesis] [AArch64] Resolving "not all operands are initialized by snippet generator"  (#142529)

Exegesis for AArch64 arch, before this patch only handles/initialise
Immediate and Register Operands.
For opcodes requiring rest operand types exegesis exits with Error:
`"not all operands are initialised by snippet generator"`.

To resolve a given error we have to initialise required operand types.
i.e., For `"not all operands are initialised by snippet generator"` init
`OPERAND_SHIFT_MSL`, `OPERAND_PCREL`,
And For `"targets with target-specific operands should implement this"`
init `OPERAND_FIRST_TARGET`.


This PR adds support to the following opcodes:-
- OPERAND_SHIFT_MSL: `[MOVI|MVNI]_[2s|4s]_msl`.
- OPERAND_PCREL: `LDR[R|X|W|SW|D|S|Q]l`
- OPERAND_IMPLICIT_IMM_0:
`[UMOV|SMOV]v[i8|i16|i32|i64|i8to32|i8to64|i16to32|i32to64|i16to64]_idx0`

---
### [Experiment/Learnings]

Moreover, We found out we can similarly omit `OPERAND_UNKNOWN` with
immediate value of 0. This brute force fix helps us get major part of
(`~1000`) opcodes which throw un-init operands error. But, The correct
way to resolve is to introduce `OperandType` in AArch64 tablegen files
for opcode which have `OPERND_UNKNOWN` in `AArch64GenInstrInfo.inc`. And
add switch case for those `OperandType` in the
`randomizeTargetMCOperand()`.

As, side-effect to this temporary fix that we explored is listed below
system-level instructions throws `illegal instruction` i.e. for`MRS,
MSR, MSRpstatesvcrImm1, SYSLxt, SYSxt, UDF`.
This patch in `--mode=inverse_throughput` for opcodes `MRS, MSR,
MSRpstatesvcrImm1, SYSLxt, SYSxt, UDF` exits with handled error of
`snippet crashed while running: Illegal instruction`, they previously
used to exits with error `not all operands initialized by snippet
generator`.

[For completeness] Additionally, exegesis beforehand and with this patch
too, throws illegal instruction in throughput mode, for these opcodes
too (`APAS, DCPS1, DCPS2, DCPS3, HLT, HVC, SMC, STGM, STZGM`). Will look
into them later.

--- 
### [Summary]
Thus, Only 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>"`.

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..168cc585e6532
--- /dev/null
+++ b/llvm/test/tools/llvm-exegesis/AArch64/error-resolution.s
@@ -0,0 +1,78 @@
+# 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: Not all operands were initialized by the snippet generator for UMOVvi16_idx0 opcode
+# UMOVvi16_idx0_latency:      ---
+# UMOVvi16_idx0_latency-NEXT: mode: latency
+# UMOVvi16_idx0_latency-NEXT: key:
+# UMOVvi16_idx0_latency-NEXT:   instructions:
+# UMOVvi16_idx0_latency-NEXT:     UMOVvi16_idx0 [[REG1:W[0-9]+|LR]] [[REG2:Q[0-9]+|LR]] i_0x0
+# UMOVvi16_idx0_latency: ...
+
+# UMOVvi16_idx0_throughput-NOT: 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..ee699e0b42bab 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 temporary fix works by defaulting all OPERAND_UNKNOWN to
+  // immediate value 0, but this introduce illegal instruction error for below
+  // 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