Index: lib/Analysis/InlineCost.cpp =================================================================== --- lib/Analysis/InlineCost.cpp +++ lib/Analysis/InlineCost.cpp @@ -54,6 +54,11 @@ cl::init(45), cl::desc("Threshold for inlining cold callsites")); +cl::opt DisableCygprofileInlining( + "disable-cygprofile-inlining", + cl::desc("Disable inlining of calls to __cyg_profile functions"), + cl::init(false)); + // We introduce this threshold to help performance of instrumentation based // PGO before we actually hook up inliner with analysis passes such as BPI and // BFI. @@ -1072,10 +1077,18 @@ ExposesReturnsTwice = true; return false; } + if (CS.isCall() && cast(CS.getInstruction())->cannotDuplicate()) ContainsNoDuplicateCall = true; if (Function *F = CS.getCalledFunction()) { + // Ignore call instructions generated by -fprofile-functions. They will not + // be cloned, and should not affect the inlining decision. + if (DisableCygprofileInlining && + (F->getName() == "__cyg_profile_func_enter" || + F->getName() == "__cyg_profile_func_exit")) + return false; + // When we have a concrete function, first try to simplify it directly. if (simplifyCallSite(F, CS)) return true; Index: lib/Transforms/Utils/CloneFunction.cpp =================================================================== --- lib/Transforms/Utils/CloneFunction.cpp +++ lib/Transforms/Utils/CloneFunction.cpp @@ -36,6 +36,8 @@ #include using namespace llvm; +extern cl::opt DisableCygprofileInlining; + /// See comments in Cloning.h. BasicBlock *llvm::CloneBasicBlock(const BasicBlock *BB, ValueToValueMapTy &VMap, const Twine &NameSuffix, Function *F, @@ -298,7 +300,8 @@ // Have we already cloned this block? if (BBEntry) return; - + + // Nope, clone it now. BasicBlock *NewBB; BBEntry = NewBB = BasicBlock::Create(BB->getContext()); @@ -325,6 +328,16 @@ // loop doesn't include the terminator. for (BasicBlock::const_iterator II = StartingInst, IE = --BB->end(); II != IE; ++II) { + // Drop call instructions generated by -fprofile-functions. + if (DisableCygprofileInlining) { + if (const CallInst *CI = dyn_cast(II)) { + if (const Function *Callee = CI->getCalledFunction()) { + if (Callee->getName() == "__cyg_profile_func_enter" || + Callee->getName() == "__cyg_profile_func_exit") + continue; + } + } + } Instruction *NewInst = II->clone(); Index: test/Transforms/Inline/cygprofile-instrumentation.ll =================================================================== --- /dev/null +++ test/Transforms/Inline/cygprofile-instrumentation.ll @@ -0,0 +1,39 @@ +; RUN: opt < %s -inline -S | FileCheck %s --check-prefix=CHECK --check-prefix=INLINE +; RUN: opt < %s -inline -inline-threshold=1 -disable-cygprofile-inlining -S | FileCheck %s --check-prefix=CHECK --check-prefix=NOINLINE + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +declare void @__cyg_profile_func_enter(i8*, i8*) +declare void @__cyg_profile_func_exit(i8*, i8*) +declare i8* @llvm.returnaddress(i32) + +define internal void @g() { +entry: + %callsite = call i8* @llvm.returnaddress(i32 0) + call void @__cyg_profile_func_enter(i8* bitcast (void ()* @g to i8*), i8* %callsite) + %callsite1 = call i8* @llvm.returnaddress(i32 0) + call void @__cyg_profile_func_exit(i8* bitcast (void ()* @g to i8*), i8* %callsite1) + ret void +} + +define void @f() { +; CHECK-LABEL: @f +; The call to @g should be inlined, but whether or not @g's cygprofile calls +; should be inlined depends on the use of -disable-cygprofile-inlining. + +; CHECK: call void @__cyg_profile_func_enter +; CHECK-NOT: call void @g() +; INLINE: call void @__cyg_profile_func_enter +; NOINLINE-NOT: call void @__cyg_profile_func_enter +; CHECK: call void @__cyg_profile_func_exit +; INLINE: call void @__cyg_profile_func_exit +; NOINLINE-NOT: call void @__cyg_profile_func_exit + +entry: + %callsite = call i8* @llvm.returnaddress(i32 0) + call void @__cyg_profile_func_enter(i8* bitcast (void ()* @f to i8*), i8* %callsite) + call void @g() + %callsite1 = call i8* @llvm.returnaddress(i32 0) + call void @__cyg_profile_func_exit(i8* bitcast (void ()* @f to i8*), i8* %callsite1) + ret void +}