LLVM: lib/Transforms/Instrumentation/PGOCtxProfLowering.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
28#include
29
30using namespace llvm;
31
32#define DEBUG_TYPE "ctx-instr-lower"
33
37 "A function name, assumed to be global, which will be treated as the "
38 "root of an interesting graph, which will be profiled independently "
39 "from other similar graphs."));
40
44
45
46
48static auto StartCtx = "__llvm_ctx_profile_start_context";
49static auto ReleaseCtx = "__llvm_ctx_profile_release_context";
50static auto GetCtx = "__llvm_ctx_profile_get_context";
52static auto CallsiteTLS = "__llvm_ctx_profile_callsite";
53}
54
55namespace {
56
57class CtxInstrumentationLowerer final {
60 Type *ContextNodeTy = nullptr;
62
66 Function *ReleaseCtx = nullptr;
69 Constant *CannotBeRootInitializer = nullptr;
70
71public:
73
75};
76
77
78
79
80
81std::pair<uint32_t, uint32_t> getNumCountersAndCallsites(const Function &F) {
83 uint32_t NumCallsites = 0;
84 for (const auto &BB : F) {
85 for (const auto &I : BB) {
87 uint32_t V =
88 static_cast<uint32_t>(Incr->getNumCounters()->getZExtValue());
90 "expected all llvm.instrprof.increment[.step] intrinsics to "
91 "have the same total nr of counters parameter");
94 uint32_t V =
95 static_cast<uint32_t>(CSIntr->getNumCounters()->getZExtValue());
96 assert((!NumCallsites || V == NumCallsites) &&
97 "expected all llvm.instrprof.callsite intrinsics to have the "
98 "same total nr of callsites parameter");
99 NumCallsites = V;
100 }
101#ifdef NDEBUG
103 return std::make_pair(NumCounters, NumCallsites);
104#endif
105 }
106 }
108}
109
111 F.getContext().emitError("[ctxprof] The function " + F.getName() +
112 " was indicated as context root but " + Reason +
113 ", which is not supported.");
114}
115}
116
117
118
119
120CtxInstrumentationLowerer::CtxInstrumentationLowerer(Module &M,
123 auto *PointerTy = PointerType::get(M.getContext(), 0);
124 auto *SanitizerMutexType = Type::getInt8Ty(M.getContext());
125 auto *I32Ty = Type::getInt32Ty(M.getContext());
126 auto *I64Ty = Type::getInt64Ty(M.getContext());
127
128#define _PTRDECL(_, __) PointerTy,
129#define _VOLATILE_PTRDECL(_, __) PointerTy,
130#define _CONTEXT_ROOT PointerTy,
131#define _MUTEXDECL(_) SanitizerMutexType,
132
134 M.getContext(), {CTXPROF_FUNCTION_DATA(_PTRDECL, _CONTEXT_ROOT,
135 _VOLATILE_PTRDECL, _MUTEXDECL)});
136#undef _PTRDECL
137#undef _CONTEXT_ROOT
138#undef _VOLATILE_PTRDECL
139#undef _MUTEXDECL
140
141#define _PTRDECL(_, __) Constant::getNullValue(PointerTy),
142#define _VOLATILE_PTRDECL(_, __) _PTRDECL(_, __)
143#define _MUTEXDECL(_) Constant::getNullValue(SanitizerMutexType),
144#define _CONTEXT_ROOT \
145 Constant::getIntegerValue( \
146 PointerTy, \
147 APInt(M.getDataLayout().getPointerTypeSizeInBits(PointerTy), 1U)),
151#undef _PTRDECL
152#undef _CONTEXT_ROOT
153#undef _VOLATILE_PTRDECL
154#undef _MUTEXDECL
155
156
158 I64Ty,
159 PointerTy,
160 I32Ty,
161 I32Ty,
162 });
163
164
165
167 if (const auto *F = M.getFunction(Fname)) {
168 if (F->isDeclaration())
169 continue;
170 ContextRootSet.insert(F);
171 for (const auto &BB : *F)
172 for (const auto &I : BB)
174 if (CB->isMustTailCall())
175 emitUnsupportedRootError(*F, "it features musttail calls");
176 }
177 }
178
179
181 M.getOrInsertFunction(
184 {PointerTy,
185 I64Ty, I32Ty,
186 I32Ty },
187 false))
188 .getCallee());
192 {PointerTy,
193 PointerTy,
194 I64Ty,
195 I32Ty,
196 I32Ty},
197 false))
198 .getCallee());
201 FunctionType::get(Type::getVoidTy(M.getContext()),
202 {
203 PointerTy,
204 },
205 false))
206 .getCallee());
207
208
209 CallsiteInfoTLS =
212 CallsiteInfoTLS->setThreadLocal(true);
219}
220
223 CtxInstrumentationLowerer Lowerer(M, MAM);
225 for (auto &F : M)
226 Changed |= Lowerer.lowerFunction(F);
228}
229
230bool CtxInstrumentationLowerer::lowerFunction(Function &F) {
231 if (F.isDeclaration())
232 return false;
233
234
235
237 for (auto &BB : F)
240 I.eraseFromParent();
241 if (ContextRootSet.contains(&F))
242 emitUnsupportedRootError(F, "it does not return");
243 return true;
244 }
245
248
250 auto [NumCounters, NumCallsites] = getNumCountersAndCallsites(F);
251
252 Value *Context = nullptr;
253 Value *RealContext = nullptr;
254
255 StructType *ThisContextType = nullptr;
256 Value *TheRootFunctionData = nullptr;
257 Value *ExpectedCalleeTLSAddr = nullptr;
258 Value *CallsiteInfoTLSAddr = nullptr;
259 const bool HasMusttail = [&F]() {
260 for (auto &BB : F)
261 for (auto &I : BB)
263 if (CB->isMustTailCall())
264 return true;
265 return false;
266 }();
267
268 if (HasMusttail && ContextRootSet.contains(&F)) {
269 F.getContext().emitError(
270 "[ctx_prof] A function with musttail calls was explicitly requested as "
271 "root. That is not supported because we cannot instrument a return "
272 "instruction to release the context: " +
273 F.getName());
274 return false;
275 }
276 auto &Head = F.getEntryBlock();
277 for (auto &I : Head) {
278
280 assert(Mark->getIndex()->isZero());
281
283 Guid = Builder.getInt64(
285
286
287
289 F.getContext(),
290 {ContextNodeTy, ArrayType::get(Builder.getInt64Ty(), NumCounters),
291 ArrayType::get(Builder.getPtrTy(), NumCallsites)});
292
293
294
295
296
297
298
299
300
301
304 HasMusttail ? CannotBeRootInitializer
306
307 if (ContextRootSet.contains(&F)) {
308 Context = Builder.CreateCall(
309 StartCtx, {TheRootFunctionData, Guid, Builder.getInt32(NumCounters),
310 Builder.getInt32(NumCallsites)});
311 ORE.emit(
313 } else {
314 Context = Builder.CreateCall(GetCtx, {TheRootFunctionData, &F, Guid,
316 Builder.getInt32(NumCallsites)});
317 ORE.emit([&] {
319 });
320 }
321
322 auto *CtxAsInt = Builder.CreatePtrToInt(Context, Builder.getInt64Ty());
323 if (NumCallsites > 0) {
324
325
326 auto *Index = Builder.CreateAnd(CtxAsInt, Builder.getInt64(1));
327
328 ExpectedCalleeTLSAddr = Builder.CreateGEP(
330 Builder.CreateThreadLocalAddress(ExpectedCalleeTLS), {Index});
331 CallsiteInfoTLSAddr = Builder.CreateGEP(
332 Builder.getInt32Ty(),
333 Builder.CreateThreadLocalAddress(CallsiteInfoTLS), {Index});
334 }
335
336
337
338
339
340 RealContext = Builder.CreateIntToPtr(
341 Builder.CreateAnd(CtxAsInt, Builder.getInt64(-2)),
343 I.eraseFromParent();
344 break;
345 }
346 }
348 ORE.emit([&] {
350 << "Function doesn't have instrumentation, skipping";
351 });
352 return false;
353 }
354
355 bool ContextWasReleased = false;
356 for (auto &BB : F) {
360 switch (Instr->getIntrinsicID()) {
361 case llvm::Intrinsic::instrprof_increment:
362 case llvm::Intrinsic::instrprof_increment_step: {
363
364
366 auto *GEP = Builder.CreateGEP(
367 ThisContextType, RealContext,
368 {Builder.getInt32(0), Builder.getInt32(1), AsStep->getIndex()});
369 Builder.CreateStore(
370 Builder.CreateAdd(Builder.CreateLoad(Builder.getInt64Ty(), GEP),
371 AsStep->getStep()),
373 } break;
374 case llvm::Intrinsic::instrprof_callsite:
375
376
377
379 Builder.CreateStore(CSIntrinsic->getCallee(), ExpectedCalleeTLSAddr,
380 true);
381
382
383
384
385
386
387
388
389
390 Builder.CreateStore(
391 Builder.CreateGEP(ThisContextType, Context,
392 {Builder.getInt32(0), Builder.getInt32(2),
393 CSIntrinsic->getIndex()}),
394 CallsiteInfoTLSAddr, true);
395 break;
396 }
397 I.eraseFromParent();
399
401 Builder.CreateCall(ReleaseCtx, {TheRootFunctionData});
402 ContextWasReleased = true;
403 }
404 }
405 }
406 if (!HasMusttail && !ContextWasReleased)
408 "[ctx_prof] A function that doesn't have musttail calls was "
409 "instrumented but it has no `ret` "
410 "instructions above which to release the context: " +
411 F.getName());
412 return true;
413}
414
418 for (auto &F : M) {
419 if (F.isDeclaration())
420 continue;
421 if (F.hasFnAttribute(Attribute::NoInline))
422 continue;
423 if (.isWeakForLinker())
424 continue;
425
426 if (F.hasFnAttribute(Attribute::AlwaysInline))
427 F.removeFnAttr(Attribute::AlwaysInline);
428
429 F.addFnAttr(Attribute::NoInline);
431 }
435}
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 uint64_t getGUID(const Function &F)
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.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
Definition PGOCtxProfLowering.cpp:415
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
Definition PGOCtxProfLowering.cpp:221
static bool isCtxIRPGOInstrEnabled()
Definition PGOCtxProfLowering.cpp:41
static PointerType * getUnqual(Type *ElementType)
This constructs a pointer to an object of the specified type in the default address space (address sp...
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.
StringRef - 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.
LLVM_ABI LLVMContext & getContext() const
All values hold a context through their type.
Pass manager infrastructure for declaring and invalidating analyses.
static auto CallsiteTLS
Definition PGOCtxProfLowering.cpp:52
static auto ReleaseCtx
Definition PGOCtxProfLowering.cpp:49
static auto StartCtx
Definition PGOCtxProfLowering.cpp:48
static auto GetCtx
Definition PGOCtxProfLowering.cpp:50
static auto ExpectedCalleeTLS
Definition PGOCtxProfLowering.cpp:51
NodeAddr< InstrNode * > Instr
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast - 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 - 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 - 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.