[Lldb-commits] [lldb] [llvm] [DWARF] Add DW_OP_NVIDIA_mux vendor extension (PR #216314)
Matt Davis via lldb-commits
lldb-commits at lists.llvm.org
Fri Aug 14 06:13:43 PDT 2026
https://github.com/enferex created https://github.com/llvm/llvm-project/pull/216314
DW_OP_NVIDIA_mux (0xeb) takes a 1-byte unsigned selector, giving NVIDIA an extension space behind a single opcode in the crowded DW_OP_lo_user..DW_OP_hi_user range. The selector is opaque to LLVM; no NVIDIA operation semantics are defined here.
Assissted-by: LLM
>From b30ca547804cfc30b0d15484aa18a65f340e0f2f Mon Sep 17 00:00:00 2001
From: Matt Davis <mattd at nvidia.com>
Date: Thu, 13 Aug 2026 18:36:19 +0000
Subject: [PATCH] [DWARF] Add DW_OP_NVIDIA_mux vendor extension
DW_OP_NVIDIA_mux (0xeb) takes a 1-byte unsigned selector, giving NVIDIA
an extension space behind a single opcode in the crowded
DW_OP_lo_user..DW_OP_hi_user range. The selector is opaque to LLVM; no
NVIDIA operation semantics are defined here.
Assissted-by: LLM
---
lldb/source/Expression/DWARFExpression.cpp | 1 +
llvm/include/llvm/BinaryFormat/Dwarf.def | 7 ++++
llvm/include/llvm/BinaryFormat/Dwarf.h | 1 +
.../DWARF/LowLevel/DWARFExpression.cpp | 2 +
llvm/unittests/BinaryFormat/DwarfTest.cpp | 11 ++++++
.../DWARFExpressionCompactPrinterTest.cpp | 39 +++++++++++++++++++
6 files changed, 61 insertions(+)
diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp
index 2dbf61a14eac4..8b5944f206675 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -214,6 +214,7 @@ GetOpcodeDataSize(const DataExtractor &data, const lldb::offset_t data_offset,
case DW_OP_HP_unmod_range:
case DW_OP_HP_tls:
case DW_OP_INTEL_bit_piece:
+ case DW_OP_NVIDIA_mux:
case DW_OP_WASM_location:
case DW_OP_WASM_location_int:
case DW_OP_APPLE_uninit:
diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.def b/llvm/include/llvm/BinaryFormat/Dwarf.def
index 32195aae562c3..885216bdc2de9 100644
--- a/llvm/include/llvm/BinaryFormat/Dwarf.def
+++ b/llvm/include/llvm/BinaryFormat/Dwarf.def
@@ -920,6 +920,13 @@ HANDLE_DW_OP(0xe5, HP_unmod_range, -1, -1, 0, HP)
HANDLE_DW_OP(0xe6, HP_tls, -1, -1, 0, HP)
HANDLE_DW_OP(0xe8, INTEL_bit_piece, -1, -1, 0, INTEL)
+// Extension for NVIDIA. DW_OP_NVIDIA_mux acts as an extension multiplexer: its
+// single 1-byte unsigned operand selects an NVIDIA-specific operation. This
+// keeps the cost of the whole NVIDIA extension family at one encoding in the
+// scarce DW_OP_lo_user..DW_OP_hi_user range. The selector value is opaque to
+// LLVM; no NVIDIA operation semantics are defined here.
+HANDLE_DW_OP(0xeb, NVIDIA_mux, 1, -1, 0, NVIDIA)
+
// Extensions for WebAssembly.
HANDLE_DW_OP(0xed, WASM_location, -1, -1, 0, WASM)
HANDLE_DW_OP(0xee, WASM_location_int, -1, -1, 0, WASM)
diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.h b/llvm/include/llvm/BinaryFormat/Dwarf.h
index 46124019206f2..ee7031b239479 100644
--- a/llvm/include/llvm/BinaryFormat/Dwarf.h
+++ b/llvm/include/llvm/BinaryFormat/Dwarf.h
@@ -83,6 +83,7 @@ enum LLVMConstants : uint32_t {
DWARF_VENDOR_HP,
DWARF_VENDOR_IBM,
DWARF_VENDOR_INTEL,
+ DWARF_VENDOR_NVIDIA,
DWARF_VENDOR_PGI,
DWARF_VENDOR_SUN,
DWARF_VENDOR_UPC,
diff --git a/llvm/lib/DebugInfo/DWARF/LowLevel/DWARFExpression.cpp b/llvm/lib/DebugInfo/DWARF/LowLevel/DWARFExpression.cpp
index 61bd6fcb65bfa..654fb459feb37 100644
--- a/llvm/lib/DebugInfo/DWARF/LowLevel/DWARFExpression.cpp
+++ b/llvm/lib/DebugInfo/DWARF/LowLevel/DWARFExpression.cpp
@@ -103,6 +103,8 @@ static std::vector<Desc> getOpDescriptions() {
Descriptions[DW_OP_GNU_entry_value] = Desc(Op::Dwarf4, Op::SizeLEB);
Descriptions[DW_OP_GNU_implicit_pointer] =
Desc(Op::Dwarf4, Op::SizeRefAddr, Op::SignedSizeLEB);
+ // The operand is an opaque 8-bit selector for an NVIDIA-specific operation.
+ Descriptions[DW_OP_NVIDIA_mux] = Desc(Op::Dwarf5, Op::Size1);
// This Description acts as a marker that getSubOpDesc must be called
// to fetch the final Description for the operation. Each such final
// Description must share the same first SizeSubOpLEB operand.
diff --git a/llvm/unittests/BinaryFormat/DwarfTest.cpp b/llvm/unittests/BinaryFormat/DwarfTest.cpp
index c9522226c6031..0366bd7b7610e 100644
--- a/llvm/unittests/BinaryFormat/DwarfTest.cpp
+++ b/llvm/unittests/BinaryFormat/DwarfTest.cpp
@@ -48,6 +48,9 @@ TEST(DwarfTest, getOperationEncoding) {
EXPECT_EQ(DW_OP_deref, getOperationEncoding("DW_OP_deref"));
EXPECT_EQ(DW_OP_bit_piece, getOperationEncoding("DW_OP_bit_piece"));
+ // A vendor extension.
+ EXPECT_EQ(DW_OP_NVIDIA_mux, getOperationEncoding("DW_OP_NVIDIA_mux"));
+
// Invalid ops.
EXPECT_EQ(0u, getOperationEncoding("DW_OP_otherthings"));
EXPECT_EQ(0u, getOperationEncoding("other"));
@@ -57,6 +60,14 @@ TEST(DwarfTest, getOperationEncoding) {
EXPECT_EQ(0u, getOperationEncoding("DW_OP_hi_user"));
}
+TEST(DwarfTest, OperationEncodingString) {
+ // A vendor extension.
+ EXPECT_EQ("DW_OP_NVIDIA_mux", OperationEncodingString(DW_OP_NVIDIA_mux));
+
+ // Unassigned encodings in the vendor range shouldn't be stringified.
+ EXPECT_EQ(StringRef(), OperationEncodingString(DW_OP_hi_user));
+}
+
TEST(DwarfTest, LanguageStringOnInvalid) {
// This is invalid, so it shouldn't be stringified.
EXPECT_EQ(StringRef(), LanguageString(0));
diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFExpressionCompactPrinterTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFExpressionCompactPrinterTest.cpp
index e328f0ffa8809..a853a22360c95 100644
--- a/llvm/unittests/DebugInfo/DWARF/DWARFExpressionCompactPrinterTest.cpp
+++ b/llvm/unittests/DebugInfo/DWARF/DWARFExpressionCompactPrinterTest.cpp
@@ -208,6 +208,45 @@ TEST_F(DWARFExpressionCompactPrinterTest, Test_OP_LLVM_user_unknown_subop) {
"DW_OP_LLVM_form_aspace_address (2)>");
}
+// DW_OP_NVIDIA_mux carries an opaque 8-bit selector, so the compact printer
+// cannot know its stack effect and must bail out naming the opcode.
+TEST_F(DWARFExpressionCompactPrinterTest, Test_OP_NVIDIA_mux) {
+ TestExprPrinterFailure({DW_OP_NVIDIA_mux, 0xa5},
+ "<unknown op DW_OP_NVIDIA_mux (235)>");
+}
+
+// The selector is a fixed 1-byte operand, so the full printer must consume
+// exactly one byte and print its value.
+TEST(NVIDIAMux, Full_DW_OP_NVIDIA_mux) {
+ const uint8_t Enc[] = {DW_OP_NVIDIA_mux, 0xa5};
+
+ std::string Result;
+ raw_string_ostream OS(Result);
+ DataExtractor DE(Enc, true);
+ DWARFExpression Expr(DE, 8);
+
+ DIDumpOptions DumpOpts;
+ printDwarfExpression(&Expr, OS, DumpOpts, nullptr);
+
+ EXPECT_EQ(OS.str(), "DW_OP_NVIDIA_mux 0xa5");
+}
+
+// A trailing operation must still decode, proving the selector advanced the
+// offset by exactly one byte.
+TEST(NVIDIAMux, Full_DW_OP_NVIDIA_mux_TrailingOp) {
+ const uint8_t Enc[] = {DW_OP_NVIDIA_mux, 0xa5, DW_OP_stack_value};
+
+ std::string Result;
+ raw_string_ostream OS(Result);
+ DataExtractor DE(Enc, true);
+ DWARFExpression Expr(DE, 8);
+
+ DIDumpOptions DumpOpts;
+ printDwarfExpression(&Expr, OS, DumpOpts, nullptr);
+
+ EXPECT_EQ(OS.str(), "DW_OP_NVIDIA_mux 0xa5, DW_OP_stack_value");
+}
+
// NVPTX packs virtual register names into DWARF register numbers, so compact
// printing without a callback must recover the name and return true.
TEST(NVPTXPackedRegister, Compact_DW_OP_regx_NoMRI) {
More information about the lldb-commits
mailing list