[llvm] [llvm-exegesis] Debug generated disassembly (PR #142540)
Lakshay Kumar via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 4 03:36:16 PDT 2025
https://github.com/lakshayk-nv updated https://github.com/llvm/llvm-project/pull/142540
>From 3c9421c4185a27e8e6256f41b0e9e8898b08ad41 Mon Sep 17 00:00:00 2001
From: lakshayk-nv <lakshayk at nvidia.com>
Date: Fri, 30 May 2025 03:46:29 -0700
Subject: [PATCH 01/10] [llvm-exegesis] Added Debug flag for print disassembly
using objdump
---
.../llvm-exegesis/lib/BenchmarkRunner.cpp | 31 +++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
index a7771b99e97b1..bc2b0b4750e6a 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
@@ -29,6 +29,8 @@
#include <cmath>
#include <memory>
#include <string>
+#include "llvm/Support/Debug.h"
+#define DEBUG_TYPE "exegesis-benchmark-runner"
#ifdef __linux__
#ifdef HAVE_LIBPFM
@@ -709,6 +711,35 @@ std::pair<Error, Benchmark> BenchmarkRunner::runConfiguration(
}
outs() << "Check generated assembly with: /usr/bin/objdump -d "
<< *ObjectFilePath << "\n";
+
+ int StdOutFD, StdErrFD;
+ SmallString<128> StdOutFile, StdErrFile;
+ sys::fs::createTemporaryFile("temp-objdump-out", "txt", StdOutFD, StdOutFile);
+ sys::fs::createTemporaryFile("temp-objdump-err", "txt", StdErrFD, StdErrFile);
+
+ std::vector<std::optional<StringRef>> Redirects = {
+ std::nullopt, // stdin
+ StringRef(StdOutFile), // stdout
+ StringRef(StdErrFile) // stderr
+ };
+
+#ifdef __linux__
+ std::string ErrMsg;
+ int Result = sys::ExecuteAndWait(
+ "/usr/bin/objdump", {"/usr/bin/objdump", "-d", *ObjectFilePath},
+ std::nullopt, Redirects, 0, 0, &ErrMsg);
+ auto StdOutBuf = MemoryBuffer::getFile(StdOutFile);
+ if (StdOutBuf && !(*StdOutBuf)->getBuffer().empty())
+ LLVM_DEBUG(dbgs() << "[llvm-exegesis][objdump] Generated assembly:\n"
+ << (*StdOutBuf)->getBuffer() << '\n');
+ auto StdErrBuf = MemoryBuffer::getFile(StdErrFile);
+ if (StdErrBuf && !(*StdErrBuf)->getBuffer().empty())
+ LLVM_DEBUG(dbgs() << "[llvm-exegesis][objdump] stderr:\n"
+ << (*StdErrBuf)->getBuffer() << '\n');
+ if (!ErrMsg.empty())
+ LLVM_DEBUG(dbgs() << "[llvm-exegesis][objdump] process error: " << ErrMsg << '\n');
+#endif
+ sys::fs::remove(StdOutFile); sys::fs::remove(StdErrFile);
}
if (BenchmarkPhaseSelector < BenchmarkPhaseSelectorE::Measure) {
>From 7d61a14b246ebd6b82fe046d63407a813d65da19 Mon Sep 17 00:00:00 2001
From: lakshayk-nv <lakshayk at nvidia.com>
Date: Mon, 2 Jun 2025 22:53:56 -0700
Subject: [PATCH 02/10] [llvm-exegesis] Formatting changes
---
.../llvm-exegesis/lib/BenchmarkRunner.cpp | 23 +++++++++++--------
1 file changed, 13 insertions(+), 10 deletions(-)
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
index bc2b0b4750e6a..7c2a6c966106a 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
@@ -20,6 +20,7 @@
#include "llvm/ADT/Twine.h"
#include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX
#include "llvm/Support/CrashRecoveryContext.h"
+#include "llvm/Support/Debug.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -29,7 +30,6 @@
#include <cmath>
#include <memory>
#include <string>
-#include "llvm/Support/Debug.h"
#define DEBUG_TYPE "exegesis-benchmark-runner"
#ifdef __linux__
@@ -712,18 +712,19 @@ std::pair<Error, Benchmark> BenchmarkRunner::runConfiguration(
outs() << "Check generated assembly with: /usr/bin/objdump -d "
<< *ObjectFilePath << "\n";
+#ifdef __linux__
int StdOutFD, StdErrFD;
SmallString<128> StdOutFile, StdErrFile;
- sys::fs::createTemporaryFile("temp-objdump-out", "txt", StdOutFD, StdOutFile);
- sys::fs::createTemporaryFile("temp-objdump-err", "txt", StdErrFD, StdErrFile);
-
+ sys::fs::createTemporaryFile("temp-objdump-out", "txt", StdOutFD,
+ StdOutFile);
+ sys::fs::createTemporaryFile("temp-objdump-err", "txt", StdErrFD,
+ StdErrFile);
std::vector<std::optional<StringRef>> Redirects = {
- std::nullopt, // stdin
- StringRef(StdOutFile), // stdout
- StringRef(StdErrFile) // stderr
+ std::nullopt, // stdin
+ StringRef(StdOutFile), // stdout
+ StringRef(StdErrFile) // stderr
};
-#ifdef __linux__
std::string ErrMsg;
int Result = sys::ExecuteAndWait(
"/usr/bin/objdump", {"/usr/bin/objdump", "-d", *ObjectFilePath},
@@ -737,9 +738,11 @@ std::pair<Error, Benchmark> BenchmarkRunner::runConfiguration(
LLVM_DEBUG(dbgs() << "[llvm-exegesis][objdump] stderr:\n"
<< (*StdErrBuf)->getBuffer() << '\n');
if (!ErrMsg.empty())
- LLVM_DEBUG(dbgs() << "[llvm-exegesis][objdump] process error: " << ErrMsg << '\n');
+ LLVM_DEBUG(dbgs() << "[llvm-exegesis][objdump] process error: " << ErrMsg
+ << '\n');
+ sys::fs::remove(StdOutFile);
+ sys::fs::remove(StdErrFile);
#endif
- sys::fs::remove(StdOutFile); sys::fs::remove(StdErrFile);
}
if (BenchmarkPhaseSelector < BenchmarkPhaseSelectorE::Measure) {
>From e53e3c8813d305edc2e1cdbeebc3dde372458c7f Mon Sep 17 00:00:00 2001
From: lakshayk-nv <lakshayk at nvidia.com>
Date: Mon, 30 Jun 2025 20:57:58 -0700
Subject: [PATCH 03/10] [llvm-exegesis] Debug (print or preview) generated
assembly without external dependency outside llvm project
---
.../llvm-exegesis/lib/BenchmarkRunner.cpp | 128 +++++++++++++-----
llvm/tools/llvm-exegesis/llvm-exegesis.cpp | 4 +-
2 files changed, 97 insertions(+), 35 deletions(-)
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
index 7c2a6c966106a..6e733f59a6b65 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
@@ -8,6 +8,7 @@
#include "BenchmarkRunner.h"
#include "Assembler.h"
+#include "DisassemblerHelper.h"
#include "Error.h"
#include "MCInstrDescView.h"
#include "MmapUtils.h"
@@ -18,19 +19,21 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/MC/TargetRegistry.h"
#include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Error.h"
+#include "llvm/Support/Format.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/Signals.h"
+#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/SystemZ/zOSSupport.h"
#include <cmath>
#include <memory>
#include <string>
-#define DEBUG_TYPE "exegesis-benchmark-runner"
#ifdef __linux__
#ifdef HAVE_LIBPFM
@@ -657,8 +660,97 @@ BenchmarkRunner::getRunnableConfiguration(
if (Error E = Snippet.takeError())
return std::move(E);
RC.ObjectFile = getObjectFromBuffer(*Snippet);
- }
+ // Print the assembled snippet by disassembling the binary data
+ // Extract the actual function bytes from the object file
+ std::vector<uint8_t> FunctionBytes;
+ if (auto Err = getBenchmarkFunctionBytes(*Snippet, FunctionBytes)) {
+ dbgs() << "Failed to extract function bytes: " << toString(std::move(Err))
+ << "\n";
+ } else {
+ DisassemblerHelper DisHelper(State);
+ ArrayRef<uint8_t> Bytes(FunctionBytes);
+
+ // Decode all instructions first
+ struct InstructionInfo {
+ std::string Text;
+ uint64_t Address;
+ std::string HexBytes;
+ };
+ std::vector<InstructionInfo> Instructions;
+ uint64_t Address = 0;
+
+ while (!Bytes.empty()) {
+ MCInst Inst;
+ uint64_t Size;
+ if (DisHelper.decodeInst(Inst, Size, Bytes)) {
+ // Format instruction text
+ std::string InstStr;
+ raw_string_ostream OS(InstStr);
+ DisHelper.printInst(&Inst, OS);
+
+ // Create hex string for this instruction (big-endian order)
+ std::string HexStr;
+ raw_string_ostream HexOS(HexStr);
+ for (int i = Size - 1; i >= 0; --i) {
+ HexOS << format_hex_no_prefix(Bytes[i], 2);
+ }
+
+ Instructions.push_back({OS.str(), Address, HexOS.str()});
+ Bytes = Bytes.slice(Size);
+ Address += Size;
+ } else {
+ Instructions.push_back({"<decode error>", Address, ""});
+ break;
+ }
+ }
+
+ auto printSnippet = [&](bool Preview, size_t PreviewFirst = 10,
+ size_t PreviewLast = 3) {
+ dbgs() << "```\n";
+ size_t N = Instructions.size();
+ // Print first "PreviewFirst" lines or all if less
+ for (size_t i = 0; i < std::min(size_t(PreviewFirst), N); ++i) {
+ dbgs() << format_hex_no_prefix(Instructions[i].Address, 0) << ":\t"
+ << Instructions[i].HexBytes << Instructions[i].Text << '\n';
+ }
+ if (N > (PreviewFirst + PreviewLast)) {
+ if (Preview) {
+ dbgs() << "...\t(" << (N - PreviewFirst - PreviewLast)
+ << " more instructions)\n";
+ } else {
+ // Print all middle lines
+ for (size_t i = PreviewFirst; i < N - PreviewLast; ++i) {
+ dbgs() << format_hex_no_prefix(Instructions[i].Address, 0)
+ << ":\t" << Instructions[i].HexBytes
+ << Instructions[i].Text << '\n';
+ }
+ }
+ // Print last "PreviewLast" lines
+ for (size_t i = N - PreviewLast; i < N; ++i) {
+ dbgs() << format_hex_no_prefix(Instructions[i].Address, 0) << ":\t"
+ << Instructions[i].HexBytes << Instructions[i].Text << '\n';
+ }
+ }
+ dbgs() << "```\n";
+ };
+
+ // Preview generated assembly snippet
+ {
+#undef DEBUG_TYPE
+#define DEBUG_TYPE "preview-gen-assembly"
+ LLVM_DEBUG(dbgs() << "Generated assembly snippet:\n");
+ LLVM_DEBUG(printSnippet(true));
+#undef DEBUG_TYPE
+#define DEBUG_TYPE "print-gen-assembly"
+ }
+ // Print generated assembly snippet
+ {
+ LLVM_DEBUG(dbgs() << "Generated assembly snippet:\n");
+ LLVM_DEBUG(printSnippet(false));
+ }
+ }
+ }
return std::move(RC);
}
@@ -711,38 +803,6 @@ std::pair<Error, Benchmark> BenchmarkRunner::runConfiguration(
}
outs() << "Check generated assembly with: /usr/bin/objdump -d "
<< *ObjectFilePath << "\n";
-
-#ifdef __linux__
- int StdOutFD, StdErrFD;
- SmallString<128> StdOutFile, StdErrFile;
- sys::fs::createTemporaryFile("temp-objdump-out", "txt", StdOutFD,
- StdOutFile);
- sys::fs::createTemporaryFile("temp-objdump-err", "txt", StdErrFD,
- StdErrFile);
- std::vector<std::optional<StringRef>> Redirects = {
- std::nullopt, // stdin
- StringRef(StdOutFile), // stdout
- StringRef(StdErrFile) // stderr
- };
-
- std::string ErrMsg;
- int Result = sys::ExecuteAndWait(
- "/usr/bin/objdump", {"/usr/bin/objdump", "-d", *ObjectFilePath},
- std::nullopt, Redirects, 0, 0, &ErrMsg);
- auto StdOutBuf = MemoryBuffer::getFile(StdOutFile);
- if (StdOutBuf && !(*StdOutBuf)->getBuffer().empty())
- LLVM_DEBUG(dbgs() << "[llvm-exegesis][objdump] Generated assembly:\n"
- << (*StdOutBuf)->getBuffer() << '\n');
- auto StdErrBuf = MemoryBuffer::getFile(StdErrFile);
- if (StdErrBuf && !(*StdErrBuf)->getBuffer().empty())
- LLVM_DEBUG(dbgs() << "[llvm-exegesis][objdump] stderr:\n"
- << (*StdErrBuf)->getBuffer() << '\n');
- if (!ErrMsg.empty())
- LLVM_DEBUG(dbgs() << "[llvm-exegesis][objdump] process error: " << ErrMsg
- << '\n');
- sys::fs::remove(StdOutFile);
- sys::fs::remove(StdErrFile);
-#endif
}
if (BenchmarkPhaseSelector < BenchmarkPhaseSelectorE::Measure) {
diff --git a/llvm/tools/llvm-exegesis/llvm-exegesis.cpp b/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
index babcffeb9666a..3ca0924cfbf2b 100644
--- a/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
+++ b/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
@@ -482,7 +482,8 @@ void benchmarkMain() {
InitializeAllExegesisTargets();
#define LLVM_EXEGESIS(TargetName) \
LLVMInitialize##TargetName##AsmPrinter(); \
- LLVMInitialize##TargetName##AsmParser();
+ LLVMInitialize##TargetName##AsmParser(); \
+ LLVMInitialize##TargetName##Disassembler();
#include "llvm/Config/TargetExegesis.def"
const LLVMState State = ExitOnErr(
@@ -635,6 +636,7 @@ static void analysisMain() {
InitializeAllExegesisTargets();
#define LLVM_EXEGESIS(TargetName) \
LLVMInitialize##TargetName##AsmPrinter(); \
+ LLVMInitialize##TargetName##AsmParser(); \
LLVMInitialize##TargetName##Disassembler();
#include "llvm/Config/TargetExegesis.def"
>From 8caf0413e0d665170f411b92189eb6e10b3eeb4e Mon Sep 17 00:00:00 2001
From: lakshayk-nv <lakshayk at nvidia.com>
Date: Mon, 30 Jun 2025 21:07:42 -0700
Subject: [PATCH 04/10] [llvm-exegesis] Clang format
---
llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
index 6e733f59a6b65..5acc3cbf480be 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
@@ -19,18 +19,18 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
-#include "llvm/MC/TargetRegistry.h"
#include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX
+#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Error.h"
-#include "llvm/Support/Format.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Format.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/Signals.h"
-#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/SystemZ/zOSSupport.h"
+#include "llvm/Support/TargetSelect.h"
#include <cmath>
#include <memory>
#include <string>
>From b57c3ab5cfca7058cb5a5bea8e1e5cfadcf7cc27 Mon Sep 17 00:00:00 2001
From: lakshayk-nv <lakshayk at nvidia.com>
Date: Mon, 30 Jun 2025 21:12:40 -0700
Subject: [PATCH 05/10] [llvm-exegesis] Cleanup changes
---
llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp | 2 +-
llvm/tools/llvm-exegesis/llvm-exegesis.cpp | 1 -
2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
index 5acc3cbf480be..857bc577767f4 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
@@ -649,7 +649,6 @@ BenchmarkRunner::getRunnableConfiguration(
BenchmarkResult.AssembledSnippet))
return std::move(Err);
}
-
// Assemble enough repetitions of the snippet so we have at least
// MinInstructions instructions.
if (BenchmarkPhaseSelector >
@@ -751,6 +750,7 @@ BenchmarkRunner::getRunnableConfiguration(
}
}
}
+
return std::move(RC);
}
diff --git a/llvm/tools/llvm-exegesis/llvm-exegesis.cpp b/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
index 3ca0924cfbf2b..b5820f8669f1d 100644
--- a/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
+++ b/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
@@ -636,7 +636,6 @@ static void analysisMain() {
InitializeAllExegesisTargets();
#define LLVM_EXEGESIS(TargetName) \
LLVMInitialize##TargetName##AsmPrinter(); \
- LLVMInitialize##TargetName##AsmParser(); \
LLVMInitialize##TargetName##Disassembler();
#include "llvm/Config/TargetExegesis.def"
>From 7e9550e668e26fa3678e21455b825fb7562745e8 Mon Sep 17 00:00:00 2001
From: lakshayk-nv <lakshayk at nvidia.com>
Date: Tue, 1 Jul 2025 02:30:05 -0700
Subject: [PATCH 06/10] [llvm-exegesis] Add tests for generated assembly
snippets in AArch64
---
.../llvm-exegesis/AArch64/debug-gen-asm.s | 22 +++++++++++++++++++
.../llvm-exegesis/lib/BenchmarkRunner.cpp | 1 +
2 files changed, 23 insertions(+)
create mode 100644 llvm/test/tools/llvm-exegesis/AArch64/debug-gen-asm.s
diff --git a/llvm/test/tools/llvm-exegesis/AArch64/debug-gen-asm.s b/llvm/test/tools/llvm-exegesis/AArch64/debug-gen-asm.s
new file mode 100644
index 0000000000000..d1b96f02e3986
--- /dev/null
+++ b/llvm/test/tools/llvm-exegesis/AArch64/debug-gen-asm.s
@@ -0,0 +1,22 @@
+REQUIRES: aarch64-registered-target
+
+RUN: llvm-exegesis -mcpu=neoverse-v2 --benchmark-phase=measure --min-instructions=100 --mode=latency --debug-only="preview-gen-assembly" --opcode-name=ADDVv4i16v 2>&1 | FileCheck %s -check-prefix=PREVIEW
+
+PREVIEW: Generated assembly snippet:
+PREVIEW-NEXT: ```
+PREVIEW: {{.*}} movi d{{[0-9]+}}, #0000000000000000
+PREVIEW-NEXT: {{.*}} addv h{{[0-9]+}}, v{{[0-9]+}}.4h
+PREVIEW: {{.*}} addv h{{[0-9]+}}, v{{[0-9]+}}.4h
+PREVIEW: ... ({{[0-9]+}} more instructions)
+PREVIEW-NEXT: {{.*}} addv h{{[0-9]+}}, v{{[0-9]+}}.4h
+PREVIEW: {{.*}} ret
+PREVIEW-NEXT:```
+
+RUN: llvm-exegesis -mcpu=neoverse-v2 --benchmark-phase=measure --min-instructions=100 --mode=latency --debug-only="print-gen-assembly" --opcode-name=ADDVv4i16v 2>&1 | FileCheck %s -check-prefix=PRINT
+
+PRINT: Generated assembly snippet:
+PRINT-NEXT: ```
+PRINT: {{.*}} movi d{{[0-9]+}}, #0000000000000000
+PRINT: {{.*}} addv h{{[0-9]+}}, v{{[0-9]+}}.4h
+PRINT: {{.*}} ret
+PRINT-NEXT: ```
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
index 857bc577767f4..789326287f4e9 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
@@ -649,6 +649,7 @@ BenchmarkRunner::getRunnableConfiguration(
BenchmarkResult.AssembledSnippet))
return std::move(Err);
}
+
// Assemble enough repetitions of the snippet so we have at least
// MinInstructions instructions.
if (BenchmarkPhaseSelector >
>From 1e97fad43d93c84373a350c9386a085c653b041a Mon Sep 17 00:00:00 2001
From: lakshayk-nv <lakshayk at nvidia.com>
Date: Wed, 2 Jul 2025 03:27:24 -0700
Subject: [PATCH 07/10] [llvm-exegesis] Refactor assembly snippet printing into
helper functions
---
.../llvm-exegesis/lib/BenchmarkRunner.cpp | 183 +++++++++---------
1 file changed, 95 insertions(+), 88 deletions(-)
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
index 789326287f4e9..28fef72ebd3ac 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
@@ -31,6 +31,7 @@
#include "llvm/Support/Signals.h"
#include "llvm/Support/SystemZ/zOSSupport.h"
#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/raw_ostream.h"
#include <cmath>
#include <memory>
#include <string>
@@ -593,6 +594,99 @@ class SubProcessFunctionExecutorImpl
const std::optional<int> BenchmarkProcessCPU;
};
#endif // __linux__
+
+// Helper function to print generated assembly snippets
+void printGeneratedAssembly(
+ const std::vector<std::pair<std::string, std::pair<uint64_t, std::string>>>
+ &Instructions,
+ bool Preview, size_t PreviewFirst = 10, size_t PreviewLast = 3) {
+ dbgs() << "```\n";
+ size_t N = Instructions.size();
+ // Print first "PreviewFirst" lines or all if less
+ for (size_t i = 0; i < std::min(size_t(PreviewFirst), N); ++i) {
+ dbgs() << format_hex_no_prefix(Instructions[i].second.first, 0) << ":\t"
+ << Instructions[i].second.second << Instructions[i].first << '\n';
+ }
+ if (N > (PreviewFirst + PreviewLast)) {
+ if (Preview) {
+ dbgs() << "...\t(" << (N - PreviewFirst - PreviewLast)
+ << " more instructions)\n";
+ } else {
+ // Print all middle lines
+ for (size_t i = PreviewFirst; i < N - PreviewLast; ++i) {
+ dbgs() << format_hex_no_prefix(Instructions[i].second.first, 0) << ":\t"
+ << Instructions[i].second.second << Instructions[i].first
+ << '\n';
+ }
+ }
+ // Print last "PreviewLast" lines
+ for (size_t i = N - PreviewLast; i < N; ++i) {
+ dbgs() << format_hex_no_prefix(Instructions[i].second.first, 0) << ":\t"
+ << Instructions[i].second.second << Instructions[i].first << '\n';
+ }
+ }
+ dbgs() << "```\n";
+}
+
+// Function to extract and print assembly from snippet
+void printAssembledSnippet(const LLVMState &State,
+ const SmallString<0> &Snippet) {
+ // Extract the actual function bytes from the object file
+ std::vector<uint8_t> FunctionBytes;
+ if (auto Err = getBenchmarkFunctionBytes(Snippet, FunctionBytes)) {
+ dbgs() << "Failed to extract function bytes: " << toString(std::move(Err))
+ << "\n";
+ return;
+ }
+
+ DisassemblerHelper DisHelper(State);
+ ArrayRef<uint8_t> Bytes(FunctionBytes);
+
+ // Decode all instructions first
+ std::vector<std::pair<std::string, std::pair<uint64_t, std::string>>>
+ Instructions;
+ uint64_t Address = 0;
+
+ while (!Bytes.empty()) {
+ MCInst Inst;
+ uint64_t Size;
+ if (DisHelper.decodeInst(Inst, Size, Bytes)) {
+ // Format instruction text
+ std::string InstStr;
+ raw_string_ostream OS(InstStr);
+ DisHelper.printInst(&Inst, OS);
+
+ // Create hex string for this instruction (big-endian order)
+ std::string HexStr;
+ raw_string_ostream HexOS(HexStr);
+ for (int i = Size - 1; i >= 0; --i) {
+ HexOS << format_hex_no_prefix(Bytes[i], 2);
+ }
+
+ Instructions.push_back({OS.str(), {Address, HexOS.str()}});
+ Bytes = Bytes.slice(Size);
+ Address += Size;
+ } else {
+ Instructions.push_back({"<decode error>", {Address, ""}});
+ break;
+ }
+ }
+
+ // Preview generated assembly snippet
+ {
+#undef DEBUG_TYPE
+#define DEBUG_TYPE "preview-gen-assembly"
+ LLVM_DEBUG(dbgs() << "Generated assembly snippet:\n");
+ LLVM_DEBUG(printGeneratedAssembly(Instructions, true));
+#undef DEBUG_TYPE
+#define DEBUG_TYPE "print-gen-assembly"
+ }
+ // Print generated assembly snippet
+ {
+ LLVM_DEBUG(dbgs() << "Generated assembly snippet:\n");
+ LLVM_DEBUG(printGeneratedAssembly(Instructions, false));
+ }
+}
} // namespace
Expected<SmallString<0>> BenchmarkRunner::assembleSnippet(
@@ -662,94 +756,7 @@ BenchmarkRunner::getRunnableConfiguration(
RC.ObjectFile = getObjectFromBuffer(*Snippet);
// Print the assembled snippet by disassembling the binary data
- // Extract the actual function bytes from the object file
- std::vector<uint8_t> FunctionBytes;
- if (auto Err = getBenchmarkFunctionBytes(*Snippet, FunctionBytes)) {
- dbgs() << "Failed to extract function bytes: " << toString(std::move(Err))
- << "\n";
- } else {
- DisassemblerHelper DisHelper(State);
- ArrayRef<uint8_t> Bytes(FunctionBytes);
-
- // Decode all instructions first
- struct InstructionInfo {
- std::string Text;
- uint64_t Address;
- std::string HexBytes;
- };
- std::vector<InstructionInfo> Instructions;
- uint64_t Address = 0;
-
- while (!Bytes.empty()) {
- MCInst Inst;
- uint64_t Size;
- if (DisHelper.decodeInst(Inst, Size, Bytes)) {
- // Format instruction text
- std::string InstStr;
- raw_string_ostream OS(InstStr);
- DisHelper.printInst(&Inst, OS);
-
- // Create hex string for this instruction (big-endian order)
- std::string HexStr;
- raw_string_ostream HexOS(HexStr);
- for (int i = Size - 1; i >= 0; --i) {
- HexOS << format_hex_no_prefix(Bytes[i], 2);
- }
-
- Instructions.push_back({OS.str(), Address, HexOS.str()});
- Bytes = Bytes.slice(Size);
- Address += Size;
- } else {
- Instructions.push_back({"<decode error>", Address, ""});
- break;
- }
- }
-
- auto printSnippet = [&](bool Preview, size_t PreviewFirst = 10,
- size_t PreviewLast = 3) {
- dbgs() << "```\n";
- size_t N = Instructions.size();
- // Print first "PreviewFirst" lines or all if less
- for (size_t i = 0; i < std::min(size_t(PreviewFirst), N); ++i) {
- dbgs() << format_hex_no_prefix(Instructions[i].Address, 0) << ":\t"
- << Instructions[i].HexBytes << Instructions[i].Text << '\n';
- }
- if (N > (PreviewFirst + PreviewLast)) {
- if (Preview) {
- dbgs() << "...\t(" << (N - PreviewFirst - PreviewLast)
- << " more instructions)\n";
- } else {
- // Print all middle lines
- for (size_t i = PreviewFirst; i < N - PreviewLast; ++i) {
- dbgs() << format_hex_no_prefix(Instructions[i].Address, 0)
- << ":\t" << Instructions[i].HexBytes
- << Instructions[i].Text << '\n';
- }
- }
- // Print last "PreviewLast" lines
- for (size_t i = N - PreviewLast; i < N; ++i) {
- dbgs() << format_hex_no_prefix(Instructions[i].Address, 0) << ":\t"
- << Instructions[i].HexBytes << Instructions[i].Text << '\n';
- }
- }
- dbgs() << "```\n";
- };
-
- // Preview generated assembly snippet
- {
-#undef DEBUG_TYPE
-#define DEBUG_TYPE "preview-gen-assembly"
- LLVM_DEBUG(dbgs() << "Generated assembly snippet:\n");
- LLVM_DEBUG(printSnippet(true));
-#undef DEBUG_TYPE
-#define DEBUG_TYPE "print-gen-assembly"
- }
- // Print generated assembly snippet
- {
- LLVM_DEBUG(dbgs() << "Generated assembly snippet:\n");
- LLVM_DEBUG(printSnippet(false));
- }
- }
+ printAssembledSnippet(State, *Snippet);
}
return std::move(RC);
>From 989d7b0ca0691bff46b4079581ba57e8cdd42ac5 Mon Sep 17 00:00:00 2001
From: lakshayk-nv <lakshayk at nvidia.com>
Date: Wed, 2 Jul 2025 23:03:53 -0700
Subject: [PATCH 08/10] [llvm-exegesis] Refactor instruction decoding and
assembly snippet generation
---
.../llvm-exegesis/lib/BenchmarkRunner.cpp | 70 ++++++++++---------
1 file changed, 36 insertions(+), 34 deletions(-)
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
index 28fef72ebd3ac..89ac5d7eefb71 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
@@ -603,73 +603,72 @@ void printGeneratedAssembly(
dbgs() << "```\n";
size_t N = Instructions.size();
// Print first "PreviewFirst" lines or all if less
- for (size_t i = 0; i < std::min(size_t(PreviewFirst), N); ++i) {
+ for (size_t i = 0; i < std::min(size_t(PreviewFirst), N); ++i)
dbgs() << format_hex_no_prefix(Instructions[i].second.first, 0) << ":\t"
<< Instructions[i].second.second << Instructions[i].first << '\n';
- }
+
if (N > (PreviewFirst + PreviewLast)) {
- if (Preview) {
+ if (Preview)
dbgs() << "...\t(" << (N - PreviewFirst - PreviewLast)
<< " more instructions)\n";
- } else {
+ else {
// Print all middle lines
- for (size_t i = PreviewFirst; i < N - PreviewLast; ++i) {
+ for (size_t i = PreviewFirst; i < N - PreviewLast; ++i)
dbgs() << format_hex_no_prefix(Instructions[i].second.first, 0) << ":\t"
<< Instructions[i].second.second << Instructions[i].first
<< '\n';
- }
}
// Print last "PreviewLast" lines
- for (size_t i = N - PreviewLast; i < N; ++i) {
+ for (size_t i = N - PreviewLast; i < N; ++i)
dbgs() << format_hex_no_prefix(Instructions[i].second.first, 0) << ":\t"
<< Instructions[i].second.second << Instructions[i].first << '\n';
- }
}
dbgs() << "```\n";
}
// Function to extract and print assembly from snippet
-void printAssembledSnippet(const LLVMState &State,
- const SmallString<0> &Snippet) {
+Error printAssembledSnippet(const LLVMState &State,
+ const SmallString<0> &Snippet) {
// Extract the actual function bytes from the object file
std::vector<uint8_t> FunctionBytes;
- if (auto Err = getBenchmarkFunctionBytes(Snippet, FunctionBytes)) {
- dbgs() << "Failed to extract function bytes: " << toString(std::move(Err))
- << "\n";
- return;
- }
+ if (auto Err = getBenchmarkFunctionBytes(Snippet, FunctionBytes))
+ return make_error<Failure>("Failed to extract function bytes: " +
+ toString(std::move(Err)));
DisassemblerHelper DisHelper(State);
- ArrayRef<uint8_t> Bytes(FunctionBytes);
+ size_t Offset = 0;
+ const size_t FunctionBytesSize = FunctionBytes.size();
// Decode all instructions first
std::vector<std::pair<std::string, std::pair<uint64_t, std::string>>>
Instructions;
uint64_t Address = 0;
- while (!Bytes.empty()) {
+ while (Offset < FunctionBytesSize) {
MCInst Inst;
uint64_t Size;
- if (DisHelper.decodeInst(Inst, Size, Bytes)) {
- // Format instruction text
- std::string InstStr;
- raw_string_ostream OS(InstStr);
- DisHelper.printInst(&Inst, OS);
-
- // Create hex string for this instruction (big-endian order)
- std::string HexStr;
- raw_string_ostream HexOS(HexStr);
- for (int i = Size - 1; i >= 0; --i) {
- HexOS << format_hex_no_prefix(Bytes[i], 2);
- }
+ ArrayRef<uint8_t> Bytes(FunctionBytes.data() + Offset,
+ FunctionBytesSize - Offset);
- Instructions.push_back({OS.str(), {Address, HexOS.str()}});
- Bytes = Bytes.slice(Size);
- Address += Size;
- } else {
+ if (!DisHelper.decodeInst(Inst, Size, Bytes)) {
Instructions.push_back({"<decode error>", {Address, ""}});
break;
}
+
+ // Format instruction text
+ std::string InstStr;
+ raw_string_ostream OS(InstStr);
+ DisHelper.printInst(&Inst, OS);
+
+ // Create hex string for this instruction (big-endian order)
+ std::string HexStr;
+ raw_string_ostream HexOS(HexStr);
+ for (int i = Size - 1; i >= 0; --i)
+ HexOS << format_hex_no_prefix(Bytes[i], 2);
+
+ Instructions.push_back({OS.str(), {Address, HexOS.str()}});
+ Offset += Size;
+ Address += Size;
}
// Preview generated assembly snippet
@@ -686,6 +685,8 @@ void printAssembledSnippet(const LLVMState &State,
LLVM_DEBUG(dbgs() << "Generated assembly snippet:\n");
LLVM_DEBUG(printGeneratedAssembly(Instructions, false));
}
+
+ return Error::success();
}
} // namespace
@@ -756,7 +757,8 @@ BenchmarkRunner::getRunnableConfiguration(
RC.ObjectFile = getObjectFromBuffer(*Snippet);
// Print the assembled snippet by disassembling the binary data
- printAssembledSnippet(State, *Snippet);
+ if (Error E = printAssembledSnippet(State, *Snippet))
+ return std::move(E);
}
return std::move(RC);
>From a987b50eea76717d287314564bd924c06ba75e44 Mon Sep 17 00:00:00 2001
From: lakshayk-nv <lakshayk at nvidia.com>
Date: Fri, 4 Jul 2025 01:06:18 -0700
Subject: [PATCH 09/10] [llvm-exegesis] Introduced --print-gen-assembly=<> for
number of lines to print
---
.../llvm-exegesis/AArch64/debug-gen-asm.s | 18 +--
.../llvm-exegesis/lib/BenchmarkRunner.cpp | 106 +++++++++---------
2 files changed, 56 insertions(+), 68 deletions(-)
diff --git a/llvm/test/tools/llvm-exegesis/AArch64/debug-gen-asm.s b/llvm/test/tools/llvm-exegesis/AArch64/debug-gen-asm.s
index d1b96f02e3986..119814f1c62fe 100644
--- a/llvm/test/tools/llvm-exegesis/AArch64/debug-gen-asm.s
+++ b/llvm/test/tools/llvm-exegesis/AArch64/debug-gen-asm.s
@@ -1,22 +1,12 @@
REQUIRES: aarch64-registered-target
-RUN: llvm-exegesis -mcpu=neoverse-v2 --benchmark-phase=measure --min-instructions=100 --mode=latency --debug-only="preview-gen-assembly" --opcode-name=ADDVv4i16v 2>&1 | FileCheck %s -check-prefix=PREVIEW
+RUN: llvm-exegesis -mcpu=neoverse-v2 --benchmark-phase=measure --min-instructions=100 --mode=latency --print-gen-assembly=10 --opcode-name=ADDVv4i16v 2>&1 | FileCheck %s -check-prefix=PREVIEW
PREVIEW: Generated assembly snippet:
PREVIEW-NEXT: ```
-PREVIEW: {{.*}} movi d{{[0-9]+}}, #0000000000000000
-PREVIEW-NEXT: {{.*}} addv h{{[0-9]+}}, v{{[0-9]+}}.4h
-PREVIEW: {{.*}} addv h{{[0-9]+}}, v{{[0-9]+}}.4h
+PREVIEW: {{[04]}}: {{.*}} movi d{{[0-9]+}}, #0000000000000000
+PREVIEW-NEXT: {{[48]}}: {{.*}} addv h{{[0-9]+}}, v{{[0-9]+}}.4h
PREVIEW: ... ({{[0-9]+}} more instructions)
PREVIEW-NEXT: {{.*}} addv h{{[0-9]+}}, v{{[0-9]+}}.4h
PREVIEW: {{.*}} ret
-PREVIEW-NEXT:```
-
-RUN: llvm-exegesis -mcpu=neoverse-v2 --benchmark-phase=measure --min-instructions=100 --mode=latency --debug-only="print-gen-assembly" --opcode-name=ADDVv4i16v 2>&1 | FileCheck %s -check-prefix=PRINT
-
-PRINT: Generated assembly snippet:
-PRINT-NEXT: ```
-PRINT: {{.*}} movi d{{[0-9]+}}, #0000000000000000
-PRINT: {{.*}} addv h{{[0-9]+}}, v{{[0-9]+}}.4h
-PRINT: {{.*}} ret
-PRINT-NEXT: ```
+PREVIEW-NEXT:```
\ No newline at end of file
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
index 89ac5d7eefb71..c2c796e29552a 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
@@ -21,6 +21,7 @@
#include "llvm/ADT/Twine.h"
#include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX
#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Error.h"
@@ -59,6 +60,12 @@
namespace llvm {
namespace exegesis {
+static cl::opt<int> PrintGenAssembly(
+ "print-gen-assembly", cl::Optional, cl::init(0),
+ cl::desc("Print generated assembly snippets. -1 prints all lines, "
+ "positive N prints first N lines with truncated middle part"),
+ cl::cat(BenchmarkOptions));
+
BenchmarkRunner::BenchmarkRunner(const LLVMState &State, Benchmark::ModeE Mode,
BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
ExecutionModeE ExecutionMode,
@@ -595,35 +602,36 @@ class SubProcessFunctionExecutorImpl
};
#endif // __linux__
+// Structure to hold instruction information for assembly printing
+struct InstructionInfo {
+ std::string Text;
+ uint64_t Address;
+ std::string HexBytes;
+};
+
// Helper function to print generated assembly snippets
-void printGeneratedAssembly(
- const std::vector<std::pair<std::string, std::pair<uint64_t, std::string>>>
- &Instructions,
- bool Preview, size_t PreviewFirst = 10, size_t PreviewLast = 3) {
- dbgs() << "```\n";
- size_t N = Instructions.size();
- // Print first "PreviewFirst" lines or all if less
- for (size_t i = 0; i < std::min(size_t(PreviewFirst), N); ++i)
- dbgs() << format_hex_no_prefix(Instructions[i].second.first, 0) << ":\t"
- << Instructions[i].second.second << Instructions[i].first << '\n';
-
- if (N > (PreviewFirst + PreviewLast)) {
- if (Preview)
- dbgs() << "...\t(" << (N - PreviewFirst - PreviewLast)
- << " more instructions)\n";
- else {
- // Print all middle lines
- for (size_t i = PreviewFirst; i < N - PreviewLast; ++i)
- dbgs() << format_hex_no_prefix(Instructions[i].second.first, 0) << ":\t"
- << Instructions[i].second.second << Instructions[i].first
- << '\n';
- }
- // Print last "PreviewLast" lines
- for (size_t i = N - PreviewLast; i < N; ++i)
- dbgs() << format_hex_no_prefix(Instructions[i].second.first, 0) << ":\t"
- << Instructions[i].second.second << Instructions[i].first << '\n';
- }
- dbgs() << "```\n";
+void printInstructions(const std::vector<InstructionInfo> &Instructions,
+ int InitialLinesCount, int LastLinesCount) {
+ int N = Instructions.size();
+ outs() << "Generated assembly snippet:\n```\n";
+
+ // Print initial lines
+ for (int i = 0; i < InitialLinesCount; ++i)
+ outs() << format_hex_no_prefix(Instructions[i].Address, 0) << ":\t"
+ << Instructions[i].HexBytes << Instructions[i].Text << '\n';
+
+ // Show truncation message if needed
+ int SkippedInstructions = N - InitialLinesCount - LastLinesCount;
+ if (SkippedInstructions > 0)
+ outs() << "...\t(" << SkippedInstructions << " more instructions)\n";
+
+ // Print last min(PreviewLast, N - PreviewFirst) lines
+ int LastLinesToPrint = std::min(
+ LastLinesCount, N > InitialLinesCount ? N - InitialLinesCount : 0);
+ for (int i = N - LastLinesToPrint; i < N; ++i)
+ outs() << format_hex_no_prefix(Instructions[i].Address, 0) << ":\t"
+ << Instructions[i].HexBytes << Instructions[i].Text << '\n';
+ outs() << "```\n";
}
// Function to extract and print assembly from snippet
@@ -635,23 +643,20 @@ Error printAssembledSnippet(const LLVMState &State,
return make_error<Failure>("Failed to extract function bytes: " +
toString(std::move(Err)));
- DisassemblerHelper DisHelper(State);
- size_t Offset = 0;
- const size_t FunctionBytesSize = FunctionBytes.size();
-
// Decode all instructions first
- std::vector<std::pair<std::string, std::pair<uint64_t, std::string>>>
- Instructions;
+ DisassemblerHelper DisHelper(State);
uint64_t Address = 0;
+ std::vector<InstructionInfo> Instructions;
+ const size_t FunctionBytesSize = FunctionBytes.size();
- while (Offset < FunctionBytesSize) {
+ while (Address < FunctionBytesSize) {
MCInst Inst;
uint64_t Size;
- ArrayRef<uint8_t> Bytes(FunctionBytes.data() + Offset,
- FunctionBytesSize - Offset);
+ ArrayRef<uint8_t> Bytes(FunctionBytes.data() + Address,
+ FunctionBytesSize - Address);
if (!DisHelper.decodeInst(Inst, Size, Bytes)) {
- Instructions.push_back({"<decode error>", {Address, ""}});
+ Instructions.push_back({"<decode error>", Address, ""});
break;
}
@@ -666,26 +671,19 @@ Error printAssembledSnippet(const LLVMState &State,
for (int i = Size - 1; i >= 0; --i)
HexOS << format_hex_no_prefix(Bytes[i], 2);
- Instructions.push_back({OS.str(), {Address, HexOS.str()}});
- Offset += Size;
+ Instructions.push_back({OS.str(), Address, HexOS.str()});
Address += Size;
}
- // Preview generated assembly snippet
- {
-#undef DEBUG_TYPE
-#define DEBUG_TYPE "preview-gen-assembly"
- LLVM_DEBUG(dbgs() << "Generated assembly snippet:\n");
- LLVM_DEBUG(printGeneratedAssembly(Instructions, true));
-#undef DEBUG_TYPE
-#define DEBUG_TYPE "print-gen-assembly"
- }
- // Print generated assembly snippet
- {
- LLVM_DEBUG(dbgs() << "Generated assembly snippet:\n");
- LLVM_DEBUG(printGeneratedAssembly(Instructions, false));
- }
+ if (PrintGenAssembly == 0 || PrintGenAssembly < -1)
+ return Error::success();
+ int InitialLinesCount = PrintGenAssembly;
+ int LastLinesCount = 3;
+ if (PrintGenAssembly == -1 ||
+ PrintGenAssembly > static_cast<int>(Instructions.size()))
+ InitialLinesCount = Instructions.size() - LastLinesCount;
+ printInstructions(Instructions, InitialLinesCount, LastLinesCount);
return Error::success();
}
} // namespace
>From 4acfe17aa4b2d7b6b601e054db280bbbd829fccb Mon Sep 17 00:00:00 2001
From: lakshayk-nv <lakshayk at nvidia.com>
Date: Fri, 4 Jul 2025 03:35:48 -0700
Subject: [PATCH 10/10] [llvm-exegesis] Newline added in testfile
---
llvm/test/tools/llvm-exegesis/AArch64/debug-gen-asm.s | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/test/tools/llvm-exegesis/AArch64/debug-gen-asm.s b/llvm/test/tools/llvm-exegesis/AArch64/debug-gen-asm.s
index 119814f1c62fe..3bb6bf962a2ca 100644
--- a/llvm/test/tools/llvm-exegesis/AArch64/debug-gen-asm.s
+++ b/llvm/test/tools/llvm-exegesis/AArch64/debug-gen-asm.s
@@ -9,4 +9,4 @@ PREVIEW-NEXT: {{[48]}}: {{.*}} addv h{{[0-9]+}}, v{{[0-9]+}}.4h
PREVIEW: ... ({{[0-9]+}} more instructions)
PREVIEW-NEXT: {{.*}} addv h{{[0-9]+}}, v{{[0-9]+}}.4h
PREVIEW: {{.*}} ret
-PREVIEW-NEXT:```
\ No newline at end of file
+PREVIEW-NEXT:```
More information about the llvm-commits
mailing list