[llvm] [llvm-exegesis] Add did-you-mean hint for unknown opcodes (PR #203463)

Quanye Yang via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 11 23:12:06 PDT 2026


https://github.com/quanyeyang created https://github.com/llvm/llvm-project/pull/203463

Fixes #203199

When skipping a benchmark entry with an unknown opcode name, suggest the
nearest matching opcode if the edit distance is <= 1 (similar to
OptTable::findNearest).

Example:
```text
warning: skipping benchmark entry: No opcode with name 'VADDPDYrrr' - did you mean 'VADDPDYrr' ?
```

And Tested with:
- `llvm-lit llvm/test/tools/llvm-exegesis/X86/analysis-unknown-opcode-did-you-mean.test`
- `llvm-lit llvm/test/tools/llvm-exegesis/X86/analysis-skip-unknown-opcode.test`

>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] [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;
   }
 



More information about the llvm-commits mailing list