1*8bcb0991SDimitry Andric //===----- X86AvoidTrailingCall.cpp - Insert int3 after trailing calls ----===// 2*8bcb0991SDimitry Andric // 3*8bcb0991SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*8bcb0991SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*8bcb0991SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*8bcb0991SDimitry Andric // 7*8bcb0991SDimitry Andric //===----------------------------------------------------------------------===// 8*8bcb0991SDimitry Andric // 9*8bcb0991SDimitry Andric // The Windows x64 unwinder has trouble unwinding the stack when a return 10*8bcb0991SDimitry Andric // address points to the end of the function. This pass maintains the invariant 11*8bcb0991SDimitry Andric // that every return address is inside the bounds of its parent function or 12*8bcb0991SDimitry Andric // funclet by inserting int3 if the last instruction would otherwise be a call. 13*8bcb0991SDimitry Andric // 14*8bcb0991SDimitry Andric //===----------------------------------------------------------------------===// 15*8bcb0991SDimitry Andric 16*8bcb0991SDimitry Andric #include "X86.h" 17*8bcb0991SDimitry Andric #include "X86InstrInfo.h" 18*8bcb0991SDimitry Andric #include "X86Subtarget.h" 19*8bcb0991SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 20*8bcb0991SDimitry Andric 21*8bcb0991SDimitry Andric #define DEBUG_TYPE "x86-avoid-trailing-call" 22*8bcb0991SDimitry Andric 23*8bcb0991SDimitry Andric using namespace llvm; 24*8bcb0991SDimitry Andric 25*8bcb0991SDimitry Andric namespace { 26*8bcb0991SDimitry Andric 27*8bcb0991SDimitry Andric class X86AvoidTrailingCallPass : public MachineFunctionPass { 28*8bcb0991SDimitry Andric public: 29*8bcb0991SDimitry Andric X86AvoidTrailingCallPass() : MachineFunctionPass(ID) {} 30*8bcb0991SDimitry Andric 31*8bcb0991SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 32*8bcb0991SDimitry Andric 33*8bcb0991SDimitry Andric private: 34*8bcb0991SDimitry Andric StringRef getPassName() const override { 35*8bcb0991SDimitry Andric return "X86 avoid trailing call pass"; 36*8bcb0991SDimitry Andric } 37*8bcb0991SDimitry Andric static char ID; 38*8bcb0991SDimitry Andric }; 39*8bcb0991SDimitry Andric 40*8bcb0991SDimitry Andric char X86AvoidTrailingCallPass::ID = 0; 41*8bcb0991SDimitry Andric 42*8bcb0991SDimitry Andric } // end anonymous namespace 43*8bcb0991SDimitry Andric 44*8bcb0991SDimitry Andric FunctionPass *llvm::createX86AvoidTrailingCallPass() { 45*8bcb0991SDimitry Andric return new X86AvoidTrailingCallPass(); 46*8bcb0991SDimitry Andric } 47*8bcb0991SDimitry Andric 48*8bcb0991SDimitry Andric // A real instruction is a non-meta, non-pseudo instruction. Some pseudos 49*8bcb0991SDimitry Andric // expand to nothing, and some expand to code. This logic conservatively assumes 50*8bcb0991SDimitry Andric // they might expand to nothing. 51*8bcb0991SDimitry Andric static bool isRealInstruction(MachineInstr &MI) { 52*8bcb0991SDimitry Andric return !MI.isPseudo() && !MI.isMetaInstruction(); 53*8bcb0991SDimitry Andric } 54*8bcb0991SDimitry Andric 55*8bcb0991SDimitry Andric // Return true if this is a call instruction, but not a tail call. 56*8bcb0991SDimitry Andric static bool isCallInstruction(const MachineInstr &MI) { 57*8bcb0991SDimitry Andric return MI.isCall() && !MI.isReturn(); 58*8bcb0991SDimitry Andric } 59*8bcb0991SDimitry Andric 60*8bcb0991SDimitry Andric bool X86AvoidTrailingCallPass::runOnMachineFunction(MachineFunction &MF) { 61*8bcb0991SDimitry Andric const X86Subtarget &STI = MF.getSubtarget<X86Subtarget>(); 62*8bcb0991SDimitry Andric const X86InstrInfo &TII = *STI.getInstrInfo(); 63*8bcb0991SDimitry Andric assert(STI.isTargetWin64() && "pass only runs on Win64"); 64*8bcb0991SDimitry Andric 65*8bcb0991SDimitry Andric // FIXME: Perhaps this pass should also replace SEH_Epilogue by inserting nops 66*8bcb0991SDimitry Andric // before epilogues. 67*8bcb0991SDimitry Andric 68*8bcb0991SDimitry Andric bool Changed = false; 69*8bcb0991SDimitry Andric for (MachineBasicBlock &MBB : MF) { 70*8bcb0991SDimitry Andric // Look for basic blocks that precede funclet entries or are at the end of 71*8bcb0991SDimitry Andric // the function. 72*8bcb0991SDimitry Andric MachineBasicBlock *NextMBB = MBB.getNextNode(); 73*8bcb0991SDimitry Andric if (NextMBB && !NextMBB->isEHFuncletEntry()) 74*8bcb0991SDimitry Andric continue; 75*8bcb0991SDimitry Andric 76*8bcb0991SDimitry Andric // Find the last real instruction in this block, or previous blocks if this 77*8bcb0991SDimitry Andric // block is empty. 78*8bcb0991SDimitry Andric MachineBasicBlock::reverse_iterator LastRealInstr; 79*8bcb0991SDimitry Andric for (MachineBasicBlock &RMBB : 80*8bcb0991SDimitry Andric make_range(MBB.getReverseIterator(), MF.rend())) { 81*8bcb0991SDimitry Andric LastRealInstr = llvm::find_if(reverse(RMBB), isRealInstruction); 82*8bcb0991SDimitry Andric if (LastRealInstr != RMBB.rend()) 83*8bcb0991SDimitry Andric break; 84*8bcb0991SDimitry Andric } 85*8bcb0991SDimitry Andric 86*8bcb0991SDimitry Andric // Do nothing if this function or funclet has no instructions. 87*8bcb0991SDimitry Andric if (LastRealInstr == MF.begin()->rend()) 88*8bcb0991SDimitry Andric continue; 89*8bcb0991SDimitry Andric 90*8bcb0991SDimitry Andric // If this is a call instruction, insert int3 right after it with the same 91*8bcb0991SDimitry Andric // DebugLoc. Convert back to a forward iterator and advance the insertion 92*8bcb0991SDimitry Andric // position once. 93*8bcb0991SDimitry Andric if (isCallInstruction(*LastRealInstr)) { 94*8bcb0991SDimitry Andric LLVM_DEBUG({ 95*8bcb0991SDimitry Andric dbgs() << "inserting int3 after trailing call instruction:\n"; 96*8bcb0991SDimitry Andric LastRealInstr->dump(); 97*8bcb0991SDimitry Andric dbgs() << '\n'; 98*8bcb0991SDimitry Andric }); 99*8bcb0991SDimitry Andric 100*8bcb0991SDimitry Andric MachineBasicBlock::iterator MBBI = std::next(LastRealInstr.getReverse()); 101*8bcb0991SDimitry Andric BuildMI(*LastRealInstr->getParent(), MBBI, LastRealInstr->getDebugLoc(), 102*8bcb0991SDimitry Andric TII.get(X86::INT3)); 103*8bcb0991SDimitry Andric Changed = true; 104*8bcb0991SDimitry Andric } 105*8bcb0991SDimitry Andric } 106*8bcb0991SDimitry Andric 107*8bcb0991SDimitry Andric return Changed; 108*8bcb0991SDimitry Andric } 109