[llvm] 464d9d9 - [RemoveDIs][DebugInfo][IR] Add parsing for non-intrinsic debug values (#79818)

via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 7 05:05:08 PST 2024


Author: Stephen Tozer
Date: 2024-03-07T13:05:04Z
New Revision: 464d9d96b3565ead06396ffb8d02b4dcf9cb9556

URL: https://github.com/llvm/llvm-project/commit/464d9d96b3565ead06396ffb8d02b4dcf9cb9556
DIFF: https://github.com/llvm/llvm-project/commit/464d9d96b3565ead06396ffb8d02b4dcf9cb9556.diff

LOG: [RemoveDIs][DebugInfo][IR] Add parsing for non-intrinsic debug values (#79818)

This patch adds support for parsing the proposed non-instruction debug
info ("RemoveDIs") from textual IR, and adds a test for the parser as well
as a set of verifier tests that are dependent on parsing to fire.

An important detail of this patch is the fact that although we can now
parse in the RemoveDIs (new) and Intrinsic (old) debug info formats, we
will always convert back to the old format at the end of parsing - this
is done for two reasons: firstly to ensure that every tool is able to
process IR printed in the new format, regardless of whether that tool
has had RemoveDIs support added, and secondly to maintain the effect of
the existing flags: for the tools where support for the new format has
been added, we will run LLVM passes in the new format iff
`--try-experimental-debuginfo-iterators=true`, and we will print in the
new format iff `--write-experimental-debuginfo-iterators=true`; the
format of the textual IR input should have no effect on either of these
features.

Added: 
    llvm/test/Assembler/dbg-record-invalid-0.ll
    llvm/test/Assembler/dbg-record-invalid-1.ll
    llvm/test/Assembler/dbg-record-invalid-2.ll
    llvm/test/Assembler/dbg-record-invalid-3.ll
    llvm/test/Assembler/dbg-record-invalid-4.ll
    llvm/test/Assembler/dbg-record-invalid-5.ll
    llvm/test/Assembler/dbg-record-invalid-6.ll
    llvm/test/Assembler/dbg-record-invalid-7.ll
    llvm/test/Assembler/dbg-record-invalid-8.ll
    llvm/test/DebugInfo/roundtrip-non-instruction-debug-info.ll
    llvm/test/Verifier/RemoveDI/blockbyref.ll
    llvm/test/Verifier/RemoveDI/dbg-invalid-vector.ll
    llvm/test/Verifier/RemoveDI/di-subroutine-localvar.ll
    llvm/test/Verifier/RemoveDI/diexpression-entry-value-llvm-ir.ll
    llvm/test/Verifier/RemoveDI/fnarg-debuginfo.ll
    llvm/test/Verifier/RemoveDI/fnarg-nodebug.ll
    llvm/test/Verifier/RemoveDI/invalid-disubrange-count-node.ll
    llvm/test/Verifier/RemoveDI/llvm.dbg.declare-address.ll
    llvm/test/Verifier/RemoveDI/llvm.dbg.declare-expression.ll
    llvm/test/Verifier/RemoveDI/llvm.dbg.declare-variable.ll
    llvm/test/Verifier/RemoveDI/llvm.dbg.intrinsic-dbg-attachment.ll
    llvm/test/Verifier/RemoveDI/llvm.dbg.value-expression.ll
    llvm/test/Verifier/RemoveDI/llvm.dbg.value-value.ll
    llvm/test/Verifier/RemoveDI/llvm.dbg.value-variable.ll
    llvm/test/Verifier/RemoveDI/set1.ll

Modified: 
    llvm/include/llvm/AsmParser/LLParser.h
    llvm/include/llvm/AsmParser/LLToken.h
    llvm/include/llvm/IR/DebugProgramInstruction.h
    llvm/lib/AsmParser/LLLexer.cpp
    llvm/lib/AsmParser/LLParser.cpp
    llvm/lib/IR/DebugProgramInstruction.cpp
    llvm/lib/IR/Verifier.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/AsmParser/LLParser.h b/llvm/include/llvm/AsmParser/LLParser.h
index f07f4c61f9d649..e5e1ade8b38b36 100644
--- a/llvm/include/llvm/AsmParser/LLParser.h
+++ b/llvm/include/llvm/AsmParser/LLParser.h
@@ -178,6 +178,9 @@ namespace llvm {
     /// UpgradeDebuginfo so it can generate broken bitcode.
     bool UpgradeDebugInfo;
 
+    bool SeenNewDbgInfoFormat = false;
+    bool SeenOldDbgInfoFormat = false;
+
     std::string SourceFileName;
 
   public:
@@ -573,6 +576,7 @@ namespace llvm {
     bool parseMDNodeTail(MDNode *&N);
     bool parseMDNodeVector(SmallVectorImpl<Metadata *> &Elts);
     bool parseMetadataAttachment(unsigned &Kind, MDNode *&MD);
+    bool parseDebugRecord(DbgRecord *&DR, PerFunctionState &PFS);
     bool parseInstructionMetadata(Instruction &Inst);
     bool parseGlobalObjectMetadataAttachment(GlobalObject &GO);
     bool parseOptionalFunctionMetadata(Function &F);

diff  --git a/llvm/include/llvm/AsmParser/LLToken.h b/llvm/include/llvm/AsmParser/LLToken.h
index 3c34706ee03e82..5863a8d6e8ee84 100644
--- a/llvm/include/llvm/AsmParser/LLToken.h
+++ b/llvm/include/llvm/AsmParser/LLToken.h
@@ -36,6 +36,7 @@ enum Kind {
   exclaim, // !
   bar,     // |
   colon,   // :
+  hash,    // #
 
   kw_vscale,
   kw_x,
@@ -479,6 +480,7 @@ enum Kind {
   DISPFlag,         // DISPFlagFoo
   DwarfMacinfo,     // DW_MACINFO_foo
   ChecksumKind,     // CSK_foo
+  DbgRecordType,    // dbg_foo
 
   // Type valued tokens (TyVal).
   Type,

diff  --git a/llvm/include/llvm/IR/DebugProgramInstruction.h b/llvm/include/llvm/IR/DebugProgramInstruction.h
index cf30b4d0b0aaf0..a8faf415a3ea87 100644
--- a/llvm/include/llvm/IR/DebugProgramInstruction.h
+++ b/llvm/include/llvm/IR/DebugProgramInstruction.h
@@ -223,9 +223,19 @@ inline raw_ostream &operator<<(raw_ostream &OS, const DbgRecord &R) {
 class DPLabel : public DbgRecord {
   DbgRecordParamRef<DILabel> Label;
 
+  /// This constructor intentionally left private, so that it is only called via
+  /// "createUnresolvedDPLabel", which clearly expresses that it is for parsing
+  /// only.
+  DPLabel(MDNode *Label, MDNode *DL);
+
 public:
   DPLabel(DILabel *Label, DebugLoc DL);
 
+  /// For use during parsing; creates a DPLabel from as-of-yet unresolved
+  /// MDNodes. Trying to access the resulting DPLabel's fields before they are
+  /// resolved, or if they resolve to the wrong type, will result in a crash.
+  static DPLabel *createUnresolvedDPLabel(MDNode *Label, MDNode *DL);
+
   DPLabel *clone() const;
   void print(raw_ostream &O, bool IsForDebug = false) const;
   void print(raw_ostream &ROS, ModuleSlotTracker &MST, bool IsForDebug) const;
@@ -286,6 +296,29 @@ class DPValue : public DbgRecord, protected DebugValueUser {
           DIAssignID *AssignID, Metadata *Address,
           DIExpression *AddressExpression, const DILocation *DI);
 
+private:
+  /// Private constructor for creating new instances during parsing only. Only
+  /// called through `createUnresolvedDPValue` below, which makes clear that
+  /// this is used for parsing only, and will later return a subclass depending
+  /// on which Type is passed.
+  DPValue(LocationType Type, Metadata *Val, MDNode *Variable,
+          MDNode *Expression, MDNode *AssignID, Metadata *Address,
+          MDNode *AddressExpression, MDNode *DI);
+
+public:
+  /// Used to create DPValues during parsing, where some metadata references may
+  /// still be unresolved. Although for some fields a generic `Metadata*`
+  /// argument is accepted for forward type-references, the verifier and
+  /// accessors will reject incorrect types later on. The function is used for
+  /// all types of DPValues for simplicity while parsing, but asserts if any
+  /// necessary fields are empty or unused fields are not empty, i.e. if the
+  /// #dbg_assign fields are used for a non-dbg-assign type.
+  static DPValue *createUnresolvedDPValue(LocationType Type, Metadata *Val,
+                                          MDNode *Variable, MDNode *Expression,
+                                          MDNode *AssignID, Metadata *Address,
+                                          MDNode *AddressExpression,
+                                          MDNode *DI);
+
   static DPValue *createDPVAssign(Value *Val, DILocalVariable *Variable,
                                   DIExpression *Expression,
                                   DIAssignID *AssignID, Value *Address,

diff  --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp
index 5d8a50eee13068..02f64fcfac4f0c 100644
--- a/llvm/lib/AsmParser/LLLexer.cpp
+++ b/llvm/lib/AsmParser/LLLexer.cpp
@@ -438,9 +438,12 @@ lltok::Kind LLLexer::LexCaret() {
 
 /// Lex all tokens that start with a # character.
 ///    AttrGrpID ::= #[0-9]+
+///    Hash ::= #
 lltok::Kind LLLexer::LexHash() {
   // Handle AttrGrpID: #[0-9]+
-  return LexUIntID(lltok::AttrGrpID);
+  if (isdigit(static_cast<unsigned char>(CurPtr[0])))
+    return LexUIntID(lltok::AttrGrpID);
+  return lltok::hash;
 }
 
 /// Lex a label, integer type, keyword, or hexadecimal integer constant.
@@ -923,6 +926,21 @@ lltok::Kind LLLexer::LexIdentifier() {
 
 #undef DWKEYWORD
 
+// Keywords for debug record types.
+#define DBGRECORDTYPEKEYWORD(STR)                                              \
+  do {                                                                         \
+    if (Keyword == "dbg_" #STR) {                                              \
+      StrVal = #STR;                                                           \
+      return lltok::DbgRecordType;                                             \
+    }                                                                          \
+  } while (false)
+
+  DBGRECORDTYPEKEYWORD(value);
+  DBGRECORDTYPEKEYWORD(declare);
+  DBGRECORDTYPEKEYWORD(assign);
+  DBGRECORDTYPEKEYWORD(label);
+#undef DBGRECORDTYPEKEYWORD
+
   if (Keyword.starts_with("DIFlag")) {
     StrVal.assign(Keyword.begin(), Keyword.end());
     return lltok::DIFlag;

diff  --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index a91e2f690999e0..e140c94195205a 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -62,6 +62,8 @@ static cl::opt<bool> AllowIncompleteIR(
         "Allow incomplete IR on a best effort basis (references to unknown "
         "metadata will be dropped)"));
 
+extern llvm::cl::opt<bool> UseNewDbgInfoFormat;
+
 static std::string getTypeString(Type *T) {
   std::string Result;
   raw_string_ostream Tmp(Result);
@@ -69,6 +71,15 @@ static std::string getTypeString(Type *T) {
   return Tmp.str();
 }
 
+// Currently, we should always process modules in the old debug info format by
+// default regardless of the module's format in IR; convert it to the old format
+// here.
+bool finalizeDebugInfoFormat(Module *M) {
+  if (M)
+    M->setIsNewDbgInfoFormat(false);
+  return false;
+}
+
 /// Run: module ::= toplevelentity*
 bool LLParser::Run(bool UpgradeDebugInfo,
                    DataLayoutCallbackTy DataLayoutCallback) {
@@ -86,7 +97,7 @@ bool LLParser::Run(bool UpgradeDebugInfo,
   }
 
   return parseTopLevelEntities() || validateEndOfModule(UpgradeDebugInfo) ||
-         validateEndOfIndex();
+         validateEndOfIndex() || finalizeDebugInfoFormat(M);
 }
 
 bool LLParser::parseStandaloneConstantValue(Constant *&C,
@@ -6041,6 +6052,17 @@ bool LLParser::parseTypeAndBasicBlock(BasicBlock *&BB, LocTy &Loc,
   return false;
 }
 
+bool isOldDbgFormatIntrinsic(StringRef Name) {
+  // Exit early for the common (non-debug-intrinsic) case.
+  // We can make this the only check when we begin supporting all "llvm.dbg"
+  // intrinsics in the new debug info format.
+  if (!Name.starts_with("llvm.dbg."))
+    return false;
+  Intrinsic::ID FnID = Function::lookupIntrinsicID(Name);
+  return FnID == Intrinsic::dbg_declare || FnID == Intrinsic::dbg_value ||
+         FnID == Intrinsic::dbg_assign;
+}
+
 /// FunctionHeader
 ///   ::= OptionalLinkage OptionalPreemptionSpecifier OptionalVisibility
 ///       OptionalCallingConv OptRetAttrs OptUnnamedAddr Type GlobalName
@@ -6390,9 +6412,31 @@ bool LLParser::parseBasicBlock(PerFunctionState &PFS) {
 
   std::string NameStr;
 
-  // parse the instructions in this block until we get a terminator.
+  // Parse the instructions and debug values in this block until we get a
+  // terminator.
   Instruction *Inst;
+  auto DeleteDbgRecord = [](DbgRecord *DR) { DR->deleteRecord(); };
+  using DbgRecordPtr = std::unique_ptr<DbgRecord, decltype(DeleteDbgRecord)>;
+  SmallVector<DbgRecordPtr> TrailingDbgRecord;
   do {
+    // Handle debug records first - there should always be an instruction
+    // following the debug records, i.e. they cannot appear after the block
+    // terminator.
+    while (Lex.getKind() == lltok::hash) {
+      if (SeenOldDbgInfoFormat)
+        return error(Lex.getLoc(), "debug record should not appear in a module "
+                                   "containing debug info intrinsics");
+      SeenNewDbgInfoFormat = true;
+      Lex.Lex();
+      if (!M->IsNewDbgInfoFormat)
+        M->convertToNewDbgValues();
+
+      DbgRecord *DR;
+      if (parseDebugRecord(DR, PFS))
+        return true;
+      TrailingDbgRecord.emplace_back(DR, DeleteDbgRecord);
+    }
+
     // This instruction may have three possibilities for a name: a) none
     // specified, b) name specified "%foo =", c) number specified: "%4 =".
     LocTy NameLoc = Lex.getLoc();
@@ -6437,11 +6481,121 @@ bool LLParser::parseBasicBlock(PerFunctionState &PFS) {
     // Set the name on the instruction.
     if (PFS.setInstName(NameID, NameStr, NameLoc, Inst))
       return true;
+
+    // Attach any preceding debug values to this instruction.
+    for (DbgRecordPtr &DR : TrailingDbgRecord)
+      BB->insertDPValueBefore(DR.release(), Inst->getIterator());
+    TrailingDbgRecord.clear();
   } while (!Inst->isTerminator());
 
+  assert(TrailingDbgRecord.empty() &&
+         "All debug values should have been attached to an instruction.");
+
   return false;
 }
 
+/// parseDebugRecord
+///   ::= #dbg_label '(' MDNode ')'
+///   ::= #dbg_type '(' Metadata ',' MDNode ',' Metadata ','
+///                 (MDNode ',' Metadata ',' Metadata ',')? MDNode ')'
+bool LLParser::parseDebugRecord(DbgRecord *&DR, PerFunctionState &PFS) {
+  using RecordKind = DbgRecord::Kind;
+  using LocType = DPValue::LocationType;
+  LocTy DPVLoc = Lex.getLoc();
+  if (Lex.getKind() != lltok::DbgRecordType)
+    return error(DPVLoc, "expected debug record type here");
+  RecordKind RecordType = StringSwitch<RecordKind>(Lex.getStrVal())
+                              .Case("declare", RecordKind::ValueKind)
+                              .Case("value", RecordKind::ValueKind)
+                              .Case("assign", RecordKind::ValueKind)
+                              .Case("label", RecordKind::LabelKind);
+
+  // Parsing labels is trivial; parse here and early exit, otherwise go into the
+  // full DPValue processing stage.
+  if (RecordType == RecordKind::LabelKind) {
+    Lex.Lex();
+    if (parseToken(lltok::lparen, "Expected '(' here"))
+      return true;
+    MDNode *Label;
+    if (parseMDNode(Label))
+      return true;
+    if (parseToken(lltok::comma, "Expected ',' here"))
+      return true;
+    MDNode *DbgLoc;
+    if (parseMDNode(DbgLoc))
+      return true;
+    if (parseToken(lltok::rparen, "Expected ')' here"))
+      return true;
+    DR = DPLabel::createUnresolvedDPLabel(Label, DbgLoc);
+    return false;
+  }
+
+  LocType ValueType = StringSwitch<LocType>(Lex.getStrVal())
+                          .Case("declare", LocType::Declare)
+                          .Case("value", LocType::Value)
+                          .Case("assign", LocType::Assign);
+
+  Lex.Lex();
+  if (parseToken(lltok::lparen, "Expected '(' here"))
+    return true;
+
+  // Parse Value field.
+  Metadata *ValLocMD;
+  if (parseMetadata(ValLocMD, &PFS))
+    return true;
+  if (parseToken(lltok::comma, "Expected ',' here"))
+    return true;
+
+  // Parse Variable field.
+  MDNode *Variable;
+  if (parseMDNode(Variable))
+    return true;
+  if (parseToken(lltok::comma, "Expected ',' here"))
+    return true;
+
+  // Parse Expression field.
+  MDNode *Expression;
+  if (parseMDNode(Expression))
+    return true;
+  if (parseToken(lltok::comma, "Expected ',' here"))
+    return true;
+
+  // Parse additional fields for #dbg_assign.
+  MDNode *AssignID = nullptr;
+  Metadata *AddressLocation = nullptr;
+  MDNode *AddressExpression = nullptr;
+  if (ValueType == LocType::Assign) {
+    // Parse DIAssignID.
+    if (parseMDNode(AssignID))
+      return true;
+    if (parseToken(lltok::comma, "Expected ',' here"))
+      return true;
+
+    // Parse address ValueAsMetadata.
+    if (parseMetadata(AddressLocation, &PFS))
+      return true;
+    if (parseToken(lltok::comma, "Expected ',' here"))
+      return true;
+
+    // Parse address DIExpression.
+    if (parseMDNode(AddressExpression))
+      return true;
+    if (parseToken(lltok::comma, "Expected ',' here"))
+      return true;
+  }
+
+  /// Parse DILocation.
+  MDNode *DebugLoc;
+  if (parseMDNode(DebugLoc))
+    return true;
+
+  if (parseToken(lltok::rparen, "Expected ')' here"))
+    return true;
+  DR = DPValue::createUnresolvedDPValue(ValueType, ValLocMD, Variable,
+                                        Expression, AssignID, AddressLocation,
+                                        AddressExpression, DebugLoc);
+  return false;
+}
 //===----------------------------------------------------------------------===//
 // Instruction Parsing.
 //===----------------------------------------------------------------------===//
@@ -7669,6 +7823,16 @@ bool LLParser::parseCall(Instruction *&Inst, PerFunctionState &PFS,
     }
     CI->setFastMathFlags(FMF);
   }
+
+  if (CalleeID.Kind == ValID::t_GlobalName &&
+      isOldDbgFormatIntrinsic(CalleeID.StrVal)) {
+    if (SeenNewDbgInfoFormat) {
+      CI->deleteValue();
+      return error(CallLoc, "llvm.dbg intrinsic should not appear in a module "
+                            "using non-intrinsic debug info");
+    }
+    SeenOldDbgInfoFormat = true;
+  }
   CI->setAttributes(PAL);
   ForwardRefAttrGroups[CI] = FwdRefAttrGrps;
   Inst = CI;

diff  --git a/llvm/lib/IR/DebugProgramInstruction.cpp b/llvm/lib/IR/DebugProgramInstruction.cpp
index a8d64024e1797b..5ff1e8c19db68b 100644
--- a/llvm/lib/IR/DebugProgramInstruction.cpp
+++ b/llvm/lib/IR/DebugProgramInstruction.cpp
@@ -138,11 +138,38 @@ DbgRecord::createDebugIntrinsic(Module *M, Instruction *InsertBefore) const {
   llvm_unreachable("unsupported DbgRecord kind");
 }
 
+DPLabel::DPLabel(MDNode *Label, MDNode *DL)
+    : DbgRecord(LabelKind, DebugLoc(DL)), Label(Label) {
+  assert(Label && "Unexpected nullptr");
+  assert((isa<DILabel>(Label) || Label->isTemporary()) &&
+         "Label type must be or resolve to a DILabel");
+}
 DPLabel::DPLabel(DILabel *Label, DebugLoc DL)
     : DbgRecord(LabelKind, DL), Label(Label) {
   assert(Label && "Unexpected nullptr");
 }
 
+DPLabel *DPLabel::createUnresolvedDPLabel(MDNode *Label, MDNode *DL) {
+  return new DPLabel(Label, DL);
+}
+
+DPValue::DPValue(DPValue::LocationType Type, Metadata *Val, MDNode *Variable,
+                 MDNode *Expression, MDNode *AssignID, Metadata *Address,
+                 MDNode *AddressExpression, MDNode *DI)
+    : DbgRecord(ValueKind, DebugLoc(DI)),
+      DebugValueUser({Val, Address, AssignID}), Type(Type), Variable(Variable),
+      Expression(Expression), AddressExpression(AddressExpression) {}
+
+DPValue *DPValue::createUnresolvedDPValue(DPValue::LocationType Type,
+                                          Metadata *Val, MDNode *Variable,
+                                          MDNode *Expression, MDNode *AssignID,
+                                          Metadata *Address,
+                                          MDNode *AddressExpression,
+                                          MDNode *DI) {
+  return new DPValue(Type, Val, Variable, Expression, AssignID, Address,
+                     AddressExpression, DI);
+}
+
 DPValue *DPValue::createDPValue(Value *Location, DILocalVariable *DV,
                                 DIExpression *Expr, const DILocation *DI) {
   return new DPValue(ValueAsMetadata::get(Location), DV, Expr, DI,

diff  --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 74c7354e7bf1bb..fd5f7d57c258d4 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -6291,7 +6291,7 @@ void Verifier::visit(DPValue &DPV) {
           Var->getRawType());
 
   auto *DLNode = DPV.getDebugLoc().getAsMDNode();
-  CheckDI(isa_and_nonnull<DILocation>(DLNode), "invalid #dbg record location",
+  CheckDI(isa_and_nonnull<DILocation>(DLNode), "invalid #dbg record DILocation",
           &DPV, DLNode);
   DILocation *Loc = DPV.getDebugLoc();
 

diff  --git a/llvm/test/Assembler/dbg-record-invalid-0.ll b/llvm/test/Assembler/dbg-record-invalid-0.ll
new file mode 100644
index 00000000000000..feb513a405f9ec
--- /dev/null
+++ b/llvm/test/Assembler/dbg-record-invalid-0.ll
@@ -0,0 +1,38 @@
+;; Test that we get a parser error when a debug record appears post-terminator.
+;; Note: From the parser's perspective, the error is that the debug record is
+;; appearing at the start of a new unnamed basic block which contains no actual
+;; instructions.
+; RUN: not llvm-as < %s 2>&1 | FileCheck %s
+; ModuleID = '<stdin>'
+source_filename = "<stdin>"
+
+define dso_local i32 @f(i32 %a) !dbg !7 {
+entry:
+  ret i32 %a, !dbg !18
+    #dbg_value(!DIArgList(i32 %a), !12, !DIExpression(), !14)
+; CHECK: <stdin>:[[@LINE+1]]:1: error: expected instruction opcode
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 18.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "print.c", directory: "/tmp")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 5}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{!"clang version 18.0.0"}
+!7 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 3, type: !8, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10, !10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !{!12, !13}
+!12 = !DILocalVariable(name: "a", arg: 1, scope: !7, file: !1, line: 3, type: !10)
+!13 = !DILocalVariable(name: "b", scope: !7, file: !1, line: 3, type: !10)
+!14 = !DILocation(line: 3, column: 15, scope: !7)
+!15 = distinct !DIAssignID()
+!16 = !DILocation(line: 3, column: 20, scope: !7)
+!17 = !DILocation(line: 3, column: 25, scope: !7)
+!18 = !DILocation(line: 3, column: 30, scope: !7)

diff  --git a/llvm/test/Assembler/dbg-record-invalid-1.ll b/llvm/test/Assembler/dbg-record-invalid-1.ll
new file mode 100644
index 00000000000000..7ab5751777e8cf
--- /dev/null
+++ b/llvm/test/Assembler/dbg-record-invalid-1.ll
@@ -0,0 +1,39 @@
+;; Test that we get a parser error when a debug intrinsic appears in the same
+;; module as a debug record.
+; RUN: not llvm-as < %s 2>&1 | FileCheck %s
+; ModuleID = '<stdin>'
+source_filename = "<stdin>"
+
+define dso_local i32 @f(i32 %a) !dbg !7 {
+entry:
+    #dbg_value(!DIArgList(i32 %a), !12, !DIExpression(), !14)
+; CHECK: <stdin>:[[@LINE+1]]:8: error: llvm.dbg intrinsic should not appear in a module using non-intrinsic debug info
+  call void @llvm.dbg.value(metadata i32 %a, metadata !12, metadata !DIExpression()), !dbg !14
+  ret i32 %a, !dbg !18
+}
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 18.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "print.c", directory: "/tmp")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 5}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{!"clang version 18.0.0"}
+!7 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 3, type: !8, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10, !10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !{!12, !13}
+!12 = !DILocalVariable(name: "a", arg: 1, scope: !7, file: !1, line: 3, type: !10)
+!13 = !DILocalVariable(name: "b", scope: !7, file: !1, line: 3, type: !10)
+!14 = !DILocation(line: 3, column: 15, scope: !7)
+!15 = distinct !DIAssignID()
+!16 = !DILocation(line: 3, column: 20, scope: !7)
+!17 = !DILocation(line: 3, column: 25, scope: !7)
+!18 = !DILocation(line: 3, column: 30, scope: !7)

diff  --git a/llvm/test/Assembler/dbg-record-invalid-2.ll b/llvm/test/Assembler/dbg-record-invalid-2.ll
new file mode 100644
index 00000000000000..a019f73feab9c5
--- /dev/null
+++ b/llvm/test/Assembler/dbg-record-invalid-2.ll
@@ -0,0 +1,36 @@
+;; Test that we get a parser error when we have a debug record with an
+;; incorrect number of arguments.
+; RUN: not llvm-as < %s 2>&1 | FileCheck %s
+; ModuleID = '<stdin>'
+source_filename = "<stdin>"
+
+define dso_local i32 @f(i32 %a) !dbg !7 {
+entry:
+; CHECK: <stdin>:[[@LINE+1]]:24: error: expected '!' here
+    #dbg_value(i32 %a, i32 0, !DIExpression(), !14)
+  ret i32 %a, !dbg !18
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 18.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "print.c", directory: "/tmp")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 5}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{!"clang version 18.0.0"}
+!7 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 3, type: !8, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10, !10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !{!12, !13}
+!12 = !DILocalVariable(name: "a", arg: 1, scope: !7, file: !1, line: 3, type: !10)
+!13 = !DILocalVariable(name: "b", scope: !7, file: !1, line: 3, type: !10)
+!14 = !DILocation(line: 3, column: 15, scope: !7)
+!15 = distinct !DIAssignID()
+!16 = !DILocation(line: 3, column: 20, scope: !7)
+!17 = !DILocation(line: 3, column: 25, scope: !7)
+!18 = !DILocation(line: 3, column: 30, scope: !7)

diff  --git a/llvm/test/Assembler/dbg-record-invalid-3.ll b/llvm/test/Assembler/dbg-record-invalid-3.ll
new file mode 100644
index 00000000000000..e6f072373f54d5
--- /dev/null
+++ b/llvm/test/Assembler/dbg-record-invalid-3.ll
@@ -0,0 +1,39 @@
+;; Test that we get a parser error when a debug record appears in the same
+;; module as a debug intrinsic.
+; RUN: not llvm-as < %s 2>&1 | FileCheck %s
+; ModuleID = '<stdin>'
+source_filename = "<stdin>"
+
+define dso_local i32 @f(i32 %a) !dbg !7 {
+entry:
+  call void @llvm.dbg.value(metadata i32 %a, metadata !12, metadata !DIExpression()), !dbg !14
+; CHECK: <stdin>:[[@LINE+1]]:5: error: debug record should not appear in a module containing debug info intrinsics
+    #dbg_value(!DIArgList(i32 %a), !12, !DIExpression(), !14)
+  ret i32 %a, !dbg !18
+}
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 18.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "print.c", directory: "/tmp")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 5}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{!"clang version 18.0.0"}
+!7 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 3, type: !8, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10, !10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !{!12, !13}
+!12 = !DILocalVariable(name: "a", arg: 1, scope: !7, file: !1, line: 3, type: !10)
+!13 = !DILocalVariable(name: "b", scope: !7, file: !1, line: 3, type: !10)
+!14 = !DILocation(line: 3, column: 15, scope: !7)
+!15 = distinct !DIAssignID()
+!16 = !DILocation(line: 3, column: 20, scope: !7)
+!17 = !DILocation(line: 3, column: 25, scope: !7)
+!18 = !DILocation(line: 3, column: 30, scope: !7)

diff  --git a/llvm/test/Assembler/dbg-record-invalid-4.ll b/llvm/test/Assembler/dbg-record-invalid-4.ll
new file mode 100644
index 00000000000000..f898477603c8e2
--- /dev/null
+++ b/llvm/test/Assembler/dbg-record-invalid-4.ll
@@ -0,0 +1,36 @@
+;; Test that we get a parser error when we have a debug record with an invalid
+;; type.
+; RUN: not llvm-as < %s 2>&1 | FileCheck %s
+; ModuleID = '<stdin>'
+source_filename = "<stdin>"
+
+define dso_local i32 @f(i32 %a) !dbg !7 {
+entry:
+; CHECK: <stdin>:[[@LINE+1]]:6: error: expected debug record type here
+    #dbg_invalid(!DIArgList(i32 %a), !12, !DIExpression(), !14)
+  ret i32 %a, !dbg !18
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 18.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "print.c", directory: "/tmp")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 5}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{!"clang version 18.0.0"}
+!7 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 3, type: !8, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10, !10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !{!12, !13}
+!12 = !DILocalVariable(name: "a", arg: 1, scope: !7, file: !1, line: 3, type: !10)
+!13 = !DILocalVariable(name: "b", scope: !7, file: !1, line: 3, type: !10)
+!14 = !DILocation(line: 3, column: 15, scope: !7)
+!15 = distinct !DIAssignID()
+!16 = !DILocation(line: 3, column: 20, scope: !7)
+!17 = !DILocation(line: 3, column: 25, scope: !7)
+!18 = !DILocation(line: 3, column: 30, scope: !7)

diff  --git a/llvm/test/Assembler/dbg-record-invalid-5.ll b/llvm/test/Assembler/dbg-record-invalid-5.ll
new file mode 100644
index 00000000000000..5ea588b87668c4
--- /dev/null
+++ b/llvm/test/Assembler/dbg-record-invalid-5.ll
@@ -0,0 +1,35 @@
+;; Test that we get a parser error when a basic block contains only a debug
+;; record.
+; RUN: not llvm-as < %s 2>&1 | FileCheck %s
+; ModuleID = '<stdin>'
+source_filename = "<stdin>"
+
+define dso_local i32 @f(i32 %a) !dbg !7 {
+entry:
+    #dbg_value(!DIArgList(i32 %a), !12, !DIExpression(), !14)
+; CHECK: <stdin>:[[@LINE+1]]:1: error: expected instruction opcode
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 18.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "print.c", directory: "/tmp")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 5}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{!"clang version 18.0.0"}
+!7 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 3, type: !8, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10, !10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !{!12, !13}
+!12 = !DILocalVariable(name: "a", arg: 1, scope: !7, file: !1, line: 3, type: !10)
+!13 = !DILocalVariable(name: "b", scope: !7, file: !1, line: 3, type: !10)
+!14 = !DILocation(line: 3, column: 15, scope: !7)
+!15 = distinct !DIAssignID()
+!16 = !DILocation(line: 3, column: 20, scope: !7)
+!17 = !DILocation(line: 3, column: 25, scope: !7)
+!18 = !DILocation(line: 3, column: 30, scope: !7)

diff  --git a/llvm/test/Assembler/dbg-record-invalid-6.ll b/llvm/test/Assembler/dbg-record-invalid-6.ll
new file mode 100644
index 00000000000000..72dafcdb97fce4
--- /dev/null
+++ b/llvm/test/Assembler/dbg-record-invalid-6.ll
@@ -0,0 +1,36 @@
+;; Test that we get a parser error when we have a debug record with an
+;; incorrect number of arguments.
+; RUN: not llvm-as < %s 2>&1 | FileCheck %s
+; ModuleID = '<stdin>'
+source_filename = "<stdin>"
+
+define dso_local i32 @f(i32 %a) !dbg !7 {
+entry:
+; CHECK: <stdin>:[[@LINE+1]]:46: error: expected '!' here
+    #dbg_value(i32 %a, !12, !DIExpression(), i32 0)
+  ret i32 %a, !dbg !18
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 18.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "print.c", directory: "/tmp")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 5}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{!"clang version 18.0.0"}
+!7 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 3, type: !8, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10, !10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !{!12, !13}
+!12 = !DILocalVariable(name: "a", arg: 1, scope: !7, file: !1, line: 3, type: !10)
+!13 = !DILocalVariable(name: "b", scope: !7, file: !1, line: 3, type: !10)
+!14 = !DILocation(line: 3, column: 15, scope: !7)
+!15 = distinct !DIAssignID()
+!16 = !DILocation(line: 3, column: 20, scope: !7)
+!17 = !DILocation(line: 3, column: 25, scope: !7)
+!18 = !DILocation(line: 3, column: 30, scope: !7)

diff  --git a/llvm/test/Assembler/dbg-record-invalid-7.ll b/llvm/test/Assembler/dbg-record-invalid-7.ll
new file mode 100644
index 00000000000000..036a85a2977fc7
--- /dev/null
+++ b/llvm/test/Assembler/dbg-record-invalid-7.ll
@@ -0,0 +1,36 @@
+;; Test that we get a parser error when we have a debug record with an incorrect
+;; number of arguments.
+; RUN: not llvm-as < %s 2>&1 | FileCheck %s
+; ModuleID = '<stdin>'
+source_filename = "<stdin>"
+
+define dso_local i32 @f(i32 %a) !dbg !7 {
+entry:
+; CHECK: <stdin>:[[@LINE+1]]:44: error: Expected ',' here
+    #dbg_value(i32 %a, !12, !DIExpression())
+  ret i32 %a, !dbg !18
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 18.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "print.c", directory: "/tmp")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 5}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{!"clang version 18.0.0"}
+!7 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 3, type: !8, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10, !10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !{!12, !13}
+!12 = !DILocalVariable(name: "a", arg: 1, scope: !7, file: !1, line: 3, type: !10)
+!13 = !DILocalVariable(name: "b", scope: !7, file: !1, line: 3, type: !10)
+!14 = !DILocation(line: 3, column: 15, scope: !7)
+!15 = distinct !DIAssignID()
+!16 = !DILocation(line: 3, column: 20, scope: !7)
+!17 = !DILocation(line: 3, column: 25, scope: !7)
+!18 = !DILocation(line: 3, column: 30, scope: !7)

diff  --git a/llvm/test/Assembler/dbg-record-invalid-8.ll b/llvm/test/Assembler/dbg-record-invalid-8.ll
new file mode 100644
index 00000000000000..d0b8f36d7895c5
--- /dev/null
+++ b/llvm/test/Assembler/dbg-record-invalid-8.ll
@@ -0,0 +1,36 @@
+;; Test that we get a parser error when we have a debug assign record with an
+;; incorrect number of arguments.
+; RUN: not llvm-as < %s 2>&1 | FileCheck %s
+; ModuleID = '<stdin>'
+source_filename = "<stdin>"
+
+define dso_local i32 @f(i32 %a) !dbg !7 {
+entry:
+; CHECK: <stdin>:[[@LINE+1]]:50: error: Expected ',' here
+    #dbg_assign(i32 %a, !12, !DIExpression(), !14)
+  ret i32 %a, !dbg !18
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 18.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "print.c", directory: "/tmp")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 5}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{!"clang version 18.0.0"}
+!7 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 3, type: !8, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10, !10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !{!12, !13}
+!12 = !DILocalVariable(name: "a", arg: 1, scope: !7, file: !1, line: 3, type: !10)
+!13 = !DILocalVariable(name: "b", scope: !7, file: !1, line: 3, type: !10)
+!14 = !DILocation(line: 3, column: 15, scope: !7)
+!15 = distinct !DIAssignID()
+!16 = !DILocation(line: 3, column: 20, scope: !7)
+!17 = !DILocation(line: 3, column: 25, scope: !7)
+!18 = !DILocation(line: 3, column: 30, scope: !7)

diff  --git a/llvm/test/DebugInfo/roundtrip-non-instruction-debug-info.ll b/llvm/test/DebugInfo/roundtrip-non-instruction-debug-info.ll
new file mode 100644
index 00000000000000..b15b76d1690c41
--- /dev/null
+++ b/llvm/test/DebugInfo/roundtrip-non-instruction-debug-info.ll
@@ -0,0 +1,94 @@
+;; Test that we can write in the old debug info format.
+; RUN: opt --passes=verify -S --write-experimental-debuginfo=false < %s \
+; RUN:   | FileCheck %s --check-prefixes=CHECK,OLDDBG --implicit-check-not=llvm.dbg --implicit-check-not=#dbg
+
+;; Test that we can write in the new debug info format...
+; RUN: opt --passes=verify -S --write-experimental-debuginfo=true < %s \
+; RUN:   | FileCheck %s --check-prefixes=CHECK,NEWDBG --implicit-check-not=llvm.dbg --implicit-check-not=#dbg
+
+;; ...and then read the new format and write the old format.
+; RUN: opt --passes=verify -S --write-experimental-debuginfo=true < %s \
+; RUN:   | opt --passes=verify -S --write-experimental-debuginfo=false \
+; RUN:   | FileCheck %s --check-prefixes=CHECK,OLDDBG  --implicit-check-not=llvm.dbg --implicit-check-not=#dbg
+
+;; Test also that the new flag is independent of the flag that enables use of
+;; these non-instruction debug info during LLVM passes.
+; RUN: opt --passes=verify -S --try-experimental-debuginfo-iterators --write-experimental-debuginfo=false < %s \
+; RUN:   | FileCheck %s --check-prefixes=CHECK,OLDDBG --implicit-check-not=llvm.dbg --implicit-check-not=#dbg
+; RUN: opt --passes=verify -S --try-experimental-debuginfo-iterators --write-experimental-debuginfo=true < %s \
+; RUN:   | FileCheck %s --check-prefixes=CHECK,NEWDBG --implicit-check-not=llvm.dbg --implicit-check-not=#dbg
+
+; CHECK: @f(i32 %[[VAL_A:[0-9a-zA-Z]+]])
+; CHECK-NEXT: entry:
+; OLDDBG-NEXT: call void @llvm.dbg.value(metadata i32 %[[VAL_A]], metadata ![[VAR_A:[0-9]+]], metadata !DIExpression()), !dbg ![[LOC_1:[0-9]+]]
+; NEWDBG-NEXT: {{^}}    #dbg_value(i32 %[[VAL_A]], ![[VAR_A:[0-9]+]], !DIExpression(), ![[LOC_1:[0-9]+]])
+; CHECK-NEXT: {{^}}  %[[VAL_B:[0-9a-zA-Z]+]] = alloca
+; OLDDBG-NEXT: call void @llvm.dbg.declare(metadata ptr %[[VAL_B]], metadata ![[VAR_B:[0-9]+]], metadata !DIExpression()), !dbg ![[LOC_2:[0-9]+]]
+; NEWDBG-NEXT: {{^}}    #dbg_declare(ptr %[[VAL_B]], ![[VAR_B:[0-9]+]], !DIExpression(), ![[LOC_2:[0-9]+]])
+; CHECK-NEXT: {{^}}  %[[VAL_ADD:[0-9a-zA-Z]+]] = add i32 %[[VAL_A]], 5
+; OLDDBG-NEXT: call void @llvm.dbg.value(metadata !DIArgList(i32 %[[VAL_A]], i32 %[[VAL_ADD]]), metadata ![[VAR_A]], metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus)), !dbg ![[LOC_3:[0-9]+]]
+; NEWDBG-NEXT: {{^}}    #dbg_value(!DIArgList(i32 %[[VAL_A]], i32 %[[VAL_ADD]]), ![[VAR_A]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus), ![[LOC_3:[0-9]+]])
+; OLDDBG-NEXT: call void @llvm.dbg.label(metadata ![[LABEL_ID:[0-9]+]]), !dbg ![[LOC_3]]
+; NEWDBG-NEXT: {{^}}    #dbg_label(![[LABEL_ID:[0-9]+]], ![[LOC_3]])
+; CHECK-NEXT: {{^}}  store i32 %[[VAL_ADD]]{{.+}}, !DIAssignID ![[ASSIGNID:[0-9]+]]
+; OLDDBG-NEXT: call void @llvm.dbg.assign(metadata i32 %[[VAL_ADD]], metadata ![[VAR_B]], metadata !DIExpression(), metadata ![[ASSIGNID]], metadata ptr %[[VAL_B]], metadata !DIExpression()), !dbg ![[LOC_4:[0-9]+]]
+; NEWDBG-NEXT: {{^}}    #dbg_assign(i32 %[[VAL_ADD]], ![[VAR_B]], !DIExpression(), ![[ASSIGNID]], ptr %[[VAL_B]], !DIExpression(), ![[LOC_4:[0-9]+]])
+; CHECK-NEXT: {{^}}  ret i32
+
+; OLDDBG-DAG: declare void @llvm.dbg.value
+; OLDDBG-DAG: declare void @llvm.dbg.declare
+; OLDDBG-DAG: declare void @llvm.dbg.assign
+; OLDDBG-DAG: declare void @llvm.dbg.label
+
+; CHECK-DAG: llvm.dbg.cu
+; CHECK-DAG: ![[VAR_A]] = !DILocalVariable(name: "a"
+; CHECK-DAG: ![[VAR_B]] = !DILocalVariable(name: "b"
+; CHECK-DAG: ![[LOC_1]] = !DILocation(line: 3, column: 15
+; CHECK-DAG: ![[LOC_2]] = !DILocation(line: 3, column: 20
+; CHECK-DAG: ![[LOC_3]] = !DILocation(line: 3, column: 25
+; CHECK-DAG: ![[LOC_4]] = !DILocation(line: 3, column: 30
+; CHECK-DAG: ![[LABEL_ID]] = !DILabel(
+
+define dso_local i32 @f(i32 %a) !dbg !7 {
+entry:
+  call void @llvm.dbg.value(metadata i32 %a, metadata !20, metadata !DIExpression()), !dbg !30
+  %b = alloca i32, !dbg !30, !DIAssignID !40
+  call void @llvm.dbg.declare(metadata ptr %b, metadata !21, metadata !DIExpression()), !dbg !31
+  %add = add i32 %a, 5, !dbg !31
+  call void @llvm.dbg.value(metadata !DIArgList(i32 %a, i32 %add), metadata !20, metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus)), !dbg !32
+  call void @llvm.dbg.label(metadata !50), !dbg !32
+  store i32 %add, ptr %b, !dbg !32, !DIAssignID !40
+  call void @llvm.dbg.assign(metadata i32 %add, metadata !21, metadata !DIExpression(), metadata !40, metadata ptr %b, metadata !DIExpression()), !dbg !33
+  ret i32 %add, !dbg !33
+
+}
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+declare void @llvm.dbg.declare(metadata, metadata, metadata)
+declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata)
+declare void @llvm.dbg.label(metadata)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 18.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "print.c", directory: "/tmp")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 5}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{!"clang version 18.0.0"}
+!7 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 3, type: !8, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !13)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!12, !12}
+!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!13 = !{!20, !21}
+!20 = !DILocalVariable(name: "a", arg: 1, scope: !7, file: !1, line: 3, type: !12)
+!21 = !DILocalVariable(name: "b", scope: !7, file: !1, line: 3, type: !12)
+!30 = !DILocation(line: 3, column: 15, scope: !7)
+!31 = !DILocation(line: 3, column: 20, scope: !7)
+!32 = !DILocation(line: 3, column: 25, scope: !7)
+!33 = !DILocation(line: 3, column: 30, scope: !7)
+!40 = distinct !DIAssignID()
+!50 = !DILabel(scope: !7, name: "label", file: !1, line: 3)
\ No newline at end of file

diff  --git a/llvm/test/Verifier/RemoveDI/blockbyref.ll b/llvm/test/Verifier/RemoveDI/blockbyref.ll
new file mode 100644
index 00000000000000..86321a6ae78e80
--- /dev/null
+++ b/llvm/test/Verifier/RemoveDI/blockbyref.ll
@@ -0,0 +1,18 @@
+; RUN: llvm-as -disable-output <%s 2>&1| FileCheck %s
+
+; CHECK: DIBlockByRefStruct on DICompositeType is no longer supported
+; CHECK: warning: ignoring invalid debug info
+
+define void @foo() {
+entry:
+  %s = alloca i32
+    #dbg_declare(ptr %s, !2, !DIExpression(), !DILocation(scope: !1))
+  ret void
+}
+
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+!1 = distinct !DISubprogram()
+!2 = !DILocalVariable(scope: !1, type: !3)
+!3 = !DICompositeType(tag: DW_TAG_structure_type, flags: DIFlagReservedBit4)

diff  --git a/llvm/test/Verifier/RemoveDI/dbg-invalid-vector.ll b/llvm/test/Verifier/RemoveDI/dbg-invalid-vector.ll
new file mode 100644
index 00000000000000..0832c361c3080e
--- /dev/null
+++ b/llvm/test/Verifier/RemoveDI/dbg-invalid-vector.ll
@@ -0,0 +1,35 @@
+; RUN: opt -passes=verify -disable-output <%s 2>&1 | FileCheck %s
+;
+; This test creates an invalid vector by defining multiple elements for the
+; vector's DICompositeType definition.  A vector should only have one element
+; in its DICompositeType 'elements' array.
+;
+; CHECK: invalid vector
+
+ at f.foo = private unnamed_addr constant <6 x float> zeroinitializer, align 32
+
+define void @f() {
+  %1 = alloca <6 x float>, align 32
+    #dbg_declare(ptr %1, !10, !DIExpression(), !18)
+  ret void
+}
+
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "test.c", directory: "/dbg/info")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!7 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 3, type: !8, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)
+!8 = !DISubroutineType(types: !9)
+!9 = !{null}
+!10 = !DILocalVariable(name: "foo", scope: !7, file: !1, line: 4, type: !12)
+!12 = !DICompositeType(tag: DW_TAG_array_type, baseType: !13, size: 256, flags: DIFlagVector, elements: !14)
+!13 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float)
+!14 = !{!15, !19}
+!15 = !DISubrange(count: 6)
+!18 = !DILocation(line: 4, column: 48, scope: !7)
+!19 = !DISubrange(count: 42)

diff  --git a/llvm/test/Verifier/RemoveDI/di-subroutine-localvar.ll b/llvm/test/Verifier/RemoveDI/di-subroutine-localvar.ll
new file mode 100644
index 00000000000000..14e58883989968
--- /dev/null
+++ b/llvm/test/Verifier/RemoveDI/di-subroutine-localvar.ll
@@ -0,0 +1,41 @@
+; RUN: opt %s -passes=verify 2>&1 | FileCheck %s
+; CHECK: invalid type
+; CHECK: !20 = !DILocalVariable(name: "f", scope: !21, file: !13, line: 970, type: !14)
+; CHECK: !14 = !DISubroutineType(types: !15)
+
+
+%timespec.0.1.2.3.0.1.2 = type { i64, i64 }
+define internal i64 @init_vdso_clock_gettime(i32, ptr nonnull) unnamed_addr !dbg !142 {
+    #dbg_value(ptr null, !162, !DIExpression(), !167)
+  ret i64 -38, !dbg !168
+}
+!llvm.module.flags = !{!0}
+!llvm.dbg.cu = !{!1}
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+!1 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, producer: "zig 0.3.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !3, globals: !76)
+!2 = !DIFile(filename: "test", directory: ".")
+!3 = !{!4}
+!4 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "Arch", scope: !5, file: !5, line: 44, baseType: !6, size: 8, align: 8, elements: !7)
+!5 = !DIFile(filename: "builtin.zig", directory: "/home/andy/.local/share/zig/stage1/builtin/ugMGxVES9OkDAffv3xhJS3KQVy0Wm1xPM3Bc6x4MBuup5aetdi5pVTrGRG2aDAn0")
+!6 = !DIBasicType(name: "u7", size: 8, encoding: DW_ATE_unsigned)
+!7 = !{!8}
+!8 = !DIEnumerator(name: "armv8_5a", value: 0)
+!76 = !{!77}
+!77 = !DIGlobalVariableExpression(var: !78, expr: !DIExpression())
+!78 = distinct !DIGlobalVariable(name: "arch", linkageName: "arch", scope: !5, file: !5, line: 437, type: !4, isLocal: true, isDefinition: true)
+!81 = !DIFile(filename: "index.zig", directory: "/store/dev/zig/build-llvm8-debug/lib/zig/std/os/linux")
+!142 = distinct !DISubprogram(name: "init_vdso_clock_gettime", scope: !81, file: !81, line: 968, type: !143, scopeLine: 968, flags: DIFlagStaticMember, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !1, retainedNodes: !153)
+!143 = !DISubroutineType(types: !144)
+!144 = !{!145}
+!145 = !DIBasicType(name: "usize", size: 64, encoding: DW_ATE_unsigned)
+!146 = !DIBasicType(name: "i32", size: 32, encoding: DW_ATE_signed)
+!153 = !{!154}
+!154 = !DILocalVariable(name: "clk", arg: 1, scope: !142, file: !81, line: 968, type: !146)
+!162 = !DILocalVariable(name: "f", scope: !163, file: !81, line: 970, type: !143)
+!163 = distinct !DILexicalBlock(scope: !164, file: !81, line: 969, column: 5)
+!164 = distinct !DILexicalBlock(scope: !165, file: !81, line: 968, column: 66)
+!165 = distinct !DILexicalBlock(scope: !166, file: !81, line: 968, column: 45)
+!166 = distinct !DILexicalBlock(scope: !142, file: !81, line: 968, column: 35)
+!167 = !DILocation(line: 970, column: 5, scope: !163)
+!168 = !DILocation(line: 972, column: 28, scope: !169)
+!169 = distinct !DILexicalBlock(scope: !163, file: !81, line: 970, column: 5)

diff  --git a/llvm/test/Verifier/RemoveDI/diexpression-entry-value-llvm-ir.ll b/llvm/test/Verifier/RemoveDI/diexpression-entry-value-llvm-ir.ll
new file mode 100644
index 00000000000000..881ec4a86fb644
--- /dev/null
+++ b/llvm/test/Verifier/RemoveDI/diexpression-entry-value-llvm-ir.ll
@@ -0,0 +1,34 @@
+; RUN: llvm-as -disable-output <%s 2>&1| FileCheck %s
+
+; CHECK-NOT: #dbg_value
+; CHECK: Entry values are only allowed in MIR unless they target a swiftasync Argument
+; CHECK: #dbg_value(i32 %param, !{{.*}}, !DIExpression(DW_OP_LLVM_entry_value, 1)
+; CHECK-NOT: #dbg_value
+; CHECK-NOT: Entry values are only allowed
+; CHECK: warning: ignoring invalid debug info
+
+define void @foo(i32 %param, ptr swiftasync %ok_param) !dbg !4 {
+entry:
+    #dbg_value(i32 %param, !8, !DIExpression(DW_OP_LLVM_entry_value, 1), !9)
+    #dbg_value(ptr %ok_param, !8, !DIExpression(DW_OP_LLVM_entry_value, 1), !9)
+    #dbg_value(ptr poison, !8, !DIExpression(DW_OP_LLVM_entry_value, 1), !9)
+    #dbg_value(ptr undef, !8, !DIExpression(DW_OP_LLVM_entry_value, 1), !9)
+  ret void
+}
+
+
+attributes #0 = { nounwind readnone speculatable willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, emissionKind: FullDebug)
+!1 = !DIFile(filename: "a.c", directory: "/")
+!2 = !{i32 2, !"Dwarf Version", i32 4}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, type: !5, unit: !0)
+!5 = !DISubroutineType(types: !6)
+!6 = !{null, !7}
+!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!8 = !DILocalVariable(name: "param", arg: 1, scope: !4, file: !1, type: !7)
+!9 = !DILocation(line: 0, scope: !4)

diff  --git a/llvm/test/Verifier/RemoveDI/fnarg-debuginfo.ll b/llvm/test/Verifier/RemoveDI/fnarg-debuginfo.ll
new file mode 100644
index 00000000000000..db1a9a8ba18945
--- /dev/null
+++ b/llvm/test/Verifier/RemoveDI/fnarg-debuginfo.ll
@@ -0,0 +1,26 @@
+; RUN: llvm-as -disable-output < %s -o /dev/null 2>&1 | FileCheck %s
+
+
+define void @foo() !dbg !2 {
+entry:
+  %a = alloca i32
+  ; CHECK: conflicting debug info for argument
+    #dbg_value(i32 0, !3, !DIExpression(), !6)
+    #dbg_declare(ptr %a, !4, !DIExpression(), !6)
+  ret void, !dbg !6
+}
+
+; CHECK: warning: ignoring invalid debug info
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", emissionKind: FullDebug)
+!1 = !DIFile(filename: "x.c", directory: "/")
+!2 = distinct !DISubprogram(name: "foo", scope: !0, isDefinition: true, unit: !0)
+!3 = !DILocalVariable(name: "a", arg: 1, scope: !2, file: !1, line: 1, type: !5)
+!4 = !DILocalVariable(name: "b", arg: 1, scope: !2, file: !1, line: 1, type: !5)
+!5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!6 = !DILocation(line: 1, scope: !2)
+!7 = !{i32 2, !"Dwarf Version", i32 4}
+!8 = !{i32 1, !"Debug Info Version", i32 3}

diff  --git a/llvm/test/Verifier/RemoveDI/fnarg-nodebug.ll b/llvm/test/Verifier/RemoveDI/fnarg-nodebug.ll
new file mode 100644
index 00000000000000..f5526030278eb9
--- /dev/null
+++ b/llvm/test/Verifier/RemoveDI/fnarg-nodebug.ll
@@ -0,0 +1,58 @@
+; RUN: llvm-as < %s -o %t
+; RUN: llvm-dis < %t -o - | FileCheck %s
+; Created at -O1 from:
+; int sink(int);
+; __attribute__((always_inline)) int f(int i) { return sink(i); }
+; __attribute__((always_inline)) int g(int j) { return sink(j); }
+; __attribute__((nodebug)) int nodebug(int k) { return f(k)+g(k); }
+source_filename = "t.c"
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.12.0"
+
+declare i32 @sink(i32) local_unnamed_addr
+
+define i32 @nodebug(i32 %k) local_unnamed_addr #2 {
+entry:
+; This should not set off the FnArg Verifier. The two variables are in 
diff errent scopes.
+    #dbg_value(i32 %k, !12, !13, !14)
+  %call.k = tail call i32 @sink(i32 %k) #4, !dbg !15
+    #dbg_value(i32 %k, !19, !13, !20)
+  %call.k3 = tail call i32 @sink(i32 %k) #4, !dbg !21
+  %add = add nsw i32 %call.k3, %call.k
+  ret i32 %add
+}
+
+; Function Attrs: nounwind readnone
+
+attributes #2 = { nounwind ssp uwtable }
+attributes #3 = { nounwind readnone }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 5.0.0 (trunk 297153) (llvm/trunk 297155)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "t.c", directory: "/tmp")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"PIC Level", i32 2}
+!6 = !{!"clang version 5.0.0 (trunk 297153) (llvm/trunk 297155)"}
+!7 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 2, type: !8, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !11)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10, !10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !{!12}
+; CHECK: !DILocalVariable(name: "i", arg: 1
+!12 = !DILocalVariable(name: "i", arg: 1, scope: !7, file: !1, line: 2, type: !10)
+!13 = !DIExpression()
+!14 = !DILocation(line: 2, column: 42, scope: !7)
+!15 = !DILocation(line: 2, column: 54, scope: !7)
+!16 = !DILocation(line: 2, column: 47, scope: !7)
+!17 = distinct !DISubprogram(name: "g", scope: !1, file: !1, line: 3, type: !8, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !18)
+!18 = !{!19}
+; CHECK: !DILocalVariable(name: "j", arg: 1
+!19 = !DILocalVariable(name: "j", arg: 1, scope: !17, file: !1, line: 3, type: !10)
+!20 = !DILocation(line: 3, column: 42, scope: !17)
+!21 = !DILocation(line: 3, column: 54, scope: !17)
+!22 = !DILocation(line: 3, column: 47, scope: !17)

diff  --git a/llvm/test/Verifier/RemoveDI/invalid-disubrange-count-node.ll b/llvm/test/Verifier/RemoveDI/invalid-disubrange-count-node.ll
new file mode 100644
index 00000000000000..f36cee5946e473
--- /dev/null
+++ b/llvm/test/Verifier/RemoveDI/invalid-disubrange-count-node.ll
@@ -0,0 +1,36 @@
+; RUN: llvm-as < %s -disable-output 2>&1 | FileCheck %s
+
+define void @foo(i32 %n) {
+entry:
+  %0 = zext i32 %n to i64
+  %vla = alloca i32, i64 %0, align 16
+    #dbg_declare(ptr %vla, !19, !DIExpression(), !18)
+  ret void
+}
+
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 5.0.1", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "vla.c", directory: "/path/to")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{!"clang version 5.0.1"}
+!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 20, type: !8, isLocal: false, isDefinition: true, scopeLine: 20, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !11)
+!8 = !DISubroutineType(types: !9)
+!9 = !{null, !10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !{!16, !19}
+!12 = !DIExpression()
+!16 = !DILocalVariable(name: "vla_expr", scope: !7, file: !1, line: 21, type: !17)
+!17 = !DIBasicType(name: "long unsigned int", size: 64, encoding: DW_ATE_unsigned)
+!18 = !DILocation(line: 21, column: 7, scope: !7)
+!19 = !DILocalVariable(name: "vla", scope: !7, file: !1, line: 21, type: !20)
+!20 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, align: 32, elements: !21)
+!21 = !{!22}
+; CHECK: Count must be signed constant or DIVariable or DIExpression
+!22 = !DISubrange(count: !17)

diff  --git a/llvm/test/Verifier/RemoveDI/llvm.dbg.declare-address.ll b/llvm/test/Verifier/RemoveDI/llvm.dbg.declare-address.ll
new file mode 100644
index 00000000000000..9d400b892ce8c1
--- /dev/null
+++ b/llvm/test/Verifier/RemoveDI/llvm.dbg.declare-address.ll
@@ -0,0 +1,16 @@
+; RUN: llvm-as -disable-output <%s 2>&1 | FileCheck %s
+; CHECK: invalid #dbg record address/value
+; CHECK-NEXT: #dbg_declare({{.*}})
+; CHECK-NEXT: !""
+; CHECK: warning: ignoring invalid debug info
+
+define void @foo(i32 %a) {
+entry:
+  %s = alloca i32
+    #dbg_declare(!"", !DILocalVariable(scope: !1), !DIExpression(), !DILocation(scope: !1))
+  ret void
+}
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+!1 = distinct !DISubprogram()

diff  --git a/llvm/test/Verifier/RemoveDI/llvm.dbg.declare-expression.ll b/llvm/test/Verifier/RemoveDI/llvm.dbg.declare-expression.ll
new file mode 100644
index 00000000000000..b52c15cb3f8816
--- /dev/null
+++ b/llvm/test/Verifier/RemoveDI/llvm.dbg.declare-expression.ll
@@ -0,0 +1,16 @@
+; RUN: llvm-as -disable-output <%s 2>&1 | FileCheck %s
+; CHECK: invalid #dbg record expression
+; CHECK-NEXT: #dbg_declare({{.*}})
+; CHECK-NEXT: !{}
+; CHECK: warning: ignoring invalid debug info
+
+define void @foo(i32 %a) {
+entry:
+  %s = alloca i32
+    #dbg_declare(ptr %s, !DILocalVariable(scope: !1), !{}, !DILocation(scope: !1))
+  ret void
+}
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+!1 = distinct !DISubprogram()

diff  --git a/llvm/test/Verifier/RemoveDI/llvm.dbg.declare-variable.ll b/llvm/test/Verifier/RemoveDI/llvm.dbg.declare-variable.ll
new file mode 100644
index 00000000000000..db2b0e0a54e2bd
--- /dev/null
+++ b/llvm/test/Verifier/RemoveDI/llvm.dbg.declare-variable.ll
@@ -0,0 +1,17 @@
+; RUN: llvm-as -disable-output <%s 2>&1 | FileCheck %s
+; CHECK: invalid #dbg record variable
+; CHECK-NEXT: #dbg_declare({{.*}})
+; CHECK-NEXT: !{}
+; CHECK: warning: ignoring invalid debug info
+
+define void @foo(i32 %a) {
+entry:
+  %s = alloca i32
+    #dbg_declare(ptr %s, !{}, !DIExpression(), !DILocation(scope: !1))
+  ret void
+}
+
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+!1 = distinct !DISubprogram()

diff  --git a/llvm/test/Verifier/RemoveDI/llvm.dbg.intrinsic-dbg-attachment.ll b/llvm/test/Verifier/RemoveDI/llvm.dbg.intrinsic-dbg-attachment.ll
new file mode 100644
index 00000000000000..1839821ab14070
--- /dev/null
+++ b/llvm/test/Verifier/RemoveDI/llvm.dbg.intrinsic-dbg-attachment.ll
@@ -0,0 +1,55 @@
+; RUN: llvm-as -disable-output <%s 2>&1 | FileCheck %s
+define void @foo() {
+entry:
+    #dbg_value(
+      ptr undef,
+      !DILocalVariable(scope: !1),
+      !DIExpression(),
+      !{})
+; CHECK-LABEL: invalid #dbg record DILocation
+; CHECK-NEXT: #dbg_value({{.*}})
+
+    #dbg_declare(
+      ptr undef,
+      !DILocalVariable(scope: !1),
+      !DIExpression(),
+      !{})
+; CHECK-LABEL: invalid #dbg record DILocation
+; CHECK-NEXT: #dbg_declare({{.*}})
+
+    #dbg_value(
+      ptr undef,
+      !DILocalVariable(scope: !1),
+      !DIExpression(),
+      !DILocation(scope: !2))
+; CHECK-LABEL: mismatched subprogram between #dbg record variable and DILocation
+; CHECK-NEXT: #dbg_value({{[^,]+}}, ![[VAR:[0-9]+]], {{[^,]+}}, ![[LOC:[0-9]+]]
+; CHECK-NEXT: label %entry
+; CHECK-NEXT: ptr @foo
+; CHECK-NEXT: ![[VAR]] = !DILocalVariable({{.*}}scope: ![[VARSP:[0-9]+]]
+; CHECK-NEXT: ![[VARSP]] = distinct !DISubprogram(
+; CHECK-NEXT: ![[LOC]] = !DILocation({{.*}}scope: ![[LOCSP:[0-9]+]]
+; CHECK-NEXT: ![[LOCSP]] = distinct !DISubprogram(
+
+    #dbg_declare(
+      ptr undef,
+      !DILocalVariable(scope: !1),
+      !DIExpression(),
+      !DILocation(scope: !2))
+; CHECK-LABEL: mismatched subprogram between #dbg record variable and DILocation
+; CHECK-NEXT: #dbg_declare({{[^,]+}}, ![[VAR:[0-9]+]], {{.*[^,]+}}, ![[LOC:[0-9]+]]
+; CHECK-NEXT: label %entry
+; CHECK-NEXT: ptr @foo
+; CHECK-NEXT: ![[VAR]] = !DILocalVariable({{.*}}scope: ![[VARSP:[0-9]+]]
+; CHECK-NEXT: ![[VARSP]] = distinct !DISubprogram(
+; CHECK-NEXT: ![[LOC]] = !DILocation({{.*}}scope: ![[LOCSP:[0-9]+]]
+; CHECK-NEXT: ![[LOCSP]] = distinct !DISubprogram(
+
+  ret void
+}
+
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+!1 = distinct !DISubprogram(name: "foo")
+!2 = distinct !DISubprogram(name: "bar")

diff  --git a/llvm/test/Verifier/RemoveDI/llvm.dbg.value-expression.ll b/llvm/test/Verifier/RemoveDI/llvm.dbg.value-expression.ll
new file mode 100644
index 00000000000000..cbd93c1ce6a4d6
--- /dev/null
+++ b/llvm/test/Verifier/RemoveDI/llvm.dbg.value-expression.ll
@@ -0,0 +1,16 @@
+; RUN: llvm-as -disable-output <%s 2>&1 | FileCheck %s
+; CHECK: invalid #dbg record expression
+; CHECK-NEXT: #dbg_value({{.*}})
+; CHECK-NEXT: !{}
+; CHECK: warning: ignoring invalid debug info
+
+define void @foo(i32 %a) {
+entry:
+  %s = alloca i32
+    #dbg_value(ptr %s, !DILocalVariable(scope: !1), !{}, !DILocation(scope: !1))
+  ret void
+}
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+!1 = distinct !DISubprogram()

diff  --git a/llvm/test/Verifier/RemoveDI/llvm.dbg.value-value.ll b/llvm/test/Verifier/RemoveDI/llvm.dbg.value-value.ll
new file mode 100644
index 00000000000000..b6fcde250526be
--- /dev/null
+++ b/llvm/test/Verifier/RemoveDI/llvm.dbg.value-value.ll
@@ -0,0 +1,17 @@
+; RUN: llvm-as -disable-output <%s 2>&1 | FileCheck %s
+; CHECK: invalid #dbg record address/value
+; CHECK-NEXT: #dbg_value({{.*}})
+; CHECK-NEXT: !""
+; CHECK: warning: ignoring invalid debug info
+
+define void @foo(i32 %a) {
+entry:
+  %s = alloca i32
+    #dbg_value(!"", !DILocalVariable(scope: !1), !DIExpression(), !DILocation(scope: !1))
+  ret void
+}
+
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+!1 = distinct !DISubprogram()

diff  --git a/llvm/test/Verifier/RemoveDI/llvm.dbg.value-variable.ll b/llvm/test/Verifier/RemoveDI/llvm.dbg.value-variable.ll
new file mode 100644
index 00000000000000..0a5fe79453d721
--- /dev/null
+++ b/llvm/test/Verifier/RemoveDI/llvm.dbg.value-variable.ll
@@ -0,0 +1,17 @@
+; RUN: llvm-as -disable-output <%s 2>&1 | FileCheck %s
+; CHECK: invalid #dbg record variable
+; CHECK-NEXT: #dbg_value({{.*}})
+; CHECK-NEXT: !{}
+; CHECK: warning: ignoring invalid debug info
+
+define void @foo(i32 %a) {
+entry:
+  %s = alloca i32
+    #dbg_value(ptr %s, !{}, !DIExpression(), !DILocation(scope: !1))
+  ret void
+}
+
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+!1 = distinct !DISubprogram()

diff  --git a/llvm/test/Verifier/RemoveDI/set1.ll b/llvm/test/Verifier/RemoveDI/set1.ll
new file mode 100644
index 00000000000000..d54ba8876c366c
--- /dev/null
+++ b/llvm/test/Verifier/RemoveDI/set1.ll
@@ -0,0 +1,62 @@
+; RUN: llvm-as -disable-output <%s 2>&1 | FileCheck %s
+
+define void @Main__Test() #0 !dbg !17 {
+entry:
+  %as = alloca i64, align 8
+  %bs = alloca i64, align 8
+  br label %second, !dbg !21
+
+second:                                           ; preds = %entry
+    #dbg_declare(ptr %as, !22, !DIExpression(), !25)
+    #dbg_declare(ptr %bs, !26, !DIExpression(), !25)
+  store i64 36028797018972298, ptr %as, align 8, !dbg !28
+  store i64 85, ptr %bs, align 8, !dbg !29
+  ret void, !dbg !21
+}
+
+; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
+
+!llvm.ident = !{!0}
+!llvm.dbg.cu = !{!1}
+!llvm.module.flags = !{!14, !15, !16}
+
+!0 = !{!"versions- cm3: d5.10.0 llvm: 12.0"}
+!1 = distinct !DICompileUnit(language: DW_LANG_Modula3, file: !2, producer: "cm3", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !3)
+!2 = !DIFile(filename: "Main.m3", directory: "/home/peter/cm3/settest/src")
+!3 = !{!4}
+!4 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "Enum", scope: !2, file: !2, line: 11, size: 8, align: 8, elements: !5)
+!5 = !{!6, !7, !8, !9, !10, !11, !12, !13}
+!6 = !DIEnumerator(name: "alpha", value: 0)
+!7 = !DIEnumerator(name: "beta", value: 1)
+!8 = !DIEnumerator(name: "gamma", value: 2)
+!9 = !DIEnumerator(name: "delta", value: 3)
+!10 = !DIEnumerator(name: "epsilon", value: 4)
+!11 = !DIEnumerator(name: "theta", value: 5)
+!12 = !DIEnumerator(name: "psi", value: 6)
+!13 = !DIEnumerator(name: "zeta", value: 7)
+!14 = !{i64 2, !"Dwarf Version", i64 4}
+!15 = !{i64 2, !"Debug Info Version", i64 3}
+!16 = !{i64 2, !"wchar_size", i64 2}
+!17 = distinct !DISubprogram(name: "Test", linkageName: "Main__Test", scope: !2, file: !2, line: 11, type: !18, scopeLine: 11, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !20)
+!18 = !DISubroutineType(types: !19)
+!19 = !{null}
+!20 = !{}
+!21 = !DILocation(line: 20, scope: !17)
+!22 = !DILocalVariable(name: "as", scope: !17, file: !2, line: 11, type: !23)
+; CHECK: invalid set base type
+!23 = !DIDerivedType(tag: DW_TAG_set_type, name: "SS", scope: !2, file: !2, line: 11, baseType: !24, size: 64, align: 64)
+!24 = !DIBasicType(name: "SR", size: 8, encoding: DW_ATE_signed)
+!25 = !DILocation(line: 11, scope: !17)
+!26 = !DILocalVariable(name: "bs", scope: !17, file: !2, line: 11, type: !27)
+!27 = !DIDerivedType(tag: DW_TAG_set_type, name: "ST", scope: !2, file: !2, line: 11, baseType: !23, size: 64, align: 64)
+!28 = !DILocation(line: 17, scope: !17)
+!29 = !DILocation(line: 18, scope: !17)
+!30 = distinct !DISubprogram(name: "Main_M3", linkageName: "Main_M3", scope: !2, file: !2, line: 22, type: !31, scopeLine: 22, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !20)
+!31 = !DISubroutineType(types: !32)
+!32 = !{!33, !35}
+!33 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "ADDR", baseType: !34, size: 64, align: 64)
+!34 = !DICompositeType(tag: DW_TAG_class_type, name: "ADDR__HeapObject", scope: !2, file: !2, line: 22, size: 64, align: 64, elements: !19, identifier: "AJWxb1")
+!35 = !DIBasicType(name: "INTEGER", size: 64, encoding: DW_ATE_signed)
+!36 = !DILocation(line: 23, scope: !30)
+!37 = !DILocalVariable(name: "mode", arg: 1, scope: !30, file: !2, line: 22, type: !35)
+!38 = !DILocation(line: 22, scope: !30)


        


More information about the llvm-commits mailing list