diff options
| -rw-r--r-- | clang/include/clang/AST/Attr.h | 1 | ||||
| -rw-r--r-- | clang/include/clang/Basic/Attr.td | 5 | ||||
| -rw-r--r-- | clang/include/clang/Driver/CC1Options.td | 2 | ||||
| -rw-r--r-- | clang/include/clang/Driver/Options.td | 1 | ||||
| -rw-r--r-- | clang/include/clang/Frontend/CodeGenOptions.h | 1 | ||||
| -rw-r--r-- | clang/lib/AST/AttrImpl.cpp | 1 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.cpp | 41 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.h | 9 | ||||
| -rw-r--r-- | clang/lib/Driver/Tools.cpp | 2 | ||||
| -rw-r--r-- | clang/lib/Frontend/CompilerInvocation.cpp | 2 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 21 | ||||
| -rw-r--r-- | clang/test/CodeGen/instrument-functions.c | 18 | 
12 files changed, 103 insertions, 1 deletions
diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h index b67b53b10e7..0f0215a7c8d 100644 --- a/clang/include/clang/AST/Attr.h +++ b/clang/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/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 4b85bb20db2..98871d26204 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/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/clang/include/clang/Driver/CC1Options.td b/clang/include/clang/Driver/CC1Options.td index ab9f9027435..c1de8b1d3a9 100644 --- a/clang/include/clang/Driver/CC1Options.td +++ b/clang/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/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 7ac04bec9d4..f7af6dbe041 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/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/clang/include/clang/Frontend/CodeGenOptions.h b/clang/include/clang/Frontend/CodeGenOptions.h index bfee72cba4c..2d21f1d30b0 100644 --- a/clang/include/clang/Frontend/CodeGenOptions.h +++ b/clang/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/clang/lib/AST/AttrImpl.cpp b/clang/lib/AST/AttrImpl.cpp index 6db43c95652..b09ba895c01 100644 --- a/clang/lib/AST/AttrImpl.cpp +++ b/clang/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/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index af062356f65..8a0b41a7cad 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/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/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 0fdb60ccbba..f797c2c4ffc 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/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/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp index ae197fbeba6..cf866c3d476 100644 --- a/clang/lib/Driver/Tools.cpp +++ b/clang/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/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index a925047d945..e7a75a619dc 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/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/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 5858de06698..dee10fb608a 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/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/clang/test/CodeGen/instrument-functions.c b/clang/test/CodeGen/instrument-functions.c new file mode 100644 index 00000000000..d80385e2239 --- /dev/null +++ b/clang/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; +}  | 

