31#define DEBUG_TYPE "ctx-instr-lower"
36 "A function name, assumed to be global, which will be treated as the "
37 "root of an interesting graph, which will be profiled independently "
38 "from other similar graphs."));
47static auto StartCtx =
"__llvm_ctx_profile_start_context";
48static auto ReleaseCtx =
"__llvm_ctx_profile_release_context";
49static auto GetCtx =
"__llvm_ctx_profile_get_context";
56class CtxInstrumentationLowerer final {
59 Type *ContextNodeTy =
nullptr;
68 Constant *CannotBeRootInitializer =
nullptr;
80std::pair<uint32_t, uint32_t> getNumCountersAndCallsites(
const Function &
F) {
81 uint32_t NumCounters = 0;
82 uint32_t NumCallsites = 0;
83 for (
const auto &BB :
F) {
84 for (
const auto &
I : BB) {
87 static_cast<uint32_t
>(Incr->getNumCounters()->getZExtValue());
88 assert((!NumCounters || V == NumCounters) &&
89 "expected all llvm.instrprof.increment[.step] intrinsics to "
90 "have the same total nr of counters parameter");
94 static_cast<uint32_t
>(CSIntr->getNumCounters()->getZExtValue());
95 assert((!NumCallsites || V == NumCallsites) &&
96 "expected all llvm.instrprof.callsite intrinsics to have the "
97 "same total nr of callsites parameter");
101 if (NumCounters && NumCallsites)
102 return std::make_pair(NumCounters, NumCallsites);
106 return {NumCounters, NumCallsites};
110 F.getContext().emitError(
"[ctxprof] The function " +
F.getName() +
111 " was indicated as context root but " + Reason +
112 ", which is not supported.");
119CtxInstrumentationLowerer::CtxInstrumentationLowerer(
Module &M,
122 auto *
PointerTy = PointerType::get(
M.getContext(), 0);
123 auto *SanitizerMutexType = Type::getInt8Ty(
M.getContext());
124 auto *I32Ty = Type::getInt32Ty(
M.getContext());
125 auto *I64Ty = Type::getInt64Ty(
M.getContext());
127#define _PTRDECL(_, __) PointerTy,
128#define _VOLATILE_PTRDECL(_, __) PointerTy,
129#define _CONTEXT_ROOT PointerTy,
130#define _MUTEXDECL(_) SanitizerMutexType,
133 M.getContext(), {CTXPROF_FUNCTION_DATA(_PTRDECL, _CONTEXT_ROOT,
134 _VOLATILE_PTRDECL, _MUTEXDECL)});
137#undef _VOLATILE_PTRDECL
140#define _PTRDECL(_, __) Constant::getNullValue(PointerTy),
141#define _VOLATILE_PTRDECL(_, __) _PTRDECL(_, __)
142#define _MUTEXDECL(_) Constant::getNullValue(SanitizerMutexType),
143#define _CONTEXT_ROOT \
144 Constant::getIntegerValue( \
146 APInt(M.getDataLayout().getPointerTypeSizeInBits(PointerTy), 1U)),
152#undef _VOLATILE_PTRDECL
166 if (
const auto *
F =
M.getFunction(Fname)) {
167 if (
F->isDeclaration())
169 ContextRootSet.insert(
F);
170 for (
const auto &BB : *
F)
171 for (
const auto &
I : BB)
173 if (CB->isMustTailCall())
174 emitUnsupportedRootError(*
F,
"it features musttail calls");
180 M.getOrInsertFunction(
200 FunctionType::get(Type::getVoidTy(
M.getContext()),
211 CallsiteInfoTLS->setThreadLocal(
true);
222 CtxInstrumentationLowerer Lowerer(M,
MAM);
225 Changed |= Lowerer.lowerFunction(
F);
229bool CtxInstrumentationLowerer::lowerFunction(
Function &
F) {
230 if (
F.isDeclaration())
240 if (ContextRootSet.contains(&
F))
241 emitUnsupportedRootError(
F,
"it does not return");
249 auto [NumCounters, NumCallsites] = getNumCountersAndCallsites(
F);
251 Value *Context =
nullptr;
252 Value *RealContext =
nullptr;
255 Value *TheRootFunctionData =
nullptr;
256 Value *ExpectedCalleeTLSAddr =
nullptr;
257 Value *CallsiteInfoTLSAddr =
nullptr;
258 const bool HasMusttail = [&
F]() {
262 if (CB->isMustTailCall())
267 if (HasMusttail && ContextRootSet.contains(&
F)) {
268 F.getContext().emitError(
269 "[ctx_prof] A function with musttail calls was explicitly requested as "
270 "root. That is not supported because we cannot instrument a return "
271 "instruction to release the context: " +
275 auto &Head =
F.getEntryBlock();
276 for (
auto &
I : Head) {
279 assert(Mark->getIndex()->isZero());
288 {ContextNodeTy, ArrayType::get(Builder.getInt64Ty(), NumCounters),
289 ArrayType::get(Builder.getPtrTy(), NumCallsites)});
302 HasMusttail ? CannotBeRootInitializer
305 if (ContextRootSet.contains(&
F)) {
307 StartCtx, {TheRootFunctionData,
Guid, Builder.getInt32(NumCounters),
308 Builder.getInt32(NumCallsites)});
312 Context = Builder.CreateCall(GetCtx, {TheRootFunctionData, &
F,
Guid,
313 Builder.getInt32(NumCounters),
314 Builder.getInt32(NumCallsites)});
320 auto *CtxAsInt = Builder.CreatePtrToInt(
Context, Builder.getInt64Ty());
321 if (NumCallsites > 0) {
324 auto *
Index = Builder.CreateAnd(CtxAsInt, Builder.getInt64(1));
326 ExpectedCalleeTLSAddr = Builder.CreateGEP(
328 Builder.CreateThreadLocalAddress(ExpectedCalleeTLS), {Index});
329 CallsiteInfoTLSAddr = Builder.CreateGEP(
330 Builder.getInt32Ty(),
331 Builder.CreateThreadLocalAddress(CallsiteInfoTLS), {Index});
338 RealContext = Builder.CreateIntToPtr(
339 Builder.CreateAnd(CtxAsInt, Builder.getInt64(-2)),
348 <<
"Function doesn't have instrumentation, skipping";
353 bool ContextWasReleased =
false;
358 switch (
Instr->getIntrinsicID()) {
359 case llvm::Intrinsic::instrprof_increment:
360 case llvm::Intrinsic::instrprof_increment_step: {
364 auto *
GEP = Builder.CreateGEP(
365 ThisContextType, RealContext,
366 {Builder.getInt32(0), Builder.getInt32(1), AsStep->getIndex()});
368 Builder.CreateAdd(Builder.CreateLoad(Builder.getInt64Ty(),
GEP),
372 case llvm::Intrinsic::instrprof_callsite:
377 Builder.CreateStore(CSIntrinsic->getCallee(), ExpectedCalleeTLSAddr,
389 Builder.CreateGEP(ThisContextType,
Context,
390 {Builder.getInt32(0), Builder.getInt32(2),
391 CSIntrinsic->getIndex()}),
392 CallsiteInfoTLSAddr,
true);
399 Builder.CreateCall(ReleaseCtx, {TheRootFunctionData});
400 ContextWasReleased =
true;
404 if (!HasMusttail && !ContextWasReleased)
406 "[ctx_prof] A function that doesn't have musttail calls was "
407 "instrumented but it has no `ret` "
408 "instructions above which to release the context: " +
417 if (
F.isDeclaration())
419 if (
F.hasFnAttribute(Attribute::NoInline))
421 if (!
F.isWeakForLinker())
424 if (
F.hasFnAttribute(Attribute::AlwaysInline))
425 F.removeFnAttr(Attribute::AlwaysInline);
427 F.addFnAttr(Attribute::NoInline);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
#define CTXPROF_FUNCTION_DATA(PTRDECL, CONTEXT_PTR, VOLATILE_PTRDECL, MUTEXDECL)
The internal structure of FunctionData.
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
#define _VOLATILE_PTRDECL(_, __)
static cl::list< std::string > ContextRoots("profile-context-root", cl::Hidden, cl::desc("A function name, assumed to be global, which will be treated as the " "root of an interesting graph, which will be profiled independently " "from other similar graphs."))
FunctionAnalysisManager FAM
ModuleAnalysisManager MAM
static LLVM_ABI Constant * get(StructType *T, ArrayRef< Constant * > V)
This is an important base class in LLVM.
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
Implements a dense probed hash-table based set.
@ HiddenVisibility
The GV is hidden.
@ InternalLinkage
Rename collisions when linking (static functions).
@ ExternalLinkage
Externally visible function.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
LLVM_ABI void emitError(const Instruction *I, const Twine &ErrorStr)
emitError - Emit an error message to the currently installed error handler with optional location inf...
A Module instance is used to store all the information related to an LLVM module.
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
static LLVM_ABI bool isCtxIRPGOInstrEnabled()
static PointerType * getUnqual(LLVMContext &C)
This constructs an opaque pointer to an object in the default address space (address space zero).
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Represent a constant reference to a string, i.e.
Class to represent struct types.
static LLVM_ABI StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM Value Representation.
LLVMContext & getContext() const
All values hold a context through their type.
Pass manager infrastructure for declaring and invalidating analyses.
static auto ExpectedCalleeTLS
NodeAddr< InstrNode * > Instr
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
LLVM_ABI bool canReturn(const Function &F)
Return true if there is at least a path through which F can return, false if there is no such path.