[llvm] [llvm-exegesis] Add did-you-mean hint for unknown opcodes (PR #203463)
Quanye Yang via llvm-commits
llvm-commits at lists.llvm.org
Fri Jun 12 21:22:59 PDT 2026
https://github.com/quanyeyang updated https://github.com/llvm/llvm-project/pull/203463
>From ac2267ef6b5c992cc9bbe8e865175ee69ba8875a Mon Sep 17 00:00:00 2001
From: quanyeyang <quanyemostima at gmail.com>
Date: Fri, 12 Jun 2026 14:07:01 +0800
Subject: [PATCH 1/2] [llvm-exegesis] Add did-you-mean hint for unknown opcodes
Signed-off-by: quanyeyang <quanyemostima at gmail.com>
---
.../analysis-unknown-opcode-did-you-mean.test | 39 +++++++++++++++++++
.../llvm-exegesis/lib/BenchmarkResult.cpp | 37 +++++++++++++++++-
2 files changed, 75 insertions(+), 1 deletion(-)
create mode 100644 llvm/test/tools/llvm-exegesis/X86/analysis-unknown-opcode-did-you-mean.test
diff --git a/llvm/test/tools/llvm-exegesis/X86/analysis-unknown-opcode-did-you-mean.test b/llvm/test/tools/llvm-exegesis/X86/analysis-unknown-opcode-did-you-mean.test
new file mode 100644
index 0000000000000..32fe6c965ba72
--- /dev/null
+++ b/llvm/test/tools/llvm-exegesis/X86/analysis-unknown-opcode-did-you-mean.test
@@ -0,0 +1,39 @@
+# Verify that skipping an entry with a misspelled opcode name includes a
+# "did you mean ?" hint when a close match exists.
+
+# RUN: llvm-exegesis -mode=analysis -benchmarks-file=%s -analysis-clusters-output-file=- -analysis-clustering-epsilon=0.1 -analysis-inconsistency-epsilon=0.1 -analysis-numpoints=1 2> %t.err | FileCheck -check-prefix=CHECK-CLUSTERS %s
+# RUN: FileCheck -check-prefix=CHECK-WARN %s < %t.err
+
+# CHECK-WARN: warning: skipping benchmark entry: No opcode with name 'VADDPDYrrr' - did you mean 'VADDPDYrr' ?
+# CHECK-WARN: warning: skipped 1 benchmark entries that could not be parsed
+
+# CHECK-CLUSTERS: {{^}}cluster_id,opcode_name,config,sched_class,
+# CHECK-CLUSTERS-NEXT: {{^}}0,
+
+---
+mode: uops
+key:
+ instructions:
+ - 'VADDPDYrrr RAX'
+ config: ''
+ register_initial_values: []
+cpu_name: znver3
+llvm_triple: x86_64-pc-linux-gnu
+num_repetitions: 10000
+measurements: []
+error: ''
+...
+---
+mode: uops
+key:
+ instructions:
+ - 'CMOV16rm AX AX RDI i_0x1 %noreg i_0x0 %noreg i_0x0'
+ config: ''
+ register_initial_values: []
+cpu_name: znver3
+llvm_triple: x86_64-pc-linux-gnu
+num_repetitions: 10000
+measurements:
+ - { key: NumMicroOps, value: 1.0146, per_snippet_value: 14.2044 }
+error: ''
+...
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
index 1d1a376d3505b..018cbcb7941e4 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
@@ -16,11 +16,13 @@
#include "llvm/ADT/bit.h"
#include "llvm/ObjectYAML/YAML.h"
#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
static constexpr char kIntegerPrefix[] = "i_0x";
static constexpr char kDoublePrefix[] = "f_";
@@ -156,11 +158,44 @@ struct YamlContext {
return InstrName;
}
+ std::optional<StringRef> findNearestOpcodeName(StringRef InstrName) const {
+ unsigned BestDistance = 2;
+ StringRef Nearest;
+
+ for (const auto &Entry : OpcodeNameToOpcodeIdx) {
+ StringRef Candidate = Entry.getFirst();
+
+ size_t CandidateSize = Candidate.size();
+ size_t InstrSize = InstrName.size();
+ size_t AbsDiff = CandidateSize > InstrSize ? CandidateSize - InstrSize
+ : InstrSize - CandidateSize;
+
+ if (AbsDiff >= BestDistance)
+ continue;
+
+ unsigned Distance =
+ InstrName.edit_distance(Candidate, /*AllowReplacements=*/true,
+ /*MaxEditDistance=*/BestDistance - 1);
+
+ if (Distance < BestDistance) {
+ BestDistance = Distance;
+ Nearest = Candidate;
+ }
+ }
+
+ if (BestDistance <= 1 && !Nearest.empty())
+ return Nearest;
+ return std::nullopt;
+ }
+
unsigned getInstrOpcode(StringRef InstrName) {
auto Iter = OpcodeNameToOpcodeIdx.find(InstrName);
if (Iter != OpcodeNameToOpcodeIdx.end())
return Iter->second;
- ErrorStream << "No opcode with name '" << InstrName << "'\n";
+ ErrorStream << "No opcode with name '" << InstrName << "'";
+ if (std::optional<StringRef> Nearest = findNearestOpcodeName(InstrName))
+ ErrorStream << " - did you mean '" << *Nearest << "' ?";
+ ErrorStream << "\n";
return 0;
}
>From 04802f83122dc5c89d4f119a3e5a73d906461032 Mon Sep 17 00:00:00 2001
From: quanyeyang <quanyemostima at gmail.com>
Date: Sat, 13 Jun 2026 12:20:50 +0800
Subject: [PATCH 2/2] some minor fixes and add a negative test case
Signed-off-by: quanyeyang <quanyemostima at gmail.com>
---
.../analysis-unknown-opcode-did-you-mean.test | 16 +++++++++++++++-
llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp | 15 ++++++++-------
2 files changed, 23 insertions(+), 8 deletions(-)
diff --git a/llvm/test/tools/llvm-exegesis/X86/analysis-unknown-opcode-did-you-mean.test b/llvm/test/tools/llvm-exegesis/X86/analysis-unknown-opcode-did-you-mean.test
index 32fe6c965ba72..0de0ed3126262 100644
--- a/llvm/test/tools/llvm-exegesis/X86/analysis-unknown-opcode-did-you-mean.test
+++ b/llvm/test/tools/llvm-exegesis/X86/analysis-unknown-opcode-did-you-mean.test
@@ -5,7 +5,8 @@
# RUN: FileCheck -check-prefix=CHECK-WARN %s < %t.err
# CHECK-WARN: warning: skipping benchmark entry: No opcode with name 'VADDPDYrrr' - did you mean 'VADDPDYrr' ?
-# CHECK-WARN: warning: skipped 1 benchmark entries that could not be parsed
+# CHECK-WARN: warning: skipping benchmark entry: No opcode with name 'foo'{{$}}
+# CHECK-WARN: warning: skipped 2 benchmark entries that could not be parsed
# CHECK-CLUSTERS: {{^}}cluster_id,opcode_name,config,sched_class,
# CHECK-CLUSTERS-NEXT: {{^}}0,
@@ -37,3 +38,16 @@ measurements:
- { key: NumMicroOps, value: 1.0146, per_snippet_value: 14.2044 }
error: ''
...
+---
+mode: uops
+key:
+ instructions:
+ - 'foo RAX'
+ config: ''
+ register_initial_values: []
+cpu_name: znver3
+llvm_triple: x86_64-pc-linux-gnu
+num_repetitions: 10000
+measurements: []
+error: ''
+...
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
index 018cbcb7941e4..474158f5e6960 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
@@ -22,7 +22,7 @@
#include "llvm/Support/Format.h"
#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
-#include <optional>
+#include <cstdlib>
static constexpr char kIntegerPrefix[] = "i_0x";
static constexpr char kDoublePrefix[] = "f_";
@@ -158,7 +158,7 @@ struct YamlContext {
return InstrName;
}
- std::optional<StringRef> findNearestOpcodeName(StringRef InstrName) const {
+ StringRef findNearestOpcodeName(StringRef InstrName) const {
unsigned BestDistance = 2;
StringRef Nearest;
@@ -180,21 +180,22 @@ struct YamlContext {
if (Distance < BestDistance) {
BestDistance = Distance;
Nearest = Candidate;
+ if (BestDistance == 1)
+ break;
}
}
- if (BestDistance <= 1 && !Nearest.empty())
- return Nearest;
- return std::nullopt;
+ return Nearest;
}
unsigned getInstrOpcode(StringRef InstrName) {
auto Iter = OpcodeNameToOpcodeIdx.find(InstrName);
if (Iter != OpcodeNameToOpcodeIdx.end())
return Iter->second;
+
ErrorStream << "No opcode with name '" << InstrName << "'";
- if (std::optional<StringRef> Nearest = findNearestOpcodeName(InstrName))
- ErrorStream << " - did you mean '" << *Nearest << "' ?";
+ if (StringRef Nearest = findNearestOpcodeName(InstrName); !Nearest.empty())
+ ErrorStream << " - did you mean '" << Nearest << "' ?";
ErrorStream << "\n";
return 0;
}
More information about the llvm-commits
mailing list