summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Wennborg <hans@hanshq.net>2017-11-14 21:09:45 +0000
committerHans Wennborg <hans@hanshq.net>2017-11-14 21:09:45 +0000
commite1ecd61b9813453ceb442f71a75ee3c1b28189f0 (patch)
tree1d5586b860a8ab6bf75f9a4a68127c7d5667d6dd
parent817d7f36e9bf0dbd82ddfb2b76e8b23fe9a18d4e (diff)
downloadbcm5719-llvm-e1ecd61b9813453ceb442f71a75ee3c1b28189f0.tar.gz
bcm5719-llvm-e1ecd61b9813453ceb442f71a75ee3c1b28189f0.zip
Rename CountingFunctionInserter and use for both mcount and cygprofile calls, before and after inlining
Clang implements the -finstrument-functions flag inherited from GCC, which inserts calls to __cyg_profile_func_{enter,exit} on function entry and exit. This is useful for getting a trace of how the functions in a program are executed. Normally, the calls remain even if a function is inlined into another function, but it is useful to be able to turn this off for users who are interested in a lower-level trace, i.e. one that reflects what functions are called post-inlining. (We use this to generate link order files for Chromium.) LLVM already has a pass for inserting similar instrumentation calls to mcount(), which it does after inlining. This patch renames and extends that pass to handle calls both to mcount and the cygprofile functions, before and/or after inlining as controlled by function attributes. Differential Revision: https://reviews.llvm.org/D39287 llvm-svn: 318195
-rw-r--r--llvm/include/llvm/CodeGen/Passes.h3
-rw-r--r--llvm/include/llvm/InitializePasses.h3
-rw-r--r--llvm/include/llvm/LinkAllPasses.h3
-rw-r--r--llvm/include/llvm/Transforms/Scalar.h10
-rw-r--r--llvm/include/llvm/Transforms/Utils/EntryExitInstrumenter.h36
-rw-r--r--llvm/lib/CodeGen/CMakeLists.txt1
-rw-r--r--llvm/lib/CodeGen/CodeGen.cpp1
-rw-r--r--llvm/lib/CodeGen/CountingFunctionInserter.cpp58
-rw-r--r--llvm/lib/CodeGen/TargetPassConfig.cpp4
-rw-r--r--llvm/lib/Passes/PassBuilder.cpp1
-rw-r--r--llvm/lib/Passes/PassRegistry.def2
-rw-r--r--llvm/lib/Transforms/IPO/PassManagerBuilder.cpp1
-rw-r--r--llvm/lib/Transforms/Scalar/Scalar.cpp2
-rw-r--r--llvm/lib/Transforms/Utils/CMakeLists.txt1
-rw-r--r--llvm/lib/Transforms/Utils/EntryExitInstrumenter.cpp148
-rw-r--r--llvm/test/CodeGen/PowerPC/mcount-insertion.ll40
-rw-r--r--llvm/test/CodeGen/X86/O0-pipeline.ll2
-rw-r--r--llvm/test/Transforms/CountingFunctionInserter/mcount.ll79
-rw-r--r--llvm/tools/llc/llc.cpp3
-rw-r--r--llvm/tools/opt/opt.cpp3
20 files changed, 316 insertions, 85 deletions
diff --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h
index c106ff6cdfe..4370d116e08 100644
--- a/llvm/include/llvm/CodeGen/Passes.h
+++ b/llvm/include/llvm/CodeGen/Passes.h
@@ -43,9 +43,6 @@ namespace llvm {
/// the entry block.
FunctionPass *createUnreachableBlockEliminationPass();
- /// Insert mcount-like function calls.
- FunctionPass *createCountingFunctionInserterPass();
-
/// MachineFunctionPrinter pass - This pass prints out the machine function to
/// the given stream as a debugging tool.
MachineFunctionPass *
diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h
index 6abe9992291..4935ba1a30d 100644
--- a/llvm/include/llvm/InitializePasses.h
+++ b/llvm/include/llvm/InitializePasses.h
@@ -99,7 +99,8 @@ void initializeConstantMergeLegacyPassPass(PassRegistry&);
void initializeConstantPropagationPass(PassRegistry&);
void initializeCorrelatedValuePropagationPass(PassRegistry&);
void initializeCostModelAnalysisPass(PassRegistry&);
-void initializeCountingFunctionInserterPass(PassRegistry&);
+void initializeEntryExitInstrumenterPass(PassRegistry&);
+void initializePostInlineEntryExitInstrumenterPass(PassRegistry&);
void initializeCrossDSOCFIPass(PassRegistry&);
void initializeDAEPass(PassRegistry&);
void initializeDAHPass(PassRegistry&);
diff --git a/llvm/include/llvm/LinkAllPasses.h b/llvm/include/llvm/LinkAllPasses.h
index 2862b46f58c..39d1ec6cffb 100644
--- a/llvm/include/llvm/LinkAllPasses.h
+++ b/llvm/include/llvm/LinkAllPasses.h
@@ -166,7 +166,8 @@ namespace {
(void) llvm::createInstCountPass();
(void) llvm::createConstantHoistingPass();
(void) llvm::createCodeGenPreparePass();
- (void) llvm::createCountingFunctionInserterPass();
+ (void) llvm::createEntryExitInstrumenterPass();
+ (void) llvm::createPostInlineEntryExitInstrumenterPass();
(void) llvm::createEarlyCSEPass();
(void) llvm::createGVNHoistPass();
(void) llvm::createMergedLoadStoreMotionPass();
diff --git a/llvm/include/llvm/Transforms/Scalar.h b/llvm/include/llvm/Transforms/Scalar.h
index 0cf1115dc97..07d3d7fc8f6 100644
--- a/llvm/include/llvm/Transforms/Scalar.h
+++ b/llvm/include/llvm/Transforms/Scalar.h
@@ -582,6 +582,16 @@ ModulePass *createNameAnonGlobalPass();
// used.
//
FunctionPass *createLibCallsShrinkWrapPass();
+
+//===----------------------------------------------------------------------===//
+//
+// EntryExitInstrumenter pass - Instrument function entry/exit with calls to
+// mcount(), @__cyg_profile_func_{enter,exit} and the like. There are two
+// variants, intended to run pre- and post-inlining, respectively.
+//
+FunctionPass *createEntryExitInstrumenterPass();
+FunctionPass *createPostInlineEntryExitInstrumenterPass();
+
} // End llvm namespace
#endif
diff --git a/llvm/include/llvm/Transforms/Utils/EntryExitInstrumenter.h b/llvm/include/llvm/Transforms/Utils/EntryExitInstrumenter.h
new file mode 100644
index 00000000000..f50c5c92208
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Utils/EntryExitInstrumenter.h
@@ -0,0 +1,36 @@
+//===- EntryExitInstrumenter.h - Function Entry/Exit Instrumentation ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// EntryExitInstrumenter pass - Instrument function entry/exit with calls to
+// mcount(), @__cyg_profile_func_{enter,exit} and the like. There are two
+// variants, intended to run pre- and post-inlining, respectively.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_UTILS_ENTRYEXITINSTRUMENTER_H
+#define LLVM_TRANSFORMS_UTILS_ENTRYEXITINSTRUMENTER_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+class Function;
+
+struct EntryExitInstrumenterPass
+ : public PassInfoMixin<EntryExitInstrumenterPass> {
+ EntryExitInstrumenterPass(bool PostInlining) : PostInlining(PostInlining) {}
+
+ PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
+
+ bool PostInlining;
+};
+
+} // namespace llvm
+
+#endif // LLVM_TRANSFORMS_UTILS_ENTRYEXITINSTRUMENTER_H
diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt
index df04cf85049..4b4662bb0ac 100644
--- a/llvm/lib/CodeGen/CMakeLists.txt
+++ b/llvm/lib/CodeGen/CMakeLists.txt
@@ -11,7 +11,6 @@ add_llvm_library(LLVMCodeGen
CallingConvLower.cpp
CodeGen.cpp
CodeGenPrepare.cpp
- CountingFunctionInserter.cpp
CriticalAntiDepBreaker.cpp
DeadMachineInstructionElim.cpp
DetectDeadLanes.cpp
diff --git a/llvm/lib/CodeGen/CodeGen.cpp b/llvm/lib/CodeGen/CodeGen.cpp
index 2f119554a1e..c0d7eb4cf47 100644
--- a/llvm/lib/CodeGen/CodeGen.cpp
+++ b/llvm/lib/CodeGen/CodeGen.cpp
@@ -24,7 +24,6 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
initializeBranchFolderPassPass(Registry);
initializeBranchRelaxationPass(Registry);
initializeCodeGenPreparePass(Registry);
- initializeCountingFunctionInserterPass(Registry);
initializeDeadMachineInstructionElimPass(Registry);
initializeDetectDeadLanesPass(Registry);
initializeDwarfEHPreparePass(Registry);
diff --git a/llvm/lib/CodeGen/CountingFunctionInserter.cpp b/llvm/lib/CodeGen/CountingFunctionInserter.cpp
deleted file mode 100644
index 15af09807ba..00000000000
--- a/llvm/lib/CodeGen/CountingFunctionInserter.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-//===- CountingFunctionInserter.cpp - Insert mcount-like function calls ---===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Insert calls to counter functions, such as mcount, intended to be called
-// once per function, at the beginning of each function.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Analysis/GlobalsModRef.h"
-#include "llvm/CodeGen/Passes.h"
-#include "llvm/IR/Function.h"
-#include "llvm/IR/Instructions.h"
-#include "llvm/IR/Module.h"
-#include "llvm/IR/Type.h"
-#include "llvm/Pass.h"
-using namespace llvm;
-
-namespace {
- struct CountingFunctionInserter : public FunctionPass {
- static char ID; // Pass identification, replacement for typeid
- CountingFunctionInserter() : FunctionPass(ID) {
- initializeCountingFunctionInserterPass(*PassRegistry::getPassRegistry());
- }
-
- void getAnalysisUsage(AnalysisUsage &AU) const override {
- AU.addPreserved<GlobalsAAWrapperPass>();
- }
-
- bool runOnFunction(Function &F) override {
- StringRef CountingFunctionName =
- F.getFnAttribute("counting-function").getValueAsString();
- if (CountingFunctionName.empty())
- return false;
-
- Type *VoidTy = Type::getVoidTy(F.getContext());
- Constant *CountingFn =
- F.getParent()->getOrInsertFunction(CountingFunctionName,
- VoidTy);
- CallInst::Create(CountingFn, "", &*F.begin()->getFirstInsertionPt());
- return true;
- }
- };
-
- char CountingFunctionInserter::ID = 0;
-}
-
-INITIALIZE_PASS(CountingFunctionInserter, "cfinserter",
- "Inserts calls to mcount-like functions", false, false)
-
-FunctionPass *llvm::createCountingFunctionInserterPass() {
- return new CountingFunctionInserter();
-}
diff --git a/llvm/lib/CodeGen/TargetPassConfig.cpp b/llvm/lib/CodeGen/TargetPassConfig.cpp
index 59e88ba3bda..3f2a31a69cf 100644
--- a/llvm/lib/CodeGen/TargetPassConfig.cpp
+++ b/llvm/lib/CodeGen/TargetPassConfig.cpp
@@ -625,8 +625,8 @@ void TargetPassConfig::addIRPasses() {
if (getOptLevel() != CodeGenOpt::None && !DisablePartialLibcallInlining)
addPass(createPartiallyInlineLibCallsPass());
- // Insert calls to mcount-like functions.
- addPass(createCountingFunctionInserterPass());
+ // Instrument function entry and exit, e.g. with calls to mcount().
+ addPass(createPostInlineEntryExitInstrumenterPass());
// Add scalarization of target's unsupported masked memory intrinsics pass.
// the unsupported intrinsic will be replaced with a chain of basic blocks,
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index f72b38e61e7..c9b4acfe3da 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -136,6 +136,7 @@
#include "llvm/Transforms/Scalar/TailRecursionElimination.h"
#include "llvm/Transforms/Utils/AddDiscriminators.h"
#include "llvm/Transforms/Utils/BreakCriticalEdges.h"
+#include "llvm/Transforms/Utils/EntryExitInstrumenter.h"
#include "llvm/Transforms/Utils/LCSSA.h"
#include "llvm/Transforms/Utils/LibCallsShrinkWrap.h"
#include "llvm/Transforms/Utils/LoopSimplify.h"
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index ae0d0ac1e10..a5015a7910e 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -151,6 +151,8 @@ FUNCTION_PASS("dot-cfg", CFGPrinterPass())
FUNCTION_PASS("dot-cfg-only", CFGOnlyPrinterPass())
FUNCTION_PASS("early-cse", EarlyCSEPass(/*UseMemorySSA=*/false))
FUNCTION_PASS("early-cse-memssa", EarlyCSEPass(/*UseMemorySSA=*/true))
+FUNCTION_PASS("ee-instrument", EntryExitInstrumenterPass(/*PostInlining=*/false))
+FUNCTION_PASS("post-inline-ee-instrument", EntryExitInstrumenterPass(/*PostInlining=*/true))
FUNCTION_PASS("gvn-hoist", GVNHoistPass())
FUNCTION_PASS("instcombine", InstCombinePass())
FUNCTION_PASS("instsimplify", InstSimplifierPass())
diff --git a/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp b/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp
index 5d373665509..abab7e194ad 100644
--- a/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp
+++ b/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp
@@ -241,6 +241,7 @@ void PassManagerBuilder::addInstructionCombiningPass(
void PassManagerBuilder::populateFunctionPassManager(
legacy::FunctionPassManager &FPM) {
addExtensionsToPM(EP_EarlyAsPossible, FPM);
+ FPM.add(createEntryExitInstrumenterPass());
// Add LibraryInfo if we have some.
if (LibraryInfo)
diff --git a/llvm/lib/Transforms/Scalar/Scalar.cpp b/llvm/lib/Transforms/Scalar/Scalar.cpp
index 8a5ae1b8731..01d557f8113 100644
--- a/llvm/lib/Transforms/Scalar/Scalar.cpp
+++ b/llvm/lib/Transforms/Scalar/Scalar.cpp
@@ -100,6 +100,8 @@ void llvm::initializeScalarOpts(PassRegistry &Registry) {
initializeLoopLoadEliminationPass(Registry);
initializeLoopSimplifyCFGLegacyPassPass(Registry);
initializeLoopVersioningPassPass(Registry);
+ initializeEntryExitInstrumenterPass(Registry);
+ initializePostInlineEntryExitInstrumenterPass(Registry);
}
void LLVMInitializeScalarOpts(LLVMPassRegistryRef R) {
diff --git a/llvm/lib/Transforms/Utils/CMakeLists.txt b/llvm/lib/Transforms/Utils/CMakeLists.txt
index 8561ec78b1c..f3bf0d8c248 100644
--- a/llvm/lib/Transforms/Utils/CMakeLists.txt
+++ b/llvm/lib/Transforms/Utils/CMakeLists.txt
@@ -10,6 +10,7 @@ add_llvm_library(LLVMTransformUtils
CodeExtractor.cpp
CtorUtils.cpp
DemoteRegToStack.cpp
+ EntryExitInstrumenter.cpp
EscapeEnumerator.cpp
Evaluator.cpp
FlattenCFG.cpp
diff --git a/llvm/lib/Transforms/Utils/EntryExitInstrumenter.cpp b/llvm/lib/Transforms/Utils/EntryExitInstrumenter.cpp
new file mode 100644
index 00000000000..ba6f67e15ca
--- /dev/null
+++ b/llvm/lib/Transforms/Utils/EntryExitInstrumenter.cpp
@@ -0,0 +1,148 @@
+//===- EntryExitInstrumenter.cpp - Function Entry/Exit Instrumentation ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Utils/EntryExitInstrumenter.h"
+#include "llvm/Analysis/GlobalsModRef.h"
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Type.h"
+#include "llvm/Pass.h"
+#include "llvm/Transforms/Scalar.h"
+using namespace llvm;
+
+static void insertCall(Function &CurFn, StringRef Func,
+ Instruction *InsertionPt) {
+ Module &M = *InsertionPt->getParent()->getParent()->getParent();
+ LLVMContext &C = InsertionPt->getParent()->getContext();
+
+ if (Func == "mcount" ||
+ Func == ".mcount" ||
+ Func == "\01__gnu_mcount_nc" ||
+ Func == "\01_mcount" ||
+ Func == "\01mcount" ||
+ Func == "__mcount" ||
+ Func == "_mcount") {
+ Constant *Fn = M.getOrInsertFunction(Func, Type::getVoidTy(C));
+ CallInst::Create(Fn, "", InsertionPt);
+ return;
+ }
+
+ if (Func == "__cyg_profile_func_enter" || Func == "__cyg_profile_func_exit") {
+ Type *ArgTypes[] = {Type::getInt8PtrTy(C), Type::getInt8PtrTy(C)};
+
+ Constant *Fn = M.getOrInsertFunction(
+ Func, FunctionType::get(Type::getVoidTy(C), ArgTypes, false));
+
+ Instruction *RetAddr = CallInst::Create(
+ Intrinsic::getDeclaration(&M, Intrinsic::returnaddress),
+ ArrayRef<Value *>(ConstantInt::get(Type::getInt32Ty(C), 0)), "",
+ InsertionPt);
+
+ Value *Args[] = {ConstantExpr::getBitCast(&CurFn, Type::getInt8PtrTy(C)),
+ RetAddr};
+
+ CallInst::Create(Fn, ArrayRef<Value *>(Args), "", InsertionPt);
+ return;
+ }
+
+ // We only know how to call a fixed set of instrumentation functions, because
+ // they all expect different arguments, etc.
+ report_fatal_error(Twine("Unknown instrumentation function: '") + Func + "'");
+}
+
+static bool runOnFunction(Function &F, bool PostInlining) {
+ StringRef EntryAttr = PostInlining ? "instrument-function-entry-inlined"
+ : "instrument-function-entry";
+
+ StringRef ExitAttr = PostInlining ? "instrument-function-exit-inlined"
+ : "instrument-function-exit";
+
+ StringRef EntryFunc = F.getFnAttribute(EntryAttr).getValueAsString();
+ StringRef ExitFunc = F.getFnAttribute(ExitAttr).getValueAsString();
+
+ bool Changed = false;
+
+ // If the attribute is specified, insert instrumentation and then "consume"
+ // the attribute so that it's not inserted again if the pass should happen to
+ // run later for some reason.
+
+ if (!EntryFunc.empty()) {
+ insertCall(F, EntryFunc, &*F.begin()->getFirstInsertionPt());
+ Changed = true;
+ F.removeAttribute(AttributeList::FunctionIndex, EntryAttr);
+ }
+
+ if (!ExitFunc.empty()) {
+ for (BasicBlock &BB : F) {
+ TerminatorInst *T = BB.getTerminator();
+ if (isa<ReturnInst>(T)) {
+ insertCall(F, ExitFunc, T);
+ Changed = true;
+ }
+ }
+ F.removeAttribute(AttributeList::FunctionIndex, ExitAttr);
+ }
+
+ return Changed;
+}
+
+namespace {
+struct EntryExitInstrumenter : public FunctionPass {
+ static char ID;
+ EntryExitInstrumenter() : FunctionPass(ID) {
+ initializeEntryExitInstrumenterPass(*PassRegistry::getPassRegistry());
+ }
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.addPreserved<GlobalsAAWrapperPass>();
+ }
+ bool runOnFunction(Function &F) override { return ::runOnFunction(F, false); }
+};
+char EntryExitInstrumenter::ID = 0;
+
+struct PostInlineEntryExitInstrumenter : public FunctionPass {
+ static char ID;
+ PostInlineEntryExitInstrumenter() : FunctionPass(ID) {
+ initializePostInlineEntryExitInstrumenterPass(
+ *PassRegistry::getPassRegistry());
+ }
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.addPreserved<GlobalsAAWrapperPass>();
+ }
+ bool runOnFunction(Function &F) override { return ::runOnFunction(F, true); }
+};
+char PostInlineEntryExitInstrumenter::ID = 0;
+}
+
+INITIALIZE_PASS(
+ EntryExitInstrumenter, "ee-instrument",
+ "Instrument function entry/exit with calls to e.g. mcount() (pre inlining)",
+ false, false);
+
+INITIALIZE_PASS(PostInlineEntryExitInstrumenter, "post-inline-ee-instrument",
+ "Instrument function entry/exit with calls to e.g. mcount() "
+ "(post inlining)",
+ false, false);
+
+FunctionPass *llvm::createEntryExitInstrumenterPass() {
+ return new EntryExitInstrumenter();
+}
+
+FunctionPass *llvm::createPostInlineEntryExitInstrumenterPass() {
+ return new PostInlineEntryExitInstrumenter();
+}
+
+PreservedAnalyses
+llvm::EntryExitInstrumenterPass::run(Function &F, FunctionAnalysisManager &AM) {
+ runOnFunction(F, PostInlining);
+ PreservedAnalyses PA;
+ PA.preserveSet<CFGAnalyses>();
+ return PA;
+}
diff --git a/llvm/test/CodeGen/PowerPC/mcount-insertion.ll b/llvm/test/CodeGen/PowerPC/mcount-insertion.ll
index 04e8571d6f4..cbb7947be21 100644
--- a/llvm/test/CodeGen/PowerPC/mcount-insertion.ll
+++ b/llvm/test/CodeGen/PowerPC/mcount-insertion.ll
@@ -1,16 +1,46 @@
-; RUN: llc < %s | FileCheck %s
+; RUN: opt -ee-instrument < %s | opt -inline | llc | FileCheck %s
+
+; The run-line mimics how Clang might run the instrumentation passes.
+
target datalayout = "E-m:e-i64:64-n32:64"
target triple = "powerpc64-bgq-linux"
-define void @test1() #0 {
+
+define void @leaf_function() #0 {
entry:
ret void
-; CHECK-LABEL: @test1
+; CHECK-LABEL: leaf_function:
; CHECK: bl mcount
-; CHECK-NOT: mcount
+; CHECK-NOT: bl
+; CHECK: bl __cyg_profile_func_enter
+; CHECK-NOT: bl
+; CHECK: bl __cyg_profile_func_exit
+; CHECK-NOT: bl
; CHECK: blr
}
-attributes #0 = { "counting-function"="mcount" }
+define void @root_function() #0 {
+entry:
+ call void @leaf_function()
+ ret void
+
+; CHECK-LABEL: root_function:
+; CHECK: bl mcount
+; CHECK-NOT: bl
+; CHECK: bl __cyg_profile_func_enter
+; CHECK-NOT: bl
+
+; Entry and exit calls, inlined from @leaf_function()
+; CHECK: bl __cyg_profile_func_enter
+; CHECK-NOT: bl
+; CHECK: bl __cyg_profile_func_exit
+; CHECK-NOT: bl
+
+; CHECK: bl __cyg_profile_func_exit
+; CHECK-NOT: bl
+; CHECK: blr
+}
+
+attributes #0 = { "instrument-function-entry-inlined"="mcount" "instrument-function-entry"="__cyg_profile_func_enter" "instrument-function-exit"="__cyg_profile_func_exit" }
diff --git a/llvm/test/CodeGen/X86/O0-pipeline.ll b/llvm/test/CodeGen/X86/O0-pipeline.ll
index 1f7415ee2af..cb7dabefe45 100644
--- a/llvm/test/CodeGen/X86/O0-pipeline.ll
+++ b/llvm/test/CodeGen/X86/O0-pipeline.ll
@@ -22,7 +22,7 @@
; CHECK-NEXT: Lower Garbage Collection Instructions
; CHECK-NEXT: Shadow Stack GC Lowering
; CHECK-NEXT: Remove unreachable blocks from the CFG
-; CHECK-NEXT: Inserts calls to mcount-like functions
+; CHECK-NEXT: Instrument function entry/exit with calls to e.g. mcount() (post inlining)
; CHECK-NEXT: Scalarize Masked Memory Intrinsics
; CHECK-NEXT: Expand reduction intrinsics
; CHECK-NEXT: Rewrite Symbols
diff --git a/llvm/test/Transforms/CountingFunctionInserter/mcount.ll b/llvm/test/Transforms/CountingFunctionInserter/mcount.ll
index 88297c7d825..6d9aaab18c6 100644
--- a/llvm/test/Transforms/CountingFunctionInserter/mcount.ll
+++ b/llvm/test/Transforms/CountingFunctionInserter/mcount.ll
@@ -1,27 +1,86 @@
-; RUN: opt -S -cfinserter < %s | FileCheck %s
+; RUN: opt -passes="function(ee-instrument),cgscc(inline),function(post-inline-ee-instrument)" -S < %s | FileCheck %s
+
+; Running the passes twice should not result in more instrumentation.
+; RUN: opt -passes="function(ee-instrument),function(ee-instrument),cgscc(inline),function(post-inline-ee-instrument),function(post-inline-ee-instrument)" -S < %s | FileCheck %s
+
target datalayout = "E-m:e-i64:64-n32:64"
target triple = "powerpc64-bgq-linux"
-define void @test1() #0 {
+define void @leaf_function() #0 {
entry:
ret void
-; CHECK-LABEL: define void @test1()
+; CHECK-LABEL: define void @leaf_function()
; CHECK: entry:
; CHECK-NEXT: call void @mcount()
-; CHECK: ret void
+; CHECK-NEXT: %0 = call i8* @llvm.returnaddress(i32 0)
+; CHECK-NEXT: call void @__cyg_profile_func_enter(i8* bitcast (void ()* @leaf_function to i8*), i8* %0)
+; CHECK-NEXT: %1 = call i8* @llvm.returnaddress(i32 0)
+; CHECK-NEXT: call void @__cyg_profile_func_exit(i8* bitcast (void ()* @leaf_function to i8*), i8* %1)
+; CHECK-NEXT: ret void
}
-define void @test2() #1 {
+
+define void @root_function() #0 {
entry:
+ call void @leaf_function()
ret void
-; CHECK-LABEL: define void @test2()
+; CHECK-LABEL: define void @root_function()
; CHECK: entry:
-; CHECK-NEXT: call void @.mcount()
-; CHECK: ret void
+; CHECK-NEXT: call void @mcount()
+
+; CHECK-NEXT %0 = call i8* @llvm.returnaddress(i32 0)
+; CHECK-NEXT call void @__cyg_profile_func_enter(i8* bitcast (void ()* @root_function to i8*), i8* %0)
+
+; Entry and exit calls, inlined from @leaf_function()
+; CHECK-NEXT %1 = call i8* @llvm.returnaddress(i32 0)
+; CHECK-NEXT call void @__cyg_profile_func_enter(i8* bitcast (void ()* @leaf_function to i8*), i8* %1)
+; CHECK-NEXT %2 = call i8* @llvm.returnaddress(i32 0)
+; CHECK-NEXT call void @__cyg_profile_func_exit(i8* bitcast (void ()* @leaf_function to i8*), i8* %2)
+; CHECK-NEXT %3 = call i8* @llvm.returnaddress(i32 0)
+
+; CHECK-NEXT call void @__cyg_profile_func_exit(i8* bitcast (void ()* @root_function to i8*), i8* %3)
+; CHECK-NEXT ret void
}
-attributes #0 = { "counting-function"="mcount" }
-attributes #1 = { "counting-function"=".mcount" }
+attributes #0 = { "instrument-function-entry-inlined"="mcount" "instrument-function-entry"="__cyg_profile_func_enter" "instrument-function-exit"="__cyg_profile_func_exit" }
+
+
+; The mcount function has many different names.
+
+define void @f1() #1 { entry: ret void }
+; CHECK-LABEL: define void @f1
+; CHECK: call void @.mcount
+
+define void @f2() #2 { entry: ret void }
+; CHECK-LABEL: define void @f2
+; CHECK: call void @"\01__gnu_mcount_nc"
+
+define void @f3() #3 { entry: ret void }
+; CHECK-LABEL: define void @f3
+; CHECK: call void @"\01_mcount"
+
+define void @f4() #4 { entry: ret void }
+; CHECK-LABEL: define void @f4
+; CHECK: call void @"\01mcount"
+
+define void @f5() #5 { entry: ret void }
+; CHECK-LABEL: define void @f5
+; CHECK: call void @__mcount
+
+define void @f6() #6 { entry: ret void }
+; CHECK-LABEL: define void @f6
+; CHECK: call void @_mcount
+
+
+; The attributes are "consumed" when the instrumentation is inserted.
+; CHECK: attributes
+; CHECK-NOT: instrument-function
+attributes #1 = { "instrument-function-entry-inlined"=".mcount" }
+attributes #2 = { "instrument-function-entry-inlined"="\01__gnu_mcount_nc" }
+attributes #3 = { "instrument-function-entry-inlined"="\01_mcount" }
+attributes #4 = { "instrument-function-entry-inlined"="\01mcount" }
+attributes #5 = { "instrument-function-entry-inlined"="__mcount" }
+attributes #6 = { "instrument-function-entry-inlined"="_mcount" }
diff --git a/llvm/tools/llc/llc.cpp b/llvm/tools/llc/llc.cpp
index fe6b97e34b6..0a3d3dbcc0b 100644
--- a/llvm/tools/llc/llc.cpp
+++ b/llvm/tools/llc/llc.cpp
@@ -291,7 +291,8 @@ int main(int argc, char **argv) {
initializeCodeGen(*Registry);
initializeLoopStrengthReducePass(*Registry);
initializeLowerIntrinsicsPass(*Registry);
- initializeCountingFunctionInserterPass(*Registry);
+ initializeEntryExitInstrumenterPass(*Registry);
+ initializePostInlineEntryExitInstrumenterPass(*Registry);
initializeUnreachableBlockElimLegacyPassPass(*Registry);
initializeConstantHoistingLegacyPassPass(*Registry);
initializeScalarOpts(*Registry);
diff --git a/llvm/tools/opt/opt.cpp b/llvm/tools/opt/opt.cpp
index 0371cd0372f..b11daecb739 100644
--- a/llvm/tools/opt/opt.cpp
+++ b/llvm/tools/opt/opt.cpp
@@ -403,7 +403,8 @@ int main(int argc, char **argv) {
initializePreISelIntrinsicLoweringLegacyPassPass(Registry);
initializeGlobalMergePass(Registry);
initializeInterleavedAccessPass(Registry);
- initializeCountingFunctionInserterPass(Registry);
+ initializeEntryExitInstrumenterPass(Registry);
+ initializePostInlineEntryExitInstrumenterPass(Registry);
initializeUnreachableBlockElimLegacyPassPass(Registry);
initializeExpandReductionsPass(Registry);
initializeWriteBitcodePassPass(Registry);
OpenPOWER on IntegriCloud