diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td index b033f889fbf61..c925d41511a23 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td +++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td @@ -1322,6 +1322,8 @@ def move_vec_shift : Operand { 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 3a0021e3c132d..76b642ca8d3e1 100644 --- a/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp +++ b/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp @@ -114,6 +114,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 setRegTo(const MCSubtargetInfo &STI, MCRegister Reg, const APInt &Value) const override { @@ -152,6 +156,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( + Twine("Unimplemented operand type: MCOI::OperandType:") + .concat(Twine(static_cast(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; }