66//
77// ===----------------------------------------------------------------------===//
88//
9- // The Windows x64 unwinder has trouble unwinding the stack when a return
10- // address points to the end of the function. This pass maintains the invariant
11- // that every return address is inside the bounds of its parent function or
12- // funclet by inserting int3 if the last instruction would otherwise be a call.
9+ // The Windows x64 unwinder decodes the instruction stream during unwinding.
10+ // The unwinder decodes forward from the current PC to detect epilogue code
11+ // patterns.
12+ //
13+ // First, this means that there must be an instruction after every
14+ // call instruction for the unwinder to decode. LLVM must maintain the invariant
15+ // that the last instruction of a function or funclet is not a call, or the
16+ // unwinder may decode into the next function. Similarly, a call may not
17+ // immediately precede an epilogue code pattern. As of this writing, the
18+ // SEH_Epilogue pseudo instruction takes care of that.
19+ //
20+ // Second, all non-tail call jump targets must be within the *half-open*
21+ // interval of the bounds of the function. The unwinder distinguishes between
22+ // internal jump instructions and tail calls in an epilogue sequence by checking
23+ // the jump target against the function bounds from the .pdata section. This
24+ // means that the last regular MBB of an LLVM function must not be empty if
25+ // there are regular jumps targeting it.
26+ //
27+ // This pass upholds these invariants by ensuring that blocks at the end of a
28+ // function or funclet are a) not empty and b) do not end in a CALL instruction.
29+ //
30+ // Unwinder implementation for reference:
31+ // https://github.com/dotnet/coreclr/blob/a9f3fc16483eecfc47fb79c362811d870be02249/src/unwinder/amd64/unwinder_amd64.cpp#L1015
1332//
1433// ===----------------------------------------------------------------------===//
1534
1837#include " X86Subtarget.h"
1938#include " llvm/CodeGen/MachineInstrBuilder.h"
2039
21- #define DEBUG_TYPE " x86-avoid-trailing-call"
40+ #define AVOIDCALL_DESC " X86 avoid trailing call pass"
41+ #define AVOIDCALL_NAME " x86-avoid-trailing-call"
42+
43+ #define DEBUG_TYPE AVOIDCALL_NAME
2244
2345using namespace llvm ;
2446
2547namespace {
26-
2748class X86AvoidTrailingCallPass : public MachineFunctionPass {
2849public:
2950 X86AvoidTrailingCallPass () : MachineFunctionPass(ID) {}
3051
3152 bool runOnMachineFunction (MachineFunction &MF) override ;
3253
33- private:
34- StringRef getPassName () const override {
35- return " X86 avoid trailing call pass" ;
36- }
3754 static char ID;
55+
56+ private:
57+ StringRef getPassName () const override { return AVOIDCALL_DESC; }
3858};
59+ } // end anonymous namespace
3960
4061char X86AvoidTrailingCallPass::ID = 0 ;
4162
42- } // end anonymous namespace
43-
4463FunctionPass *llvm::createX86AvoidTrailingCallPass () {
4564 return new X86AvoidTrailingCallPass ();
4665}
4766
67+ INITIALIZE_PASS (X86AvoidTrailingCallPass, AVOIDCALL_NAME, AVOIDCALL_DESC, false , false )
68+
4869// A real instruction is a non-meta, non-pseudo instruction. Some pseudos
4970// expand to nothing, and some expand to code. This logic conservatively assumes
5071// they might expand to nothing.
@@ -62,6 +83,11 @@ bool X86AvoidTrailingCallPass::runOnMachineFunction(MachineFunction &MF) {
6283 const X86InstrInfo &TII = *STI.getInstrInfo ();
6384 assert (STI.isTargetWin64 () && " pass only runs on Win64" );
6485
86+ // We don't need to worry about any of the invariants described above if there
87+ // is no unwind info (CFI).
88+ if (!MF.hasWinCFI ())
89+ return false ;
90+
6591 // FIXME: Perhaps this pass should also replace SEH_Epilogue by inserting nops
6692 // before epilogues.
6793
@@ -73,33 +99,34 @@ bool X86AvoidTrailingCallPass::runOnMachineFunction(MachineFunction &MF) {
7399 if (NextMBB && !NextMBB->isEHFuncletEntry ())
74100 continue ;
75101
76- // Find the last real instruction in this block, or previous blocks if this
77- // block is empty.
78- MachineBasicBlock::reverse_iterator LastRealInstr;
79- for (MachineBasicBlock &RMBB :
80- make_range (MBB.getReverseIterator (), MF.rend ())) {
81- LastRealInstr = llvm::find_if (reverse (RMBB), isRealInstruction);
82- if (LastRealInstr != RMBB.rend ())
83- break ;
84- }
85-
86- // Do nothing if this function or funclet has no instructions.
87- if (LastRealInstr == MF.begin ()->rend ())
88- continue ;
102+ // Find the last real instruction in this block.
103+ auto LastRealInstr = llvm::find_if (reverse (MBB), isRealInstruction);
89104
90- // If this is a call instruction, insert int3 right after it with the same
91- // DebugLoc. Convert back to a forward iterator and advance the insertion
92- // position once.
93- if (isCallInstruction (*LastRealInstr)) {
105+ // If the block is empty or the last real instruction is a call instruction,
106+ // insert an int3. If there is a call instruction, insert the int3 between
107+ // the call and any labels or other meta instructions. If the block is
108+ // empty, insert at block end.
109+ bool IsEmpty = LastRealInstr == MBB.rend ();
110+ bool IsCall = !IsEmpty && isCallInstruction (*LastRealInstr);
111+ if (IsEmpty || IsCall) {
94112 LLVM_DEBUG ({
95- dbgs () << " inserting int3 after trailing call instruction:\n " ;
96- LastRealInstr->dump ();
97- dbgs () << ' \n ' ;
113+ if (IsCall) {
114+ dbgs () << " inserting int3 after trailing call instruction:\n " ;
115+ LastRealInstr->dump ();
116+ dbgs () << ' \n ' ;
117+ } else {
118+ dbgs () << " inserting int3 in trailing empty MBB:\n " ;
119+ MBB.dump ();
120+ }
98121 });
99122
100- MachineBasicBlock::iterator MBBI = std::next (LastRealInstr.getReverse ());
101- BuildMI (*LastRealInstr->getParent (), MBBI, LastRealInstr->getDebugLoc (),
102- TII.get (X86::INT3));
123+ MachineBasicBlock::iterator MBBI = MBB.end ();
124+ DebugLoc DL;
125+ if (IsCall) {
126+ MBBI = std::next (LastRealInstr.getReverse ());
127+ DL = LastRealInstr->getDebugLoc ();
128+ }
129+ BuildMI (MBB, MBBI, DL, TII.get (X86::INT3));
103130 Changed = true ;
104131 }
105132 }
0 commit comments