[PATCH] An intrinsic and lowering for instrumentation based profiling
Duncan P. N. Exon Smith
dexonsmith at apple.com
Fri Dec 5 10:10:12 PST 2014
> On 2014-Dec-04, at 15:50, Justin Bogner <mail at justinbogner.com> wrote:
>
> This introduces the ``llvm.instrprof_increment`` intrinsic and the
> ``-instrprof`` pass. These provide the infrastructure for writing
> counters for profiling, as in clang's ``-fprofile-instr-generate``.
>
> The implementation of the instrprof pass is ported directly out of the
> CodeGenPGO classes in clang, and with the followup in clang that rips
> that code out to use these new intrinsics this ends up being NFC.
>
> Doing the instrumentation this way opens some doors in terms of
> improving the counter performance. For example, this will make it
> simple to experiment with alternate lowering strategies, and allows us
> to try handling profiling specially in some optimizations if we want
> to.
>
> Finally, this drastically simplifies the frontend and puts all of the
> lowering logic in one place.
>
> <instrprof-intrinsic.patch>
> diff --git a/docs/LangRef.rst b/docs/LangRef.rst
> index 3412ed3..68e4d65 100644
> --- a/docs/LangRef.rst
> +++ b/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>, i32 <num-counters>,
> + i64 <hash>, i64 <counter-index>)
The types seem off: you have an `i32` for the number of counters but an
`i64` for the index into them. I think `i32` makes sense for both.
Bike-shed: I think it'd be clearer to reorder the arguments so the
counter index and number of counters are adjacent. I'd prefer either of:
(i8* <name>, i64 <hash>, i32 <counter-index>, i32 <num-counters>)
(i8* <name>, i64 <hash>, i32 <num-counters>, i32 <counter-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 and third arguments are the number of counters in this set
> +and a hash value that can be used by the consumer of the profile data
> +to detect changes to the instrumented source. It is an error if
> +``num-counters`` or ``hash`` 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/include/llvm/IR/IntrinsicInst.h b/include/llvm/IR/IntrinsicInst.h
> index e3d7999..dbdc210 100644
> --- a/include/llvm/IR/IntrinsicInst.h
> +++ b/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 *getNumCounters() const {
> + return cast<ConstantInt>(const_cast<Value *>(getArgOperand(1)));
> + }
> +
> + ConstantInt *getHash() const {
> + return cast<ConstantInt>(const_cast<Value *>(getArgOperand(2)));
> + }
> +
> + ConstantInt *getIndex() const {
> + return cast<ConstantInt>(const_cast<Value *>(getArgOperand(3)));
> + }
> + };
> }
>
> #endif
> diff --git a/include/llvm/IR/Intrinsics.td b/include/llvm/IR/Intrinsics.td
> index 5457e95..9d59be1 100644
> --- a/include/llvm/IR/Intrinsics.td
> +++ b/include/llvm/IR/Intrinsics.td
> @@ -287,6 +287,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_i32_ty,
> + llvm_i64_ty, llvm_i64_ty],
> + []>;
> +
> //===------------------- Standard C Library Intrinsics --------------------===//
> //
>
> diff --git a/include/llvm/InitializePasses.h b/include/llvm/InitializePasses.h
> index edce794..2b99e1b 100644
> --- a/include/llvm/InitializePasses.h
> +++ b/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/include/llvm/LinkAllPasses.h b/include/llvm/LinkAllPasses.h
> index 2c16c8c..fad3865 100644
> --- a/include/llvm/LinkAllPasses.h
> +++ b/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/include/llvm/Transforms/Instrumentation.h b/include/llvm/Transforms/Instrumentation.h
> index 4737cb3..24e3ef7 100644
> --- a/include/llvm/Transforms/Instrumentation.h
> +++ b/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/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
> index eeecbf1..35473d2 100644
> --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
> +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
> @@ -5477,6 +5477,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/lib/Transforms/Instrumentation/CMakeLists.txt b/lib/Transforms/Instrumentation/CMakeLists.txt
> index a6a3106..92e1091 100644
> --- a/lib/Transforms/Instrumentation/CMakeLists.txt
> +++ b/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/lib/Transforms/Instrumentation/InstrProfiling.cpp b/lib/Transforms/Instrumentation/InstrProfiling.cpp
> new file mode 100644
> index 0000000..6c9cc26
> --- /dev/null
> +++ b/lib/Transforms/Instrumentation/InstrProfiling.cpp
> @@ -0,0 +1,313 @@
> +//===-- 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.
> + bool emitRegistration();
> +
> + /// Emit the necessary plumbing to pull in the runtime initialization.
> + bool emitRuntimeHook();
> +
> + /// Add uses of our data variables and runtime hook.
> + bool emitUses();
> +
> + /// Create a static initializer for our data, on platforms that need it.
> + bool 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;
> + }
> + MadeChange |= emitRegistration();
> + MadeChange |= emitRuntimeHook();
> + MadeChange |= emitUses();
> + MadeChange |= emitInitialization();
> + return MadeChange;
Why isn't this the following?
if (!MadeChange)
return false;
emitRegistration();
emitRuntimeHook();
emitUses();
emitInitialization();
return true;
In particular, should the pass emit anything if there are no counters?
Why?
Can you add a test for when the pass gets run but there aren't any
counters? (What you're testing for depends on the above...)
> +}
> +
> +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;
> +}
> +
> +bool InstrProfiling::emitRegistration() {
> + // Don't do this for Darwin. compiler-rt uses linker magic.
> + if (Triple(M->getTargetTriple()).isOSDarwin())
> + return false;
> + if (UsedVars.empty())
> + return false;
> +
> + // 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();
> + return true;
> +}
> +
> +bool 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 false;
> +
> + // 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);
> +
> + return true;
> +}
> +
> +bool InstrProfiling::emitUses() {
> + if (UsedVars.empty())
> + return false;
> +
> + 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");
It feels kind of awkward to delete and recreate `@llvm.used`, I'd rather
just reset its initializer. But since you need to collect its current
members anyway, maybe that's just as awkward...
> + return true;
> +}
> +
> +bool InstrProfiling::emitInitialization() {
> + Constant *RegisterF = M->getFunction("__llvm_profile_register_functions");
> + if (!RegisterF)
> + return false;
> +
> + // 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);
> + return true;
> +}
> diff --git a/lib/Transforms/Instrumentation/Instrumentation.cpp b/lib/Transforms/Instrumentation/Instrumentation.cpp
> index 8e95367..a91fc0e 100644
> --- a/lib/Transforms/Instrumentation/Instrumentation.cpp
> +++ b/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/test/Instrumentation/InstrProfiling/noruntime.ll b/test/Instrumentation/InstrProfiling/noruntime.ll
> new file mode 100644
> index 0000000..c812495
> --- /dev/null
> +++ b/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
> +
> + at __llvm_profile_runtime = global i32 0, align 4
> +
> + at __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), i32 1, i64 0, i64 0)
> + ret void
> +}
> +
> +declare void @llvm.instrprof.increment(i8*, i32, i64, i64)
> diff --git a/test/Instrumentation/InstrProfiling/platform.ll b/test/Instrumentation/InstrProfiling/platform.ll
> new file mode 100644
> index 0000000..86dec0b
> --- /dev/null
> +++ b/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
> +
> + at __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), i32 1, i64 0, i64 0)
> + ret void
> +}
> +
> +declare void @llvm.instrprof.increment(i8*, i32, i64, i64)
> +
> +;; 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/test/Instrumentation/InstrProfiling/profiling.ll b/test/Instrumentation/InstrProfiling/profiling.ll
> new file mode 100644
> index 0000000..7a12858
> --- /dev/null
> +++ b/test/Instrumentation/InstrProfiling/profiling.ll
> @@ -0,0 +1,37 @@
> +; RUN: opt < %s -instrprof -S | FileCheck %s
> +
> +target triple = "x86_64-apple-macosx10.10.0"
> +
> + at __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
> + at __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
> + at 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), i32 1, i64 0, i64 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), i32 1, i64 0, i64 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), i32 3, i64 0, i64 0)
> + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8]* @baz_prof_name, i32 0, i32 0), i32 3, i64 0, i64 1)
> + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8]* @baz_prof_name, i32 0, i32 0), i32 3, i64 0, i64 2)
> + ret void
> +}
> +
> +declare void @llvm.instrprof.increment(i8*, i32, i64, i64)
> +
> +; CHECK: @llvm.used = appending global {{.*}} @__llvm_profile_data_foo {{.*}} @__llvm_profile_data_bar {{.*}} @__llvm_profile_data_baz {{.*}} section "llvm.metadata"
>
More information about the llvm-commits
mailing list