[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