From f73c9c11e70e8367f4b9e549effe8a673061b95d Mon Sep 17 00:00:00 2001 From: Hal Finkel Date: Thu, 1 Sep 2016 09:42:39 +0000 Subject: [PATCH] Add a counter-function insertion pass As discussed in https://reviews.llvm.org/D22666, our current mechanism to support -pg profiling, where we insert calls to mcount(), or some similar function, is fundamentally broken. We insert these calls in the frontend, which means they get duplicated when inlining, and so the accumulated execution counts for the inlined-into functions are wrong. Because we don't want the presence of these functions to affect optimizaton, they should be inserted in the backend. Here's a pass which would do just that. The knowledge of the name of the counting function lives in the frontend, so we're passing it here as a function attribute. Clang will be updated to use this mechanism. Differential Revision: https://reviews.llvm.org/D22825 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@280347 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/CodeGen/Passes.h | 3 + include/llvm/InitializePasses.h | 1 + include/llvm/LinkAllPasses.h | 1 + lib/CodeGen/CMakeLists.txt | 1 + lib/CodeGen/CodeGen.cpp | 1 + lib/CodeGen/CountingFunctionInserter.cpp | 62 +++++++++++++++++++ lib/CodeGen/TargetPassConfig.cpp | 3 + test/CodeGen/PowerPC/mcount-insertion.ll | 16 +++++ .../CountingFunctionInserter/mcount.ll | 27 ++++++++ tools/llc/llc.cpp | 1 + tools/opt/opt.cpp | 1 + 11 files changed, 117 insertions(+) create mode 100644 lib/CodeGen/CountingFunctionInserter.cpp create mode 100644 test/CodeGen/PowerPC/mcount-insertion.ll create mode 100644 test/Transforms/CountingFunctionInserter/mcount.ll diff --git a/include/llvm/CodeGen/Passes.h b/include/llvm/CodeGen/Passes.h index 09e66098748..94e3c32c92b 100644 --- a/include/llvm/CodeGen/Passes.h +++ b/include/llvm/CodeGen/Passes.h @@ -43,6 +43,9 @@ 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/include/llvm/InitializePasses.h b/include/llvm/InitializePasses.h index e3e131cf9ff..3c7fc63605d 100644 --- a/include/llvm/InitializePasses.h +++ b/include/llvm/InitializePasses.h @@ -92,6 +92,7 @@ void initializeCallGraphPrinterLegacyPassPass(PassRegistry&); void initializeCallGraphViewerPass(PassRegistry&); void initializeCallGraphWrapperPassPass(PassRegistry &); void initializeCodeGenPreparePass(PassRegistry&); +void initializeCountingFunctionInserterPass(PassRegistry&); void initializeConstantHoistingLegacyPassPass(PassRegistry&); void initializeConstantMergeLegacyPassPass(PassRegistry &); void initializeConstantPropagationPass(PassRegistry&); diff --git a/include/llvm/LinkAllPasses.h b/include/llvm/LinkAllPasses.h index 16c5f5c5c7c..4c55f8cfaa7 100644 --- a/include/llvm/LinkAllPasses.h +++ b/include/llvm/LinkAllPasses.h @@ -160,6 +160,7 @@ namespace { (void) llvm::createInstCountPass(); (void) llvm::createConstantHoistingPass(); (void) llvm::createCodeGenPreparePass(); + (void) llvm::createCountingFunctionInserterPass(); (void) llvm::createEarlyCSEPass(); (void) llvm::createGVNHoistPass(); (void) llvm::createMergedLoadStoreMotionPass(); diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt index f68bac98564..ed86e6e544a 100644 --- a/lib/CodeGen/CMakeLists.txt +++ b/lib/CodeGen/CMakeLists.txt @@ -10,6 +10,7 @@ add_llvm_library(LLVMCodeGen CallingConvLower.cpp CodeGen.cpp CodeGenPrepare.cpp + CountingFunctionInserter.cpp CriticalAntiDepBreaker.cpp DeadMachineInstructionElim.cpp DetectDeadLanes.cpp diff --git a/lib/CodeGen/CodeGen.cpp b/lib/CodeGen/CodeGen.cpp index 5cd43df05d6..59f52ba7954 100644 --- a/lib/CodeGen/CodeGen.cpp +++ b/lib/CodeGen/CodeGen.cpp @@ -23,6 +23,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) { initializeAtomicExpandPass(Registry); initializeBranchFolderPassPass(Registry); initializeCodeGenPreparePass(Registry); + initializeCountingFunctionInserterPass(Registry); initializeDeadMachineInstructionElimPass(Registry); initializeDetectDeadLanesPass(Registry); initializeDwarfEHPreparePass(Registry); diff --git a/lib/CodeGen/CountingFunctionInserter.cpp b/lib/CodeGen/CountingFunctionInserter.cpp new file mode 100644 index 00000000000..1e46a7a99e7 --- /dev/null +++ b/lib/CodeGen/CountingFunctionInserter.cpp @@ -0,0 +1,62 @@ +//===- 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(); + } + + bool runOnFunction(Function &F) override { + std::string CountingFunctionName = + F.getFnAttribute("counting-function").getValueAsString(); + if (CountingFunctionName.empty()) + return false; + + Type *VoidTy = Type::getVoidTy(F.getContext()); + Constant *CountingFn = + F.getParent()->getOrInsertFunction(CountingFunctionName, + VoidTy, nullptr); + CallInst::Create(CountingFn, "", &*F.begin()->getFirstInsertionPt()); + return true; + } + }; + + char CountingFunctionInserter::ID = 0; +} + +INITIALIZE_PASS(CountingFunctionInserter, "cfinserter", + "Inserts calls to mcount-like functions", false, false) + +//===----------------------------------------------------------------------===// +// +// CountingFunctionInserter - Give any unnamed non-void instructions "tmp" names. +// +FunctionPass *llvm::createCountingFunctionInserterPass() { + return new CountingFunctionInserter(); +} diff --git a/lib/CodeGen/TargetPassConfig.cpp b/lib/CodeGen/TargetPassConfig.cpp index 1244681592b..782a1d951b5 100644 --- a/lib/CodeGen/TargetPassConfig.cpp +++ b/lib/CodeGen/TargetPassConfig.cpp @@ -477,6 +477,9 @@ void TargetPassConfig::addIRPasses() { if (getOptLevel() != CodeGenOpt::None && !DisablePartialLibcallInlining) addPass(createPartiallyInlineLibCallsPass()); + + // Insert calls to mcount-like functions. + addPass(createCountingFunctionInserterPass()); } /// Turn exception handling constructs into something the code generators can diff --git a/test/CodeGen/PowerPC/mcount-insertion.ll b/test/CodeGen/PowerPC/mcount-insertion.ll new file mode 100644 index 00000000000..04e8571d6f4 --- /dev/null +++ b/test/CodeGen/PowerPC/mcount-insertion.ll @@ -0,0 +1,16 @@ +; RUN: llc < %s | FileCheck %s +target datalayout = "E-m:e-i64:64-n32:64" +target triple = "powerpc64-bgq-linux" + +define void @test1() #0 { +entry: + ret void + +; CHECK-LABEL: @test1 +; CHECK: bl mcount +; CHECK-NOT: mcount +; CHECK: blr +} + +attributes #0 = { "counting-function"="mcount" } + diff --git a/test/Transforms/CountingFunctionInserter/mcount.ll b/test/Transforms/CountingFunctionInserter/mcount.ll new file mode 100644 index 00000000000..88297c7d825 --- /dev/null +++ b/test/Transforms/CountingFunctionInserter/mcount.ll @@ -0,0 +1,27 @@ +; RUN: opt -S -cfinserter < %s | FileCheck %s +target datalayout = "E-m:e-i64:64-n32:64" +target triple = "powerpc64-bgq-linux" + +define void @test1() #0 { +entry: + ret void + +; CHECK-LABEL: define void @test1() +; CHECK: entry: +; CHECK-NEXT: call void @mcount() +; CHECK: ret void +} + +define void @test2() #1 { +entry: + ret void + +; CHECK-LABEL: define void @test2() +; CHECK: entry: +; CHECK-NEXT: call void @.mcount() +; CHECK: ret void +} + +attributes #0 = { "counting-function"="mcount" } +attributes #1 = { "counting-function"=".mcount" } + diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp index d3ef4154c51..865da497bc5 100644 --- a/tools/llc/llc.cpp +++ b/tools/llc/llc.cpp @@ -254,6 +254,7 @@ int main(int argc, char **argv) { initializeCodeGen(*Registry); initializeLoopStrengthReducePass(*Registry); initializeLowerIntrinsicsPass(*Registry); + initializeCountingFunctionInserterPass(*Registry); initializeUnreachableBlockElimLegacyPassPass(*Registry); // Register the target printer for --version. diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index 02976820c67..6564d0ae144 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -384,6 +384,7 @@ int main(int argc, char **argv) { initializePreISelIntrinsicLoweringLegacyPassPass(Registry); initializeGlobalMergePass(Registry); initializeInterleavedAccessPass(Registry); + initializeCountingFunctionInserterPass(Registry); initializeUnreachableBlockElimLegacyPassPass(Registry); #ifdef LINK_POLLY_INTO_TOOLS