[llvm] [DebugInfo] Keep validating after register and entry-value ops (PR #214057)

Eric Christopher via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 7 09:54:08 PDT 2026


https://github.com/echristo updated https://github.com/llvm/llvm-project/pull/214057

>From 0b2e27b00beead29da65372e5583a3847f1221b9 Mon Sep 17 00:00:00 2001
From: Eric Christopher <echristopher at nvidia.com>
Date: Fri, 31 Jul 2026 11:53:25 -0700
Subject: [PATCH 1/2] [DebugInfo] Keep validating after register and
 entry-value ops

DIExpression::isValid() returned as soon as it saw a register or a valid
entry-value operation. Keep walking the expression so a malformed operation
later in the expression does not get accepted.

This came out of our review of the verifier changes for DIArgList location
indices, and the history makes the early returns look unintended. That check
walks the DIExpression after calling isValid(), and we noticed that isValid()
returned early for register and entry-value operations without checking the
suffix. Split this out so the DIArgList check can rely on isValid() before
walking the expression.

LLVM already produces and consumes valid suffixes after these operations.

An A/B synthetic stress test added about 0.5 ms of verifier time for 100,000
unique expressions with four-operation suffixes. A pathological case with
10,000 unique expressions and 64-operation suffixes added about 0.9 ms.
Verification remains linear in the number of unique expression operands, which
seems reasonable for checking the full expression.

Tested with make check.
---
 llvm/lib/IR/DebugInfoMetadata.cpp  | 6 ++++--
 llvm/unittests/IR/MetadataTest.cpp | 7 +++++++
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp
index 88f7f2f6240e0..4be2f53fe0c80 100644
--- a/llvm/lib/IR/DebugInfoMetadata.cpp
+++ b/llvm/lib/IR/DebugInfoMetadata.cpp
@@ -1766,7 +1766,7 @@ bool DIExpression::isValid() const {
     uint64_t Op = I->getOp();
     if ((Op >= dwarf::DW_OP_reg0 && Op <= dwarf::DW_OP_reg31) ||
         (Op >= dwarf::DW_OP_breg0 && Op <= dwarf::DW_OP_breg31))
-      return true;
+      continue;
 
     // Check that the operand is valid.
     switch (Op) {
@@ -1805,7 +1805,9 @@ bool DIExpression::isValid() const {
       auto FirstOp = expr_op_begin();
       if (FirstOp->getOp() == dwarf::DW_OP_LLVM_arg && FirstOp->getArg(0) == 0)
         ++FirstOp;
-      return I->get() == FirstOp->get() && I->getArg(0) == 1;
+      if (I->get() != FirstOp->get() || I->getArg(0) != 1)
+        return false;
+      break;
     }
     case dwarf::DW_OP_LLVM_implicit_pointer:
     case dwarf::DW_OP_LLVM_convert:
diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp
index 65398b5ca2b1f..b17fcc5c65b03 100644
--- a/llvm/unittests/IR/MetadataTest.cpp
+++ b/llvm/unittests/IR/MetadataTest.cpp
@@ -4274,10 +4274,12 @@ TEST_F(DIExpressionTest, isValid) {
   EXPECT_VALID(dwarf::DW_OP_LLVM_fragment, 3, 7);
   EXPECT_VALID(dwarf::DW_OP_plus_uconst, 6, dwarf::DW_OP_deref);
   EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_plus_uconst, 6);
+  EXPECT_VALID(dwarf::DW_OP_breg0, 0, dwarf::DW_OP_plus_uconst, 6);
   EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_LLVM_fragment, 3, 7);
   EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_plus_uconst, 6,
                dwarf::DW_OP_LLVM_fragment, 3, 7);
   EXPECT_VALID(dwarf::DW_OP_LLVM_entry_value, 1);
+  EXPECT_VALID(dwarf::DW_OP_LLVM_entry_value, 1, dwarf::DW_OP_plus_uconst, 6);
   EXPECT_VALID(dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_LLVM_entry_value, 1);
 
   // Invalid constructions.
@@ -4295,6 +4297,11 @@ TEST_F(DIExpressionTest, isValid) {
                  dwarf::DW_OP_LLVM_entry_value, 1);
   EXPECT_INVALID(dwarf::DW_OP_LLVM_arg, 1, dwarf::DW_OP_LLVM_entry_value, 1);
 
+  // A valid operation doesn't make a malformed suffix valid.
+  EXPECT_INVALID(dwarf::DW_OP_reg0, dwarf::DW_OP_LLVM_arg);
+  EXPECT_INVALID(dwarf::DW_OP_breg0, 0, dwarf::DW_OP_LLVM_arg);
+  EXPECT_INVALID(dwarf::DW_OP_LLVM_entry_value, 1, dwarf::DW_OP_LLVM_arg);
+
 #undef EXPECT_VALID
 #undef EXPECT_INVALID
 }

>From 1e3c93ae52590262f2af6131ef59507f4dc12193 Mon Sep 17 00:00:00 2001
From: Eric Christopher <echristopher at nvidia.com>
Date: Wed, 5 Aug 2026 22:24:48 -0700
Subject: [PATCH 2/2] Update tests after review feedback

---
 llvm/unittests/IR/MetadataTest.cpp | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp
index b17fcc5c65b03..21292f9a398c7 100644
--- a/llvm/unittests/IR/MetadataTest.cpp
+++ b/llvm/unittests/IR/MetadataTest.cpp
@@ -4274,6 +4274,7 @@ TEST_F(DIExpressionTest, isValid) {
   EXPECT_VALID(dwarf::DW_OP_LLVM_fragment, 3, 7);
   EXPECT_VALID(dwarf::DW_OP_plus_uconst, 6, dwarf::DW_OP_deref);
   EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_plus_uconst, 6);
+  EXPECT_VALID(dwarf::DW_OP_reg0, dwarf::DW_OP_deref);
   EXPECT_VALID(dwarf::DW_OP_breg0, 0, dwarf::DW_OP_plus_uconst, 6);
   EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_LLVM_fragment, 3, 7);
   EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_plus_uconst, 6,
@@ -4298,9 +4299,11 @@ TEST_F(DIExpressionTest, isValid) {
   EXPECT_INVALID(dwarf::DW_OP_LLVM_arg, 1, dwarf::DW_OP_LLVM_entry_value, 1);
 
   // A valid operation doesn't make a malformed suffix valid.
-  EXPECT_INVALID(dwarf::DW_OP_reg0, dwarf::DW_OP_LLVM_arg);
+  EXPECT_INVALID(dwarf::DW_OP_reg0, dwarf::DW_OP_stack_value,
+                 dwarf::DW_OP_deref);
   EXPECT_INVALID(dwarf::DW_OP_breg0, 0, dwarf::DW_OP_LLVM_arg);
-  EXPECT_INVALID(dwarf::DW_OP_LLVM_entry_value, 1, dwarf::DW_OP_LLVM_arg);
+  EXPECT_INVALID(dwarf::DW_OP_LLVM_entry_value, 1,
+                 dwarf::DW_OP_LLVM_entry_value, 1);
 
 #undef EXPECT_VALID
 #undef EXPECT_INVALID



More information about the llvm-commits mailing list