[cfe-commits] [patch] Implement -finstrument-functions

Nelson Elhage nelhage at nelhage.com
Tue Jun 22 22:07:13 PDT 2010


My apologies -- I was using an out-of-date git mirror. Attached, and
I'll be sure to make sure to check the actual svn trunk in the future.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: instrument-functions.diff
Type: text/x-diff
Size: 1320 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20100623/fa4ecad2/attachment.diff>
-------------- next part --------------


On Tue, 22 Jun 2010 21:28:23 -0700, Chris Lattner <clattner at apple.com> wrote:
> Thanks Nelson,
> 
> Can you rediff this against mainline?  I already attached your
> previous patch, so I need the diff from it to this update.
> 
> -Chris
> 
> On Jun 22, 2010, at 6:51 PM, Nelson Elhage wrote:
> 
> > Attached. No worries about the misunderstanding. I added a comment
> > showing the type of the instrumentation functions, which will hopefully
> > make things slightly clearer.
> > 
> > <instrument-functions.diff>
> > 
> > On Mon, 21 Jun 2010 17:07:17 -0700, Chris Lattner <clattner at apple.com> wrote:
> >> On Jun 19, 2010, at 4:34 PM, Nelson Elhage wrote:
> >>> Oops, I caught another bug in testing (apparently not caught by the test
> >>> suite -- I'll consider sending a separate patch to add a test): I was
> >>> accidentally causing all IgnoredAttribute's to turn into
> >>> no_instrument_function.  Revised patch attached.
> >> 
> >> Great, applied in r106507, just to get it out of your tree :)
> >> 
> >>> On Sat, 19 Jun 2010 13:01:11 -0400, Nelson Elhage <nelhage at nelhage.com> wrote:
> >>>> Thanks for the comments! Revised patch is attached. There's one point I
> >>>> wasn't totally clear on, though, so this may need another revision:
> >>>> 
> >>>> On Fri, 18 Jun 2010 22:04:53 -0700, Chris Lattner <clattner at apple.com> wrote:
> >>>>> On Jun 18, 2010, at 8:41 PM, Nelson Elhage wrote:
> >>>>> 
> >>>>> 
> >>>>> +                      llvm::ConstantExpr::getBitCast(CurFn, PointerTy),
> >>>>> 
> >>>>> This can go away when you use CreateRuntimeFunction.
> >>>> 
> >>>> The instrumentation functions are typed as void (i8*, i8*). Since CurFn
> >>>> isn't an i8*, there needs to be a cast somewhere. My revised patch asks
> >>>> CreateRuntimeFunction for a __cyg_profile_func_* typed as void
> >>>> (typeof(CurFn), i8*), which it will bitcast for me. I assume this is
> >>>> what you were suggesting?
> >>>> 
> >>>> But that means that __cyg_profile_func_enter will end up declared as
> >>>> taking a pointer to whatever function type CodeGenFunction sees first,
> >>>> which seems to work fine, but doesn't seem correct. Should I be doing
> >>>> something to ensure that it gets initially declared with the correct
> >>>> type?
> >> 
> >> Ah, I see what you mean.  The old way you had it definitely is better.
> >> I didn't understand the purpose of the case.  Can you send in a patch
> >> on top of mainline that changes it back?  I'm sorry for not
> >> understanding.
> >> 
> >> Thanks for working on this!
> >> 
> >> -Chris
> 
> 
From: Nelson Elhage <nelhage at nelhage.com>
Subject: Re: [cfe-commits] [patch] Implement -finstrument-functions
To: Chris Lattner <clattner at apple.com>
Cc: cfe-commits at cs.uiuc.edu
Bcc: nelhage at mit.edu
In-Reply-To: <87tyoupldm.fsf at mit.edu>
References: <87wrtvd6ys.fsf at mit.edu> <5D3628F0-6FDE-4BC8-A7BB-E38E459129F9 at apple.com> <87tyozc5yg.fsf at mit.edu> <878w6asijt.fsf at mit.edu> <20701F4B-A3FB-41C1-A563-FF533EE931C1 at apple.com> <87tyoupldm.fsf at mit.edu>

On Tue, 22 Jun 2010 21:51:01 -0400, Nelson Elhage <nelhage at nelhage.com> wrote:
> Attached. No worries about the misunderstanding. I added a comment
> showing the type of the instrumentation functions, which will hopefully
> make things slightly clearer.
> 
> diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
> index b67b53b..0f0215a 100644
> --- a/include/clang/AST/Attr.h
> +++ b/include/clang/AST/Attr.h
> @@ -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:
> diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
> index 4b85bb2..98871d2 100644
> --- a/include/clang/Basic/Attr.td
> +++ b/include/clang/Basic/Attr.td
> @@ -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"];
>  }
> diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
> index ab9f902..c1de8b1 100644
> --- a/include/clang/Driver/CC1Options.td
> +++ b/include/clang/Driver/CC1Options.td
> @@ -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">,
> diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
> index 7ac04be..f7af6db 100644
> --- a/include/clang/Driver/Options.td
> +++ b/include/clang/Driver/Options.td
> @@ -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>;
> diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h
> index bfee72c..2d21f1d 100644
> --- a/include/clang/Frontend/CodeGenOptions.h
> +++ b/include/clang/Frontend/CodeGenOptions.h
> @@ -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.
> diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp
> index 6db43c9..b09ba89 100644
> --- a/lib/AST/AttrImpl.cpp
> +++ b/lib/AST/AttrImpl.cpp
> @@ -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)
> diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
> index af06235..704de35 100644
> --- a/lib/CodeGen/CodeGenFunction.cpp
> +++ b/lib/CodeGen/CodeGenFunction.cpp
> @@ -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,46 @@ 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::PointerType *PointerTy;
> +  const llvm::FunctionType *FunctionTy;
> +  std::vector<const llvm::Type*> ProfileFuncArgs;
> +
> +  // void __cyg_profile_func_{enter,exit} (void *this_fn, void *call_site);
> +  PointerTy = llvm::Type::getInt8PtrTy(VMContext);
> +  ProfileFuncArgs.push_back(PointerTy);
> +  ProfileFuncArgs.push_back(PointerTy);
> +  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,
> +                      llvm::ConstantExpr::getBitCast(CurFn, PointerTy),
> +                      CallSite);
> +}
> +
>  void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
>                                      llvm::Function *Fn,
>                                      const FunctionArgList &Args,
> @@ -208,6 +252,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,
> diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
> index 0fdb60c..f797c2c 100644
> --- a/lib/CodeGen/CodeGenFunction.h
> +++ b/lib/CodeGen/CodeGenFunction.h
> @@ -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.
> diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
> index ae197fb..cf866c3 100644
> --- a/lib/Driver/Tools.cpp
> +++ b/lib/Driver/Tools.cpp
> @@ -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);
> diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
> index a925047..e7a75a6 100644
> --- a/lib/Frontend/CompilerInvocation.cpp
> +++ b/lib/Frontend/CompilerInvocation.cpp
> @@ -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)
> diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
> index c5eb048..5a31c9c 100644
> --- a/lib/Sema/SemaDeclAttr.cpp
> +++ b/lib/Sema/SemaDeclAttr.cpp
> @@ -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
> index 0000000..d80385e
> --- /dev/null
> +++ b/test/CodeGen/instrument-functions.c
> @@ -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;
> +}
> 
> 
> On Mon, 21 Jun 2010 17:07:17 -0700, Chris Lattner <clattner at apple.com> wrote:
> > On Jun 19, 2010, at 4:34 PM, Nelson Elhage wrote:
> > > Oops, I caught another bug in testing (apparently not caught by the test
> > > suite -- I'll consider sending a separate patch to add a test): I was
> > > accidentally causing all IgnoredAttribute's to turn into
> > > no_instrument_function.  Revised patch attached.
> > 
> > Great, applied in r106507, just to get it out of your tree :)
> > 
> > > On Sat, 19 Jun 2010 13:01:11 -0400, Nelson Elhage <nelhage at nelhage.com> wrote:
> > >> Thanks for the comments! Revised patch is attached. There's one point I
> > >> wasn't totally clear on, though, so this may need another revision:
> > >> 
> > >> On Fri, 18 Jun 2010 22:04:53 -0700, Chris Lattner <clattner at apple.com> wrote:
> > >>> On Jun 18, 2010, at 8:41 PM, Nelson Elhage wrote:
> > >>> 
> > >>> 
> > >>> +                      llvm::ConstantExpr::getBitCast(CurFn, PointerTy),
> > >>> 
> > >>> This can go away when you use CreateRuntimeFunction.
> > >> 
> > >> The instrumentation functions are typed as void (i8*, i8*). Since CurFn
> > >> isn't an i8*, there needs to be a cast somewhere. My revised patch asks
> > >> CreateRuntimeFunction for a __cyg_profile_func_* typed as void
> > >> (typeof(CurFn), i8*), which it will bitcast for me. I assume this is
> > >> what you were suggesting?
> > >> 
> > >> But that means that __cyg_profile_func_enter will end up declared as
> > >> taking a pointer to whatever function type CodeGenFunction sees first,
> > >> which seems to work fine, but doesn't seem correct. Should I be doing
> > >> something to ensure that it gets initially declared with the correct
> > >> type?
> > 
> > Ah, I see what you mean.  The old way you had it definitely is better.
> > I didn't understand the purpose of the case.  Can you send in a patch
> > on top of mainline that changes it back?  I'm sorry for not
> > understanding.
> > 
> > Thanks for working on this!
> > 
> > -Chris
From: Nelson Elhage <nelhage at nelhage.com>
Subject: Re: [cfe-commits] [patch] Implement -finstrument-functions
To: Chris Lattner <clattner at apple.com>
Cc: cfe-commits at cs.uiuc.edu
Bcc: nelhage at mit.edu
In-Reply-To: <20701F4B-A3FB-41C1-A563-FF533EE931C1 at apple.com>
References: <87wrtvd6ys.fsf at mit.edu> <5D3628F0-6FDE-4BC8-A7BB-E38E459129F9 at apple.com> <87tyozc5yg.fsf at mit.edu> <878w6asijt.fsf at mit.edu> <20701F4B-A3FB-41C1-A563-FF533EE931C1 at apple.com>

On Mon, 21 Jun 2010 17:07:17 -0700, Chris Lattner <clattner at apple.com> wrote:
> On Jun 19, 2010, at 4:34 PM, Nelson Elhage wrote:
> > Oops, I caught another bug in testing (apparently not caught by the test
> > suite -- I'll consider sending a separate patch to add a test): I was
> > accidentally causing all IgnoredAttribute's to turn into
> > no_instrument_function.  Revised patch attached.
> 
> Great, applied in r106507, just to get it out of your tree :)
> 
> > On Sat, 19 Jun 2010 13:01:11 -0400, Nelson Elhage <nelhage at nelhage.com> wrote:
> >> Thanks for the comments! Revised patch is attached. There's one point I
> >> wasn't totally clear on, though, so this may need another revision:
> >> 
> >> On Fri, 18 Jun 2010 22:04:53 -0700, Chris Lattner <clattner at apple.com> wrote:
> >>> On Jun 18, 2010, at 8:41 PM, Nelson Elhage wrote:
> >>> 
> >>> 
> >>> +                      llvm::ConstantExpr::getBitCast(CurFn, PointerTy),
> >>> 
> >>> This can go away when you use CreateRuntimeFunction.
> >> 
> >> The instrumentation functions are typed as void (i8*, i8*). Since CurFn
> >> isn't an i8*, there needs to be a cast somewhere. My revised patch asks
> >> CreateRuntimeFunction for a __cyg_profile_func_* typed as void
> >> (typeof(CurFn), i8*), which it will bitcast for me. I assume this is
> >> what you were suggesting?
> >> 
> >> But that means that __cyg_profile_func_enter will end up declared as
> >> taking a pointer to whatever function type CodeGenFunction sees first,
> >> which seems to work fine, but doesn't seem correct. Should I be doing
> >> something to ensure that it gets initially declared with the correct
> >> type?
> 
> Ah, I see what you mean.  The old way you had it definitely is better.  I didn't understand the purpose of the case.  Can you send in a patch on top of mainline that changes it back?  I'm sorry for not understanding.
> 
> Thanks for working on this!
> 
> -Chris
From: Nelson Elhage <nelhage at nelhage.com>
Subject: Re: [cfe-commits] [patch] Implement -finstrument-functions
To: Chris Lattner <clattner at apple.com>
Cc: cfe-commits at cs.uiuc.edu
Bcc: nelhage at mit.edu
In-Reply-To: <878w6asijt.fsf at mit.edu>
References: <87wrtvd6ys.fsf at mit.edu> <5D3628F0-6FDE-4BC8-A7BB-E38E459129F9 at apple.com> <87tyozc5yg.fsf at mit.edu> <878w6asijt.fsf at mit.edu>

On Sat, 19 Jun 2010 19:34:46 -0400, Nelson Elhage <nelhage at nelhage.com> wrote:
> Oops, I caught another bug in testing (apparently not caught by the test
> suite -- I'll consider sending a separate patch to add a test): I was
> accidentally causing all IgnoredAttribute's to turn into
> no_instrument_function.  Revised patch attached.
> 
> - Nelson
> 
> diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
> index 531c74c..e9f5628 100644
> --- a/include/clang/AST/Attr.h
> +++ b/include/clang/AST/Attr.h
> @@ -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:
> diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
> index c4f02a0..088fb8d 100644
> --- a/include/clang/Basic/Attr.td
> +++ b/include/clang/Basic/Attr.td
> @@ -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"];
>  }
> diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
> index ab9f902..c1de8b1 100644
> --- a/include/clang/Driver/CC1Options.td
> +++ b/include/clang/Driver/CC1Options.td
> @@ -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">,
> diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
> index 7ac04be..f7af6db 100644
> --- a/include/clang/Driver/Options.td
> +++ b/include/clang/Driver/Options.td
> @@ -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>;
> diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h
> index bfee72c..2d21f1d 100644
> --- a/include/clang/Frontend/CodeGenOptions.h
> +++ b/include/clang/Frontend/CodeGenOptions.h
> @@ -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.
> diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp
> index 1927a22..7628d3e 100644
> --- a/lib/AST/AttrImpl.cpp
> +++ b/lib/AST/AttrImpl.cpp
> @@ -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)
> diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
> index af06235..8a0b41a 100644
> --- a/lib/CodeGen/CodeGenFunction.cpp
> +++ b/lib/CodeGen/CodeGenFunction.cpp
> @@ -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,
> diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
> index f2a35ac..8f24ef3 100644
> --- a/lib/CodeGen/CodeGenFunction.h
> +++ b/lib/CodeGen/CodeGenFunction.h
> @@ -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.
> diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
> index ae197fb..cf866c3 100644
> --- a/lib/Driver/Tools.cpp
> +++ b/lib/Driver/Tools.cpp
> @@ -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);
> diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
> index a925047..e7a75a6 100644
> --- a/lib/Frontend/CompilerInvocation.cpp
> +++ b/lib/Frontend/CompilerInvocation.cpp
> @@ -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)
> diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
> index 89848af..bcd922c 100644
> --- a/lib/Sema/SemaDeclAttr.cpp
> +++ b/lib/Sema/SemaDeclAttr.cpp
> @@ -1650,6 +1650,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) {
> @@ -1979,9 +1996,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
> index 0000000..d80385e
> --- /dev/null
> +++ b/test/CodeGen/instrument-functions.c
> @@ -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;
> +}
> 
> On Sat, 19 Jun 2010 13:01:11 -0400, Nelson Elhage <nelhage at nelhage.com> wrote:
> > Thanks for the comments! Revised patch is attached. There's one point I
> > wasn't totally clear on, though, so this may need another revision:
> > 
> > On Fri, 18 Jun 2010 22:04:53 -0700, Chris Lattner <clattner at apple.com> wrote:
> > > On Jun 18, 2010, at 8:41 PM, Nelson Elhage wrote:
> > > 
> > > 
> > > +                      llvm::ConstantExpr::getBitCast(CurFn, PointerTy),
> > > 
> > > This can go away when you use CreateRuntimeFunction.
> > 
> > The instrumentation functions are typed as void (i8*, i8*). Since CurFn
> > isn't an i8*, there needs to be a cast somewhere. My revised patch asks
> > CreateRuntimeFunction for a __cyg_profile_func_* typed as void
> > (typeof(CurFn), i8*), which it will bitcast for me. I assume this is
> > what you were suggesting?
> > 
> > But that means that __cyg_profile_func_enter will end up declared as
> > taking a pointer to whatever function type CodeGenFunction sees first,
> > which seems to work fine, but doesn't seem correct. Should I be doing
> > something to ensure that it gets initially declared with the correct
> > type?
> > 
> > > 
> > > 
> > > +static void HandleNoInstrumentFunctionAttr(Decl *d, const AttributeList &Attr, Sema &S) {
> > > +  // check the attribute arguments.
> > > 
> > > Please stay in 80 cols.
> > > 
> > > Otherwise, the patch looks great!  Thanks for adding this, please send
> > > in a revised patch and I'm happy to commit it for you if you don't
> > > already have commit access.
> > 
> > Thanks. I don't have commit access -- This is only the third patch I've
> > sent in, so I'll hold off on asking for it unless I continue coming up
> > with patches.
> > 
> > > 
> > > -Chris
> > 
> > diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
> > index 531c74c..e9f5628 100644
> > --- a/include/clang/AST/Attr.h
> > +++ b/include/clang/AST/Attr.h
> > @@ -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:
> > diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
> > index c4f02a0..088fb8d 100644
> > --- a/include/clang/Basic/Attr.td
> > +++ b/include/clang/Basic/Attr.td
> > @@ -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"];
> >  }
> > diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
> > index ab9f902..c1de8b1 100644
> > --- a/include/clang/Driver/CC1Options.td
> > +++ b/include/clang/Driver/CC1Options.td
> > @@ -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">,
> > diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
> > index 7ac04be..f7af6db 100644
> > --- a/include/clang/Driver/Options.td
> > +++ b/include/clang/Driver/Options.td
> > @@ -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>;
> > diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h
> > index bfee72c..2d21f1d 100644
> > --- a/include/clang/Frontend/CodeGenOptions.h
> > +++ b/include/clang/Frontend/CodeGenOptions.h
> > @@ -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.
> > diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp
> > index 1927a22..7628d3e 100644
> > --- a/lib/AST/AttrImpl.cpp
> > +++ b/lib/AST/AttrImpl.cpp
> > @@ -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)
> > diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
> > index af06235..8a0b41a 100644
> > --- a/lib/CodeGen/CodeGenFunction.cpp
> > +++ b/lib/CodeGen/CodeGenFunction.cpp
> > @@ -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,
> > diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
> > index f2a35ac..8f24ef3 100644
> > --- a/lib/CodeGen/CodeGenFunction.h
> > +++ b/lib/CodeGen/CodeGenFunction.h
> > @@ -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.
> > diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
> > index ae197fb..cf866c3 100644
> > --- a/lib/Driver/Tools.cpp
> > +++ b/lib/Driver/Tools.cpp
> > @@ -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);
> > diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
> > index a925047..e7a75a6 100644
> > --- a/lib/Frontend/CompilerInvocation.cpp
> > +++ b/lib/Frontend/CompilerInvocation.cpp
> > @@ -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)
> > diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
> > index 89848af..bf45ef1 100644
> > --- a/lib/Sema/SemaDeclAttr.cpp
> > +++ b/lib/Sema/SemaDeclAttr.cpp
> > @@ -1650,6 +1650,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) {
> > @@ -1980,7 +1997,7 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
> >    case AttributeList::AT_regparm:     HandleRegparmAttr     (D, Attr, S); break;
> >    case AttributeList::IgnoredAttribute:
> >    case AttributeList::AT_no_instrument_function:  // Interacts with -pg.
> > -    // Just ignore
> > +    HandleNoInstrumentFunctionAttr(D, Attr, S);
> >      break;
> >    case AttributeList::AT_stdcall:
> >    case AttributeList::AT_cdecl:
> > diff --git a/test/CodeGen/instrument-functions.c b/test/CodeGen/instrument-functions.c
> > new file mode 100644
> > index 0000000..d80385e
> > --- /dev/null
> > +++ b/test/CodeGen/instrument-functions.c
> > @@ -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;
> > +}
From: Nelson Elhage <nelhage at nelhage.com>
Subject: Re: [cfe-commits] [patch] Implement -finstrument-functions
To: Chris Lattner <clattner at apple.com>
Cc: cfe-commits at cs.uiuc.edu
Bcc: nelhage at mit.edu
In-Reply-To: <87tyozc5yg.fsf at mit.edu>
References: <87wrtvd6ys.fsf at mit.edu> <5D3628F0-6FDE-4BC8-A7BB-E38E459129F9 at apple.com> <87tyozc5yg.fsf at mit.edu>

On Sat, 19 Jun 2010 13:01:11 -0400, Nelson Elhage <nelhage at nelhage.com> wrote:
> Thanks for the comments! Revised patch is attached. There's one point I
> wasn't totally clear on, though, so this may need another revision:
> 
> On Fri, 18 Jun 2010 22:04:53 -0700, Chris Lattner <clattner at apple.com> wrote:
> > On Jun 18, 2010, at 8:41 PM, Nelson Elhage wrote:
> > 
> > 
> > +                      llvm::ConstantExpr::getBitCast(CurFn, PointerTy),
> > 
> > This can go away when you use CreateRuntimeFunction.
> 
> The instrumentation functions are typed as void (i8*, i8*). Since CurFn
> isn't an i8*, there needs to be a cast somewhere. My revised patch asks
> CreateRuntimeFunction for a __cyg_profile_func_* typed as void
> (typeof(CurFn), i8*), which it will bitcast for me. I assume this is
> what you were suggesting?
> 
> But that means that __cyg_profile_func_enter will end up declared as
> taking a pointer to whatever function type CodeGenFunction sees first,
> which seems to work fine, but doesn't seem correct. Should I be doing
> something to ensure that it gets initially declared with the correct
> type?
> 
> > 
> > 
> > +static void HandleNoInstrumentFunctionAttr(Decl *d, const AttributeList &Attr, Sema &S) {
> > +  // check the attribute arguments.
> > 
> > Please stay in 80 cols.
> > 
> > Otherwise, the patch looks great!  Thanks for adding this, please send
> > in a revised patch and I'm happy to commit it for you if you don't
> > already have commit access.
> 
> Thanks. I don't have commit access -- This is only the third patch I've
> sent in, so I'll hold off on asking for it unless I continue coming up
> with patches.
> 
> > 
> > -Chris
> 
> diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
> index 531c74c..e9f5628 100644
> --- a/include/clang/AST/Attr.h
> +++ b/include/clang/AST/Attr.h
> @@ -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:
> diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
> index c4f02a0..088fb8d 100644
> --- a/include/clang/Basic/Attr.td
> +++ b/include/clang/Basic/Attr.td
> @@ -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"];
>  }
> diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
> index ab9f902..c1de8b1 100644
> --- a/include/clang/Driver/CC1Options.td
> +++ b/include/clang/Driver/CC1Options.td
> @@ -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">,
> diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
> index 7ac04be..f7af6db 100644
> --- a/include/clang/Driver/Options.td
> +++ b/include/clang/Driver/Options.td
> @@ -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>;
> diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h
> index bfee72c..2d21f1d 100644
> --- a/include/clang/Frontend/CodeGenOptions.h
> +++ b/include/clang/Frontend/CodeGenOptions.h
> @@ -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.
> diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp
> index 1927a22..7628d3e 100644
> --- a/lib/AST/AttrImpl.cpp
> +++ b/lib/AST/AttrImpl.cpp
> @@ -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)
> diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
> index af06235..8a0b41a 100644
> --- a/lib/CodeGen/CodeGenFunction.cpp
> +++ b/lib/CodeGen/CodeGenFunction.cpp
> @@ -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,
> diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
> index f2a35ac..8f24ef3 100644
> --- a/lib/CodeGen/CodeGenFunction.h
> +++ b/lib/CodeGen/CodeGenFunction.h
> @@ -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.
> diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
> index ae197fb..cf866c3 100644
> --- a/lib/Driver/Tools.cpp
> +++ b/lib/Driver/Tools.cpp
> @@ -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);
> diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
> index a925047..e7a75a6 100644
> --- a/lib/Frontend/CompilerInvocation.cpp
> +++ b/lib/Frontend/CompilerInvocation.cpp
> @@ -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)
> diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
> index 89848af..bf45ef1 100644
> --- a/lib/Sema/SemaDeclAttr.cpp
> +++ b/lib/Sema/SemaDeclAttr.cpp
> @@ -1650,6 +1650,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) {
> @@ -1980,7 +1997,7 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
>    case AttributeList::AT_regparm:     HandleRegparmAttr     (D, Attr, S); break;
>    case AttributeList::IgnoredAttribute:
>    case AttributeList::AT_no_instrument_function:  // Interacts with -pg.
> -    // Just ignore
> +    HandleNoInstrumentFunctionAttr(D, Attr, S);
>      break;
>    case AttributeList::AT_stdcall:
>    case AttributeList::AT_cdecl:
> diff --git a/test/CodeGen/instrument-functions.c b/test/CodeGen/instrument-functions.c
> new file mode 100644
> index 0000000..d80385e
> --- /dev/null
> +++ b/test/CodeGen/instrument-functions.c
> @@ -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;
> +}
From: Nelson Elhage <nelhage at nelhage.com>
Subject: Re: [cfe-commits] [patch] Implement -finstrument-functions
To: Chris Lattner <clattner at apple.com>
Cc: cfe-commits at cs.uiuc.edu
Bcc: nelhage at mit.edu
In-Reply-To: <5D3628F0-6FDE-4BC8-A7BB-E38E459129F9 at apple.com>
References: <87wrtvd6ys.fsf at mit.edu> <5D3628F0-6FDE-4BC8-A7BB-E38E459129F9 at apple.com>

On Fri, 18 Jun 2010 22:04:53 -0700, Chris Lattner <clattner at apple.com> wrote:
> On Jun 18, 2010, at 8:41 PM, Nelson Elhage wrote:
> > 
> > This patch implements the -finstrument-functions flag, which adds calls
> > to instrument function entry and exit.
> 
> Oh no!  Why did you implement this in clang instead of as an llvm optimization pass??
> 
> Haha, just kidding ;-)
> 
> 
> Overall, the patch looks great.  Please copy the comments for ShouldInstrumentFunction/EmitFunctionInstrumentation from the header into the implementation.  Here are a few minor coding changes:
> 
> +void CodeGenFunction::EmitFunctionInstrumentation(const char *Fn) {
> ..
> +  PointerTy = llvm::PointerType::getUnqual(
> +    llvm::Type::getInt8Ty(VMContext));
> 
> This can use Type::getInt8PtrTy(VMContext)
> 
> +  llvm::Constant *F = CGM.getModule().getOrInsertFunction(Fn, FunctionTy);
> 
> This should probably use CodeGenModule::CreateRuntimeFunction instead of doing it manually.
> 
> 
> 
> +  if (Builder.isNamePreserving())
> +    CallSite->setName("callsite");
> 
> You should be able to pass the name directly into the call to "CreateCall"
> 
> 
> 
> +                      llvm::ConstantExpr::getBitCast(CurFn, PointerTy),
> 
> This can go away when you use CreateRuntimeFunction.
> 
> 
> +static void HandleNoInstrumentFunctionAttr(Decl *d, const AttributeList &Attr, Sema &S) {
> +  // check the attribute arguments.
> 
> Please stay in 80 cols.
> 
> Otherwise, the patch looks great!  Thanks for adding this, please send in a revised patch and I'm happy to commit it for you if you don't already have commit access.
> 
> -Chris
From: Nelson Elhage <nelhage at nelhage.com>
Subject: Re: [cfe-commits] [patch] Implement -finstrument-functions
To: cfe-commits at cs.uiuc.edu
Bcc: nelhage at mit.edu
In-Reply-To: <87wrtvd6ys.fsf at mit.edu>
References: <87wrtvd6ys.fsf at mit.edu>

On Fri, 18 Jun 2010 23:41:47 -0400, Nelson Elhage <nelhage at nelhage.com> wrote:
> 
> This patch implements the -finstrument-functions flag, which adds calls
> to instrument function entry and exit.
> 
> I originally sent a patch [1] to implement this as an LLVM pass; Chris
> Lattner suggested [2] this feature should just go entirely in clang,
> which is what this patch implements.
> 
> [1] http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20100531/102265.html
> [2] http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20100614/102439.html
> 
> diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
> index 531c74c..e9f5628 100644
> --- a/include/clang/AST/Attr.h
> +++ b/include/clang/AST/Attr.h
> @@ -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:
> diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
> index c4f02a0..088fb8d 100644
> --- a/include/clang/Basic/Attr.td
> +++ b/include/clang/Basic/Attr.td
> @@ -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"];
>  }
> diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
> index ab9f902..c1de8b1 100644
> --- a/include/clang/Driver/CC1Options.td
> +++ b/include/clang/Driver/CC1Options.td
> @@ -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">,
> diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
> index 7ac04be..f7af6db 100644
> --- a/include/clang/Driver/Options.td
> +++ b/include/clang/Driver/Options.td
> @@ -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>;
> diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h
> index bfee72c..2d21f1d 100644
> --- a/include/clang/Frontend/CodeGenOptions.h
> +++ b/include/clang/Frontend/CodeGenOptions.h
> @@ -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.
> diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp
> index 1927a22..7628d3e 100644
> --- a/lib/AST/AttrImpl.cpp
> +++ b/lib/AST/AttrImpl.cpp
> @@ -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)
> diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
> index af06235..89a8a4a 100644
> --- a/lib/CodeGen/CodeGenFunction.cpp
> +++ b/lib/CodeGen/CodeGenFunction.cpp
> @@ -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_function_exit");
> +
>    // Emit debug descriptor for function end.
>    if (CGDebugInfo *DI = getDebugInfo()) {
>      DI->setLocation(EndLoc);
> @@ -159,6 +163,42 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
>    }
>  }
>  
> +bool CodeGenFunction::ShouldInstrumentFunction() {
> +  if (!CGM.getCodeGenOpts().InstrumentFunctions)
> +    return false;
> +  if (CurFuncDecl->hasAttr<NoInstrumentFunctionAttr>())
> +    return false;
> +  return true;
> +}
> +
> +void CodeGenFunction::EmitFunctionInstrumentation(const char *Fn) {
> +  if (!ShouldInstrumentFunction())
> +    return;
> +
> +  llvm::PointerType *PointerTy;
> +  llvm::FunctionType *FunctionTy;
> +  std::vector<const llvm::Type*> ProfileFuncArgs;
> +
> +  PointerTy = llvm::PointerType::getUnqual(
> +    llvm::Type::getInt8Ty(VMContext));
> +  ProfileFuncArgs.push_back(PointerTy);
> +  ProfileFuncArgs.push_back(PointerTy);
> +  FunctionTy = llvm::FunctionType::get(
> +    llvm::Type::getVoidTy(VMContext),
> +    ProfileFuncArgs, false);
> +
> +  llvm::Constant *F = CGM.getModule().getOrInsertFunction(Fn, FunctionTy);
> +  llvm::CallInst *CallSite = Builder.CreateCall(
> +    llvm::Intrinsic::getDeclaration(&CGM.getModule(), llvm::Intrinsic::returnaddress),
> +    llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0));
> +  if (Builder.isNamePreserving())
> +    CallSite->setName("callsite");
> +
> +  Builder.CreateCall2(F,
> +                      llvm::ConstantExpr::getBitCast(CurFn, PointerTy),
> +                      CallSite);
> +}
> +
>  void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
>                                      llvm::Function *Fn,
>                                      const FunctionArgList &Args,
> @@ -208,6 +248,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
>      DI->EmitFunctionStart(GD, FnType, CurFn, Builder);
>    }
>  
> +  EmitFunctionInstrumentation("__cyg_profile_function_enter");
> +
>    // FIXME: Leaked.
>    // CC info is ignored, hopefully?
>    CurFnInfo = &CGM.getTypes().getFunctionInfo(FnRetTy, Args,
> diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
> index f2a35ac..8f24ef3 100644
> --- a/lib/CodeGen/CodeGenFunction.h
> +++ b/lib/CodeGen/CodeGenFunction.h
> @@ -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.
> diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
> index ae197fb..cf866c3 100644
> --- a/lib/Driver/Tools.cpp
> +++ b/lib/Driver/Tools.cpp
> @@ -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);
> diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
> index a925047..e7a75a6 100644
> --- a/lib/Frontend/CompilerInvocation.cpp
> +++ b/lib/Frontend/CompilerInvocation.cpp
> @@ -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)
> diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
> index 89848af..80a843f 100644
> --- a/lib/Sema/SemaDeclAttr.cpp
> +++ b/lib/Sema/SemaDeclAttr.cpp
> @@ -1650,6 +1650,22 @@ 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) {
> @@ -1980,7 +1996,7 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
>    case AttributeList::AT_regparm:     HandleRegparmAttr     (D, Attr, S); break;
>    case AttributeList::IgnoredAttribute:
>    case AttributeList::AT_no_instrument_function:  // Interacts with -pg.
> -    // Just ignore
> +    HandleNoInstrumentFunctionAttr(D, Attr, S);
>      break;
>    case AttributeList::AT_stdcall:
>    case AttributeList::AT_cdecl:
> diff --git a/test/CodeGen/instrument-functions.c b/test/CodeGen/instrument-functions.c
> new file mode 100644
> index 0000000..5b34641
> --- /dev/null
> +++ b/test/CodeGen/instrument-functions.c
> @@ -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_function_enter
> +// CHECK: __cyg_profile_function_exit
> +// CHECK: ret
> +  return x;
> +}
> +
> +// CHECK: @test2
> +int test2(int) __attribute__((no_instrument_function));
> +int test2(int x) {
> +// CHECK-NOT: __cyg_profile_function_enter
> +// CHECK-NOT: __cyg_profile_function_exit
> +// CHECK: ret
> +  return x;
> +}
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits


More information about the cfe-commits mailing list