diff options
| -rw-r--r-- | llvm/docs/LangRef.rst | 44 | ||||
| -rw-r--r-- | llvm/include/llvm/IR/IntrinsicInst.h | 27 | ||||
| -rw-r--r-- | llvm/include/llvm/IR/Intrinsics.td | 6 | ||||
| -rw-r--r-- | llvm/include/llvm/InitializePasses.h | 1 | ||||
| -rw-r--r-- | llvm/include/llvm/LinkAllPasses.h | 1 | ||||
| -rw-r--r-- | llvm/include/llvm/Transforms/Instrumentation.h | 12 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 2 | ||||
| -rw-r--r-- | llvm/lib/Transforms/Instrumentation/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp | 309 | ||||
| -rw-r--r-- | llvm/lib/Transforms/Instrumentation/Instrumentation.cpp | 1 | ||||
| -rw-r--r-- | llvm/test/Instrumentation/InstrProfiling/no-counters.ll | 10 | ||||
| -rw-r--r-- | llvm/test/Instrumentation/InstrProfiling/noruntime.ll | 16 | ||||
| -rw-r--r-- | llvm/test/Instrumentation/InstrProfiling/platform.ll | 29 | ||||
| -rw-r--r-- | llvm/test/Instrumentation/InstrProfiling/profiling.ll | 38 |
14 files changed, 497 insertions, 0 deletions
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 3412ed31015..181514962c9 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -7492,6 +7492,50 @@ time library. This instrinsic does *not* empty the instruction pipeline. Modifications of the current function are outside the scope of the intrinsic. +'``llvm.instrprof_increment``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +:: + + declare void @llvm.instrprof_increment(i8* <name>, i64 <hash>, + i32 <num-counters>, i32 <index>) + +Overview: +""""""""" + +The '``llvm.instrprof_increment``' intrinsic can be emitted by a +frontend for use with instrumentation based profiling. These will be +lowered by the ``-instrprof`` pass to generate execution counts of a +program at runtime. + +Arguments: +"""""""""" + +The first argument is a pointer to a global variable containing the +name of the entity being instrumented. This should generally be the +(mangled) function name for a set of counters. + +The second argument is a hash value that can be used by the consumer +of the profile data to detect changes to the instrumented source, and +the third is the number of counters associated with ``name``. It is an +error if ``hash`` or ``num-counters`` differ between two instances of +``instrprof_increment`` that refer to the same name. + +The last argument refers to which of the counters for ``name`` should +be incremented. It should be a value between 0 and ``num-counters``. + +Semantics: +"""""""""" + +This intrinsic represents an increment of a profiling counter. It will +cause the ``-instrprof`` pass to generate the appropriate data +structures and the code to increment the appropriate value, in a +format that can be written out by a compiler runtime and consumed via +the ``llvm-profdata`` tool. + Standard C Library Intrinsics ----------------------------- diff --git a/llvm/include/llvm/IR/IntrinsicInst.h b/llvm/include/llvm/IR/IntrinsicInst.h index e3d79998454..d4cb67af728 100644 --- a/llvm/include/llvm/IR/IntrinsicInst.h +++ b/llvm/include/llvm/IR/IntrinsicInst.h @@ -322,6 +322,33 @@ namespace llvm { Value *getSrc() const { return const_cast<Value*>(getArgOperand(1)); } }; + /// This represents the llvm.instrprof_increment intrinsic. + class InstrProfIncrementInst : public IntrinsicInst { + public: + static inline bool classof(const IntrinsicInst *I) { + return I->getIntrinsicID() == Intrinsic::instrprof_increment; + } + static inline bool classof(const Value *V) { + return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); + } + + GlobalVariable *getName() const { + return cast<GlobalVariable>( + const_cast<Value *>(getArgOperand(0))->stripPointerCasts()); + } + + ConstantInt *getHash() const { + return cast<ConstantInt>(const_cast<Value *>(getArgOperand(1))); + } + + ConstantInt *getNumCounters() const { + return cast<ConstantInt>(const_cast<Value *>(getArgOperand(2))); + } + + ConstantInt *getIndex() const { + return cast<ConstantInt>(const_cast<Value *>(getArgOperand(3))); + } + }; } #endif diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td index 08bdf3a2642..902f3b3187a 100644 --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -291,6 +291,12 @@ def int_stackprotector : Intrinsic<[], [llvm_ptr_ty, llvm_ptrptr_ty], []>; def int_stackprotectorcheck : Intrinsic<[], [llvm_ptrptr_ty], [IntrReadWriteArgMem]>; +// A counter increment for instrumentation based profiling. +def int_instrprof_increment : Intrinsic<[], + [llvm_ptr_ty, llvm_i64_ty, + llvm_i32_ty, llvm_i32_ty], + []>; + //===------------------- Standard C Library Intrinsics --------------------===// // diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h index edce794c286..2b99e1b2888 100644 --- a/llvm/include/llvm/InitializePasses.h +++ b/llvm/include/llvm/InitializePasses.h @@ -121,6 +121,7 @@ void initializeEarlyIfConverterPass(PassRegistry&); void initializeEdgeBundlesPass(PassRegistry&); void initializeExpandPostRAPass(PassRegistry&); void initializeGCOVProfilerPass(PassRegistry&); +void initializeInstrProfilingPass(PassRegistry&); void initializeAddressSanitizerPass(PassRegistry&); void initializeAddressSanitizerModulePass(PassRegistry&); void initializeMemorySanitizerPass(PassRegistry&); diff --git a/llvm/include/llvm/LinkAllPasses.h b/llvm/include/llvm/LinkAllPasses.h index 2c16c8ca4d9..fad38654b48 100644 --- a/llvm/include/llvm/LinkAllPasses.h +++ b/llvm/include/llvm/LinkAllPasses.h @@ -78,6 +78,7 @@ namespace { (void) llvm::createDomOnlyViewerPass(); (void) llvm::createDomViewerPass(); (void) llvm::createGCOVProfilerPass(); + (void) llvm::createInstrProfilingPass(); (void) llvm::createFunctionInliningPass(); (void) llvm::createAlwaysInlinerPass(); (void) llvm::createGlobalDCEPass(); diff --git a/llvm/include/llvm/Transforms/Instrumentation.h b/llvm/include/llvm/Transforms/Instrumentation.h index 4737cb3b0be..24e3ef783ee 100644 --- a/llvm/include/llvm/Transforms/Instrumentation.h +++ b/llvm/include/llvm/Transforms/Instrumentation.h @@ -63,6 +63,18 @@ struct GCOVOptions { ModulePass *createGCOVProfilerPass(const GCOVOptions &Options = GCOVOptions::getDefault()); +/// Options for the frontend instrumentation based profiling pass. +struct InstrProfOptions { + InstrProfOptions() : NoRedZone(false) {} + + // Add the 'noredzone' attribute to added runtime library calls. + bool NoRedZone; +}; + +/// Insert frontend instrumentation based profiling. +ModulePass *createInstrProfilingPass( + const InstrProfOptions &Options = InstrProfOptions()); + // Insert AddressSanitizer (address sanity checking) instrumentation FunctionPass *createAddressSanitizerFunctionPass(); ModulePass *createAddressSanitizerModulePass(); diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index a5fdfc55487..cab3cbf8ab5 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -5570,6 +5570,8 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { visitGCRelocate(I); return nullptr; } + case Intrinsic::instrprof_increment: + llvm_unreachable("instrprof failed to lower an increment"); } } diff --git a/llvm/lib/Transforms/Instrumentation/CMakeLists.txt b/llvm/lib/Transforms/Instrumentation/CMakeLists.txt index a6a3106041f..92e1091aa3b 100644 --- a/llvm/lib/Transforms/Instrumentation/CMakeLists.txt +++ b/llvm/lib/Transforms/Instrumentation/CMakeLists.txt @@ -5,6 +5,7 @@ add_llvm_library(LLVMInstrumentation GCOVProfiling.cpp MemorySanitizer.cpp Instrumentation.cpp + InstrProfiling.cpp SanitizerCoverage.cpp ThreadSanitizer.cpp ) diff --git a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp new file mode 100644 index 00000000000..5f73b89e855 --- /dev/null +++ b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp @@ -0,0 +1,309 @@ +//===-- InstrProfiling.cpp - Frontend instrumentation based profiling -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass lowers instrprof_increment intrinsics emitted by a frontend for +// profiling. It also builds the data structures and initialization code needed +// for updating execution counts and emitting the profile at runtime. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Instrumentation.h" + +#include "llvm/ADT/Triple.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Module.h" +#include "llvm/Transforms/Utils/ModuleUtils.h" + +using namespace llvm; + +#define DEBUG_TYPE "instrprof" + +namespace { + +class InstrProfiling : public ModulePass { +public: + static char ID; + + InstrProfiling() : ModulePass(ID) {} + + InstrProfiling(const InstrProfOptions &Options) + : ModulePass(ID), Options(Options) {} + + const char *getPassName() const override { + return "Frontend instrumentation-based coverage lowering"; + } + + bool runOnModule(Module &M) override; + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesCFG(); + } + +private: + InstrProfOptions Options; + Module *M; + DenseMap<GlobalVariable *, GlobalVariable *> RegionCounters; + std::vector<Value *> UsedVars; + + bool isMachO() const { + return Triple(M->getTargetTriple()).isOSBinFormatMachO(); + } + + /// Get the section name for the counter variables. + StringRef getCountersSection() const { + return isMachO() ? "__DATA,__llvm_prf_cnts" : "__llvm_prf_cnts"; + } + + /// Get the section name for the name variables. + StringRef getNameSection() const { + return isMachO() ? "__DATA,__llvm_prf_names" : "__llvm_prf_names"; + } + + /// Get the section name for the profile data variables. + StringRef getDataSection() const { + return isMachO() ? "__DATA,__llvm_prf_data" : "__llvm_prf_data"; + } + + /// Replace instrprof_increment with an increment of the appropriate value. + void lowerIncrement(InstrProfIncrementInst *Inc); + + /// Get the region counters for an increment, creating them if necessary. + /// + /// If the counter array doesn't yet exist, the profile data variables + /// referring to them will also be created. + GlobalVariable *getOrCreateRegionCounters(InstrProfIncrementInst *Inc); + + /// Emit runtime registration functions for each profile data variable. + void emitRegistration(); + + /// Emit the necessary plumbing to pull in the runtime initialization. + void emitRuntimeHook(); + + /// Add uses of our data variables and runtime hook. + void emitUses(); + + /// Create a static initializer for our data, on platforms that need it. + void emitInitialization(); +}; + +} // anonymous namespace + +char InstrProfiling::ID = 0; +INITIALIZE_PASS(InstrProfiling, "instrprof", + "Frontend instrumentation-based coverage lowering.", false, + false) + +ModulePass *llvm::createInstrProfilingPass(const InstrProfOptions &Options) { + return new InstrProfiling(Options); +} + +bool InstrProfiling::runOnModule(Module &M) { + bool MadeChange = false; + + this->M = &M; + RegionCounters.clear(); + UsedVars.clear(); + + for (Function &F : M) + for (BasicBlock &BB : F) + for (auto I = BB.begin(), E = BB.end(); I != E;) + if (auto *Inc = dyn_cast<InstrProfIncrementInst>(I++)) { + lowerIncrement(Inc); + MadeChange = true; + } + if (!MadeChange) + return false; + + emitRegistration(); + emitRuntimeHook(); + emitUses(); + emitInitialization(); + return true; +} + +void InstrProfiling::lowerIncrement(InstrProfIncrementInst *Inc) { + GlobalVariable *Counters = getOrCreateRegionCounters(Inc); + + IRBuilder<> Builder(Inc->getParent(), *Inc); + uint64_t Index = Inc->getIndex()->getZExtValue(); + llvm::Value *Addr = Builder.CreateConstInBoundsGEP2_64(Counters, 0, Index); + llvm::Value *Count = Builder.CreateLoad(Addr, "pgocount"); + Count = Builder.CreateAdd(Count, Builder.getInt64(1)); + Inc->replaceAllUsesWith(Builder.CreateStore(Count, Addr)); + Inc->eraseFromParent(); +} + +/// Get the name of a profiling variable for a particular function. +static std::string getVarName(InstrProfIncrementInst *Inc, StringRef VarName) { + auto *Arr = cast<ConstantDataArray>(Inc->getName()->getInitializer()); + StringRef Name = Arr->isCString() ? Arr->getAsCString() : Arr->getAsString(); + return ("__llvm_profile_" + VarName + "_" + Name).str(); +} + +GlobalVariable * +InstrProfiling::getOrCreateRegionCounters(InstrProfIncrementInst *Inc) { + GlobalVariable *Name = Inc->getName(); + auto It = RegionCounters.find(Name); + if (It != RegionCounters.end()) + return It->second; + + // Move the name variable to the right section. + Name->setSection(getNameSection()); + Name->setAlignment(1); + + uint64_t NumCounters = Inc->getNumCounters()->getZExtValue(); + LLVMContext &Ctx = M->getContext(); + ArrayType *CounterTy = ArrayType::get(Type::getInt64Ty(Ctx), NumCounters); + + // Create the counters variable. + auto *Counters = new GlobalVariable(*M, CounterTy, false, Name->getLinkage(), + Constant::getNullValue(CounterTy), + getVarName(Inc, "counters")); + Counters->setVisibility(Name->getVisibility()); + Counters->setSection(getCountersSection()); + Counters->setAlignment(8); + + RegionCounters[Inc->getName()] = Counters; + + // Create data variable. + auto *NameArrayTy = Name->getType()->getPointerElementType(); + auto *Int32Ty = Type::getInt32Ty(Ctx); + auto *Int64Ty = Type::getInt64Ty(Ctx); + auto *Int8PtrTy = Type::getInt8PtrTy(Ctx); + auto *Int64PtrTy = Type::getInt64PtrTy(Ctx); + + Type *DataTypes[] = {Int32Ty, Int32Ty, Int64Ty, Int8PtrTy, Int64PtrTy}; + auto *DataTy = StructType::get(Ctx, makeArrayRef(DataTypes)); + Constant *DataVals[] = { + ConstantInt::get(Int32Ty, NameArrayTy->getArrayNumElements()), + ConstantInt::get(Int32Ty, NumCounters), + ConstantInt::get(Int64Ty, Inc->getHash()->getZExtValue()), + ConstantExpr::getBitCast(Name, Int8PtrTy), + ConstantExpr::getBitCast(Counters, Int64PtrTy)}; + auto *Data = new GlobalVariable(*M, DataTy, true, Name->getLinkage(), + ConstantStruct::get(DataTy, DataVals), + getVarName(Inc, "data")); + Data->setVisibility(Name->getVisibility()); + Data->setSection(getDataSection()); + Data->setAlignment(8); + + // Mark the data variable as used so that it isn't stripped out. + UsedVars.push_back(Data); + + return Counters; +} + +void InstrProfiling::emitRegistration() { + // Don't do this for Darwin. compiler-rt uses linker magic. + if (Triple(M->getTargetTriple()).isOSDarwin()) + return; + + // Construct the function. + auto *VoidTy = Type::getVoidTy(M->getContext()); + auto *VoidPtrTy = Type::getInt8PtrTy(M->getContext()); + auto *RegisterFTy = FunctionType::get(VoidTy, false); + auto *RegisterF = Function::Create(RegisterFTy, GlobalValue::InternalLinkage, + "__llvm_profile_register_functions", M); + RegisterF->setUnnamedAddr(true); + if (Options.NoRedZone) + RegisterF->addFnAttr(Attribute::NoRedZone); + + auto *RuntimeRegisterTy = llvm::FunctionType::get(VoidTy, VoidPtrTy, false); + auto *RuntimeRegisterF = + Function::Create(RuntimeRegisterTy, GlobalVariable::ExternalLinkage, + "__llvm_profile_register_function", M); + + IRBuilder<> IRB(BasicBlock::Create(M->getContext(), "", RegisterF)); + for (Value *Data : UsedVars) + IRB.CreateCall(RuntimeRegisterF, IRB.CreateBitCast(Data, VoidPtrTy)); + IRB.CreateRetVoid(); +} + +void InstrProfiling::emitRuntimeHook() { + const char *const RuntimeVarName = "__llvm_profile_runtime"; + const char *const RuntimeUserName = "__llvm_profile_runtime_user"; + + // If the module's provided its own runtime, we don't need to do anything. + if (M->getGlobalVariable(RuntimeVarName)) + return; + + // Declare an external variable that will pull in the runtime initialization. + auto *Int32Ty = Type::getInt32Ty(M->getContext()); + auto *Var = + new GlobalVariable(*M, Int32Ty, false, GlobalValue::ExternalLinkage, + nullptr, RuntimeVarName); + + // Make a function that uses it. + auto *User = + Function::Create(FunctionType::get(Int32Ty, false), + GlobalValue::LinkOnceODRLinkage, RuntimeUserName, M); + User->addFnAttr(Attribute::NoInline); + if (Options.NoRedZone) + User->addFnAttr(Attribute::NoRedZone); + + IRBuilder<> IRB(BasicBlock::Create(M->getContext(), "", User)); + auto *Load = IRB.CreateLoad(Var); + IRB.CreateRet(Load); + + // Mark the user variable as used so that it isn't stripped out. + UsedVars.push_back(User); +} + +void InstrProfiling::emitUses() { + if (UsedVars.empty()) + return; + + GlobalVariable *LLVMUsed = M->getGlobalVariable("llvm.used"); + std::vector<Constant*> MergedVars; + if (LLVMUsed) { + // Collect the existing members of llvm.used. + ConstantArray *Inits = cast<ConstantArray>(LLVMUsed->getInitializer()); + for (unsigned I = 0, E = Inits->getNumOperands(); I != E; ++I) + MergedVars.push_back(Inits->getOperand(I)); + LLVMUsed->eraseFromParent(); + } + + Type *i8PTy = Type::getInt8PtrTy(M->getContext()); + // Add uses for our data. + for (auto *Value : UsedVars) + MergedVars.push_back( + ConstantExpr::getBitCast(cast<llvm::Constant>(Value), i8PTy)); + + // Recreate llvm.used. + ArrayType *ATy = ArrayType::get(i8PTy, MergedVars.size()); + LLVMUsed = new llvm::GlobalVariable( + *M, ATy, false, llvm::GlobalValue::AppendingLinkage, + llvm::ConstantArray::get(ATy, MergedVars), "llvm.used"); + + LLVMUsed->setSection("llvm.metadata"); +} + +void InstrProfiling::emitInitialization() { + Constant *RegisterF = M->getFunction("__llvm_profile_register_functions"); + if (!RegisterF) + return; + + // Create the initialization function. + auto *VoidTy = Type::getVoidTy(M->getContext()); + auto *F = + Function::Create(FunctionType::get(VoidTy, false), + GlobalValue::InternalLinkage, "__llvm_profile_init", M); + F->setUnnamedAddr(true); + F->addFnAttr(Attribute::NoInline); + if (Options.NoRedZone) + F->addFnAttr(Attribute::NoRedZone); + + // Add the basic block and the necessary calls. + IRBuilder<> IRB(BasicBlock::Create(M->getContext(), "", F)); + IRB.CreateCall(RegisterF); + IRB.CreateRetVoid(); + + appendToGlobalCtors(*M, F, 0); +} diff --git a/llvm/lib/Transforms/Instrumentation/Instrumentation.cpp b/llvm/lib/Transforms/Instrumentation/Instrumentation.cpp index 8e953671572..a91fc0ec2a4 100644 --- a/llvm/lib/Transforms/Instrumentation/Instrumentation.cpp +++ b/llvm/lib/Transforms/Instrumentation/Instrumentation.cpp @@ -25,6 +25,7 @@ void llvm::initializeInstrumentation(PassRegistry &Registry) { initializeAddressSanitizerModulePass(Registry); initializeBoundsCheckingPass(Registry); initializeGCOVProfilerPass(Registry); + initializeInstrProfilingPass(Registry); initializeMemorySanitizerPass(Registry); initializeThreadSanitizerPass(Registry); initializeSanitizerCoverageModulePass(Registry); diff --git a/llvm/test/Instrumentation/InstrProfiling/no-counters.ll b/llvm/test/Instrumentation/InstrProfiling/no-counters.ll new file mode 100644 index 00000000000..0716b0d8c6f --- /dev/null +++ b/llvm/test/Instrumentation/InstrProfiling/no-counters.ll @@ -0,0 +1,10 @@ +;; No instrumentation should be emitted if there are no counter increments. + +; RUN: opt < %s -instrprof -S | FileCheck %s +; CHECK-NOT: @__llvm_profile_counters +; CHECK-NOT: @__llvm_profile_data +; CHECK-NOT: @__llvm_profile_runtime + +define void @foo() { + ret void +} diff --git a/llvm/test/Instrumentation/InstrProfiling/noruntime.ll b/llvm/test/Instrumentation/InstrProfiling/noruntime.ll new file mode 100644 index 00000000000..e69445dc350 --- /dev/null +++ b/llvm/test/Instrumentation/InstrProfiling/noruntime.ll @@ -0,0 +1,16 @@ +;; Check that we don't emit the runtime hooks if the user provided them. + +; RUN: opt < %s -instrprof -S | FileCheck %s +; CHECK-NOT: define {{.*}} @__llvm_profile_runtime_user() +; CHECK-NOT: load i32* @__llvm_profile_runtime + +@__llvm_profile_runtime = global i32 0, align 4 + +@__llvm_profile_name_foo = hidden constant [3 x i8] c"foo" + +define void @foo() { + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8]* @__llvm_profile_name_foo, i32 0, i32 0), i64 0, i32 1, i32 0) + ret void +} + +declare void @llvm.instrprof.increment(i8*, i64, i32, i32) diff --git a/llvm/test/Instrumentation/InstrProfiling/platform.ll b/llvm/test/Instrumentation/InstrProfiling/platform.ll new file mode 100644 index 00000000000..e0327683b7f --- /dev/null +++ b/llvm/test/Instrumentation/InstrProfiling/platform.ll @@ -0,0 +1,29 @@ +;; Checks for platform specific section names and initialization code. + +; RUN: opt < %s -mtriple=x86_64-apple-macosx10.10.0 -instrprof -S | FileCheck %s -check-prefix=MACHO +; RUN: opt < %s -mtriple=x86_64-unknown-linux -instrprof -S | FileCheck %s -check-prefix=ELF + +@__llvm_profile_name_foo = hidden constant [3 x i8] c"foo" +; MACHO: @__llvm_profile_name_foo = hidden constant [3 x i8] c"foo", section "__DATA,__llvm_prf_names", align 1 +; ELF: @__llvm_profile_name_foo = hidden constant [3 x i8] c"foo", section "__llvm_prf_names", align 1 + +; MACHO: @__llvm_profile_counters_foo = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 +; ELF: @__llvm_profile_counters_foo = hidden global [1 x i64] zeroinitializer, section "__llvm_prf_cnts", align 8 + +; MACHO: @__llvm_profile_data_foo = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8 +; ELF: @__llvm_profile_data_foo = hidden constant {{.*}}, section "__llvm_prf_data", align 8 +define void @foo() { + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8]* @__llvm_profile_name_foo, i32 0, i32 0), i64 0, i32 1, i32 0) + ret void +} + +declare void @llvm.instrprof.increment(i8*, i64, i32, i32) + +;; Emit registration functions for platforms that don't find the +;; symbols by their sections. + +; MACHO-NOT: define internal void @__llvm_profile_register_functions +; ELF: define internal void @__llvm_profile_register_functions + +; MACHO-NOT: define internal void @__llvm_profile_init +; ELF: define internal void @__llvm_profile_init diff --git a/llvm/test/Instrumentation/InstrProfiling/profiling.ll b/llvm/test/Instrumentation/InstrProfiling/profiling.ll new file mode 100644 index 00000000000..246bf6b43f9 --- /dev/null +++ b/llvm/test/Instrumentation/InstrProfiling/profiling.ll @@ -0,0 +1,38 @@ +; RUN: opt < %s -instrprof -S | FileCheck %s + +target triple = "x86_64-apple-macosx10.10.0" + +@__llvm_profile_name_foo = hidden constant [3 x i8] c"foo" +; CHECK: @__llvm_profile_name_foo = hidden constant [3 x i8] c"foo", section "__DATA,__llvm_prf_names", align 1 +@__llvm_profile_name_bar = hidden constant [4 x i8] c"bar\00" +; CHECK: @__llvm_profile_name_bar = hidden constant [4 x i8] c"bar\00", section "__DATA,__llvm_prf_names", align 1 +@baz_prof_name = hidden constant [3 x i8] c"baz" +; CHECK: @baz_prof_name = hidden constant [3 x i8] c"baz", section "__DATA,__llvm_prf_names", align 1 + +; CHECK: @__llvm_profile_counters_foo = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 +; CHECK: @__llvm_profile_data_foo = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8 +define void @foo() { + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8]* @__llvm_profile_name_foo, i32 0, i32 0), i64 0, i32 1, i32 0) + ret void +} + +; CHECK: @__llvm_profile_counters_bar = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 +; CHECK: @__llvm_profile_data_bar = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8 +define void @bar() { + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([4 x i8]* @__llvm_profile_name_bar, i32 0, i32 0), i64 0, i32 1, i32 0) + ret void +} + +; CHECK: @__llvm_profile_counters_baz = hidden global [3 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 +; CHECK: @__llvm_profile_data_baz = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8 +define void @baz() { + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8]* @baz_prof_name, i32 0, i32 0), i64 0, i32 3, i32 0) + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8]* @baz_prof_name, i32 0, i32 0), i64 0, i32 3, i32 1) + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8]* @baz_prof_name, i32 0, i32 0), i64 0, i32 3, i32 2) + ret void +} + +declare void @llvm.instrprof.increment(i8*, i64, i32, i32) + +; CHECK: @__llvm_profile_runtime = external global i32 +; CHECK: @llvm.used = appending global {{.*}} @__llvm_profile_data_foo {{.*}} @__llvm_profile_data_bar {{.*}} @__llvm_profile_data_baz {{.*}} section "llvm.metadata" |

