forked from OSchip/llvm-project
implement support for -finstrument-functions, patch by Nelson
Elhage! llvm-svn: 106507
This commit is contained in:
parent
b2c4a99d52
commit
3c77a355e0
|
@ -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:
|
||||
|
|
|
@ -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"];
|
||||
}
|
||||
|
|
|
@ -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">,
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue