augusto2112 created this revision.
augusto2112 added reviewers: aprantl, arphaman, jingham.
Herald added a subscriber: hiraditya.
Herald added a reviewer: aaron.ballman.
Herald added a project: All.
augusto2112 requested review of this revision.
Herald added projects: clang, LLVM.
Herald added subscribers: llvm-commits, cfe-commits.

Add a trampoline attribute to clang, which indicates to debuggers that
stepping into the function should jump to the argument passed in the
attribute instead.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D146595

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Sema/Sema.h
  clang/lib/CodeGen/CGDebugInfo.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/test/CodeGen/attr-trampoline-method.cpp
  clang/test/CodeGen/attr-trampoline.c
  llvm/include/llvm/IR/DIBuilder.h
  llvm/lib/CodeGen/MachineOutliner.cpp
  llvm/lib/IR/DIBuilder.cpp

Index: llvm/lib/IR/DIBuilder.cpp
===================================================================
--- llvm/lib/IR/DIBuilder.cpp
+++ llvm/lib/IR/DIBuilder.cpp
@@ -881,7 +881,7 @@
     unsigned LineNo, DISubroutineType *Ty, unsigned VIndex, int ThisAdjustment,
     DIType *VTableHolder, DINode::DIFlags Flags,
     DISubprogram::DISPFlags SPFlags, DITemplateParameterArray TParams,
-    DITypeArray ThrownTypes) {
+    DITypeArray ThrownTypes, StringRef TargetFuncName) {
   assert(getNonCompileUnitScope(Context) &&
          "Methods should have both a Context and a context that isn't "
          "the compile unit.");
@@ -891,7 +891,7 @@
       /*IsDistinct=*/IsDefinition, VMContext, cast<DIScope>(Context), Name,
       LinkageName, F, LineNo, Ty, LineNo, VTableHolder, VIndex, ThisAdjustment,
       Flags, SPFlags, IsDefinition ? CUNode : nullptr, TParams, nullptr,
-      nullptr, ThrownTypes);
+      nullptr, ThrownTypes, nullptr, TargetFuncName);
 
   if (IsDefinition)
     AllSubprograms.push_back(SP);
Index: llvm/lib/CodeGen/MachineOutliner.cpp
===================================================================
--- llvm/lib/CodeGen/MachineOutliner.cpp
+++ llvm/lib/CodeGen/MachineOutliner.cpp
@@ -799,7 +799,8 @@
         0, /* Line 0 is reserved for compiler-generated code. */
         DINode::DIFlags::FlagArtificial /* Compiler-generated code. */,
         /* Outlined code is optimized code by definition. */
-        DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized);
+        DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized, nullptr,
+        nullptr, nullptr, nullptr, SP->getTargetFuncName());
 
     // Don't add any new variables to the subprogram.
     DB.finalizeSubprogram(OutlinedSP);
Index: llvm/include/llvm/IR/DIBuilder.h
===================================================================
--- llvm/include/llvm/IR/DIBuilder.h
+++ llvm/include/llvm/IR/DIBuilder.h
@@ -790,15 +790,16 @@
     /// \param SPFlags       Additional flags specific to subprograms.
     /// \param TParams       Function template parameters.
     /// \param ThrownTypes   Exception types this function may throw.
-    DISubprogram *
-    createMethod(DIScope *Scope, StringRef Name, StringRef LinkageName,
-                 DIFile *File, unsigned LineNo, DISubroutineType *Ty,
-                 unsigned VTableIndex = 0, int ThisAdjustment = 0,
-                 DIType *VTableHolder = nullptr,
-                 DINode::DIFlags Flags = DINode::FlagZero,
-                 DISubprogram::DISPFlags SPFlags = DISubprogram::SPFlagZero,
-                 DITemplateParameterArray TParams = nullptr,
-                 DITypeArray ThrownTypes = nullptr);
+    /// \param TargetFuncName The name of the target function if this is
+    ///                       a trampoline.
+    DISubprogram *createMethod(
+        DIScope *Scope, StringRef Name, StringRef LinkageName, DIFile *File,
+        unsigned LineNo, DISubroutineType *Ty, unsigned VTableIndex = 0,
+        int ThisAdjustment = 0, DIType *VTableHolder = nullptr,
+        DINode::DIFlags Flags = DINode::FlagZero,
+        DISubprogram::DISPFlags SPFlags = DISubprogram::SPFlagZero,
+        DITemplateParameterArray TParams = nullptr,
+        DITypeArray ThrownTypes = nullptr, StringRef TargetFuncName = "");
 
     /// Create common block entry for a Fortran common block.
     /// \param Scope       Scope of this common block.
Index: clang/test/CodeGen/attr-trampoline.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/attr-trampoline.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -debug-info-kind=limited -emit-llvm -o - %s | FileCheck %s
+
+void bar(void) {}
+
+__attribute__((trampoline("bar")))
+void foo(void) {
+  bar();
+}
+
+// CHECK: DISubprogram(name: "foo"{{.*}} targetFuncName: "bar"
Index: clang/test/CodeGen/attr-trampoline-method.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/attr-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 {
+__attribute__((trampoline("bar")))
+void foo(void) {
+  bar();
+}
+};
+
+int main() {
+  A().foo();
+}
+
+// CHECK: DISubprogram(name: "foo"{{.*}} targetFuncName: "bar"
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -4879,6 +4879,20 @@
   return ::new (Context) SwiftNameAttr(Context, SNA, Name);
 }
 
+TrampolineAttr *Sema::mergeTrampolineAttr(Decl *D, const TrampolineAttr &TA,
+                                        StringRef Name) {
+  if (const auto *PrevSNA = D->getAttr<TrampolineAttr>()) {
+    if (PrevSNA->getName() != Name && !PrevSNA->isImplicit()) {
+      Diag(PrevSNA->getLocation(), diag::err_attributes_are_not_compatible)
+          << PrevSNA << &TA;
+      Diag(TA.getLoc(), diag::note_conflicting_attribute);
+    }
+
+    D->dropAttr<TrampolineAttr>();
+  }
+  return ::new (Context) TrampolineAttr(Context, TA, Name);
+}
+
 OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D,
                                               const AttributeCommonInfo &CI) {
   if (AlwaysInlineAttr *Inline = D->getAttr<AlwaysInlineAttr>()) {
@@ -6758,6 +6772,15 @@
   D->addAttr(::new (S.Context) SwiftNameAttr(S.Context, AL, Name));
 }
 
+static void handleTrampoline(Sema &S, Decl *D, const ParsedAttr &AL) {
+  StringRef Name;
+  SourceLocation Loc;
+  if (!S.checkStringLiteralArgumentAttr(AL, 0, Name, &Loc))
+    return;
+
+  D->addAttr(::new (S.Context) TrampolineAttr(S.Context, AL, Name));
+}
+
 static void handleSwiftAsyncName(Sema &S, Decl *D, const ParsedAttr &AL) {
   StringRef Name;
   SourceLocation Loc;
@@ -9294,6 +9317,10 @@
     handleSwiftAsyncError(S, D, AL);
     break;
 
+  case ParsedAttr::AT_Trampoline:
+    handleTrampoline(S, D, AL);
+    break;
+
   // XRay attributes.
   case ParsedAttr::AT_XRayLogArgs:
     handleXRayLogArgsAttr(S, D, AL);
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -2927,6 +2927,8 @@
     NewAttr = S.mergeMinSizeAttr(D, *MA);
   else if (const auto *SNA = dyn_cast<SwiftNameAttr>(Attr))
     NewAttr = S.mergeSwiftNameAttr(D, *SNA, SNA->getName());
+  else if (const auto *TA = dyn_cast<TrampolineAttr>(Attr))
+    NewAttr = S.mergeTrampolineAttr(D, *TA, TA->getName());
   else if (const auto *OA = dyn_cast<OptimizeNoneAttr>(Attr))
     NewAttr = S.mergeOptimizeNoneAttr(D, *OA);
   else if (const auto *InternalLinkageA = dyn_cast<InternalLinkageAttr>(Attr))
Index: clang/lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- clang/lib/CodeGen/CGDebugInfo.cpp
+++ clang/lib/CodeGen/CGDebugInfo.cpp
@@ -68,6 +68,14 @@
   return D->hasAttr<AlignedAttr>() ? D->getMaxAlignment() : 0;
 }
 
+static StringRef getTargetFuncName(const Decl *D) {
+  if (!D)
+    return {};
+  if (auto *Trampoline = D->getAttr<TrampolineAttr>())
+    return Trampoline->getName();
+  return {};
+}
+
 CGDebugInfo::CGDebugInfo(CodeGenModule &CGM)
     : CGM(CGM), DebugKind(CGM.getCodeGenOpts().getDebugInfo()),
       DebugTypeExtRefs(CGM.getCodeGenOpts().DebugTypeExtRefs),
@@ -1918,10 +1926,11 @@
       completeUnusedClass(*CD->getParent());
 
   llvm::DINodeArray TParamsArray = CollectFunctionTemplateParams(Method, Unit);
+  StringRef TargetFuncName = getTargetFuncName(Method);
   llvm::DISubprogram *SP = DBuilder.createMethod(
       RecordTy, MethodName, MethodLinkageName, MethodDefUnit, MethodLine,
       MethodTy, VIndex, ThisAdjustment, ContainingType, Flags, SPFlags,
-      TParamsArray.get());
+      TParamsArray.get(), nullptr, TargetFuncName);
 
   SPCache[Method->getCanonicalDecl()].reset(SP);
 
@@ -3849,10 +3858,12 @@
   if (Stub) {
     Flags |= getCallSiteRelatedAttrs();
     SPFlags |= llvm::DISubprogram::SPFlagDefinition;
+    StringRef TargetFuncName = getTargetFuncName(FD);
     return DBuilder.createFunction(
         DContext, Name, LinkageName, Unit, Line,
         getOrCreateFunctionType(GD.getDecl(), FnType, Unit), 0, Flags, SPFlags,
-        TParamsArray.get(), getFunctionDeclaration(FD));
+        TParamsArray.get(), getFunctionDeclaration(FD), nullptr, nullptr,
+        TargetFuncName);
   }
 
   llvm::DISubprogram *SP = DBuilder.createTempFunctionFwdDecl(
@@ -3998,9 +4009,11 @@
   if (It == TypeCache.end())
     return nullptr;
   auto *InterfaceType = cast<llvm::DICompositeType>(It->second);
+  StringRef TargetFuncName = getTargetFuncName(D);
   llvm::DISubprogram *FD = DBuilder.createFunction(
       InterfaceType, getObjCMethodName(OMD), StringRef(),
-      InterfaceType->getFile(), LineNo, FnType, LineNo, Flags, SPFlags);
+      InterfaceType->getFile(), LineNo, FnType, LineNo, Flags, SPFlags, nullptr,
+      nullptr, nullptr, nullptr, TargetFuncName);
   DBuilder.finalizeSubprogram(FD);
   ObjCMethodCache[ID].push_back({FD, OMD->isDirectMethod()});
   return FD;
@@ -4182,6 +4195,8 @@
     Annotations = CollectBTFDeclTagAnnotations(D);
   }
 
+  StringRef TargetFuncName = getTargetFuncName(D);
+
   // FIXME: The function declaration we're constructing here is mostly reusing
   // declarations from CXXMethodDecl and not constructing new ones for arbitrary
   // FunctionDecls. When/if we fix this we can have FDContext be TheCU/null for
@@ -4190,7 +4205,7 @@
   llvm::DISubprogram *SP = DBuilder.createFunction(
       FDContext, Name, LinkageName, Unit, LineNo, DIFnType, ScopeLine,
       FlagsForDef, SPFlagsForDef, TParamsArray.get(), Decl, nullptr,
-      Annotations);
+      Annotations, TargetFuncName);
   Fn->setSubprogram(SP);
   // We might get here with a VarDecl in the case we're generating
   // code for the initialization of globals. Do not record these decls
@@ -4251,9 +4266,11 @@
 
   llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(D);
   llvm::DISubroutineType *STy = getOrCreateFunctionType(D, FnType, Unit);
-  llvm::DISubprogram *SP = DBuilder.createFunction(
-      FDContext, Name, LinkageName, Unit, LineNo, STy, ScopeLine, Flags,
-      SPFlags, TParamsArray.get(), nullptr, nullptr, Annotations);
+  StringRef TargetFuncName = getTargetFuncName(D);
+  llvm::DISubprogram *SP =
+      DBuilder.createFunction(FDContext, Name, LinkageName, Unit, LineNo, STy,
+                              ScopeLine, Flags, SPFlags, TParamsArray.get(),
+                              nullptr, nullptr, Annotations, TargetFuncName);
 
   // Preserve btf_decl_tag attributes for parameters of extern functions
   // for BPF target. The parameters created in this loop are attached as
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -3668,6 +3668,8 @@
   MinSizeAttr *mergeMinSizeAttr(Decl *D, const AttributeCommonInfo &CI);
   SwiftNameAttr *mergeSwiftNameAttr(Decl *D, const SwiftNameAttr &SNA,
                                     StringRef Name);
+  TrampolineAttr *mergeTrampolineAttr(Decl *D, const TrampolineAttr &TA,
+                                      StringRef Name);
   OptimizeNoneAttr *mergeOptimizeNoneAttr(Decl *D,
                                           const AttributeCommonInfo &CI);
   InternalLinkageAttr *mergeInternalLinkageAttr(Decl *D, const ParsedAttr &AL);
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -6900,6 +6900,31 @@
   }];
 }
 
+def TrampolineDocs : Documentation {
+  let Category = DocCatFunction;
+  let Heading = "trampoline";
+  let Content = [{
+The ``trampoline`` attribute indicates that the current function is a trampoline. 
+The argument is the mangled name of the symbol that debuggers should jump to instead 
+when entering the trampoline function. 
+
+For example:
+
+.. code-block:: c
+
+  int bar(void) {
+    return 42;
+  }
+
+  __attribute__((trampoline("bar")))
+  int foo(void) {
+    return bar();
+  }
+
+Indicates to debuggers that stepping into ``foo`` should jump directly to ``bar`` instead.
+  }];
+}
+
 def ReadOnlyPlacementDocs : Documentation {
   let Category = DocCatType;
   let Content = [{This attribute is attached to a structure, class or union declaration.
@@ -6947,3 +6972,5 @@
 its underlying representation to be a WebAssembly ``funcref``.
   }];
 }
+
+
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -770,6 +770,13 @@
   let SimpleHandler = 1;
 }
 
+def Trampoline : InheritableAttr {
+  let Spellings = [GNU<"trampoline">];
+  let Subjects = SubjectList<[Function, ObjCMethod]>;
+  let Args = [StringArgument<"Name">];
+  let Documentation = [TrampolineDocs];
+}
+
 def XRayInstrument : InheritableAttr {
   let Spellings = [Clang<"xray_always_instrument">,
                    Clang<"xray_never_instrument">];
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to