forked from OSchip/llvm-project
[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
This commit is contained in:
parent
adc35b689f
commit
65600cb2a7
|
@ -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
|
||||
"""""""""""""""
|
||||
|
||||
|
|
|
@ -161,7 +161,8 @@ enum {
|
|||
LLVMDIMacroFileMetadataKind,
|
||||
LLVMDICommonBlockMetadataKind,
|
||||
LLVMDIStringTypeMetadataKind,
|
||||
LLVMDIGenericSubrangeMetadataKind
|
||||
LLVMDIGenericSubrangeMetadataKind,
|
||||
LLVMDIArgListMetadataKind
|
||||
};
|
||||
typedef unsigned LLVMMetadataKind;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -3510,6 +3510,52 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// 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,
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -299,6 +299,9 @@ public:
|
|||
/// 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 @@ public:
|
|||
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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -335,6 +335,8 @@ private:
|
|||
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) {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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 << " = ";
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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@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@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)
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue