]> granicus.if.org Git - clang/commitdiff
implement support for -finstrument-functions, patch by Nelson
authorChris Lattner <sabre@nondot.org>
Tue, 22 Jun 2010 00:03:40 +0000 (00:03 +0000)
committerChris Lattner <sabre@nondot.org>
Tue, 22 Jun 2010 00:03:40 +0000 (00:03 +0000)
Elhage!

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@106507 91177308-0d34-0410-b5e6-96231b3b80d8

12 files changed:
include/clang/AST/Attr.h
include/clang/Basic/Attr.td
include/clang/Driver/CC1Options.td
include/clang/Driver/Options.td
include/clang/Frontend/CodeGenOptions.h
lib/AST/AttrImpl.cpp
lib/CodeGen/CodeGenFunction.cpp
lib/CodeGen/CodeGenFunction.h
lib/Driver/Tools.cpp
lib/Frontend/CompilerInvocation.cpp
lib/Sema/SemaDeclAttr.cpp
test/CodeGen/instrument-functions.c [new file with mode: 0644]

index b67b53b10e75b7de9dcaf766125d172b26f8ad33..0f0215a7c8d6812cd4ec7cdd38369c14ae0289d4 100644 (file)
@@ -300,6 +300,7 @@ DEF_SIMPLE_ATTR(Deprecated);
 DEF_SIMPLE_ATTR(GNUInline);
 DEF_SIMPLE_ATTR(Malloc);
 DEF_SIMPLE_ATTR(NoReturn);
+DEF_SIMPLE_ATTR(NoInstrumentFunction);
 
 class SectionAttr : public AttrWithString {
 public:
index 4b85bb20db2e79c99903a5e07bc9ead2f9699e19..98871d26204fbc58a6e3e053005fe42fd094942b 100644 (file)
@@ -261,6 +261,11 @@ def NoReturn : Attr {
   let Namespaces = ["", "std"];
 }
 
+def NoInstrumentFunction : Attr {
+  let Spellings = ["no_instrument_function"];
+  let Subjects = [Function];
+}
+
 def NoThrow : Attr {
   let Spellings = ["nothrow"];
 }
index ab9f902743507567f5252767bf5e4a58f94803ff..c1de8b1d3a908a585b3e9d9e5cce7d2d12e5fc02 100644 (file)
@@ -123,6 +123,8 @@ def fno_common : Flag<"-fno-common">,
   HelpText<"Compile common globals like normal definitions">;
 def no_implicit_float : Flag<"-no-implicit-float">,
   HelpText<"Don't generate implicit floating point instructions (x86-only)">;
+def finstrument_functions : Flag<"-finstrument-functions">,
+  HelpText<"Generate calls to instrument function entry and exit">;
 def fno_merge_all_constants : Flag<"-fno-merge-all-constants">,
   HelpText<"Disallow merging of constants.">;
 def fno_threadsafe_statics : Flag<"-fno-threadsafe-statics">,
index 7ac04bec9d44d3fcc2f831eeaaf73625da19ac84..f7af6dbe04152fd2605e08e6ba715133cf2189ea 100644 (file)
@@ -278,6 +278,7 @@ def filelist : Separate<"-filelist">, Flags<[LinkerInput]>;
 def findirect_virtual_calls : Flag<"-findirect-virtual-calls">, Group<f_Group>;
 def finline_functions : Flag<"-finline-functions">, Group<clang_ignored_f_Group>;
 def finline : Flag<"-finline">, Group<clang_ignored_f_Group>;
+def finstrument_functions : Flag<"-finstrument-functions">, Group<f_Group>;
 def fkeep_inline_functions : Flag<"-fkeep-inline-functions">, Group<clang_ignored_f_Group>;
 def flat__namespace : Flag<"-flat_namespace">;
 def flax_vector_conversions : Flag<"-flax-vector-conversions">, Group<f_Group>;
index bfee72cba4c92fda7346d56cde2845eb3c46c1b4..2d21f1d30b0c1e74eb418f68fd24c3faa7669588 100644 (file)
@@ -47,6 +47,7 @@ public:
                                   /// done.
   unsigned DisableRedZone    : 1; /// Set when -mno-red-zone is enabled.
   unsigned FunctionSections  : 1; /// Set when -ffunction-sections is enabled
+  unsigned InstrumentFunctions : 1; /// Set when -finstrument-functions is enabled
   unsigned MergeAllConstants : 1; /// Merge identical constants.
   unsigned NoCommon          : 1; /// Set when -fno-common or C++ is enabled.
   unsigned NoImplicitFloat   : 1; /// Set when -mno-implicit-float is enabled.
index 6db43c956522b1731edbfad8a1a736d9fe505332..b09ba895c0195a766e88507978acff17c6f4bf3c 100644 (file)
@@ -93,6 +93,7 @@ DEF_SIMPLE_ATTR_CLONE(NSReturnsNotRetained)
 DEF_SIMPLE_ATTR_CLONE(NSReturnsRetained)
 DEF_SIMPLE_ATTR_CLONE(NoDebug)
 DEF_SIMPLE_ATTR_CLONE(NoInline)
+DEF_SIMPLE_ATTR_CLONE(NoInstrumentFunction)
 DEF_SIMPLE_ATTR_CLONE(NoReturn)
 DEF_SIMPLE_ATTR_CLONE(NoThrow)
 DEF_SIMPLE_ATTR_CLONE(ObjCException)
index af062356f65a54e92da63b1e44af7337e97df5af..8a0b41a7cad2ddd5c39388170447558fa4644f49 100644 (file)
@@ -20,7 +20,9 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/StmtCXX.h"
+#include "clang/Frontend/CodeGenOptions.h"
 #include "llvm/Target/TargetData.h"
+#include "llvm/Intrinsics.h"
 using namespace clang;
 using namespace CodeGen;
 
@@ -127,6 +129,8 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
   // Emit function epilog (to return).
   EmitReturnBlock();
 
+  EmitFunctionInstrumentation("__cyg_profile_func_exit");
+
   // Emit debug descriptor for function end.
   if (CGDebugInfo *DI = getDebugInfo()) {
     DI->setLocation(EndLoc);
@@ -159,6 +163,41 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
   }
 }
 
+/// ShouldInstrumentFunction - Return true if the current function should be
+/// instrumented with __cyg_profile_func_* calls
+bool CodeGenFunction::ShouldInstrumentFunction() {
+  if (!CGM.getCodeGenOpts().InstrumentFunctions)
+    return false;
+  if (CurFuncDecl->hasAttr<NoInstrumentFunctionAttr>())
+    return false;
+  return true;
+}
+
+/// EmitFunctionInstrumentation - Emit LLVM code to call the specified
+/// instrumentation function with the current function and the call site, if
+/// function instrumentation is enabled.
+void CodeGenFunction::EmitFunctionInstrumentation(const char *Fn) {
+  if (!ShouldInstrumentFunction())
+    return;
+
+  const llvm::FunctionType *FunctionTy;
+  std::vector<const llvm::Type*> ProfileFuncArgs;
+
+  ProfileFuncArgs.push_back(CurFn->getType());
+  ProfileFuncArgs.push_back(llvm::Type::getInt8PtrTy(VMContext));
+  FunctionTy = llvm::FunctionType::get(
+    llvm::Type::getVoidTy(VMContext),
+    ProfileFuncArgs, false);
+
+  llvm::Constant *F = CGM.CreateRuntimeFunction(FunctionTy, Fn);
+  llvm::CallInst *CallSite = Builder.CreateCall(
+    CGM.getIntrinsic(llvm::Intrinsic::returnaddress, 0, 0),
+    llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0),
+    "callsite");
+
+  Builder.CreateCall2(F, CurFn, CallSite);
+}
+
 void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
                                     llvm::Function *Fn,
                                     const FunctionArgList &Args,
@@ -208,6 +247,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
     DI->EmitFunctionStart(GD, FnType, CurFn, Builder);
   }
 
+  EmitFunctionInstrumentation("__cyg_profile_func_enter");
+
   // FIXME: Leaked.
   // CC info is ignored, hopefully?
   CurFnInfo = &CGM.getTypes().getFunctionInfo(FnRetTy, Args,
index 0fdb60ccbba91d1b07bc283bf0bac95ad1328786..f797c2c4ffce24cbef7c95bcaed2bd3f5e6086f0 100644 (file)
@@ -566,6 +566,15 @@ public:
   void EmitDtorEpilogue(const CXXDestructorDecl *Dtor,
                         CXXDtorType Type);
 
+  /// ShouldInstrumentFunction - Return true if the current function should be
+  /// instrumented with __cyg_profile_func_* calls
+  bool ShouldInstrumentFunction();
+
+  /// EmitFunctionInstrumentation - Emit LLVM code to call the specified
+  /// instrumentation function with the current function and the call site, if
+  /// function instrumentation is enabled.
+  void EmitFunctionInstrumentation(const char *Fn);
+
   /// EmitFunctionProlog - Emit the target specific LLVM code to load the
   /// arguments for the given function. This is also responsible for naming the
   /// LLVM function arguments.
index ae197fbeba6a9134a91ef0c3c335bf4c79a87ff5..cf866c3d47645c5b34379cc6683eb6025cf32b90 100644 (file)
@@ -1021,6 +1021,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   Args.AddAllArgs(CmdArgs, options::OPT_ffunction_sections);
   Args.AddAllArgs(CmdArgs, options::OPT_fdata_sections);
 
+  Args.AddAllArgs(CmdArgs, options::OPT_finstrument_functions);
+
   Args.AddLastArg(CmdArgs, options::OPT_nostdinc);
   Args.AddLastArg(CmdArgs, options::OPT_nostdincxx);
   Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc);
index a925047d9456b7418fa0084b56784735dcbfd1ff..e7a75a619dca7e9b010a7d899279604e252542a7 100644 (file)
@@ -840,6 +840,8 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
   Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name);
   Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier);
 
+  Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions);
+
   if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) {
     llvm::StringRef Name = A->getValue(Args);
     unsigned Method = llvm::StringSwitch<unsigned>(Name)
index 5858de06698af7480247e71f54805f5c758d2db4..dee10fb608a1b3e02ae1671c156bebee463672a3 100644 (file)
@@ -1698,6 +1698,23 @@ static void HandleNoInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
   d->addAttr(::new (S.Context) NoInlineAttr());
 }
 
+static void HandleNoInstrumentFunctionAttr(Decl *d, const AttributeList &Attr,
+                                           Sema &S) {
+  // check the attribute arguments.
+  if (Attr.getNumArgs() != 0) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+    return;
+  }
+
+  if (!isa<FunctionDecl>(d)) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+    << Attr.getName() << 0 /*function*/;
+    return;
+  }
+
+  d->addAttr(::new (S.Context) NoInstrumentFunctionAttr());
+}
+
 static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
   // check the attribute arguments.
   if (Attr.getNumArgs() != 0) {
@@ -2030,9 +2047,11 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
   case AttributeList::AT_noinline:    HandleNoInlineAttr    (D, Attr, S); break;
   case AttributeList::AT_regparm:     HandleRegparmAttr     (D, Attr, S); break;
   case AttributeList::IgnoredAttribute:
-  case AttributeList::AT_no_instrument_function:  // Interacts with -pg.
     // Just ignore
     break;
+  case AttributeList::AT_no_instrument_function:  // Interacts with -pg.
+    HandleNoInstrumentFunctionAttr(D, Attr, S);
+    break;
   case AttributeList::AT_stdcall:
   case AttributeList::AT_cdecl:
   case AttributeList::AT_fastcall:
diff --git a/test/CodeGen/instrument-functions.c b/test/CodeGen/instrument-functions.c
new file mode 100644 (file)
index 0000000..d80385e
--- /dev/null
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -S -emit-llvm -o - %s -finstrument-functions | FileCheck %s
+
+// CHECK: @test1
+int test1(int x) {
+// CHECK: __cyg_profile_func_enter
+// CHECK: __cyg_profile_func_exit
+// CHECK: ret
+  return x;
+}
+
+// CHECK: @test2
+int test2(int) __attribute__((no_instrument_function));
+int test2(int x) {
+// CHECK-NOT: __cyg_profile_func_enter
+// CHECK-NOT: __cyg_profile_func_exit
+// CHECK: ret
+  return x;
+}