xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/X86/X86AvoidTrailingCall.cpp (revision 8bcb0991864975618c09697b1aca10683346d9f0)
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