xref: /freebsd/contrib/llvm-project/llvm/lib/Transforms/Utils/EntryExitInstrumenter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- EntryExitInstrumenter.cpp - Function Entry/Exit Instrumentation ----===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "llvm/Transforms/Utils/EntryExitInstrumenter.h"
100b57cec5SDimitry Andric #include "llvm/Analysis/GlobalsModRef.h"
110b57cec5SDimitry Andric #include "llvm/IR/DebugInfoMetadata.h"
12fe6060f1SDimitry Andric #include "llvm/IR/Dominators.h"
130b57cec5SDimitry Andric #include "llvm/IR/Function.h"
140b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
155ffd83dbSDimitry Andric #include "llvm/IR/Intrinsics.h"
160b57cec5SDimitry Andric #include "llvm/IR/Module.h"
170b57cec5SDimitry Andric #include "llvm/IR/Type.h"
18*0fca6ea1SDimitry Andric #include "llvm/InitializePasses.h"
1906c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h"
20*0fca6ea1SDimitry Andric #include "llvm/Pass.h"
21*0fca6ea1SDimitry Andric #include "llvm/Transforms/Utils.h"
22fe6060f1SDimitry Andric 
230b57cec5SDimitry Andric using namespace llvm;
240b57cec5SDimitry Andric 
insertCall(Function & CurFn,StringRef Func,BasicBlock::iterator InsertionPt,DebugLoc DL)250b57cec5SDimitry Andric static void insertCall(Function &CurFn, StringRef Func,
26*0fca6ea1SDimitry Andric                        BasicBlock::iterator InsertionPt, DebugLoc DL) {
270b57cec5SDimitry Andric   Module &M = *InsertionPt->getParent()->getParent()->getParent();
280b57cec5SDimitry Andric   LLVMContext &C = InsertionPt->getParent()->getContext();
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric   if (Func == "mcount" ||
310b57cec5SDimitry Andric       Func == ".mcount" ||
328bcb0991SDimitry Andric       Func == "llvm.arm.gnu.eabi.mcount" ||
330b57cec5SDimitry Andric       Func == "\01_mcount" ||
340b57cec5SDimitry Andric       Func == "\01mcount" ||
350b57cec5SDimitry Andric       Func == "__mcount" ||
360b57cec5SDimitry Andric       Func == "_mcount" ||
370b57cec5SDimitry Andric       Func == "__cyg_profile_func_enter_bare") {
38bdd1243dSDimitry Andric     Triple TargetTriple(M.getTargetTriple());
39bdd1243dSDimitry Andric     if (TargetTriple.isOSAIX() && Func == "__mcount") {
40bdd1243dSDimitry Andric       Type *SizeTy = M.getDataLayout().getIntPtrType(C);
415f757f3fSDimitry Andric       Type *SizePtrTy = PointerType::getUnqual(C);
42bdd1243dSDimitry Andric       GlobalVariable *GV = new GlobalVariable(M, SizeTy, /*isConstant=*/false,
43bdd1243dSDimitry Andric                                               GlobalValue::InternalLinkage,
44bdd1243dSDimitry Andric                                               ConstantInt::get(SizeTy, 0));
45bdd1243dSDimitry Andric       CallInst *Call = CallInst::Create(
46bdd1243dSDimitry Andric           M.getOrInsertFunction(Func,
47bdd1243dSDimitry Andric                                 FunctionType::get(Type::getVoidTy(C), {SizePtrTy},
48bdd1243dSDimitry Andric                                                   /*isVarArg=*/false)),
49bdd1243dSDimitry Andric           {GV}, "", InsertionPt);
50bdd1243dSDimitry Andric       Call->setDebugLoc(DL);
51bdd1243dSDimitry Andric     } else {
520b57cec5SDimitry Andric       FunctionCallee Fn = M.getOrInsertFunction(Func, Type::getVoidTy(C));
530b57cec5SDimitry Andric       CallInst *Call = CallInst::Create(Fn, "", InsertionPt);
540b57cec5SDimitry Andric       Call->setDebugLoc(DL);
55bdd1243dSDimitry Andric     }
560b57cec5SDimitry Andric     return;
570b57cec5SDimitry Andric   }
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric   if (Func == "__cyg_profile_func_enter" || Func == "__cyg_profile_func_exit") {
605f757f3fSDimitry Andric     Type *ArgTypes[] = {PointerType::getUnqual(C), PointerType::getUnqual(C)};
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric     FunctionCallee Fn = M.getOrInsertFunction(
630b57cec5SDimitry Andric         Func, FunctionType::get(Type::getVoidTy(C), ArgTypes, false));
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric     Instruction *RetAddr = CallInst::Create(
660b57cec5SDimitry Andric         Intrinsic::getDeclaration(&M, Intrinsic::returnaddress),
670b57cec5SDimitry Andric         ArrayRef<Value *>(ConstantInt::get(Type::getInt32Ty(C), 0)), "",
680b57cec5SDimitry Andric         InsertionPt);
690b57cec5SDimitry Andric     RetAddr->setDebugLoc(DL);
700b57cec5SDimitry Andric 
715f757f3fSDimitry Andric     Value *Args[] = {&CurFn, RetAddr};
720b57cec5SDimitry Andric     CallInst *Call =
730b57cec5SDimitry Andric         CallInst::Create(Fn, ArrayRef<Value *>(Args), "", InsertionPt);
740b57cec5SDimitry Andric     Call->setDebugLoc(DL);
750b57cec5SDimitry Andric     return;
760b57cec5SDimitry Andric   }
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric   // We only know how to call a fixed set of instrumentation functions, because
790b57cec5SDimitry Andric   // they all expect different arguments, etc.
800b57cec5SDimitry Andric   report_fatal_error(Twine("Unknown instrumentation function: '") + Func + "'");
810b57cec5SDimitry Andric }
820b57cec5SDimitry Andric 
runOnFunction(Function & F,bool PostInlining)830b57cec5SDimitry Andric static bool runOnFunction(Function &F, bool PostInlining) {
8406c3fb27SDimitry Andric   // The asm in a naked function may reasonably expect the argument registers
8506c3fb27SDimitry Andric   // and the return address register (if present) to be live. An inserted
8606c3fb27SDimitry Andric   // function call will clobber these registers. Simply skip naked functions for
8706c3fb27SDimitry Andric   // all targets.
8806c3fb27SDimitry Andric   if (F.hasFnAttribute(Attribute::Naked))
8906c3fb27SDimitry Andric     return false;
9006c3fb27SDimitry Andric 
910b57cec5SDimitry Andric   StringRef EntryAttr = PostInlining ? "instrument-function-entry-inlined"
920b57cec5SDimitry Andric                                      : "instrument-function-entry";
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric   StringRef ExitAttr = PostInlining ? "instrument-function-exit-inlined"
950b57cec5SDimitry Andric                                     : "instrument-function-exit";
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric   StringRef EntryFunc = F.getFnAttribute(EntryAttr).getValueAsString();
980b57cec5SDimitry Andric   StringRef ExitFunc = F.getFnAttribute(ExitAttr).getValueAsString();
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric   bool Changed = false;
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric   // If the attribute is specified, insert instrumentation and then "consume"
1030b57cec5SDimitry Andric   // the attribute so that it's not inserted again if the pass should happen to
1040b57cec5SDimitry Andric   // run later for some reason.
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric   if (!EntryFunc.empty()) {
1070b57cec5SDimitry Andric     DebugLoc DL;
1080b57cec5SDimitry Andric     if (auto SP = F.getSubprogram())
109e8d8bef9SDimitry Andric       DL = DILocation::get(SP->getContext(), SP->getScopeLine(), 0, SP);
1100b57cec5SDimitry Andric 
111*0fca6ea1SDimitry Andric     insertCall(F, EntryFunc, F.begin()->getFirstInsertionPt(), DL);
1120b57cec5SDimitry Andric     Changed = true;
113349cc55cSDimitry Andric     F.removeFnAttr(EntryAttr);
1140b57cec5SDimitry Andric   }
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric   if (!ExitFunc.empty()) {
1170b57cec5SDimitry Andric     for (BasicBlock &BB : F) {
1180b57cec5SDimitry Andric       Instruction *T = BB.getTerminator();
1190b57cec5SDimitry Andric       if (!isa<ReturnInst>(T))
1200b57cec5SDimitry Andric         continue;
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric       // If T is preceded by a musttail call, that's the real terminator.
123e8d8bef9SDimitry Andric       if (CallInst *CI = BB.getTerminatingMustTailCall())
1240b57cec5SDimitry Andric         T = CI;
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric       DebugLoc DL;
1270b57cec5SDimitry Andric       if (DebugLoc TerminatorDL = T->getDebugLoc())
1280b57cec5SDimitry Andric         DL = TerminatorDL;
1290b57cec5SDimitry Andric       else if (auto SP = F.getSubprogram())
130e8d8bef9SDimitry Andric         DL = DILocation::get(SP->getContext(), 0, 0, SP);
1310b57cec5SDimitry Andric 
132*0fca6ea1SDimitry Andric       insertCall(F, ExitFunc, T->getIterator(), DL);
1330b57cec5SDimitry Andric       Changed = true;
1340b57cec5SDimitry Andric     }
135349cc55cSDimitry Andric     F.removeFnAttr(ExitAttr);
1360b57cec5SDimitry Andric   }
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric   return Changed;
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric 
141*0fca6ea1SDimitry Andric namespace {
142*0fca6ea1SDimitry Andric struct PostInlineEntryExitInstrumenter : public FunctionPass {
143*0fca6ea1SDimitry Andric   static char ID;
PostInlineEntryExitInstrumenter__anonfba2004a0111::PostInlineEntryExitInstrumenter144*0fca6ea1SDimitry Andric   PostInlineEntryExitInstrumenter() : FunctionPass(ID) {
145*0fca6ea1SDimitry Andric     initializePostInlineEntryExitInstrumenterPass(
146*0fca6ea1SDimitry Andric         *PassRegistry::getPassRegistry());
147*0fca6ea1SDimitry Andric   }
getAnalysisUsage__anonfba2004a0111::PostInlineEntryExitInstrumenter148*0fca6ea1SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
149*0fca6ea1SDimitry Andric     AU.addPreserved<GlobalsAAWrapperPass>();
150*0fca6ea1SDimitry Andric     AU.addPreserved<DominatorTreeWrapperPass>();
151*0fca6ea1SDimitry Andric   }
runOnFunction__anonfba2004a0111::PostInlineEntryExitInstrumenter152*0fca6ea1SDimitry Andric   bool runOnFunction(Function &F) override { return ::runOnFunction(F, true); }
153*0fca6ea1SDimitry Andric };
154*0fca6ea1SDimitry Andric char PostInlineEntryExitInstrumenter::ID = 0;
155*0fca6ea1SDimitry Andric }
156*0fca6ea1SDimitry Andric 
157*0fca6ea1SDimitry Andric INITIALIZE_PASS_BEGIN(
158*0fca6ea1SDimitry Andric     PostInlineEntryExitInstrumenter, "post-inline-ee-instrument",
159*0fca6ea1SDimitry Andric     "Instrument function entry/exit with calls to e.g. mcount() "
160*0fca6ea1SDimitry Andric     "(post inlining)",
161*0fca6ea1SDimitry Andric     false, false)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)162*0fca6ea1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
163*0fca6ea1SDimitry Andric INITIALIZE_PASS_END(
164*0fca6ea1SDimitry Andric     PostInlineEntryExitInstrumenter, "post-inline-ee-instrument",
165*0fca6ea1SDimitry Andric     "Instrument function entry/exit with calls to e.g. mcount() "
166*0fca6ea1SDimitry Andric     "(post inlining)",
167*0fca6ea1SDimitry Andric     false, false)
168*0fca6ea1SDimitry Andric 
169*0fca6ea1SDimitry Andric FunctionPass *llvm::createPostInlineEntryExitInstrumenterPass() {
170*0fca6ea1SDimitry Andric   return new PostInlineEntryExitInstrumenter();
171*0fca6ea1SDimitry Andric }
172*0fca6ea1SDimitry Andric 
1730b57cec5SDimitry Andric PreservedAnalyses
run(Function & F,FunctionAnalysisManager & AM)1740b57cec5SDimitry Andric llvm::EntryExitInstrumenterPass::run(Function &F, FunctionAnalysisManager &AM) {
175*0fca6ea1SDimitry Andric   if (!runOnFunction(F, PostInlining))
176*0fca6ea1SDimitry Andric     return PreservedAnalyses::all();
1770b57cec5SDimitry Andric   PreservedAnalyses PA;
1780b57cec5SDimitry Andric   PA.preserveSet<CFGAnalyses>();
1790b57cec5SDimitry Andric   return PA;
1800b57cec5SDimitry Andric }
181349cc55cSDimitry Andric 
printPipeline(raw_ostream & OS,function_ref<StringRef (StringRef)> MapClassName2PassName)182349cc55cSDimitry Andric void llvm::EntryExitInstrumenterPass::printPipeline(
183349cc55cSDimitry Andric     raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) {
184349cc55cSDimitry Andric   static_cast<PassInfoMixin<llvm::EntryExitInstrumenterPass> *>(this)
185349cc55cSDimitry Andric       ->printPipeline(OS, MapClassName2PassName);
18606c3fb27SDimitry Andric   OS << '<';
187349cc55cSDimitry Andric   if (PostInlining)
188349cc55cSDimitry Andric     OS << "post-inline";
18906c3fb27SDimitry Andric   OS << '>';
190349cc55cSDimitry Andric }
191