augusto2112 updated this revision to Diff 511513.
augusto2112 added a comment.
Added release note
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D146595/new/
https://reviews.llvm.org/D146595
Files:
clang/docs/ReleaseNotes.rst
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/AttrDocs.td
clang/lib/CodeGen/CGDebugInfo.cpp
clang/test/CodeGen/attr-debug-trampoline-method.cpp
clang/test/CodeGen/attr-debug-trampoline-objc.m
clang/test/CodeGen/attr-debug-trampoline.c
clang/test/Misc/pragma-attribute-supported-attributes-list.test
clang/test/Sema/attr-debug-trampoline.c
clang/test/SemaCXX/attr-debug-trampoline-method.cpp
clang/test/SemaObjC/attr-debug-trampoline-objc.m
llvm/include/llvm/IR/DebugInfoFlags.def
llvm/include/llvm/IR/DebugInfoMetadata.h
llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
llvm/test/Assembler/disubprogram-debug-trampoline.ll
llvm/test/DebugInfo/AArch64/disubprogram-debug-trampoline.ll
llvm/unittests/IR/MetadataTest.cpp
Index: llvm/unittests/IR/MetadataTest.cpp
===================================================================
--- llvm/unittests/IR/MetadataTest.cpp
+++ llvm/unittests/IR/MetadataTest.cpp
@@ -2521,6 +2521,7 @@
assert(!IsLocalToUnit && IsDefinition && !IsOptimized &&
"bools and SPFlags have to match");
SPFlags |= DISubprogram::SPFlagDefinition;
+ SPFlags |= DISubprogram::SPFlagIsTransparentStepping;
auto *N = DISubprogram::get(
Context, Scope, Name, LinkageName, File, Line, Type, ScopeLine,
@@ -2604,12 +2605,17 @@
Flags, SPFlags ^ DISubprogram::SPFlagDefinition, Unit,
TemplateParams, Declaration, RetainedNodes, ThrownTypes,
Annotations, TargetFuncName));
- EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line,
- Type, ScopeLine + 1, ContainingType,
- VirtualIndex, ThisAdjustment, Flags, SPFlags,
- Unit, TemplateParams, Declaration,
- RetainedNodes, ThrownTypes, Annotations,
- TargetFuncName));
+ EXPECT_NE(N, DISubprogram::get(
+ Context, Scope, Name, LinkageName, File, Line, Type,
+ ScopeLine, ContainingType, VirtualIndex, ThisAdjustment,
+ Flags, SPFlags ^ DISubprogram::SPFlagIsTransparentStepping,
+ Unit, TemplateParams, Declaration, RetainedNodes,
+ ThrownTypes, Annotations, TargetFuncName));
+ EXPECT_NE(N, DISubprogram::get(
+ Context, Scope, Name, LinkageName, File, Line, Type,
+ ScopeLine + 1, ContainingType, VirtualIndex, ThisAdjustment,
+ Flags, SPFlags, Unit, TemplateParams, Declaration,
+ RetainedNodes, ThrownTypes, Annotations, TargetFuncName));
EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line,
Type, ScopeLine, getCompositeType(),
VirtualIndex, ThisAdjustment, Flags, SPFlags,
Index: llvm/test/DebugInfo/AArch64/disubprogram-debug-trampoline.ll
===================================================================
--- /dev/null
+++ llvm/test/DebugInfo/AArch64/disubprogram-debug-trampoline.ll
@@ -0,0 +1,42 @@
+; This test verifies that the proper DWARF debug info is emitted
+; for a trampoline function with no target.
+;
+; RUN: llc -filetype=obj %s -o - | llvm-dwarfdump - | FileCheck %s
+;
+; CHECK: DW_TAG_subprogram
+; CHECK: DW_AT_name ("baz")
+; CHECK: DW_AT_trampoline (true)
+;
+; ModuleID = 't.c'
+source_filename = "t.c"
+target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
+target triple = "arm64-apple-macosx13.0.0"
+
+; Function Attrs: noinline nounwind optnone ssp uwtable(sync)
+define void @baz() #0 !dbg !10 {
+entry:
+ ret void, !dbg !14
+}
+
+attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" }
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6}
+!llvm.dbg.cu = !{!7}
+!llvm.ident = !{!9}
+
+!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 13, i32 2]}
+!1 = !{i32 7, !"Dwarf Version", i32 4}
+!2 = !{i32 2, !"Debug Info Version", i32 3}
+!3 = !{i32 1, !"wchar_size", i32 4}
+!4 = !{i32 8, !"PIC Level", i32 2}
+!5 = !{i32 7, !"uwtable", i32 1}
+!6 = !{i32 7, !"frame-pointer", i32 1}
+!7 = distinct !DICompileUnit(language: DW_LANG_C11, file: !8, producer: "clang version 17.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!8 = !DIFile(filename: "t.c", directory: "/")
+!9 = !{!"clang version 17.0.0"}
+!10 = distinct !DISubprogram(name: "baz", scope: !8, file: !8, line: 3, type: !11, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagIsDebugTrampoline, unit: !7, retainedNodes: !13)
+!11 = !DISubroutineType(types: !12)
+!12 = !{null}
+!13 = !{}
+!14 = !DILocation(line: 4, column: 1, scope: !10)
+
Index: llvm/test/Assembler/disubprogram-debug-trampoline.ll
===================================================================
--- /dev/null
+++ llvm/test/Assembler/disubprogram-debug-trampoline.ll
@@ -0,0 +1,39 @@
+; This test verifies that the DISPFlagIsDebugTrampoline attribute in a DISubprogram
+; is assembled/disassembled correctly.
+;
+; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
+;
+; CHECK: !DISubprogram(name: "baz",{{.*}} DISPFlagIsDebugTrampoline
+;
+; ModuleID = 't.c'
+source_filename = "t.c"
+target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
+target triple = "arm64-apple-macosx13.0.0"
+
+; Function Attrs: noinline nounwind optnone ssp uwtable(sync)
+define void @baz() #0 !dbg !10 {
+entry:
+ ret void, !dbg !14
+}
+
+attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" }
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6}
+!llvm.dbg.cu = !{!7}
+!llvm.ident = !{!9}
+
+!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 13, i32 2]}
+!1 = !{i32 7, !"Dwarf Version", i32 4}
+!2 = !{i32 2, !"Debug Info Version", i32 3}
+!3 = !{i32 1, !"wchar_size", i32 4}
+!4 = !{i32 8, !"PIC Level", i32 2}
+!5 = !{i32 7, !"uwtable", i32 1}
+!6 = !{i32 7, !"frame-pointer", i32 1}
+!7 = distinct !DICompileUnit(language: DW_LANG_C11, file: !8, producer: "clang version 17.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!8 = !DIFile(filename: "t.c", directory: "/")
+!9 = !{!"clang version 17.0.0"}
+!10 = distinct !DISubprogram(name: "baz", scope: !8, file: !8, line: 3, type: !11, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagIsDebugTrampoline, unit: !7, retainedNodes: !13)
+!11 = !DISubroutineType(types: !12)
+!12 = !{null}
+!13 = !{}
+!14 = !DILocation(line: 4, column: 1, scope: !10)
Index: llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
===================================================================
--- llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
+++ llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
@@ -1345,6 +1345,9 @@
if (!SP->getTargetFuncName().empty())
addString(SPDie, dwarf::DW_AT_trampoline, SP->getTargetFuncName());
+ if (SP->isDebugTrampoline())
+ addFlag(SPDie, dwarf::DW_AT_trampoline);
+
if (DD->getDwarfVersion() >= 5 && SP->isDeleted())
addFlag(SPDie, dwarf::DW_AT_deleted);
}
Index: llvm/include/llvm/IR/DebugInfoMetadata.h
===================================================================
--- llvm/include/llvm/IR/DebugInfoMetadata.h
+++ llvm/include/llvm/IR/DebugInfoMetadata.h
@@ -1760,6 +1760,9 @@
bool isElemental() const { return getSPFlags() & SPFlagElemental; }
bool isRecursive() const { return getSPFlags() & SPFlagRecursive; }
bool isObjCDirect() const { return getSPFlags() & SPFlagObjCDirect; }
+ bool isDebugTrampoline() const {
+ return getSPFlags() & SPFlagIsDebugTrampoline;
+ }
/// Check if this is deleted member function.
///
Index: llvm/include/llvm/IR/DebugInfoFlags.def
===================================================================
--- llvm/include/llvm/IR/DebugInfoFlags.def
+++ llvm/include/llvm/IR/DebugInfoFlags.def
@@ -91,11 +91,12 @@
// for defaulted functions
HANDLE_DISP_FLAG((1u << 9), Deleted)
HANDLE_DISP_FLAG((1u << 11), ObjCDirect)
+HANDLE_DISP_FLAG((1u << 12), IsDebugTrampoline)
#ifdef DISP_FLAG_LARGEST_NEEDED
// Intended to be used with ADT/BitmaskEnum.h.
// NOTE: Always must be equal to largest flag, check this when adding new flags.
-HANDLE_DISP_FLAG((1 << 11), Largest)
+HANDLE_DISP_FLAG((1 << 12), Largest)
#undef DISP_FLAG_LARGEST_NEEDED
#endif
Index: clang/test/SemaObjC/attr-debug-trampoline-objc.m
===================================================================
--- /dev/null
+++ clang/test/SemaObjC/attr-debug-trampoline-objc.m
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only
+
+
+
+@interface ObjCClass
+- (void)correct __attribute__((debug_trampoline));
+- (void)one_arg __attribute__((debug_trampoline(1))); // expected-error {{'debug_trampoline' attribute takes no arguments}}
+@end
+
Index: clang/test/SemaCXX/attr-debug-trampoline-method.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/attr-debug-trampoline-method.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only
+
+
+struct S {
+[[clang::debug_trampoline]]
+void correct(void) {}
+
+[[clang::debug_trampoline(1)]] // expected-error {{'debug_trampoline' attribute takes no arguments}}
+void one_arg(void) {}
+};
+
Index: clang/test/Sema/attr-debug-trampoline.c
===================================================================
--- /dev/null
+++ clang/test/Sema/attr-debug-trampoline.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only
+
+__attribute__((debug_trampoline))
+void correct(void) {}
+
+__attribute__((debug_trampoline(1))) // expected-error {{'debug_trampoline' attribute takes no arguments}}
+void wrong_arg(void) {}
Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test
===================================================================
--- clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -186,6 +186,7 @@
// CHECK-NEXT: TargetClones (SubjectMatchRule_function)
// CHECK-NEXT: TargetVersion (SubjectMatchRule_function)
// CHECK-NEXT: TestTypestate (SubjectMatchRule_function_is_member)
+// CHECK-NEXT: TransparentStepping (SubjectMatchRule_function)
// CHECK-NEXT: TrivialABI (SubjectMatchRule_record)
// CHECK-NEXT: Uninitialized (SubjectMatchRule_variable_is_local)
// CHECK-NEXT: UnsafeBufferUsage (SubjectMatchRule_function)
Index: clang/test/CodeGen/attr-debug-trampoline.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/attr-debug-trampoline.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -debug-info-kind=limited -emit-llvm -o - %s | FileCheck %s
+
+void bar(void) {}
+
+__attribute__((debug_trampoline))
+void foo(void) {
+ bar();
+}
+
+// CHECK: DISubprogram(name: "foo"{{.*}} DISPFlagIsDebugTrampoline
Index: clang/test/CodeGen/attr-debug-trampoline-objc.m
===================================================================
--- /dev/null
+++ clang/test/CodeGen/attr-debug-trampoline-objc.m
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -debug-info-kind=limited -emit-llvm -o - %s | FileCheck %s
+
+
+@interface ObjCClass
+- (void)foo __attribute__((debug_trampoline));
+@end
+
+@implementation ObjCClass
+- (void)foo {}
+@end
+
+
+// CHECK: DISubprogram(name: "-[ObjCClass foo]"{{.*}} DISPFlagIsDebugTrampoline
Index: clang/test/CodeGen/attr-debug-trampoline-method.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/attr-debug-trampoline-method.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -debug-info-kind=limited -emit-llvm -o - %s | FileCheck %s
+
+void bar(void) {}
+
+struct A {
+[[clang::debug_trampoline()]]
+void foo(void) {
+ bar();
+}
+};
+
+int main() {
+ A().foo();
+}
+
+// CHECK: DISubprogram(name: "foo"{{.*}} DISPFlagIsDebugTrampoline
Index: clang/lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- clang/lib/CodeGen/CGDebugInfo.cpp
+++ clang/lib/CodeGen/CGDebugInfo.cpp
@@ -69,6 +69,12 @@
return D->hasAttr<AlignedAttr>() ? D->getMaxAlignment() : 0;
}
+static bool usesDebugTrampoline(const Decl *D) {
+ if (!D)
+ return false;
+ return D->hasAttr<DebugTrampolineAttr>();
+}
+
CGDebugInfo::CGDebugInfo(CodeGenModule &CGM)
: CGM(CGM), DebugKind(CGM.getCodeGenOpts().getDebugInfo()),
DebugTypeExtRefs(CGM.getCodeGenOpts().DebugTypeExtRefs),
@@ -1987,6 +1993,8 @@
SPFlags |= llvm::DISubprogram::SPFlagLocalToUnit;
if (CGM.getLangOpts().Optimize)
SPFlags |= llvm::DISubprogram::SPFlagOptimized;
+ if (usesDebugTrampoline(Method))
+ SPFlags |= llvm::DISubprogram::SPFlagIsDebugTrampoline;
// In this debug mode, emit type info for a class when its constructor type
// info is emitted.
@@ -3928,6 +3936,8 @@
if (Stub) {
Flags |= getCallSiteRelatedAttrs();
SPFlags |= llvm::DISubprogram::SPFlagDefinition;
+ if (usesDebugTrampoline(FD))
+ SPFlags |= llvm::DISubprogram::SPFlagIsDebugTrampoline;
return DBuilder.createFunction(
DContext, Name, LinkageName, Unit, Line,
getOrCreateFunctionType(GD.getDecl(), FnType, Unit), 0, Flags, SPFlags,
@@ -4077,6 +4087,8 @@
if (It == TypeCache.end())
return nullptr;
auto *InterfaceType = cast<llvm::DICompositeType>(It->second);
+ if (usesDebugTrampoline(D))
+ SPFlags |= llvm::DISubprogram::SPFlagIsDebugTrampoline;
llvm::DISubprogram *FD = DBuilder.createFunction(
InterfaceType, getObjCMethodName(OMD), StringRef(),
InterfaceType->getFile(), LineNo, FnType, LineNo, Flags, SPFlags);
@@ -4244,6 +4256,8 @@
SPFlags |= llvm::DISubprogram::SPFlagLocalToUnit;
if (CGM.getLangOpts().Optimize)
SPFlags |= llvm::DISubprogram::SPFlagOptimized;
+ if (usesDebugTrampoline(D))
+ SPFlags |= llvm::DISubprogram::SPFlagIsDebugTrampoline;
llvm::DINode::DIFlags FlagsForDef = Flags | getCallSiteRelatedAttrs();
llvm::DISubprogram::DISPFlags SPFlagsForDef =
@@ -4330,6 +4344,9 @@
llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(D);
llvm::DISubroutineType *STy = getOrCreateFunctionType(D, FnType, Unit);
+ if (usesDebugTrampoline(D))
+ SPFlags |= llvm::DISubprogram::SPFlagIsDebugTrampoline;
+
llvm::DISubprogram *SP = DBuilder.createFunction(
FDContext, Name, LinkageName, Unit, LineNo, STy, ScopeLine, Flags,
SPFlags, TParamsArray.get(), nullptr, nullptr, Annotations);
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -6903,6 +6903,66 @@
}];
}
+def DebugTrampolineDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+The ``debug_trampoline`` attribute is intended as a hint for debuggers that this
+function itself is not interesting, but it calls a function that might be. So, when
+stepping in arrives at a function with this attribute, debuggers should transparently
+step-in through it into the functions called by the annotated function (but not by
+subsequent calls made by those functions), stopping at the first one its normal rules
+for whether to stop says to stop at - or stepping out again if none qualify. Also, when
+stepping out arrives at a function with this attribute, the debugger should continue
+stepping out to its caller.
+
+For example:
+
+.. code-block:: c
+
+ int bar(void) {
+ return 42;
+ }
+
+ __attribute__((debug_trampoline))
+ int foo(void) {
+ return bar();
+ }
+
+ int caller(void) {
+ return foo();
+ }
+
+Stepping into ``foo`` should step directly into ``bar`` instead, and stepping out of ``bar``
+should stop in ``caller``.
+
+Functions with the ``debug_trampoline`` attribute can be chained together:
+
+.. code-block:: c
+
+ int baz(void) {
+ return 42;
+ }
+
+ __attribute__((debug_trampoline))
+ int bar(void) {
+ return baz();
+ }
+
+ __attribute__((debug_trampoline))
+ int foo(void) {
+ return bar();
+ }
+
+ int caller(void) {
+ return foo();
+ }
+
+In this example, stepping into ``foo`` should step directly into ``baz``, and stepping out of
+``baz`` should stop in ``caller``.
+ }];
+}
+
+
def ReadOnlyPlacementDocs : Documentation {
let Category = DocCatType;
let Content = [{This attribute is attached to a structure, class or union declaration.
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -771,6 +771,13 @@
let SimpleHandler = 1;
}
+def DebugTrampoline: InheritableAttr {
+ let Spellings = [Clang<"debug_trampoline">];
+ let Subjects = SubjectList<[Function, ObjCMethod]>;
+ let Documentation = [DebugTrampolineDocs];
+ let SimpleHandler = 1;
+}
+
def XRayInstrument : InheritableAttr {
let Spellings = [Clang<"xray_always_instrument">,
Clang<"xray_never_instrument">];
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -184,6 +184,10 @@
the compilation of the foreign language sources (e.g. Swift).
- The ``__has_attribute``, ``__has_c_attribute`` and ``__has_cpp_attribute``
preprocessor operators now return 1 also for attributes defined by plugins.
+- Introduced a new function attribute ``__attribute__((debug_trampoline))``
+ which is intended as a hint to debuggers that they should not stop at the annotated
+ function, but instead step through it when stepping in, and continuing directly to
+ its caller when stepping out.
Improvements to Clang's diagnostics
-----------------------------------
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits