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