[llvm] 65600cb - [DebugInfo] Add DIArgList MD to store multple values in DbgVariableIntrinsics
Stephen Tozer via llvm-commits
llvm-commits at lists.llvm.org
Fri Mar 5 09:02:51 PST 2021
Author: gbtozers
Date: 2021-03-05T17:02:24Z
New Revision: 65600cb2a7e940babf6c493503b9d3fd19f8cb06
URL: https://github.com/llvm/llvm-project/commit/65600cb2a7e940babf6c493503b9d3fd19f8cb06
DIFF: https://github.com/llvm/llvm-project/commit/65600cb2a7e940babf6c493503b9d3fd19f8cb06.diff
LOG: [DebugInfo] Add DIArgList MD to store multple values in DbgVariableIntrinsics
This patch adds a new metadata node, DIArgList, which contains a list of SSA
values. This node is in many ways similar in function to the existing
ValueAsMetadata node, with the difference being that it tracks a list instead of
a single value. Internally, it uses ValueAsMetadata to track the individual
values, but there is also a reasonable amount of DIArgList-specific
value-tracking logic on top of that. Similar to ValueAsMetadata, it is a special
case in parsing and printing due to the fact that it requires a function state
(as it may reference function-local values).
This patch should not result in any immediate functional change; it allows for
DIArgLists to be parsed and printed, but debug variable intrinsics do not yet
recognize them as a valid argument (outside of parsing).
Differential Revision: https://reviews.llvm.org/D88175
Added:
llvm/test/DebugInfo/Generic/debug_value_list.ll
Modified:
llvm/docs/LangRef.rst
llvm/include/llvm-c/DebugInfo.h
llvm/include/llvm/Bitcode/LLVMBitCodes.h
llvm/include/llvm/IR/DebugInfoMetadata.h
llvm/include/llvm/IR/Metadata.def
llvm/include/llvm/IR/Metadata.h
llvm/lib/AsmParser/LLParser.cpp
llvm/lib/AsmParser/LLParser.h
llvm/lib/Bitcode/Reader/BitcodeAnalyzer.cpp
llvm/lib/Bitcode/Reader/MetadataLoader.cpp
llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
llvm/lib/Bitcode/Writer/ValueEnumerator.cpp
llvm/lib/IR/AsmWriter.cpp
llvm/lib/IR/DebugInfoMetadata.cpp
llvm/lib/IR/LLVMContextImpl.h
llvm/lib/IR/Metadata.cpp
llvm/lib/IR/Verifier.cpp
llvm/lib/Transforms/Utils/ValueMapper.cpp
llvm/unittests/IR/MetadataTest.cpp
Removed:
################################################################################
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 57824151899c..9f0ccc162fd3 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -5407,6 +5407,22 @@ valid debug intrinsic.
!4 = !DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef)
!5 = !DIExpression(DW_OP_constu, 42, DW_OP_stack_value)
+DIArgList
+""""""""""""
+
+``DIArgList`` nodes hold a list of constant or SSA value references. These are
+used in :ref:`debug intrinsics<dbg_intrinsics>` (currently only in
+``llvm.dbg.value``) in combination with a ``DIExpression`` that uses the
+``DW_OP_LLVM_arg`` operator. Because a DIArgList may refer to local values
+within a function, it must only be used as a function argument, must always be
+inlined, and cannot appear in named metadata.
+
+.. code-block:: text
+
+ llvm.dbg.value(metadata !DIArgList(i32 %a, i32 %b),
+ metadata !16,
+ metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus))
+
DIFlags
"""""""""""""""
diff --git a/llvm/include/llvm-c/DebugInfo.h b/llvm/include/llvm-c/DebugInfo.h
index 5a9cd8e2ee63..8c085807914b 100644
--- a/llvm/include/llvm-c/DebugInfo.h
+++ b/llvm/include/llvm-c/DebugInfo.h
@@ -161,7 +161,8 @@ enum {
LLVMDIMacroFileMetadataKind,
LLVMDICommonBlockMetadataKind,
LLVMDIStringTypeMetadataKind,
- LLVMDIGenericSubrangeMetadataKind
+ LLVMDIGenericSubrangeMetadataKind,
+ LLVMDIArgListMetadataKind
};
typedef unsigned LLVMMetadataKind;
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index 6b24f4bdcba5..88a629493f04 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -342,8 +342,9 @@ enum MetadataCodes {
METADATA_STRING_TYPE = 41, // [distinct, name, size, align,...]
// Codes 42 and 43 are reserved for support for Fortran array specific debug
// info.
- METADATA_COMMON_BLOCK = 44, // [distinct, scope, name, variable,...]
- METADATA_GENERIC_SUBRANGE = 45 // [distinct, count, lo, up, stride]
+ METADATA_COMMON_BLOCK = 44, // [distinct, scope, name, variable,...]
+ METADATA_GENERIC_SUBRANGE = 45, // [distinct, count, lo, up, stride]
+ METADATA_ARG_LIST = 46 // [n x [type num, value num]]
};
// 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 db893bfcd54f..c76473d624f5 100644
--- a/llvm/include/llvm/IR/DebugInfoMetadata.h
+++ b/llvm/include/llvm/IR/DebugInfoMetadata.h
@@ -3510,6 +3510,52 @@ class DIMacroFile : public DIMacroNode {
}
};
+/// List of ValueAsMetadata, to be used as an argument to a dbg.value
+/// intrinsic.
+class DIArgList : public MDNode {
+ friend class LLVMContextImpl;
+ friend class MDNode;
+ using iterator = SmallVectorImpl<ValueAsMetadata *>::iterator;
+
+ SmallVector<ValueAsMetadata *, 4> Args;
+
+ DIArgList(LLVMContext &C, StorageType Storage,
+ ArrayRef<ValueAsMetadata *> Args)
+ : MDNode(C, DIArgListKind, Storage, None),
+ Args(Args.begin(), Args.end()) {
+ track();
+ }
+ ~DIArgList() { untrack(); }
+
+ static DIArgList *getImpl(LLVMContext &Context,
+ ArrayRef<ValueAsMetadata *> Args,
+ StorageType Storage, bool ShouldCreate = true);
+
+ TempDIArgList cloneImpl() const {
+ return getTemporary(getContext(), getArgs());
+ }
+
+ void track();
+ void untrack();
+ void dropAllReferences();
+
+public:
+ DEFINE_MDNODE_GET(DIArgList, (ArrayRef<ValueAsMetadata *> Args), (Args))
+
+ TempDIArgList clone() const { return cloneImpl(); }
+
+ ArrayRef<ValueAsMetadata *> getArgs() const { return Args; }
+
+ iterator args_begin() { return Args.begin(); }
+ iterator args_end() { return Args.end(); }
+
+ static bool classof(const Metadata *MD) {
+ return MD->getMetadataID() == DIArgListKind;
+ }
+
+ void handleChangedOperand(void *Ref, Metadata *New);
+};
+
/// Identifies a unique instance of a variable.
///
/// Storage for identifying a potentially inlined instance of a variable,
diff --git a/llvm/include/llvm/IR/Metadata.def b/llvm/include/llvm/IR/Metadata.def
index f31be8d1bc0c..3d3edb9328b4 100644
--- a/llvm/include/llvm/IR/Metadata.def
+++ b/llvm/include/llvm/IR/Metadata.def
@@ -114,6 +114,7 @@ HANDLE_SPECIALIZED_MDNODE_BRANCH(DIMacroNode)
HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIMacro)
HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIMacroFile)
HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DICommonBlock)
+HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIArgList)
HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIStringType)
HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIGenericSubrange)
diff --git a/llvm/include/llvm/IR/Metadata.h b/llvm/include/llvm/IR/Metadata.h
index 2a2ce347972c..6393d882a43f 100644
--- a/llvm/include/llvm/IR/Metadata.h
+++ b/llvm/include/llvm/IR/Metadata.h
@@ -299,6 +299,9 @@ class ReplaceableMetadataImpl {
/// Replace all uses of this with \c MD, which is allowed to be null.
void replaceAllUsesWith(Metadata *MD);
+ /// Returns the list of all DIArgList users of this.
+ SmallVector<Metadata *, 4> getAllArgListUsers();
+
/// Resolve all uses of this.
///
/// Resolve all uses of this, turning off RAUW permanently. If \c
@@ -378,6 +381,10 @@ class ValueAsMetadata : public Metadata, ReplaceableMetadataImpl {
Type *getType() const { return V->getType(); }
LLVMContext &getContext() const { return V->getContext(); }
+ SmallVector<Metadata *, 4> getAllArgListUsers() {
+ return ReplaceableMetadataImpl::getAllArgListUsers();
+ }
+
static void handleDeletion(Value *V);
static void handleRAUW(Value *From, Value *To);
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 7554c88887e4..816dda6b8080 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -776,6 +776,11 @@ bool LLParser::parseNamedMetadata() {
Lex.getStrVal() == "DIExpression") {
if (parseDIExpression(N, /*IsDistinct=*/false))
return true;
+ // DIArgLists should only appear inline in a function, as they may
+ // contain LocalAsMetadata arguments which require a function context.
+ } else if (Lex.getKind() == lltok::MetadataVar &&
+ Lex.getStrVal() == "DIArgList") {
+ return tokError("found DIArgList outside of function");
} else if (parseToken(lltok::exclaim, "Expected '!' here") ||
parseMDNodeID(N)) {
return true;
@@ -5297,6 +5302,36 @@ bool LLParser::parseDIExpression(MDNode *&Result, bool IsDistinct) {
return false;
}
+bool LLParser::parseDIArgList(MDNode *&Result, bool IsDistinct) {
+ return parseDIArgList(Result, IsDistinct, nullptr);
+}
+/// ParseDIArgList:
+/// ::= !DIArgList(i32 7, i64 %0)
+bool LLParser::parseDIArgList(MDNode *&Result, bool IsDistinct,
+ PerFunctionState *PFS) {
+ assert(PFS && "Expected valid function state");
+ assert(Lex.getKind() == lltok::MetadataVar && "Expected metadata type name");
+ Lex.Lex();
+
+ if (parseToken(lltok::lparen, "expected '(' here"))
+ return true;
+
+ SmallVector<ValueAsMetadata *, 4> Args;
+ if (Lex.getKind() != lltok::rparen)
+ do {
+ Metadata *MD;
+ if (parseValueAsMetadata(MD, "expected value-as-metadata operand", PFS))
+ return true;
+ Args.push_back(dyn_cast<ValueAsMetadata>(MD));
+ } while (EatIfPresent(lltok::comma));
+
+ if (parseToken(lltok::rparen, "expected ')' here"))
+ return true;
+
+ Result = GET_OR_DISTINCT(DIArgList, (Context, Args));
+ return false;
+}
+
/// parseDIGlobalVariableExpression:
/// ::= !DIGlobalVariableExpression(var: !0, expr: !1)
bool LLParser::parseDIGlobalVariableExpression(MDNode *&Result,
@@ -5407,8 +5442,14 @@ bool LLParser::parseValueAsMetadata(Metadata *&MD, const Twine &TypeMsg,
bool LLParser::parseMetadata(Metadata *&MD, PerFunctionState *PFS) {
if (Lex.getKind() == lltok::MetadataVar) {
MDNode *N;
- if (parseSpecializedMDNode(N))
+ // DIArgLists are a special case, as they are a list of ValueAsMetadata and
+ // so parsing this requires a Function State.
+ if (Lex.getStrVal() == "DIArgList") {
+ if (parseDIArgList(N, false, PFS))
+ return true;
+ } else if (parseSpecializedMDNode(N)) {
return true;
+ }
MD = N;
return false;
}
diff --git a/llvm/lib/AsmParser/LLParser.h b/llvm/lib/AsmParser/LLParser.h
index aa79823ce986..a891e136c59f 100644
--- a/llvm/lib/AsmParser/LLParser.h
+++ b/llvm/lib/AsmParser/LLParser.h
@@ -536,6 +536,8 @@ namespace llvm {
#define HANDLE_SPECIALIZED_MDNODE_LEAF(CLASS) \
bool parse##CLASS(MDNode *&Result, bool IsDistinct);
#include "llvm/IR/Metadata.def"
+ bool parseDIArgList(MDNode *&Result, bool IsDistinct,
+ PerFunctionState *PFS);
// Function Parsing.
struct ArgInfo {
diff --git a/llvm/lib/Bitcode/Reader/BitcodeAnalyzer.cpp b/llvm/lib/Bitcode/Reader/BitcodeAnalyzer.cpp
index a96e68279eaa..f577d3886e01 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeAnalyzer.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeAnalyzer.cpp
@@ -362,6 +362,7 @@ static Optional<const char *> GetCodeName(unsigned CodeID, unsigned BlockID,
STRINGIFY_CODE(METADATA, GLOBAL_VAR_EXPR)
STRINGIFY_CODE(METADATA, INDEX_OFFSET)
STRINGIFY_CODE(METADATA, INDEX)
+ STRINGIFY_CODE(METADATA, ARG_LIST)
}
case bitc::METADATA_KIND_BLOCK_ID:
switch (CodeID) {
diff --git a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp
index 8cdda62870ff..0567f96c9c25 100644
--- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp
+++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp
@@ -2076,6 +2076,16 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
return Err;
break;
}
+ case bitc::METADATA_ARG_LIST: {
+ SmallVector<ValueAsMetadata *, 4> Elts;
+ Elts.reserve(Record.size());
+ for (uint64_t Elt : Record)
+ Elts.push_back(dyn_cast_or_null<ValueAsMetadata>(getMDOrNull(Elt)));
+
+ MetadataList.assignValue(DIArgList::get(Context, Elts), NextMetadataNo);
+ NextMetadataNo++;
+ break;
+ }
}
return Error::success();
#undef GET_OR_DISTINCT
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index dd47e220d9e7..fd4b0a6a6a38 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -335,6 +335,8 @@ class ModuleBitcodeWriter : public ModuleBitcodeWriterBase {
unsigned Abbrev);
void writeDIMacroFile(const DIMacroFile *N, SmallVectorImpl<uint64_t> &Record,
unsigned Abbrev);
+ void writeDIArgList(const DIArgList *N, SmallVectorImpl<uint64_t> &Record,
+ unsigned Abbrev);
void writeDIModule(const DIModule *N, SmallVectorImpl<uint64_t> &Record,
unsigned Abbrev);
void writeDITemplateTypeParameter(const DITemplateTypeParameter *N,
@@ -1867,6 +1869,17 @@ void ModuleBitcodeWriter::writeDIMacroFile(const DIMacroFile *N,
Record.clear();
}
+void ModuleBitcodeWriter::writeDIArgList(const DIArgList *N,
+ SmallVectorImpl<uint64_t> &Record,
+ unsigned Abbrev) {
+ Record.reserve(N->getArgs().size());
+ for (ValueAsMetadata *MD : N->getArgs())
+ Record.push_back(VE.getMetadataOrNullID(MD));
+
+ Stream.EmitRecord(bitc::METADATA_ARG_LIST, Record, Abbrev);
+ Record.clear();
+}
+
void ModuleBitcodeWriter::writeDIModule(const DIModule *N,
SmallVectorImpl<uint64_t> &Record,
unsigned Abbrev) {
diff --git a/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp b/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp
index bbee8b324954..06f19604fd43 100644
--- a/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp
+++ b/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp
@@ -449,7 +449,8 @@ ValueEnumerator::ValueEnumerator(const Module &M,
}
// Local metadata is enumerated during function-incorporation.
- if (isa<LocalAsMetadata>(MD->getMetadata()))
+ if (isa<LocalAsMetadata>(MD->getMetadata()) ||
+ isa<DIArgList>(MD->getMetadata()))
continue;
EnumerateMetadata(&F, MD->getMetadata());
@@ -1031,14 +1032,26 @@ void ValueEnumerator::incorporateFunction(const Function &F) {
FirstInstID = Values.size();
SmallVector<LocalAsMetadata *, 8> FnLocalMDVector;
+ SmallVector<DIArgList *, 8> ArgListMDVector;
// Add all of the instructions.
for (const BasicBlock &BB : F) {
for (const Instruction &I : BB) {
for (const Use &OI : I.operands()) {
- if (auto *MD = dyn_cast<MetadataAsValue>(&OI))
- if (auto *Local = dyn_cast<LocalAsMetadata>(MD->getMetadata()))
+ if (auto *MD = dyn_cast<MetadataAsValue>(&OI)) {
+ if (auto *Local = dyn_cast<LocalAsMetadata>(MD->getMetadata())) {
// Enumerate metadata after the instructions they might refer to.
FnLocalMDVector.push_back(Local);
+ } else if (auto *ArgList = dyn_cast<DIArgList>(MD->getMetadata())) {
+ ArgListMDVector.push_back(ArgList);
+ for (ValueAsMetadata *VMD : ArgList->getArgs()) {
+ if (auto *Local = dyn_cast<LocalAsMetadata>(VMD)) {
+ // Enumerate metadata after the instructions they might refer
+ // to.
+ FnLocalMDVector.push_back(Local);
+ }
+ }
+ }
+ }
}
if (!I.getType()->isVoidTy())
@@ -1054,6 +1067,10 @@ void ValueEnumerator::incorporateFunction(const Function &F) {
"Missing value for metadata operand");
EnumerateFunctionLocalMetadata(F, FnLocalMDVector[i]);
}
+ // DIArgList entries must come after function-local metadata, as it is not
+ // possible to forward-reference them.
+ for (const DIArgList *ArgList : ArgListMDVector)
+ EnumerateMetadata(&F, ArgList);
}
void ValueEnumerator::purgeFunction() {
diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp
index 3ae3bf430d2f..09f21d26971d 100644
--- a/llvm/lib/IR/AsmWriter.cpp
+++ b/llvm/lib/IR/AsmWriter.cpp
@@ -1239,8 +1239,9 @@ void SlotTracker::CreateFunctionSlot(const Value *V) {
void SlotTracker::CreateMetadataSlot(const MDNode *N) {
assert(N && "Can't insert a null Value into SlotTracker!");
- // Don't make slots for DIExpressions. We just print them inline everywhere.
- if (isa<DIExpression>(N))
+ // Don't make slots for DIExpressions or DIArgLists. We just print them inline
+ // everywhere.
+ if (isa<DIExpression>(N) || isa<DIArgList>(N))
return;
unsigned DestSlot = mdnNext;
@@ -2351,6 +2352,21 @@ static void writeDIExpression(raw_ostream &Out, const DIExpression *N,
Out << ")";
}
+static void writeDIArgList(raw_ostream &Out, const DIArgList *N,
+ TypePrinting *TypePrinter, SlotTracker *Machine,
+ const Module *Context, bool FromValue = false) {
+ assert(FromValue &&
+ "Unexpected DIArgList metadata outside of value argument");
+ Out << "!DIArgList(";
+ FieldSeparator FS;
+ MDFieldPrinter Printer(Out, TypePrinter, Machine, Context);
+ for (Metadata *Arg : N->getArgs()) {
+ Out << FS;
+ WriteAsOperandInternal(Out, Arg, TypePrinter, Machine, Context, true);
+ }
+ Out << ")";
+}
+
static void writeDIGlobalVariableExpression(raw_ostream &Out,
const DIGlobalVariableExpression *N,
TypePrinting *TypePrinter,
@@ -2496,12 +2512,16 @@ static void WriteAsOperandInternal(raw_ostream &Out, const Metadata *MD,
TypePrinting *TypePrinter,
SlotTracker *Machine, const Module *Context,
bool FromValue) {
- // Write DIExpressions inline when used as a value. Improves readability of
- // debug info intrinsics.
+ // Write DIExpressions and DIArgLists inline when used as a value. Improves
+ // readability of debug info intrinsics.
if (const DIExpression *Expr = dyn_cast<DIExpression>(MD)) {
writeDIExpression(Out, Expr, TypePrinter, Machine, Context);
return;
}
+ if (const DIArgList *ArgList = dyn_cast<DIArgList>(MD)) {
+ writeDIArgList(Out, ArgList, TypePrinter, Machine, Context, FromValue);
+ return;
+ }
if (const MDNode *N = dyn_cast<MDNode>(MD)) {
std::unique_ptr<SlotTracker> MachineStorage;
@@ -3427,6 +3447,8 @@ void AssemblyWriter::printNamedMDNode(const NamedMDNode *NMD) {
// Write DIExpressions inline.
// FIXME: Ban DIExpressions in NamedMDNodes, they will serve no purpose.
MDNode *Op = NMD->getOperand(i);
+ assert(!isa<DIArgList>(Op) &&
+ "DIArgLists should not appear in NamedMDNodes");
if (auto *Expr = dyn_cast<DIExpression>(Op)) {
writeDIExpression(Out, Expr, nullptr, nullptr, nullptr);
continue;
@@ -4697,7 +4719,7 @@ static void printMetadataImpl(raw_ostream &ROS, const Metadata &MD,
/* FromValue */ true);
auto *N = dyn_cast<MDNode>(&MD);
- if (OnlyAsOperand || !N || isa<DIExpression>(MD))
+ if (OnlyAsOperand || !N || isa<DIExpression>(MD) || isa<DIArgList>(MD))
return;
OS << " = ";
diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp
index ba2638e8eb85..7bd50cea2bde 100644
--- a/llvm/lib/IR/DebugInfoMetadata.cpp
+++ b/llvm/lib/IR/DebugInfoMetadata.cpp
@@ -1515,3 +1515,42 @@ DIMacroFile *DIMacroFile::getImpl(LLVMContext &Context, unsigned MIType,
Metadata *Ops[] = { File, Elements };
DEFINE_GETIMPL_STORE(DIMacroFile, (MIType, Line), Ops);
}
+
+DIArgList *DIArgList::getImpl(LLVMContext &Context,
+ ArrayRef<ValueAsMetadata *> Args,
+ StorageType Storage, bool ShouldCreate) {
+ DEFINE_GETIMPL_LOOKUP(DIArgList, (Args));
+ DEFINE_GETIMPL_STORE_NO_OPS(DIArgList, (Args));
+}
+
+void DIArgList::handleChangedOperand(void *Ref, Metadata *New) {
+ ValueAsMetadata **OldVMPtr = static_cast<ValueAsMetadata **>(Ref);
+ assert((!New || isa<ValueAsMetadata>(New)) &&
+ "DIArgList must be passed a ValueAsMetadata");
+ untrack();
+ ValueAsMetadata *NewVM = cast_or_null<ValueAsMetadata>(New);
+ for (ValueAsMetadata *&VM : Args) {
+ if (&VM == OldVMPtr) {
+ if (NewVM)
+ VM = NewVM;
+ else
+ VM = ValueAsMetadata::get(UndefValue::get(VM->getValue()->getType()));
+ }
+ }
+ track();
+}
+void DIArgList::track() {
+ for (ValueAsMetadata *&VAM : Args)
+ if (VAM)
+ MetadataTracking::track(&VAM, *VAM, *this);
+}
+void DIArgList::untrack() {
+ for (ValueAsMetadata *&VAM : Args)
+ if (VAM)
+ MetadataTracking::untrack(&VAM, *VAM);
+}
+void DIArgList::dropAllReferences() {
+ untrack();
+ Args.clear();
+ MDNode::dropAllReferences();
+}
diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h
index 4f7e4c23ce28..b221bcd29617 100644
--- a/llvm/lib/IR/LLVMContextImpl.h
+++ b/llvm/lib/IR/LLVMContextImpl.h
@@ -1220,6 +1220,19 @@ template <> struct MDNodeKeyImpl<DIMacroFile> {
}
};
+template <> struct MDNodeKeyImpl<DIArgList> {
+ ArrayRef<ValueAsMetadata *> Args;
+
+ MDNodeKeyImpl(ArrayRef<ValueAsMetadata *> Args) : Args(Args) {}
+ MDNodeKeyImpl(const DIArgList *N) : Args(N->getArgs()) {}
+
+ bool isKeyOf(const DIArgList *RHS) const { return Args == RHS->getArgs(); }
+
+ unsigned getHashValue() const {
+ return hash_combine_range(Args.begin(), Args.end());
+ }
+};
+
/// DenseMapInfo for MDNode subclasses.
template <class NodeTy> struct MDNodeInfo {
using KeyTy = MDNodeKeyImpl<NodeTy>;
diff --git a/llvm/lib/IR/Metadata.cpp b/llvm/lib/IR/Metadata.cpp
index 7ca538995db2..6ac7215645c0 100644
--- a/llvm/lib/IR/Metadata.cpp
+++ b/llvm/lib/IR/Metadata.cpp
@@ -195,6 +195,19 @@ bool MetadataTracking::isReplaceable(const Metadata &MD) {
return ReplaceableMetadataImpl::isReplaceable(MD);
}
+SmallVector<Metadata *, 4> ReplaceableMetadataImpl::getAllArgListUsers() {
+ SmallVector<Metadata *, 4> MDUsers;
+ for (auto Pair : UseMap) {
+ OwnerTy Owner = Pair.second.first;
+ if (!Owner.is<Metadata *>())
+ continue;
+ Metadata *OwnerMD = Owner.get<Metadata *>();
+ if (OwnerMD->getMetadataID() == Metadata::DIArgListKind)
+ MDUsers.push_back(OwnerMD);
+ }
+ return MDUsers;
+}
+
void ReplaceableMetadataImpl::addRef(void *Ref, OwnerTy Owner) {
bool WasInserted =
UseMap.insert(std::make_pair(Ref, std::make_pair(Owner, NextIndex)))
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 47bfbfb19524..be8663553b52 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -1301,6 +1301,13 @@ void Verifier::visitDIMacroFile(const DIMacroFile &N) {
}
}
+void Verifier::visitDIArgList(const DIArgList &N) {
+ AssertDI(!N.getNumOperands(),
+ "DIArgList should have no operands other than a list of "
+ "ValueAsMetadata",
+ &N);
+}
+
void Verifier::visitDIModule(const DIModule &N) {
AssertDI(N.getTag() == dwarf::DW_TAG_module, "invalid tag", &N);
AssertDI(!N.getName().empty(), "anonymous module", &N);
@@ -5365,9 +5372,9 @@ void Verifier::visitConstrainedFPIntrinsic(ConstrainedFPIntrinsic &FPI) {
void Verifier::visitDbgIntrinsic(StringRef Kind, DbgVariableIntrinsic &DII) {
auto *MD = cast<MetadataAsValue>(DII.getArgOperand(0))->getMetadata();
- AssertDI(isa<ValueAsMetadata>(MD) ||
- (isa<MDNode>(MD) && !cast<MDNode>(MD)->getNumOperands()),
- "invalid llvm.dbg." + Kind + " intrinsic address/value", &DII, MD);
+ AssertDI(isa<ValueAsMetadata>(MD) || isa<DIArgList>(MD) ||
+ (isa<MDNode>(MD) && !cast<MDNode>(MD)->getNumOperands()),
+ "invalid llvm.dbg." + Kind + " intrinsic address/value", &DII, MD);
AssertDI(isa<DILocalVariable>(DII.getRawVariable()),
"invalid llvm.dbg." + Kind + " intrinsic variable", &DII,
DII.getRawVariable());
diff --git a/llvm/lib/Transforms/Utils/ValueMapper.cpp b/llvm/lib/Transforms/Utils/ValueMapper.cpp
index 0b1d8c024d84..d0ec368dd84f 100644
--- a/llvm/lib/Transforms/Utils/ValueMapper.cpp
+++ b/llvm/lib/Transforms/Utils/ValueMapper.cpp
@@ -390,6 +390,26 @@ Value *Mapper::mapValue(const Value *V) {
: MetadataAsValue::get(V->getContext(),
MDTuple::get(V->getContext(), None));
}
+ if (auto *AL = dyn_cast<DIArgList>(MD)) {
+ SmallVector<ValueAsMetadata *, 4> MappedArgs;
+ for (auto *VAM : AL->getArgs()) {
+ // Map both Local and Constant VAMs here; they will both ultimately
+ // be mapped via mapValue (apart from constants when we have no
+ // module level changes, which have an identity mapping).
+ if ((Flags & RF_NoModuleLevelChanges) && isa<ConstantAsMetadata>(VAM)) {
+ MappedArgs.push_back(VAM);
+ } else if (Value *LV = mapValue(VAM->getValue())) {
+ MappedArgs.push_back(
+ LV == VAM->getValue() ? VAM : ValueAsMetadata::get(LV));
+ } else {
+ // If we cannot map the value, set the argument as undef.
+ MappedArgs.push_back(ValueAsMetadata::get(
+ UndefValue::get(VAM->getValue()->getType())));
+ }
+ }
+ return MetadataAsValue::get(V->getContext(),
+ DIArgList::get(V->getContext(), MappedArgs));
+ }
// If this is a module-level metadata and we know that nothing at the module
// level is changing, then use an identity mapping.
diff --git a/llvm/test/DebugInfo/Generic/debug_value_list.ll b/llvm/test/DebugInfo/Generic/debug_value_list.ll
new file mode 100644
index 000000000000..177ce29b0c96
--- /dev/null
+++ b/llvm/test/DebugInfo/Generic/debug_value_list.ll
@@ -0,0 +1,50 @@
+; RUN: opt -verify < %s | opt -verify -S | FileCheck %s
+
+; Simple IR-BC-IR round-trip test for a @llvm.dbg.value that uses !DIArgList
+; and DW_OP_LLVM_arg.
+
+source_filename = ".\\debug_value_list.cpp"
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc19.16.27034"
+
+; CHECK-COUNT-3: llvm.dbg.value(
+; CHECK-SAME: metadata !DIArgList(i32 %a, i32 %b)
+; CHECK-SAME: metadata !16,
+; CHECK-SAME: metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus)
+define dso_local i32 @"?foo@@YAHHH at Z"(i32 %a, i32 %b) local_unnamed_addr !dbg !8 {
+entry:
+ call void @llvm.dbg.value(metadata !DIArgList(i32 %b), metadata !14, metadata !DIExpression(DW_OP_LLVM_arg, 0)), !dbg !17
+ call void @llvm.dbg.value(metadata !DIArgList(i32 %a), metadata !15, metadata !DIExpression(DW_OP_LLVM_arg, 0)), !dbg !17
+ call void @llvm.dbg.value(
+ metadata !DIArgList(i32 %a, i32 %b),
+ metadata !16,
+ metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus)), !dbg !17
+ %mul = mul nsw i32 %b, %a, !dbg !18
+ ret i32 %mul, !dbg !18
+}
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5, !6}
+!llvm.ident = !{!7}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 11.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "debug_value_list.cpp", directory: "/tmp")
+!2 = !{}
+!3 = !{i32 2, !"CodeView", i32 1}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 2}
+!6 = !{i32 7, !"PIC Level", i32 2}
+!7 = !{!"clang version 11.0.0"}
+!8 = distinct !DISubprogram(name: "foo", linkageName: "?foo@@YAHHH at Z", scope: !9, file: !9, line: 1, type: !10, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !13)
+!9 = !DIFile(filename: ".\\debug_value_list.cpp", directory: "/tmp")
+!10 = !DISubroutineType(types: !11)
+!11 = !{!12, !12, !12}
+!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!13 = !{!14, !15, !16}
+!14 = !DILocalVariable(name: "b", arg: 2, scope: !8, file: !9, line: 1, type: !12)
+!15 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !9, line: 1, type: !12)
+!16 = !DILocalVariable(name: "c", scope: !8, file: !9, line: 2, type: !12)
+!17 = !DILocation(line: 0, scope: !8)
+!18 = !DILocation(line: 3, scope: !8)
diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp
index 5c05076c5433..a00a49e685b9 100644
--- a/llvm/unittests/IR/MetadataTest.cpp
+++ b/llvm/unittests/IR/MetadataTest.cpp
@@ -3056,6 +3056,42 @@ TEST_F(ValueAsMetadataTest, CollidingDoubleUpdates) {
Temp->replaceAllUsesWith(nullptr);
}
+typedef MetadataTest DIArgListTest;
+
+TEST_F(DIArgListTest, get) {
+ SmallVector<ValueAsMetadata *, 2> VMs;
+ VMs.push_back(
+ ConstantAsMetadata::get(ConstantInt::get(Context, APInt(8, 0))));
+ VMs.push_back(
+ ConstantAsMetadata::get(ConstantInt::get(Context, APInt(2, 0))));
+ DIArgList *DV0 = DIArgList::get(Context, VMs);
+ DIArgList *DV1 = DIArgList::get(Context, VMs);
+ EXPECT_EQ(DV0, DV1);
+}
+
+TEST_F(DIArgListTest, UpdatesOnRAUW) {
+ Type *Ty = Type::getInt1PtrTy(Context);
+ ConstantAsMetadata *CI =
+ ConstantAsMetadata::get(ConstantInt::get(Context, APInt(8, 0)));
+ std::unique_ptr<GlobalVariable> GV0(
+ new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage));
+ auto *MD0 = ValueAsMetadata::get(GV0.get());
+
+ SmallVector<ValueAsMetadata *, 2> VMs;
+ VMs.push_back(CI);
+ VMs.push_back(MD0);
+ auto *AL = DIArgList::get(Context, VMs);
+ EXPECT_EQ(AL->getArgs()[0], CI);
+ EXPECT_EQ(AL->getArgs()[1], MD0);
+
+ std::unique_ptr<GlobalVariable> GV1(
+ new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage));
+ auto *MD1 = ValueAsMetadata::get(GV1.get());
+ GV0->replaceAllUsesWith(GV1.get());
+ EXPECT_EQ(AL->getArgs()[0], CI);
+ EXPECT_EQ(AL->getArgs()[1], MD1);
+}
+
typedef MetadataTest TrackingMDRefTest;
TEST_F(TrackingMDRefTest, UpdatesOnRAUW) {
More information about the llvm-commits
mailing list