[cfe-commits] [patch] Implement -finstrument-functions
Nelson Elhage
nelhage at nelhage.com
Sat Jun 19 16:34:46 PDT 2010
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
-------------- next part --------------
A non-text attachment was scrubbed...
Name: instrument-functions.diff
Type: text/x-diff
Size: 10666 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20100619/eb6b6ed9/attachment.diff>
-------------- next part --------------
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;
> +}
More information about the cfe-commits
mailing list