-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for builtin_verbose_trap #79230
Changes from all commits
95200f3
156e9de
78b1c45
856fd3d
5efc514
0ff6ac0
206e55d
4aa91cc
521fe91
c72fc17
5bbb01b
4896af0
7463986
c7bd914
1db9628
6881d0d
65671ff
ae3907d
e13d85c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,6 +32,7 @@ | |
#include "clang/Basic/FileManager.h" | ||
#include "clang/Basic/SourceManager.h" | ||
#include "clang/Basic/Version.h" | ||
#include "clang/CodeGen/ModuleBuilder.h" | ||
#include "clang/Frontend/FrontendOptions.h" | ||
#include "clang/Lex/HeaderSearchOptions.h" | ||
#include "clang/Lex/ModuleMap.h" | ||
|
@@ -1692,6 +1693,28 @@ llvm::DIType *CGDebugInfo::createFieldType( | |
offsetInBits, flags, debugType, Annotations); | ||
} | ||
|
||
llvm::DISubprogram * | ||
CGDebugInfo::createInlinedTrapSubprogram(StringRef FuncName, | ||
llvm::DIFile *FileScope) { | ||
// We are caching the subprogram because we don't want to duplicate | ||
// subprograms with the same message. Note that `SPFlagDefinition` prevents | ||
// subprograms from being uniqued. | ||
llvm::DISubprogram *&SP = InlinedTrapFuncMap[FuncName]; | ||
delcypher marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
if (!SP) { | ||
llvm::DISubroutineType *DIFnTy = DBuilder.createSubroutineType(nullptr); | ||
SP = DBuilder.createFunction( | ||
/*Scope=*/FileScope, /*Name=*/FuncName, /*LinkageName=*/StringRef(), | ||
/*File=*/FileScope, /*LineNo=*/0, /*Ty=*/DIFnTy, | ||
/*ScopeLine=*/0, | ||
/*Flags=*/llvm::DINode::FlagArtificial, | ||
/*SPFlags=*/llvm::DISubprogram::SPFlagDefinition, | ||
/*TParams=*/nullptr, /*ThrownTypes=*/nullptr, /*Annotations=*/nullptr); | ||
} | ||
|
||
return SP; | ||
} | ||
|
||
void CGDebugInfo::CollectRecordLambdaFields( | ||
const CXXRecordDecl *CXXDecl, SmallVectorImpl<llvm::Metadata *> &elements, | ||
llvm::DIType *RecordTy) { | ||
|
@@ -3488,6 +3511,23 @@ llvm::DIMacroFile *CGDebugInfo::CreateTempMacroFile(llvm::DIMacroFile *Parent, | |
return DBuilder.createTempMacroFile(Parent, Line, FName); | ||
} | ||
|
||
llvm::DILocation *CGDebugInfo::CreateTrapFailureMessageFor( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's currently only one caller with a fixed parameter for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @dwblaikie We currently use this function for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @dwblaikie what do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @dwblaikie any comments? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I agree with https://github.com/llvm/llvm-project/pull/79230/files#r1529429173 then - the prefix should be a parameter and I don't think it needs to be a #defined constant (CLANG_VERBOSE_TRAP_PREFIX) - and can instead be written as a literal in the caller in CGBuiltin.cpp? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, I'll make it a parameter then. I added macro There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @dwblaikie 's comment: So the name of the subprogram would be something like @Michael137 @delcypher is there a reason we cannot use the same prefix ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've updated the patch to pass a category string to the builtin. The artificial function name has the format We should probably use something other than There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @dwblaikie any other comments? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Eh, I'm not too fussed about the separator for the prefix (we control that) and category (will the category be user-visible? Like a warning group? Or is that only still an implementation detail/contract between DWARF producer and DWARF consumer? I thought it was more the latter/implementation detail? In which case we can say what characters are valid there, and I'd keep it pretty simple, like the warning group names - all lower, dash or underscore separated seems fine) |
||
llvm::DebugLoc TrapLocation, StringRef Category, StringRef FailureMsg) { | ||
// Create a debug location from `TrapLocation` that adds an artificial inline | ||
// frame. | ||
SmallString<64> FuncName(ClangTrapPrefix); | ||
|
||
FuncName += "$"; | ||
FuncName += Category; | ||
FuncName += "$"; | ||
FuncName += FailureMsg; | ||
|
||
llvm::DISubprogram *TrapSP = | ||
createInlinedTrapSubprogram(FuncName, TrapLocation->getFile()); | ||
return llvm::DILocation::get(CGM.getLLVMContext(), /*Line=*/0, /*Column=*/0, | ||
/*Scope=*/TrapSP, /*InlinedAt=*/TrapLocation); | ||
} | ||
|
||
static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) { | ||
Qualifiers Quals; | ||
do { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,7 +29,9 @@ | |
#include "llvm/IR/DebugInfo.h" | ||
#include "llvm/IR/ValueHandle.h" | ||
#include "llvm/Support/Allocator.h" | ||
#include <map> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems to not belong to this commit? |
||
#include <optional> | ||
#include <string> | ||
|
||
namespace llvm { | ||
class MDNode; | ||
|
@@ -346,6 +348,14 @@ class CGDebugInfo { | |
const FieldDecl *BitFieldDecl, const llvm::DIDerivedType *BitFieldDI, | ||
llvm::ArrayRef<llvm::Metadata *> PreviousFieldsDI, const RecordDecl *RD); | ||
|
||
/// A cache that maps names of artificial inlined functions to subprograms. | ||
llvm::StringMap<llvm::DISubprogram *> InlinedTrapFuncMap; | ||
delcypher marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/// A function that returns the subprogram corresponding to the artificial | ||
/// inlined function for traps. | ||
llvm::DISubprogram *createInlinedTrapSubprogram(StringRef FuncName, | ||
llvm::DIFile *FileScope); | ||
|
||
/// Helpers for collecting fields of a record. | ||
/// @{ | ||
void CollectRecordLambdaFields(const CXXRecordDecl *CXXDecl, | ||
|
@@ -602,6 +612,18 @@ class CGDebugInfo { | |
return CoroutineParameterMappings; | ||
} | ||
|
||
/// Create a debug location from `TrapLocation` that adds an artificial inline | ||
/// frame where the frame name is | ||
/// | ||
/// * `<Prefix>:<Category>:<FailureMsg>` | ||
/// | ||
/// `<Prefix>` is "__clang_trap_msg". | ||
/// | ||
/// This is used to store failure reasons for traps. | ||
llvm::DILocation *CreateTrapFailureMessageFor(llvm::DebugLoc TrapLocation, | ||
StringRef Category, | ||
StringRef FailureMsg); | ||
|
||
private: | ||
/// Emit call to llvm.dbg.declare for a variable declaration. | ||
/// Returns a pointer to the DILocalVariable associated with the | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// RUN: %clang_cc1 -triple arm64-apple-ios -std=c++20 -emit-llvm -debug-info-kind=limited %s -o - | FileCheck %s | ||
delcypher marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// CHECK-LABEL: define void @_Z2f0v() | ||
// CHECK: call void @llvm.trap(), !dbg ![[LOC17:.*]] | ||
|
||
// CHECK: declare void @llvm.trap() #[[ATTR1:.*]] | ||
|
||
// CHECK-LABEL: define void @_Z2f1v() | ||
// CHECK: call void @llvm.trap(), !dbg ![[LOC23:.*]] | ||
// CHECK: call void @llvm.trap(), !dbg ![[LOC25:.*]] | ||
|
||
// CHECK-LABEL: define void @_Z2f3v() | ||
// CHECK: call void @_Z2f2IXadsoKcL_ZL8constCatEEEXadsoS0_L_ZL8constMsgEEEEvv() | ||
|
||
// CHECK-LABEL: define internal void @_Z2f2IXadsoKcL_ZL8constCatEEEXadsoS0_L_ZL8constMsgEEEEvv | ||
// CHECK: call void @llvm.trap(), !dbg ![[LOC36:.*]] | ||
|
||
// CHECK: attributes #[[ATTR1]] = { cold {{.*}}} | ||
|
||
// CHECK: ![[FILESCOPE:.*]] = !DIFile(filename: "{{.*}}debug-info-verbose-trap.cpp" | ||
|
||
delcypher marked this conversation as resolved.
Show resolved
Hide resolved
|
||
char const constCat[] = "category2"; | ||
char const constMsg[] = "hello"; | ||
|
||
// CHECK: ![[SUBPROG14:.*]] = distinct !DISubprogram(name: "f0", linkageName: "_Z2f0v", | ||
// CHECK: ![[LOC17]] = !DILocation(line: 0, scope: ![[SUBPROG18:.*]], inlinedAt: ![[LOC20:.*]]) | ||
// CHECK: ![[SUBPROG18]] = distinct !DISubprogram(name: "__clang_trap_msg$category1$Argument_must_not_be_null", scope: ![[FILESCOPE]], file: ![[FILESCOPE]], type: !{{.*}}, flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: !{{.*}}) | ||
// CHECK: ![[LOC20]] = !DILocation(line: [[@LINE+2]], column: 3, scope: ![[SUBPROG14]]) | ||
void f0() { | ||
__builtin_verbose_trap("category1", "Argument_must_not_be_null"); | ||
} | ||
|
||
// CHECK: ![[SUBPROG22:.*]] = distinct !DISubprogram(name: "f1", linkageName: "_Z2f1v", | ||
// CHECK: ![[LOC23]] = !DILocation(line: 0, scope: ![[SUBPROG18]], inlinedAt: ![[LOC24:.*]]) | ||
// CHECK: ![[LOC24]] = !DILocation(line: [[@LINE+5]], column: 3, scope: ![[SUBPROG22]]) | ||
// CHECK: ![[LOC25]] = !DILocation(line: 0, scope: ![[SUBPROG26:.*]], inlinedAt: ![[LOC27:.*]]) | ||
// CHECK: ![[SUBPROG26]] = distinct !DISubprogram(name: "__clang_trap_msg$category2$hello", scope: ![[FILESCOPE]], file: ![[FILESCOPE]], type: !{{.*}}, flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: !{{.*}}) | ||
// CHECK: ![[LOC27]] = !DILocation(line: [[@LINE+3]], column: 3, scope: ![[SUBPROG22]]) | ||
void f1() { | ||
__builtin_verbose_trap("category1", "Argument_must_not_be_null"); | ||
__builtin_verbose_trap("category2", "hello"); | ||
} | ||
|
||
// CHECK: ![[SUBPROG32:.*]] = distinct !DISubprogram(name: "f2<constCat, constMsg>", linkageName: "_Z2f2IXadsoKcL_ZL8constCatEEEXadsoS0_L_ZL8constMsgEEEEvv", | ||
// CHECK: ![[LOC36]] = !DILocation(line: 0, scope: ![[SUBPROG26]], inlinedAt: ![[LOC37:.*]]) | ||
// CHECK: ![[LOC37]] = !DILocation(line: [[@LINE+3]], column: 3, scope: ![[SUBPROG32]]) | ||
template <const char * const category, const char * const reason> | ||
void f2() { | ||
__builtin_verbose_trap(category, reason); | ||
} | ||
|
||
void f3() { | ||
f2<constCat, constMsg>(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ahatanak Is this in the wrong place in the document?
__builtin_verbose_trap
is lexicographically after__builtin_nondeterministic_value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't look like the existing builtins are in lexicographical order.
__builtin_debugtrap
is followed by__builtin_trap
, which is followed by__builtin_nondeterministic_value
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, OK - that seems like more reason the prefix should be singular. Like we shouldn't add a new/distinct prefix for array bounds? Or other things we want to error out on - because it'd be an ongoing maintenance problem updating consumers like lldb each time we add one?
So maybe we should have a generic prefix we'll always use (
__builtin_trap
, say) and then maybe some identifier after that in a known format (eg: space, identifier, space) that can be used? then an error message string?