Skip to content

Commit

Permalink
[DebugInfo] generate btf_tag annotations for func parameters
Browse files Browse the repository at this point in the history
Generate btf_tag annotations for function parameters.
A field "annotations" is introduced to DILocalVariable, and
annotations are represented as an DINodeArray, similar to
DIComposite elements. The following example illustrates how
annotations are encoded in IR:
    distinct !DILocalVariable(name: "info",, arg: 1, ..., annotations: !10)
    !10 = !{!11, !12}
    !11 = !{!"btf_tag", !"a"}
    !12 = !{!"btf_tag", !"b"}

Differential Revision: https://reviews.llvm.org/D106620
  • Loading branch information
yonghong-song committed Aug 26, 2021
1 parent 7309359 commit 1bebc31
Show file tree
Hide file tree
Showing 11 changed files with 140 additions and 59 deletions.
3 changes: 2 additions & 1 deletion llvm/include/llvm/IR/DIBuilder.h
Expand Up @@ -688,7 +688,8 @@ namespace llvm {
createParameterVariable(DIScope *Scope, StringRef Name, unsigned ArgNo,
DIFile *File, unsigned LineNo, DIType *Ty,
bool AlwaysPreserve = false,
DINode::DIFlags Flags = DINode::FlagZero);
DINode::DIFlags Flags = DINode::FlagZero,
DINodeArray Annotations = nullptr);

/// Create a new descriptor for the specified
/// variable which has a complex address expression for its address.
Expand Down
28 changes: 18 additions & 10 deletions llvm/include/llvm/IR/DebugInfoMetadata.h
Expand Up @@ -3113,34 +3113,37 @@ class DILocalVariable : public DIVariable {
static DILocalVariable *getImpl(LLVMContext &Context, DIScope *Scope,
StringRef Name, DIFile *File, unsigned Line,
DIType *Type, unsigned Arg, DIFlags Flags,
uint32_t AlignInBits, StorageType Storage,
bool ShouldCreate = true) {
uint32_t AlignInBits, DINodeArray Annotations,
StorageType Storage, bool ShouldCreate = true) {
return getImpl(Context, Scope, getCanonicalMDString(Context, Name), File,
Line, Type, Arg, Flags, AlignInBits, Storage, ShouldCreate);
Line, Type, Arg, Flags, AlignInBits, Annotations.get(), Storage,
ShouldCreate);
}
static DILocalVariable *getImpl(LLVMContext &Context, Metadata *Scope,
MDString *Name, Metadata *File, unsigned Line,
Metadata *Type, unsigned Arg, DIFlags Flags,
uint32_t AlignInBits, StorageType Storage,
bool ShouldCreate = true);
uint32_t AlignInBits, Metadata *Annotations,
StorageType Storage, bool ShouldCreate = true);

TempDILocalVariable cloneImpl() const {
return getTemporary(getContext(), getScope(), getName(), getFile(),
getLine(), getType(), getArg(), getFlags(),
getAlignInBits());
getAlignInBits(), getAnnotations());
}

public:
DEFINE_MDNODE_GET(DILocalVariable,
(DILocalScope * Scope, StringRef Name, DIFile *File,
unsigned Line, DIType *Type, unsigned Arg, DIFlags Flags,
uint32_t AlignInBits),
(Scope, Name, File, Line, Type, Arg, Flags, AlignInBits))
uint32_t AlignInBits, DINodeArray Annotations),
(Scope, Name, File, Line, Type, Arg, Flags, AlignInBits,
Annotations))
DEFINE_MDNODE_GET(DILocalVariable,
(Metadata * Scope, MDString *Name, Metadata *File,
unsigned Line, Metadata *Type, unsigned Arg,
DIFlags Flags, uint32_t AlignInBits),
(Scope, Name, File, Line, Type, Arg, Flags, AlignInBits))
DIFlags Flags, uint32_t AlignInBits, Metadata *Annotations),
(Scope, Name, File, Line, Type, Arg, Flags, AlignInBits,
Annotations))

TempDILocalVariable clone() const { return cloneImpl(); }

Expand All @@ -3155,6 +3158,11 @@ class DILocalVariable : public DIVariable {
unsigned getArg() const { return Arg; }
DIFlags getFlags() const { return Flags; }

DINodeArray getAnnotations() const {
return cast_or_null<MDTuple>(getRawAnnotations());
}
Metadata *getRawAnnotations() const { return getOperand(4); }

bool isArtificial() const { return getFlags() & FlagArtificial; }
bool isObjectPointer() const { return getFlags() & FlagObjectPointer; }

Expand Down
6 changes: 4 additions & 2 deletions llvm/lib/AsmParser/LLParser.cpp
Expand Up @@ -4976,13 +4976,15 @@ bool LLParser::parseDILocalVariable(MDNode *&Result, bool IsDistinct) {
OPTIONAL(line, LineField, ); \
OPTIONAL(type, MDField, ); \
OPTIONAL(flags, DIFlagField, ); \
OPTIONAL(align, MDUnsignedField, (0, UINT32_MAX));
OPTIONAL(align, MDUnsignedField, (0, UINT32_MAX)); \
OPTIONAL(annotations, MDField, );
PARSE_MD_FIELDS();
#undef VISIT_MD_FIELDS

Result = GET_OR_DISTINCT(DILocalVariable,
(Context, scope.Val, name.Val, file.Val, line.Val,
type.Val, arg.Val, flags.Val, align.Val));
type.Val, arg.Val, flags.Val, align.Val,
annotations.Val));
return false;
}

Expand Down
11 changes: 8 additions & 3 deletions llvm/lib/Bitcode/Reader/MetadataLoader.cpp
Expand Up @@ -1961,18 +1961,23 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
bool HasTag = !HasAlignment && Record.size() > 8;
DINode::DIFlags Flags = static_cast<DINode::DIFlags>(Record[7 + HasTag]);
uint32_t AlignInBits = 0;
Metadata *Annotations = nullptr;
if (HasAlignment) {
if (Record[8 + HasTag] > (uint64_t)std::numeric_limits<uint32_t>::max())
if (Record[8] > (uint64_t)std::numeric_limits<uint32_t>::max())
return error("Alignment value is too large");
AlignInBits = Record[8 + HasTag];
AlignInBits = Record[8];
if (Record.size() > 9)
Annotations = getMDOrNull(Record[9]);
}

MetadataList.assignValue(
GET_OR_DISTINCT(DILocalVariable,
(Context, getMDOrNull(Record[1 + HasTag]),
getMDString(Record[2 + HasTag]),
getMDOrNull(Record[3 + HasTag]), Record[4 + HasTag],
getDITypeRefOrNull(Record[5 + HasTag]),
Record[6 + HasTag], Flags, AlignInBits)),
Record[6 + HasTag], Flags, AlignInBits,
Annotations)),
NextMetadataNo);
NextMetadataNo++;
break;
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
Expand Up @@ -1994,6 +1994,7 @@ void ModuleBitcodeWriter::writeDILocalVariable(
Record.push_back(N->getArg());
Record.push_back(N->getFlags());
Record.push_back(N->getAlignInBits());
Record.push_back(VE.getMetadataOrNullID(N->getAnnotations().get()));

Stream.EmitRecord(bitc::METADATA_LOCAL_VAR, Record, Abbrev);
Record.clear();
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/IR/AsmWriter.cpp
Expand Up @@ -2316,6 +2316,7 @@ static void writeDILocalVariable(raw_ostream &Out, const DILocalVariable *N,
Printer.printMetadata("type", N->getRawType());
Printer.printDIFlags("flags", N->getFlags());
Printer.printInt("align", N->getAlignInBits());
Printer.printMetadata("annotations", N->getRawAnnotations());
Out << ")";
}

Expand Down
10 changes: 6 additions & 4 deletions llvm/lib/IR/DIBuilder.cpp
Expand Up @@ -739,7 +739,7 @@ static DILocalVariable *createLocalVariable(
DenseMap<MDNode *, SmallVector<TrackingMDNodeRef, 1>> &PreservedVariables,
DIScope *Scope, StringRef Name, unsigned ArgNo, DIFile *File,
unsigned LineNo, DIType *Ty, bool AlwaysPreserve, DINode::DIFlags Flags,
uint32_t AlignInBits) {
uint32_t AlignInBits, DINodeArray Annotations = nullptr) {
// FIXME: Why getNonCompileUnitScope()?
// FIXME: Why is "!Context" okay here?
// FIXME: Why doesn't this check for a subprogram or lexical block (AFAICT
Expand All @@ -748,7 +748,8 @@ static DILocalVariable *createLocalVariable(

auto *Node =
DILocalVariable::get(VMContext, cast_or_null<DILocalScope>(Context), Name,
File, LineNo, Ty, ArgNo, Flags, AlignInBits);
File, LineNo, Ty, ArgNo, Flags, AlignInBits,
Annotations);
if (AlwaysPreserve) {
// The optimizer may remove local variables. If there is an interest
// to preserve variable info in such situation then stash it in a
Expand All @@ -772,11 +773,12 @@ DILocalVariable *DIBuilder::createAutoVariable(DIScope *Scope, StringRef Name,

DILocalVariable *DIBuilder::createParameterVariable(
DIScope *Scope, StringRef Name, unsigned ArgNo, DIFile *File,
unsigned LineNo, DIType *Ty, bool AlwaysPreserve, DINode::DIFlags Flags) {
unsigned LineNo, DIType *Ty, bool AlwaysPreserve, DINode::DIFlags Flags,
DINodeArray Annotations) {
assert(ArgNo && "Expected non-zero argument number for parameter");
return createLocalVariable(VMContext, PreservedVariables, Scope, Name, ArgNo,
File, LineNo, Ty, AlwaysPreserve, Flags,
/* AlignInBits */0);
/* AlignInBits */0, Annotations);
}

DILabel *DIBuilder::createLabel(
Expand Down
5 changes: 3 additions & 2 deletions llvm/lib/IR/DebugInfoMetadata.cpp
Expand Up @@ -1011,6 +1011,7 @@ DILocalVariable *DILocalVariable::getImpl(LLVMContext &Context, Metadata *Scope,
unsigned Line, Metadata *Type,
unsigned Arg, DIFlags Flags,
uint32_t AlignInBits,
Metadata *Annotations,
StorageType Storage,
bool ShouldCreate) {
// 64K ought to be enough for any frontend.
Expand All @@ -1020,8 +1021,8 @@ DILocalVariable *DILocalVariable::getImpl(LLVMContext &Context, Metadata *Scope,
assert(isCanonical(Name) && "Expected canonical MDString");
DEFINE_GETIMPL_LOOKUP(DILocalVariable,
(Scope, Name, File, Line, Type, Arg, Flags,
AlignInBits));
Metadata *Ops[] = {Scope, Name, File, Type};
AlignInBits, Annotations));
Metadata *Ops[] = {Scope, Name, File, Type, Annotations};
DEFINE_GETIMPL_STORE(DILocalVariable, (Line, Arg, Flags, AlignInBits), Ops);
}

Expand Down
13 changes: 8 additions & 5 deletions llvm/lib/IR/LLVMContextImpl.h
Expand Up @@ -1042,22 +1042,25 @@ template <> struct MDNodeKeyImpl<DILocalVariable> {
unsigned Arg;
unsigned Flags;
uint32_t AlignInBits;
Metadata *Annotations;

MDNodeKeyImpl(Metadata *Scope, MDString *Name, Metadata *File, unsigned Line,
Metadata *Type, unsigned Arg, unsigned Flags,
uint32_t AlignInBits)
uint32_t AlignInBits, Metadata *Annotations)
: Scope(Scope), Name(Name), File(File), Line(Line), Type(Type), Arg(Arg),
Flags(Flags), AlignInBits(AlignInBits) {}
Flags(Flags), AlignInBits(AlignInBits), Annotations(Annotations) {}
MDNodeKeyImpl(const DILocalVariable *N)
: Scope(N->getRawScope()), Name(N->getRawName()), File(N->getRawFile()),
Line(N->getLine()), Type(N->getRawType()), Arg(N->getArg()),
Flags(N->getFlags()), AlignInBits(N->getAlignInBits()) {}
Flags(N->getFlags()), AlignInBits(N->getAlignInBits()),
Annotations(N->getRawAnnotations()) {}

bool isKeyOf(const DILocalVariable *RHS) const {
return Scope == RHS->getRawScope() && Name == RHS->getRawName() &&
File == RHS->getRawFile() && Line == RHS->getLine() &&
Type == RHS->getRawType() && Arg == RHS->getArg() &&
Flags == RHS->getFlags() && AlignInBits == RHS->getAlignInBits();
Flags == RHS->getFlags() && AlignInBits == RHS->getAlignInBits() &&
Annotations == RHS->getRawAnnotations();
}

unsigned getHashValue() const {
Expand All @@ -1068,7 +1071,7 @@ template <> struct MDNodeKeyImpl<DILocalVariable> {
// clang/test/CodeGen/debug-info-257-args.c is an example of this problem,
// generated IR is random for each run and test fails with Align included.
// TODO: make hashing work fine with such situations
return hash_combine(Scope, Name, File, Line, Type, Arg, Flags);
return hash_combine(Scope, Name, File, Line, Type, Arg, Flags, Annotations);
}
};

Expand Down
46 changes: 46 additions & 0 deletions llvm/test/Bitcode/attr-btf_tag-parameter.ll
@@ -0,0 +1,46 @@
; REQUIRES: x86-registered-target
; RUN: llvm-as < %s | llvm-dis | FileCheck %s

; Function Attrs: mustprogress nofree norecurse nosync nounwind readnone uwtable willreturn
define dso_local i32 @f(i32 %a) local_unnamed_addr #0 !dbg !8 {
entry:
call void @llvm.dbg.value(metadata i32 %a, metadata !13, metadata !DIExpression()), !dbg !17
ret i32 0, !dbg !18
}

; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
declare void @llvm.dbg.value(metadata, metadata, metadata) #1

attributes #0 = { mustprogress nofree norecurse nosync nounwind readnone uwtable willreturn "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { nofree nosync nounwind readnone speculatable willreturn }

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4, !5, !6}
!llvm.ident = !{!7}

!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 13.0.0 (https://github.com/llvm/llvm-project.git c9e3139e00bcef23b236a02890b909a130d1b3d9)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
!1 = !DIFile(filename: "func.c", directory: "/home/yhs/work/tests/llvm/btf_tag")
!2 = !{}
!3 = !{i32 7, !"Dwarf Version", i32 4}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = !{i32 1, !"wchar_size", i32 4}
!6 = !{i32 7, !"uwtable", i32 1}
!7 = !{!"clang version 13.0.0 (https://github.com/llvm/llvm-project.git c9e3139e00bcef23b236a02890b909a130d1b3d9)"}
!8 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !12)
!9 = !DISubroutineType(types: !10)
!10 = !{!11, !11}
!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!12 = !{!13}
!13 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !1, line: 1, type: !11, annotations: !14)
!14 = !{!15, !16}
!15 = !{!"btf_tag", !"a"}
!16 = !{!"btf_tag", !"b"}

; CHECK: !DILocalVariable(name: "a", arg: 1,
; CHECK-SAME: annotations: ![[ANNOT:[0-9]+]]
; CHECK: ![[ANNOT]] = !{![[TAG1:[0-9]+]], ![[TAG2:[0-9]+]]}
; CHECK: ![[TAG1]] = !{!"btf_tag", !"a"}
; CHECK: ![[TAG2]] = !{!"btf_tag", !"b"}

!17 = !DILocation(line: 0, scope: !8)
!18 = !DILocation(line: 1, column: 76, scope: !8)

0 comments on commit 1bebc31

Please sign in to comment.