xref: /freebsd/contrib/llvm-project/llvm/lib/Target/X86/X86WinEHUnwindV2.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===-- X86WinEHUnwindV2.cpp - Win x64 Unwind v2 ----------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// Implements the analysis required to detect if a function can use Unwind v2
10 /// information, and emits the neccesary pseudo instructions used by MC to
11 /// generate the unwind info.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #include "MCTargetDesc/X86BaseInfo.h"
16 #include "X86.h"
17 #include "llvm/ADT/Statistic.h"
18 #include "llvm/CodeGen/MachineBasicBlock.h"
19 #include "llvm/CodeGen/MachineFunctionPass.h"
20 #include "llvm/CodeGen/MachineInstrBuilder.h"
21 #include "llvm/CodeGen/TargetInstrInfo.h"
22 #include "llvm/CodeGen/TargetSubtargetInfo.h"
23 #include "llvm/IR/DiagnosticInfo.h"
24 #include "llvm/IR/Module.h"
25 
26 using namespace llvm;
27 
28 #define DEBUG_TYPE "x86-wineh-unwindv2"
29 
30 STATISTIC(MeetsUnwindV2Criteria,
31           "Number of functions that meet Unwind v2 criteria");
32 STATISTIC(FailsUnwindV2Criteria,
33           "Number of functions that fail Unwind v2 criteria");
34 
35 static cl::opt<unsigned> MaximumUnwindCodes(
36     "x86-wineh-unwindv2-max-unwind-codes", cl::Hidden,
37     cl::desc("Maximum number of unwind codes permitted in each unwind info."),
38     cl::init(UINT8_MAX));
39 
40 static cl::opt<unsigned>
41     ForceMode("x86-wineh-unwindv2-force-mode", cl::Hidden,
42               cl::desc("Overwrites the Unwind v2 mode for testing purposes."));
43 
44 namespace {
45 
46 class X86WinEHUnwindV2 : public MachineFunctionPass {
47 public:
48   static char ID;
49 
X86WinEHUnwindV2()50   X86WinEHUnwindV2() : MachineFunctionPass(ID) {
51     initializeX86WinEHUnwindV2Pass(*PassRegistry::getPassRegistry());
52   }
53 
getPassName() const54   StringRef getPassName() const override { return "WinEH Unwind V2"; }
55 
56   bool runOnMachineFunction(MachineFunction &MF) override;
57 
58 private:
59   /// Rejects the current function due to an internal error within LLVM.
60   static bool rejectCurrentFunctionInternalError(const MachineFunction &MF,
61                                                  WinX64EHUnwindV2Mode Mode,
62                                                  StringRef Reason);
63 };
64 
65 enum class FunctionState {
66   InProlog,
67   HasProlog,
68   InEpilog,
69   FinishedEpilog,
70 };
71 
72 } // end anonymous namespace
73 
74 char X86WinEHUnwindV2::ID = 0;
75 
76 INITIALIZE_PASS(X86WinEHUnwindV2, "x86-wineh-unwindv2",
77                 "Analyze and emit instructions for Win64 Unwind v2", false,
78                 false)
79 
createX86WinEHUnwindV2Pass()80 FunctionPass *llvm::createX86WinEHUnwindV2Pass() {
81   return new X86WinEHUnwindV2();
82 }
83 
findDebugLoc(const MachineBasicBlock & MBB)84 DebugLoc findDebugLoc(const MachineBasicBlock &MBB) {
85   for (const MachineInstr &MI : MBB)
86     if (MI.getDebugLoc())
87       return MI.getDebugLoc();
88 
89   return DebugLoc::getUnknown();
90 }
91 
runOnMachineFunction(MachineFunction & MF)92 bool X86WinEHUnwindV2::runOnMachineFunction(MachineFunction &MF) {
93   WinX64EHUnwindV2Mode Mode =
94       ForceMode.getNumOccurrences()
95           ? static_cast<WinX64EHUnwindV2Mode>(ForceMode.getValue())
96           : MF.getFunction().getParent()->getWinX64EHUnwindV2Mode();
97 
98   if (Mode == WinX64EHUnwindV2Mode::Disabled)
99     return false;
100 
101   // Current state of processing the function. We'll assume that all functions
102   // start with a prolog.
103   FunctionState State = FunctionState::InProlog;
104 
105   // Prolog information.
106   SmallVector<int64_t> PushedRegs;
107   bool HasStackAlloc = false;
108   unsigned ApproximatePrologCodeCount = 0;
109 
110   // Requested changes.
111   SmallVector<MachineInstr *> UnwindV2StartLocations;
112 
113   for (MachineBasicBlock &MBB : MF) {
114     // Current epilog information. We assume that epilogs cannot cross basic
115     // block boundaries.
116     unsigned PoppedRegCount = 0;
117     bool HasStackDealloc = false;
118     MachineInstr *UnwindV2StartLocation = nullptr;
119 
120     for (MachineInstr &MI : MBB) {
121       switch (MI.getOpcode()) {
122       //
123       // Prolog handling.
124       //
125       case X86::SEH_PushReg:
126         if (State != FunctionState::InProlog)
127           llvm_unreachable("SEH_PushReg outside of prolog");
128         ApproximatePrologCodeCount++;
129         PushedRegs.push_back(MI.getOperand(0).getImm());
130         break;
131 
132       case X86::SEH_StackAlloc:
133       case X86::SEH_SetFrame:
134         if (State != FunctionState::InProlog)
135           llvm_unreachable("SEH_StackAlloc or SEH_SetFrame outside of prolog");
136         // Assume a large alloc...
137         ApproximatePrologCodeCount +=
138             (MI.getOpcode() == X86::SEH_StackAlloc) ? 3 : 1;
139         HasStackAlloc = true;
140         break;
141 
142       case X86::SEH_SaveReg:
143       case X86::SEH_SaveXMM:
144         if (State != FunctionState::InProlog)
145           llvm_unreachable("SEH_SaveXMM or SEH_SaveReg outside of prolog");
146         // Assume a big reg...
147         ApproximatePrologCodeCount += 3;
148         break;
149 
150       case X86::SEH_PushFrame:
151         if (State != FunctionState::InProlog)
152           llvm_unreachable("SEH_PushFrame outside of prolog");
153         ApproximatePrologCodeCount++;
154         break;
155 
156       case X86::SEH_EndPrologue:
157         if (State != FunctionState::InProlog)
158           llvm_unreachable("SEH_EndPrologue outside of prolog");
159         State = FunctionState::HasProlog;
160         break;
161 
162       //
163       // Epilog handling.
164       //
165       case X86::SEH_BeginEpilogue:
166         if (State != FunctionState::HasProlog)
167           llvm_unreachable("SEH_BeginEpilogue in prolog or another epilog");
168         State = FunctionState::InEpilog;
169         break;
170 
171       case X86::SEH_EndEpilogue:
172         if (State != FunctionState::InEpilog)
173           llvm_unreachable("SEH_EndEpilogue outside of epilog");
174         if (HasStackAlloc != HasStackDealloc)
175           return rejectCurrentFunctionInternalError(
176               MF, Mode,
177               "The prolog made a stack allocation, "
178               "but the epilog did not deallocate it");
179         if (PoppedRegCount != PushedRegs.size())
180           return rejectCurrentFunctionInternalError(
181               MF, Mode,
182               "The prolog pushed more registers than "
183               "the epilog popped");
184 
185         // If we didn't find the start location, then use the end of the
186         // epilog.
187         if (!UnwindV2StartLocation)
188           UnwindV2StartLocation = &MI;
189         UnwindV2StartLocations.push_back(UnwindV2StartLocation);
190         State = FunctionState::FinishedEpilog;
191         break;
192 
193       case X86::MOV64rr:
194       case X86::ADD64ri32:
195         if (State == FunctionState::InEpilog) {
196           // If the prolog contains a stack allocation, then the first
197           // instruction in the epilog must be to adjust the stack pointer.
198           if (!HasStackAlloc)
199             return rejectCurrentFunctionInternalError(
200                 MF, Mode,
201                 "The epilog is deallocating a stack "
202                 "allocation, but the prolog did "
203                 "not allocate one");
204           if (HasStackDealloc)
205             return rejectCurrentFunctionInternalError(
206                 MF, Mode,
207                 "The epilog is deallocating the stack "
208                 "allocation more than once");
209           if (PoppedRegCount > 0)
210             llvm_unreachable(
211                 "Should have raised an error: either popping before "
212                 "deallocating or deallocating without an allocation");
213 
214           HasStackDealloc = true;
215         } else if (State == FunctionState::FinishedEpilog)
216           return rejectCurrentFunctionInternalError(
217               MF, Mode, "Unexpected mov or add instruction after the epilog");
218         break;
219 
220       case X86::POP64r:
221         if (State == FunctionState::InEpilog) {
222           // After the stack pointer has been adjusted, the epilog must
223           // POP each register in reverse order of the PUSHes in the prolog.
224           PoppedRegCount++;
225           if (HasStackAlloc != HasStackDealloc)
226             return rejectCurrentFunctionInternalError(
227                 MF, Mode,
228                 "Cannot pop registers before the stack "
229                 "allocation has been deallocated");
230           if (PoppedRegCount > PushedRegs.size())
231             return rejectCurrentFunctionInternalError(
232                 MF, Mode,
233                 "The epilog is popping more registers than the prolog pushed");
234           if (PushedRegs[PushedRegs.size() - PoppedRegCount] !=
235               MI.getOperand(0).getReg())
236             return rejectCurrentFunctionInternalError(
237                 MF, Mode,
238                 "The epilog is popping a registers in "
239                 "a different order than the "
240                 "prolog pushed them");
241 
242           // Unwind v2 records the size of the epilog not from where we place
243           // SEH_BeginEpilogue (as that contains the instruction to adjust the
244           // stack pointer) but from the first POP instruction (if there is
245           // one).
246           if (!UnwindV2StartLocation) {
247             assert(PoppedRegCount == 1);
248             UnwindV2StartLocation = &MI;
249           }
250         } else if (State == FunctionState::FinishedEpilog)
251           // Unexpected instruction after the epilog.
252           return rejectCurrentFunctionInternalError(
253               MF, Mode, "Registers are being popped after the epilog");
254         break;
255 
256       default:
257         if (MI.isTerminator()) {
258           if (State == FunctionState::FinishedEpilog)
259             // Found the terminator after the epilog, we're now ready for
260             // another epilog.
261             State = FunctionState::HasProlog;
262           else if (State == FunctionState::InEpilog)
263             llvm_unreachable("Terminator in the middle of the epilog");
264         } else if (!MI.isDebugOrPseudoInstr()) {
265           if ((State == FunctionState::FinishedEpilog) ||
266               (State == FunctionState::InEpilog))
267             // Unknown instruction in or after the epilog.
268             return rejectCurrentFunctionInternalError(
269                 MF, Mode, "Unexpected instruction in or after the epilog");
270         }
271       }
272     }
273   }
274 
275   if (UnwindV2StartLocations.empty()) {
276     assert(State == FunctionState::InProlog &&
277            "If there are no epilogs, then there should be no prolog");
278     return false;
279   }
280 
281   MachineBasicBlock &FirstMBB = MF.front();
282   // Assume +1 for the "header" UOP_Epilog that contains the epilog size, and
283   // that we won't be able to use the "last epilog at the end of function"
284   // optimization.
285   if (ApproximatePrologCodeCount + UnwindV2StartLocations.size() + 1 >
286       static_cast<unsigned>(MaximumUnwindCodes)) {
287     if (Mode == WinX64EHUnwindV2Mode::Required)
288       MF.getFunction().getContext().diagnose(DiagnosticInfoGenericWithLoc(
289           "Windows x64 Unwind v2 is required, but the function '" +
290               MF.getName() +
291               "' has too many unwind codes. Try splitting the function or "
292               "reducing the number of places where it exits early with a tail "
293               "call.",
294           MF.getFunction(), findDebugLoc(FirstMBB)));
295 
296     FailsUnwindV2Criteria++;
297     return false;
298   }
299 
300   MeetsUnwindV2Criteria++;
301 
302   // Emit the pseudo instruction that marks the start of each epilog.
303   const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
304   for (MachineInstr *MI : UnwindV2StartLocations) {
305     BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
306             TII->get(X86::SEH_UnwindV2Start));
307   }
308   // Note that the function is using Unwind v2.
309   BuildMI(FirstMBB, FirstMBB.front(), findDebugLoc(FirstMBB),
310           TII->get(X86::SEH_UnwindVersion))
311       .addImm(2);
312 
313   return true;
314 }
315 
rejectCurrentFunctionInternalError(const MachineFunction & MF,WinX64EHUnwindV2Mode Mode,StringRef Reason)316 bool X86WinEHUnwindV2::rejectCurrentFunctionInternalError(
317     const MachineFunction &MF, WinX64EHUnwindV2Mode Mode, StringRef Reason) {
318   if (Mode == WinX64EHUnwindV2Mode::Required)
319     reportFatalInternalError("Windows x64 Unwind v2 is required, but LLVM has "
320                              "generated incompatible code in function '" +
321                              MF.getName() + "': " + Reason);
322 
323   FailsUnwindV2Criteria++;
324   return false;
325 }
326