1fb69e66cSEugene Zelenko //===- XRayInstrumentation.cpp - Adds XRay instrumentation to functions. --===// 252735fc4SDean Michael Berris // 352735fc4SDean Michael Berris // The LLVM Compiler Infrastructure 452735fc4SDean Michael Berris // 552735fc4SDean Michael Berris // This file is distributed under the University of Illinois Open Source 652735fc4SDean Michael Berris // License. See LICENSE.TXT for details. 752735fc4SDean Michael Berris // 852735fc4SDean Michael Berris //===----------------------------------------------------------------------===// 952735fc4SDean Michael Berris // 1052735fc4SDean Michael Berris // This file implements a MachineFunctionPass that inserts the appropriate 1152735fc4SDean Michael Berris // XRay instrumentation instructions. We look for XRay-specific attributes 1252735fc4SDean Michael Berris // on the function to determine whether we should insert the replacement 1352735fc4SDean Michael Berris // operations. 1452735fc4SDean Michael Berris // 1552735fc4SDean Michael Berris //===---------------------------------------------------------------------===// 1652735fc4SDean Michael Berris 17fb69e66cSEugene Zelenko #include "llvm/ADT/STLExtras.h" 18711dec26SDean Michael Berris #include "llvm/ADT/SmallVector.h" 19fb69e66cSEugene Zelenko #include "llvm/ADT/Triple.h" 20fb69e66cSEugene Zelenko #include "llvm/CodeGen/MachineBasicBlock.h" 216bda14b3SChandler Carruth #include "llvm/CodeGen/MachineDominators.h" 2252735fc4SDean Michael Berris #include "llvm/CodeGen/MachineFunction.h" 2352735fc4SDean Michael Berris #include "llvm/CodeGen/MachineFunctionPass.h" 2452735fc4SDean Michael Berris #include "llvm/CodeGen/MachineInstrBuilder.h" 2522f2bcf4SDean Michael Berris #include "llvm/CodeGen/MachineLoopInfo.h" 263f833edcSDavid Blaikie #include "llvm/CodeGen/TargetInstrInfo.h" 27*b3bde2eaSDavid Blaikie #include "llvm/CodeGen/TargetSubtargetInfo.h" 28fb69e66cSEugene Zelenko #include "llvm/IR/Attributes.h" 29fb69e66cSEugene Zelenko #include "llvm/IR/Function.h" 30fb69e66cSEugene Zelenko #include "llvm/Pass.h" 31fb69e66cSEugene Zelenko #include "llvm/Target/TargetMachine.h" 3252735fc4SDean Michael Berris 3352735fc4SDean Michael Berris using namespace llvm; 3452735fc4SDean Michael Berris 3552735fc4SDean Michael Berris namespace { 36fb69e66cSEugene Zelenko 37cee75361STim Shen struct InstrumentationOptions { 38cee75361STim Shen // Whether to emit PATCHABLE_TAIL_CALL. 39cee75361STim Shen bool HandleTailcall; 40cee75361STim Shen 41cee75361STim Shen // Whether to emit PATCHABLE_RET/PATCHABLE_FUNCTION_EXIT for all forms of 42cee75361STim Shen // return, e.g. conditional return. 43cee75361STim Shen bool HandleAllReturns; 44cee75361STim Shen }; 45cee75361STim Shen 4652735fc4SDean Michael Berris struct XRayInstrumentation : public MachineFunctionPass { 4752735fc4SDean Michael Berris static char ID; 4852735fc4SDean Michael Berris 4952735fc4SDean Michael Berris XRayInstrumentation() : MachineFunctionPass(ID) { 5052735fc4SDean Michael Berris initializeXRayInstrumentationPass(*PassRegistry::getPassRegistry()); 5152735fc4SDean Michael Berris } 5252735fc4SDean Michael Berris 5322f2bcf4SDean Michael Berris void getAnalysisUsage(AnalysisUsage &AU) const override { 5422f2bcf4SDean Michael Berris AU.setPreservesCFG(); 5522f2bcf4SDean Michael Berris AU.addRequired<MachineLoopInfo>(); 5622f2bcf4SDean Michael Berris AU.addPreserved<MachineLoopInfo>(); 5722f2bcf4SDean Michael Berris AU.addPreserved<MachineDominatorTree>(); 5822f2bcf4SDean Michael Berris MachineFunctionPass::getAnalysisUsage(AU); 5922f2bcf4SDean Michael Berris } 6022f2bcf4SDean Michael Berris 6152735fc4SDean Michael Berris bool runOnMachineFunction(MachineFunction &MF) override; 6246401544SDean Michael Berris 6346401544SDean Michael Berris private: 6446401544SDean Michael Berris // Replace the original RET instruction with the exit sled code ("patchable 6546401544SDean Michael Berris // ret" pseudo-instruction), so that at runtime XRay can replace the sled 6646401544SDean Michael Berris // with a code jumping to XRay trampoline, which calls the tracing handler 6746401544SDean Michael Berris // and, in the end, issues the RET instruction. 6846401544SDean Michael Berris // This is the approach to go on CPUs which have a single RET instruction, 6946401544SDean Michael Berris // like x86/x86_64. 7046401544SDean Michael Berris void replaceRetWithPatchableRet(MachineFunction &MF, 71cee75361STim Shen const TargetInstrInfo *TII, 72cee75361STim Shen InstrumentationOptions); 73a331133eSSerge Rogatch 7446401544SDean Michael Berris // Prepend the original return instruction with the exit sled code ("patchable 7546401544SDean Michael Berris // function exit" pseudo-instruction), preserving the original return 7646401544SDean Michael Berris // instruction just after the exit sled code. 7746401544SDean Michael Berris // This is the approach to go on CPUs which have multiple options for the 7846401544SDean Michael Berris // return instruction, like ARM. For such CPUs we can't just jump into the 7946401544SDean Michael Berris // XRay trampoline and issue a single return instruction there. We rather 8046401544SDean Michael Berris // have to call the trampoline and return from it to the original return 8146401544SDean Michael Berris // instruction of the function being instrumented. 8246401544SDean Michael Berris void prependRetWithPatchableExit(MachineFunction &MF, 83cee75361STim Shen const TargetInstrInfo *TII, 84cee75361STim Shen InstrumentationOptions); 8552735fc4SDean Michael Berris }; 86fb69e66cSEugene Zelenko 87fb69e66cSEugene Zelenko } // end anonymous namespace 8852735fc4SDean Michael Berris 8922f2bcf4SDean Michael Berris void XRayInstrumentation::replaceRetWithPatchableRet( 90cee75361STim Shen MachineFunction &MF, const TargetInstrInfo *TII, 91cee75361STim Shen InstrumentationOptions op) { 9246401544SDean Michael Berris // We look for *all* terminators and returns, then replace those with 9352735fc4SDean Michael Berris // PATCHABLE_RET instructions. 9452735fc4SDean Michael Berris SmallVector<MachineInstr *, 4> Terminators; 9552735fc4SDean Michael Berris for (auto &MBB : MF) { 9652735fc4SDean Michael Berris for (auto &T : MBB.terminators()) { 97e8ae5baaSDean Michael Berris unsigned Opc = 0; 98cee75361STim Shen if (T.isReturn() && 99cee75361STim Shen (op.HandleAllReturns || T.getOpcode() == TII->getReturnOpcode())) { 10052735fc4SDean Michael Berris // Replace return instructions with: 10152735fc4SDean Michael Berris // PATCHABLE_RET <Opcode>, <Operand>... 102e8ae5baaSDean Michael Berris Opc = TargetOpcode::PATCHABLE_RET; 103e8ae5baaSDean Michael Berris } 104cee75361STim Shen if (TII->isTailCall(T) && op.HandleTailcall) { 105e8ae5baaSDean Michael Berris // Treat the tail call as a return instruction, which has a 106e8ae5baaSDean Michael Berris // different-looking sled than the normal return case. 107e8ae5baaSDean Michael Berris Opc = TargetOpcode::PATCHABLE_TAIL_CALL; 108e8ae5baaSDean Michael Berris } 109e8ae5baaSDean Michael Berris if (Opc != 0) { 110e8ae5baaSDean Michael Berris auto MIB = BuildMI(MBB, T, T.getDebugLoc(), TII->get(Opc)) 11152735fc4SDean Michael Berris .addImm(T.getOpcode()); 11252735fc4SDean Michael Berris for (auto &MO : T.operands()) 113116bbab4SDiana Picus MIB.add(MO); 11452735fc4SDean Michael Berris Terminators.push_back(&T); 11552735fc4SDean Michael Berris } 11652735fc4SDean Michael Berris } 11752735fc4SDean Michael Berris } 11852735fc4SDean Michael Berris 11952735fc4SDean Michael Berris for (auto &I : Terminators) 12052735fc4SDean Michael Berris I->eraseFromParent(); 12146401544SDean Michael Berris } 12252735fc4SDean Michael Berris 12322f2bcf4SDean Michael Berris void XRayInstrumentation::prependRetWithPatchableExit( 124cee75361STim Shen MachineFunction &MF, const TargetInstrInfo *TII, 125cee75361STim Shen InstrumentationOptions op) { 126711dec26SDean Michael Berris for (auto &MBB : MF) 127cee75361STim Shen for (auto &T : MBB.terminators()) { 128cee75361STim Shen unsigned Opc = 0; 129cee75361STim Shen if (T.isReturn() && 130cee75361STim Shen (op.HandleAllReturns || T.getOpcode() == TII->getReturnOpcode())) { 131cee75361STim Shen Opc = TargetOpcode::PATCHABLE_FUNCTION_EXIT; 132cee75361STim Shen } 133cee75361STim Shen if (TII->isTailCall(T) && op.HandleTailcall) { 134cee75361STim Shen Opc = TargetOpcode::PATCHABLE_TAIL_CALL; 135cee75361STim Shen } 136cee75361STim Shen if (Opc != 0) { 137cee75361STim Shen // Prepend the return instruction with PATCHABLE_FUNCTION_EXIT or 138cee75361STim Shen // PATCHABLE_TAIL_CALL . 139cee75361STim Shen BuildMI(MBB, T, T.getDebugLoc(), TII->get(Opc)); 140cee75361STim Shen } 14146401544SDean Michael Berris } 14246401544SDean Michael Berris } 14346401544SDean Michael Berris 14446401544SDean Michael Berris bool XRayInstrumentation::runOnMachineFunction(MachineFunction &MF) { 14546401544SDean Michael Berris auto &F = *MF.getFunction(); 14646401544SDean Michael Berris auto InstrAttr = F.getFnAttribute("function-instrument"); 14746401544SDean Michael Berris bool AlwaysInstrument = !InstrAttr.hasAttribute(Attribute::None) && 14846401544SDean Michael Berris InstrAttr.isStringAttribute() && 14946401544SDean Michael Berris InstrAttr.getValueAsString() == "xray-always"; 15046401544SDean Michael Berris Attribute Attr = F.getFnAttribute("xray-instruction-threshold"); 15146401544SDean Michael Berris unsigned XRayThreshold = 0; 15246401544SDean Michael Berris if (!AlwaysInstrument) { 15346401544SDean Michael Berris if (Attr.hasAttribute(Attribute::None) || !Attr.isStringAttribute()) 15446401544SDean Michael Berris return false; // XRay threshold attribute not found. 15546401544SDean Michael Berris if (Attr.getValueAsString().getAsInteger(10, XRayThreshold)) 15646401544SDean Michael Berris return false; // Invalid value for threshold. 15722f2bcf4SDean Michael Berris 15885427c0dSSerge Rogatch // Count the number of MachineInstr`s in MachineFunction 15985427c0dSSerge Rogatch int64_t MICount = 0; 16085427c0dSSerge Rogatch for (const auto &MBB : MF) 16185427c0dSSerge Rogatch MICount += MBB.size(); 16285427c0dSSerge Rogatch 16322f2bcf4SDean Michael Berris // Check if we have a loop. 16422f2bcf4SDean Michael Berris // FIXME: Maybe make this smarter, and see whether the loops are dependent 16522f2bcf4SDean Michael Berris // on inputs or side-effects? 16622f2bcf4SDean Michael Berris MachineLoopInfo &MLI = getAnalysis<MachineLoopInfo>(); 16785427c0dSSerge Rogatch if (MLI.empty() && MICount < XRayThreshold) 16822f2bcf4SDean Michael Berris return false; // Function is too small and has no loops. 16946401544SDean Michael Berris } 17046401544SDean Michael Berris 17103b8be57SDean Michael Berris // We look for the first non-empty MachineBasicBlock, so that we can insert 17203b8be57SDean Michael Berris // the function instrumentation in the appropriate place. 173fb69e66cSEugene Zelenko auto MBI = llvm::find_if( 174fb69e66cSEugene Zelenko MF, [&](const MachineBasicBlock &MBB) { return !MBB.empty(); }); 17503b8be57SDean Michael Berris if (MBI == MF.end()) 17603b8be57SDean Michael Berris return false; // The function is empty. 17703b8be57SDean Michael Berris 17803b8be57SDean Michael Berris auto *TII = MF.getSubtarget().getInstrInfo(); 17903b8be57SDean Michael Berris auto &FirstMBB = *MBI; 18046401544SDean Michael Berris auto &FirstMI = *FirstMBB.begin(); 18146401544SDean Michael Berris 18246401544SDean Michael Berris if (!MF.getSubtarget().isXRaySupported()) { 18346401544SDean Michael Berris FirstMI.emitError("An attempt to perform XRay instrumentation for an" 18446401544SDean Michael Berris " unsupported target."); 18546401544SDean Michael Berris return false; 18646401544SDean Michael Berris } 18746401544SDean Michael Berris 18846401544SDean Michael Berris // First, insert an PATCHABLE_FUNCTION_ENTER as the first instruction of the 18946401544SDean Michael Berris // MachineFunction. 19046401544SDean Michael Berris BuildMI(FirstMBB, FirstMI, FirstMI.getDebugLoc(), 19146401544SDean Michael Berris TII->get(TargetOpcode::PATCHABLE_FUNCTION_ENTER)); 19246401544SDean Michael Berris 19346401544SDean Michael Berris switch (MF.getTarget().getTargetTriple().getArch()) { 19446401544SDean Michael Berris case Triple::ArchType::arm: 19546401544SDean Michael Berris case Triple::ArchType::thumb: 1963234d3a4SDean Michael Berris case Triple::ArchType::aarch64: 197ec657929SSagar Thakur case Triple::ArchType::mips: 198ec657929SSagar Thakur case Triple::ArchType::mipsel: 199ec657929SSagar Thakur case Triple::ArchType::mips64: 200cee75361STim Shen case Triple::ArchType::mips64el: { 20146401544SDean Michael Berris // For the architectures which don't have a single return instruction 202cee75361STim Shen InstrumentationOptions op; 203cee75361STim Shen op.HandleTailcall = false; 204cee75361STim Shen op.HandleAllReturns = true; 205cee75361STim Shen prependRetWithPatchableExit(MF, TII, op); 20646401544SDean Michael Berris break; 207cee75361STim Shen } 208cee75361STim Shen case Triple::ArchType::ppc64le: { 209cee75361STim Shen // PPC has conditional returns. Turn them into branch and plain returns. 210cee75361STim Shen InstrumentationOptions op; 211cee75361STim Shen op.HandleTailcall = false; 212cee75361STim Shen op.HandleAllReturns = true; 213cee75361STim Shen replaceRetWithPatchableRet(MF, TII, op); 214cee75361STim Shen break; 215cee75361STim Shen } 216cee75361STim Shen default: { 21746401544SDean Michael Berris // For the architectures that have a single return instruction (such as 21846401544SDean Michael Berris // RETQ on x86_64). 219cee75361STim Shen InstrumentationOptions op; 220cee75361STim Shen op.HandleTailcall = true; 221cee75361STim Shen op.HandleAllReturns = false; 222cee75361STim Shen replaceRetWithPatchableRet(MF, TII, op); 22346401544SDean Michael Berris break; 22446401544SDean Michael Berris } 225cee75361STim Shen } 22652735fc4SDean Michael Berris return true; 22752735fc4SDean Michael Berris } 22852735fc4SDean Michael Berris 22952735fc4SDean Michael Berris char XRayInstrumentation::ID = 0; 23052735fc4SDean Michael Berris char &llvm::XRayInstrumentationID = XRayInstrumentation::ID; 23122f2bcf4SDean Michael Berris INITIALIZE_PASS_BEGIN(XRayInstrumentation, "xray-instrumentation", 23222f2bcf4SDean Michael Berris "Insert XRay ops", false, false) 23322f2bcf4SDean Michael Berris INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo) 23422f2bcf4SDean Michael Berris INITIALIZE_PASS_END(XRayInstrumentation, "xray-instrumentation", 23522f2bcf4SDean Michael Berris "Insert XRay ops", false, false) 236