[llvm] [DebugInfo] Add DILayerLoc/DILayerLocList and DILocation irlayers operand (PR #215666)

via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 11 14:00:32 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-debuginfo

Author: Alexander Yermolovich (ayermolo)

<details>
<summary>Changes</summary>

Programs lowered through intermediate IRs lose their position in those IRs by the time they reach a backend: a DILocation records only the original source coordinate. Add an optional `irlayers` operand carrying one coordinate per intermediate level, so a debugger can step through the IR text a program was actually compiled from.

Layers are independent of inlinedAt; a location may carry either, both, or neither. The presence flag costs one bit of atomGroup, narrowing it from 61 to
60. Textual IR, bitcode and MIR all round-trip the new operand.

---

Patch is 78.72 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/215666.diff


23 Files Affected:

- (modified) llvm/docs/KeyInstructionsDebugInfo.md (+1-1) 
- (modified) llvm/docs/LangRef.md (+49) 
- (modified) llvm/include/llvm-c/DebugInfo.h (+2) 
- (modified) llvm/include/llvm/Bitcode/LLVMBitCodes.h (+2) 
- (modified) llvm/include/llvm/IR/DebugInfoMetadata.h (+156-18) 
- (modified) llvm/include/llvm/IR/DebugLoc.h (+6-1) 
- (modified) llvm/include/llvm/IR/Metadata.def (+2) 
- (modified) llvm/lib/AsmParser/LLParser.cpp (+40-4) 
- (modified) llvm/lib/Bitcode/Reader/BitcodeReader.cpp (+6-3) 
- (modified) llvm/lib/Bitcode/Reader/MetadataLoader.cpp (+42-6) 
- (modified) llvm/lib/Bitcode/Writer/BitcodeWriter.cpp (+30) 
- (modified) llvm/lib/CodeGen/MIRParser/MIParser.cpp (+12-1) 
- (modified) llvm/lib/IR/AsmWriter.cpp (+23) 
- (modified) llvm/lib/IR/DebugInfoMetadata.cpp (+114-17) 
- (modified) llvm/lib/IR/DebugLoc.cpp (+11-1) 
- (modified) llvm/lib/IR/LLVMContextImpl.h (+56-8) 
- (modified) llvm/lib/IR/Verifier.cpp (+16) 
- (modified) llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp (+8) 
- (added) llvm/test/Bitcode/intermediate-loc-metadata-location.ll (+58) 
- (added) llvm/test/Bitcode/intermediate-loc-roundtrip.ll (+57) 
- (added) llvm/test/CodeGen/MIR/X86/instructions-debug-location-irlayers.mir (+64) 
- (added) llvm/test/Verifier/intermediate-layerloc.ll (+37) 
- (modified) llvm/unittests/IR/DebugInfoTest.cpp (+402) 


``````````diff
diff --git a/llvm/docs/KeyInstructionsDebugInfo.md b/llvm/docs/KeyInstructionsDebugInfo.md
index 22f83f2b0a381..0ea9b84c180f1 100644
--- a/llvm/docs/KeyInstructionsDebugInfo.md
+++ b/llvm/docs/KeyInstructionsDebugInfo.md
@@ -45,7 +45,7 @@ From the perspective of a source-level debugger user:
 
 Details:
 
-1. *The metadata* - The two new `DILocation` fields are `atomGroup` and `atomRank` and are both are unsigned integers. `atomGroup` is 61 bits and `atomRank` 3 bits. Instructions in the same function with the same `(atomGroup, inlinedAt)` pair are part of the same source atom. `atomRank` determines `is_stmt` preference within that group, where a lower number is higher precedence. Higher rank instructions act as "backup" `is_stmt` locations, providing good fallback locations if/when the primary candidate gets optimized away. The default values of 0 indicate the instruction isn’t interesting - it's not an `is_stmt` candidate. If `keyInstructions` in `DISubprogram` is false (default) then the new `DILocation` metadata is ignored for the function (including inlined instances) when emitting DWARF.
+1. *The metadata* - The two new `DILocation` fields are `atomGroup` and `atomRank` and are both are unsigned integers. `atomGroup` is 60 bits and `atomRank` 3 bits; the remaining bit of the 64-bit field is `DILocation`'s `irlayers` flag. A group that does not fit in 60 bits is clamped to 0, so an out-of-range value means "not interesting" rather than silently aliasing another group. Instructions in the same function with the same `(atomGroup, inlinedAt)` pair are part of the same source atom. `atomRank` determines `is_stmt` preference within that group, where a lower number is higher precedence. Higher rank instructions act as "backup" `is_stmt` locations, providing good fallback locations if/when the primary candidate gets optimized away. The default values of 0 indicate the instruction isn’t interesting - it's not an `is_stmt` candidate. If `keyInstructions` in `DISubprogram` is false (default) then the new `DILocation` metadata is ignored for the function (including inlined instances) when emitting DWARF.
 
 2. *Clang annotates key instructions* with the new metadata. Variable assignments (stores, memory intrinsics), control flow (branches and their conditions, some unconditional branches), and exception handling instructions are annotated. Calls are ignored as they're unconditionally marked `is_stmt`.
 
diff --git a/llvm/docs/LangRef.md b/llvm/docs/LangRef.md
index 3a616e8a29fcf..c1642705ab481 100644
--- a/llvm/docs/LangRef.md
+++ b/llvm/docs/LangRef.md
@@ -7170,6 +7170,55 @@ mandatory, and points at an {ref}`DILexicalBlockFile`, an
 !0 = !DILocation(line: 2900, column: 42, scope: !1, inlinedAt: !2)
 ```
 
+The optional `irlayers:` field points at a {ref}`DILayerLocList`, giving the
+instruction's position in one or more intermediate IRs it was lowered through, in
+addition to its primary source position. It is independent of `inlinedAt:`; a
+location may have either, both, or neither.
+
+```text
+!0 = !DILocation(line: 2900, column: 42, scope: !1, irlayers: !3)
+```
+
+(DILayerLoc)=
+
+##### DILayerLoc
+
+`DILayerLoc` nodes represent a source position in one intermediate IR level that
+a program was lowered through — for example a tile IR or an MLIR module produced
+part-way through compilation. The `kind:` field names the level and the `file:`
+field points at a {ref}`DIFile` for it; both are mandatory. `line:` and
+`column:` are the position within that file.
+
+Unlike a {ref}`DILocation`, a `DILayerLoc` has no scope and no inlined-at
+context: it is a bare coordinate in a file, not a location in a scope tree.
+
+```text
+!0 = !DILayerLoc(line: 100, column: 1, file: !1, kind: "tile ir")
+```
+
+(DILayerLocList)=
+
+##### DILayerLocList
+
+`DILayerLocList` nodes hold a list of {ref}`DILayerLoc` operands, and are
+referenced by a {ref}`DILocation`'s `irlayers:` field.
+
+Operand order is preserved and is part of the node's identity — two lists with
+the same entries in a different order are different nodes — and a consumer sees
+the entries in that order. LLVM itself attaches no meaning to the order: it does
+not define which level comes first and does not check any particular arrangement,
+so any convention (such as listing levels in lowering order) is an agreement
+between a producer and its consumer.
+
+Both node types are uniqued, so instructions sharing a position at some level
+share the corresponding node.
+
+```text
+!0 = !DILayerLocList(!1, !2)
+!1 = !DILayerLoc(line: 100, column: 1, file: !3, kind: "tile ir")
+!2 = !DILayerLoc(line: 7, column: 3, file: !4, kind: "gpu ir")
+```
+
 (DILocalVariable)=
 
 ##### DILocalVariable
diff --git a/llvm/include/llvm-c/DebugInfo.h b/llvm/include/llvm-c/DebugInfo.h
index 155cbe32ee15e..21b1e021ff310 100644
--- a/llvm/include/llvm-c/DebugInfo.h
+++ b/llvm/include/llvm-c/DebugInfo.h
@@ -211,6 +211,8 @@ enum {
   LLVMDIAssignIDMetadataKind,
   LLVMDISubrangeTypeMetadataKind,
   LLVMDIFixedPointTypeMetadataKind,
+  LLVMDILayerLocMetadataKind,
+  LLVMDILayerLocListMetadataKind,
 };
 typedef unsigned LLVMMetadataKind;
 
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index 358f9a65a80af..3f7db3456ea78 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -400,6 +400,8 @@ enum MetadataCodes {
   METADATA_ASSIGN_ID = 47,        // [distinct, ...]
   METADATA_SUBRANGE_TYPE = 48,    // [distinct, ...]
   METADATA_FIXED_POINT_TYPE = 49, // [distinct, ...]
+  METADATA_LAYERLOC = 50,         // [distinct, line, column, file, kind]
+  METADATA_LAYERLOCLIST = 51,     // [distinct, n x layerloc]
 };
 
 // The constants block (CONSTANTS_BLOCK_ID) describes emission for each
diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h
index 33a1a6e482555..ab6ad11913495 100644
--- a/llvm/include/llvm/IR/DebugInfoMetadata.h
+++ b/llvm/include/llvm/IR/DebugInfoMetadata.h
@@ -2658,6 +2658,114 @@ class DISubprogram : public DILocalScope {
   }
 };
 
+/// A single intermediate-IR layer location.
+///
+/// One source coordinate in an intermediate IR level (e.g. TileIR, MLIR) that
+/// sits between the high-level source and the final LLVM IR. Lightweight: it
+/// references its \a DIFile directly (no scope, no discriminator) and stores
+/// line/column in the free Metadata subclass-data slots. Grouped behind a
+/// \a DILayerLocList on \a DILocation's optional `irlayers` operand.
+///
+/// Uses the SubclassData16 and SubclassData32 Metadata slots.
+class DILayerLoc : public MDNode {
+  friend class LLVMContextImpl;
+  friend class MDNode;
+
+  DILayerLoc(LLVMContext &C, StorageType Storage, unsigned Line,
+             unsigned Column, ArrayRef<Metadata *> Ops)
+      : MDNode(C, DILayerLocKind, Storage, Ops) {
+    assert(Ops.size() == 2 && "Expected {kind, file}");
+    assert(Column < (1u << 16) && "Expected 16-bit column");
+    SubclassData32 = Line;
+    SubclassData16 = Column;
+  }
+  ~DILayerLoc() { dropAllReferences(); }
+
+  static DILayerLoc *getImpl(LLVMContext &Context, MDString *Kind,
+                             Metadata *File, unsigned Line, unsigned Column,
+                             StorageType Storage, bool ShouldCreate = true);
+
+  TempDILayerLoc cloneImpl() const {
+    return getTemporary(getContext(), getRawKind(), getRawFile(), getLine(),
+                        getColumn());
+  }
+
+public:
+  DEFINE_MDNODE_GET(DILayerLoc,
+                    (MDString * Kind, Metadata *File, unsigned Line,
+                     unsigned Column),
+                    (Kind, File, Line, Column))
+
+  TempDILayerLoc clone() const { return cloneImpl(); }
+
+  unsigned getLine() const { return SubclassData32; }
+  unsigned getColumn() const { return SubclassData16; }
+
+  MDString *getRawKind() const {
+    return cast_if_present<MDString>(getOperand(0));
+  }
+  StringRef getKind() const {
+    if (MDString *K = getRawKind())
+      return K->getString();
+    return StringRef();
+  }
+  Metadata *getRawFile() const { return getOperand(1); }
+  DIFile *getFile() const { return cast_if_present<DIFile>(getRawFile()); }
+
+  static bool classof(const Metadata *MD) {
+    return MD->getMetadataID() == DILayerLocKind;
+  }
+};
+
+/// A uniqued list of \a DILayerLoc entries.
+///
+/// The container node behind \a DILocation's optional `irlayers` operand:
+/// essentially an \a MDTuple of \a DILayerLoc refs with typed accessors and its
+/// own metadata kind, so consumers can type-check it with
+/// `isa<DILayerLocList>`. Operand order is preserved and is part of the node's
+/// identity, but LLVM assigns it no meaning.
+class DILayerLocList : public MDNode {
+  friend class LLVMContextImpl;
+  friend class MDNode;
+
+  DILayerLocList(LLVMContext &C, StorageType Storage, unsigned Hash,
+                 ArrayRef<Metadata *> Ops)
+      : MDNode(C, DILayerLocListKind, Storage, Ops) {
+    setHash(Hash);
+  }
+  ~DILayerLocList() { dropAllReferences(); }
+
+  void setHash(unsigned Hash) { SubclassData32 = Hash; }
+  void recalculateHash();
+
+  static DILayerLocList *getImpl(LLVMContext &Context,
+                                 ArrayRef<Metadata *> Layers,
+                                 StorageType Storage, bool ShouldCreate = true);
+
+  TempDILayerLocList cloneImpl() const {
+    return getTemporary(getContext(), SmallVector<Metadata *, 4>(operands()));
+  }
+
+public:
+  /// Get the operand hash (used by the MDNodeOpsKey uniquing key).
+  unsigned getHash() const { return SubclassData32; }
+
+  DEFINE_MDNODE_GET(DILayerLocList, (ArrayRef<Metadata *> Layers), (Layers))
+
+  TempDILayerLocList clone() const { return cloneImpl(); }
+
+  unsigned getNumLayers() const { return getNumOperands(); }
+  DILayerLoc *getLayer(unsigned I) const {
+    return cast_if_present<DILayerLoc>(getOperand(I));
+  }
+  using layer_iterator = MDNode::op_iterator;
+  iterator_range<layer_iterator> layers() const { return operands(); }
+
+  static bool classof(const Metadata *MD) {
+    return MD->getMetadataID() == DILayerLocListKind;
+  }
+};
+
 /// Debug location.
 ///
 /// A debug location in source code, used for debug info and otherwise.
@@ -2668,34 +2776,40 @@ class DISubprogram : public DILocalScope {
 class DILocation : public MDNode {
   friend class LLVMContextImpl;
   friend class MDNode;
-  uint64_t AtomGroup : 61;
+  uint64_t AtomGroup : 60;
   uint64_t AtomRank : 3;
+  // Disambiguates the two optional trailing operands, layout
+  // [scope, (inlinedAt?), (irlayers?)]: irlayers is always last when present.
+  uint64_t HasIRLayers : 1;
 
   DILocation(LLVMContext &C, StorageType Storage, unsigned Line,
              unsigned Column, uint64_t AtomGroup, uint8_t AtomRank,
-             ArrayRef<Metadata *> MDs, bool ImplicitCode);
+             bool HasIRLayers, ArrayRef<Metadata *> MDs, bool ImplicitCode);
   ~DILocation() { dropAllReferences(); }
 
-  LLVM_ABI static DILocation *
-  getImpl(LLVMContext &Context, unsigned Line, unsigned Column, Metadata *Scope,
-          Metadata *InlinedAt, bool ImplicitCode, uint64_t AtomGroup,
-          uint8_t AtomRank, StorageType Storage, bool ShouldCreate = true);
+  LLVM_ABI static DILocation *getImpl(LLVMContext &Context, unsigned Line,
+                                      unsigned Column, Metadata *Scope,
+                                      Metadata *InlinedAt, bool ImplicitCode,
+                                      uint64_t AtomGroup, uint8_t AtomRank,
+                                      Metadata *IRLayers, StorageType Storage,
+                                      bool ShouldCreate = true);
   static DILocation *getImpl(LLVMContext &Context, unsigned Line,
                              unsigned Column, DILocalScope *Scope,
                              DILocation *InlinedAt, bool ImplicitCode,
                              uint64_t AtomGroup, uint8_t AtomRank,
-                             StorageType Storage, bool ShouldCreate = true) {
+                             Metadata *IRLayers, StorageType Storage,
+                             bool ShouldCreate = true) {
     return getImpl(Context, Line, Column, static_cast<Metadata *>(Scope),
                    static_cast<Metadata *>(InlinedAt), ImplicitCode, AtomGroup,
-                   AtomRank, Storage, ShouldCreate);
+                   AtomRank, IRLayers, Storage, ShouldCreate);
   }
 
   TempDILocation cloneImpl() const {
-    // Get the raw scope/inlinedAt since it is possible to invoke this on
-    // a DILocation containing temporary metadata.
+    // Get the raw scope/inlinedAt/irlayers since it is possible to invoke this
+    // on a DILocation containing temporary metadata.
     return getTemporary(getContext(), getLine(), getColumn(), getRawScope(),
                         getRawInlinedAt(), isImplicitCode(), getAtomGroup(),
-                        getAtomRank());
+                        getAtomRank(), getRawIRLayers());
   }
 
 public:
@@ -2706,7 +2820,8 @@ class DILocation : public MDNode {
     if (!getAtomGroup() && !getAtomRank())
       return this;
     return get(getContext(), getLine(), getColumn(), getScope(), getInlinedAt(),
-               isImplicitCode());
+               isImplicitCode(), /*AtomGroup=*/0, /*AtomRank=*/0,
+               getRawIRLayers());
   }
 
   // Disallow replacing operands.
@@ -2715,15 +2830,17 @@ class DILocation : public MDNode {
   DEFINE_MDNODE_GET(DILocation,
                     (unsigned Line, unsigned Column, Metadata *Scope,
                      Metadata *InlinedAt = nullptr, bool ImplicitCode = false,
-                     uint64_t AtomGroup = 0, uint8_t AtomRank = 0),
+                     uint64_t AtomGroup = 0, uint8_t AtomRank = 0,
+                     Metadata *IRLayers = nullptr),
                     (Line, Column, Scope, InlinedAt, ImplicitCode, AtomGroup,
-                     AtomRank))
+                     AtomRank, IRLayers))
   DEFINE_MDNODE_GET(DILocation,
                     (unsigned Line, unsigned Column, DILocalScope *Scope,
                      DILocation *InlinedAt = nullptr, bool ImplicitCode = false,
-                     uint64_t AtomGroup = 0, uint8_t AtomRank = 0),
+                     uint64_t AtomGroup = 0, uint8_t AtomRank = 0,
+                     Metadata *IRLayers = nullptr),
                     (Line, Column, Scope, InlinedAt, ImplicitCode, AtomGroup,
-                     AtomRank))
+                     AtomRank, IRLayers))
 
   /// Return a (temporary) clone of this.
   TempDILocation clone() const { return cloneImpl(); }
@@ -2945,11 +3062,32 @@ class DILocation : public MDNode {
 
   Metadata *getRawScope() const { return getOperand(0); }
   Metadata *getRawInlinedAt() const {
-    if (getNumOperands() == 2)
+    // Layout: [scope, (inlinedAt?), (irlayers?)]. irlayers, when present, is
+    // always the last operand; discount it before the inlinedAt count trick.
+    unsigned NonLayerOps = getNumOperands() - (HasIRLayers ? 1 : 0);
+    if (NonLayerOps == 2)
       return getOperand(1);
     return nullptr;
   }
 
+  /// The optional intermediate-IR layer list (\a DILayerLocList), or null.
+  /// Raw form: returns the operand without casting, so it is safe to call
+  /// before forward-ref resolution (the operand may still be a placeholder).
+  Metadata *getRawIRLayers() const {
+    return HasIRLayers ? getOperand(getNumOperands() - 1) : nullptr;
+  }
+  DILayerLocList *getIRLayers() const {
+    return cast_if_present<DILayerLocList>(getRawIRLayers());
+  }
+  unsigned getNumLayers() const {
+    DILayerLocList *L = getIRLayers();
+    return L ? L->getNumLayers() : 0;
+  }
+  DILayerLoc *getLayer(unsigned I) const {
+    DILayerLocList *L = getIRLayers();
+    return L ? L->getLayer(I) : nullptr;
+  }
+
   static bool classof(const Metadata *MD) {
     return MD->getMetadataID() == DILocationKind;
   }
@@ -3103,7 +3241,7 @@ DILocation::cloneWithDiscriminator(unsigned Discriminator) const {
       DILexicalBlockFile::get(getContext(), Scope, getFile(), Discriminator);
   return DILocation::get(getContext(), getLine(), getColumn(), NewScope,
                          getInlinedAt(), isImplicitCode(), getAtomGroup(),
-                         getAtomRank());
+                         getAtomRank(), getRawIRLayers());
 }
 
 unsigned DILocation::getBaseDiscriminator() const {
diff --git a/llvm/include/llvm/IR/DebugLoc.h b/llvm/include/llvm/IR/DebugLoc.h
index 34e6aadd83cae..c9a5149c80940 100644
--- a/llvm/include/llvm/IR/DebugLoc.h
+++ b/llvm/include/llvm/IR/DebugLoc.h
@@ -246,13 +246,18 @@ class DebugLoc {
       return true;
     return ((bool)*this == (bool)Other) && getLine() == Other.getLine() &&
            getCol() == Other.getCol() && getScope() == Other.getScope() &&
-           getInlinedAt() == Other.getInlinedAt();
+           getInlinedAt() == Other.getInlinedAt() &&
+           getRawIRLayers() == Other.getRawIRLayers();
   }
 
   LLVM_ABI unsigned getLine() const;
   LLVM_ABI unsigned getCol() const;
   LLVM_ABI MDNode *getScope() const;
   LLVM_ABI DILocation *getInlinedAt() const;
+  /// The raw intermediate-IR layer list (\a DILayerLocList) of the underlying
+  /// location, or null. Out-of-line so this header need not see DILocation's
+  /// definition.
+  LLVM_ABI MDNode *getRawIRLayers() const;
 
   /// Get the fully inlined-at scope for a DebugLoc.
   ///
diff --git a/llvm/include/llvm/IR/Metadata.def b/llvm/include/llvm/IR/Metadata.def
index 511bf48707f00..80817892d0d99 100644
--- a/llvm/include/llvm/IR/Metadata.def
+++ b/llvm/include/llvm/IR/Metadata.def
@@ -81,6 +81,8 @@ HANDLE_METADATA_LEAF(DIArgList)
 HANDLE_MDNODE_BRANCH(MDNode)
 HANDLE_MDNODE_LEAF_UNIQUABLE(MDTuple)
 HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DILocation)
+HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DILayerLoc)
+HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DILayerLocList)
 HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIExpression)
 HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIGlobalVariableExpression)
 HANDLE_SPECIALIZED_MDNODE_BRANCH(DINode)
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index edff818b3b152..34d583820227f 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -5784,13 +5784,49 @@ bool LLParser::parseDILocation(MDNode *&Result, bool IsDistinct) {
   OPTIONAL(inlinedAt, MDField, );                                              \
   OPTIONAL(isImplicitCode, MDBoolField, (false));                              \
   OPTIONAL(atomGroup, MDUnsignedField, (0, UINT64_MAX));                       \
-  OPTIONAL(atomRank, MDUnsignedField, (0, UINT8_MAX));
+  OPTIONAL(atomRank, MDUnsignedField, (0, UINT8_MAX));                         \
+  OPTIONAL(irlayers, MDField, );
   PARSE_MD_FIELDS();
 #undef VISIT_MD_FIELDS
 
-  Result = GET_OR_DISTINCT(
-      DILocation, (Context, line.Val, column.Val, scope.Val, inlinedAt.Val,
-                   isImplicitCode.Val, atomGroup.Val, atomRank.Val));
+  Result =
+      GET_OR_DISTINCT(DILocation, (Context, line.Val, column.Val, scope.Val,
+                                   inlinedAt.Val, isImplicitCode.Val,
+                                   atomGroup.Val, atomRank.Val, irlayers.Val));
+  return false;
+}
+
+bool LLParser::parseDILayerLoc(MDNode *&Result, bool IsDistinct) {
+#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED)                                    \
+  OPTIONAL(line, LineField, );                                                 \
+  OPTIONAL(column, ColumnField, );                                             \
+  REQUIRED(file, MDField, (/* AllowNull */ false));                            \
+  REQUIRED(kind, MDStringField, );
+  PARSE_MD_FIELDS();
+#undef VISIT_MD_FIELDS
+
+  Result = GET_OR_DISTINCT(DILayerLoc,
+                           (Context, kind.Val, file.Val, line.Val, column.Val));
+  return false;
+}
+
+bool LLParser::parseDILayerLocList(MDNode *&Result, bool IsDistinct) {
+  // ::= !DILayerLocList(!a, !b, ...)
+  Lex.Lex(); // eat the '!DILayerLocList' type name
+  if (parseToken(lltok::lparen, "expected '(' here"))
+    return true;
+  SmallVector<Metadata *, 4> Layers;
+  if (!EatIfPresent(lltok::rparen)) {
+    do {
+      Metadata *MD;
+      if (parseMetadata(MD, nullptr))
+        return true;
+      Layers.push_back(MD);
+    } while (EatIfPresent(lltok::comma));
+    if (parseToken(lltok::rparen, "expected ')' her...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/215666


More information about the llvm-commits mailing list