augusto2112 updated this revision to Diff 511515.
augusto2112 added a comment.

Updated MetadataTest.cpp


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::SPFlagIsDebugTrampoline;
 
   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::SPFlagIsDebugTrampoline,
+                   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
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to