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
26using namespace llvm;
27
28#define DEBUG_TYPE "x86-wineh-unwindv2"
29
30STATISTIC(MeetsUnwindV2Criteria,
31 "Number of functions that meet Unwind v2 criteria");
32STATISTIC(FailsUnwindV2Criteria,
33 "Number of functions that fail Unwind v2 criteria");
34
35static 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
40static cl::opt<unsigned>
41 ForceMode("x86-wineh-unwindv2-force-mode", cl::Hidden,
42 cl::desc("Overwrites the Unwind v2 mode for testing purposes."));
43
44namespace {
45
46class X86WinEHUnwindV2 : public MachineFunctionPass {
47public:
48 static char ID;
49
50 X86WinEHUnwindV2() : MachineFunctionPass(ID) {
51 initializeX86WinEHUnwindV2Pass(*PassRegistry::getPassRegistry());
52 }
53
54 StringRef getPassName() const override { return "WinEH Unwind V2"; }
55
56 bool runOnMachineFunction(MachineFunction &MF) override;
57
58private:
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
65enum class FunctionState {
66 InProlog,
67 HasProlog,
68 InEpilog,
69 FinishedEpilog,
70};
71
72} // end anonymous namespace
73
74char X86WinEHUnwindV2::ID = 0;
75
76INITIALIZE_PASS(X86WinEHUnwindV2, "x86-wineh-unwindv2",
77 "Analyze and emit instructions for Win64 Unwind v2", false,
78 false)
79
80FunctionPass *llvm::createX86WinEHUnwindV2Pass() {
81 return new X86WinEHUnwindV2();
82}
83
84DebugLoc 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
92bool 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(Elt: MI.getOperand(i: 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 Reason: "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 Reason: "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(Elt: 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 Reason: "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 Reason: "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, Reason: "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 Reason: "Cannot pop registers before the stack "
229 "allocation has been deallocated");
230 if (PoppedRegCount > PushedRegs.size())
231 return rejectCurrentFunctionInternalError(
232 MF, Mode,
233 Reason: "The epilog is popping more registers than the prolog pushed");
234 if (PushedRegs[PushedRegs.size() - PoppedRegCount] !=
235 MI.getOperand(i: 0).getReg())
236 return rejectCurrentFunctionInternalError(
237 MF, Mode,
238 Reason: "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, Reason: "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, Reason: "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(DI: 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(MBB: 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(BB&: *MI->getParent(), I: MI, MIMD: MI->getDebugLoc(),
306 MCID: TII->get(Opcode: X86::SEH_UnwindV2Start));
307 }
308 // Note that the function is using Unwind v2.
309 BuildMI(BB&: FirstMBB, I&: FirstMBB.front(), MIMD: findDebugLoc(MBB: FirstMBB),
310 MCID: TII->get(Opcode: X86::SEH_UnwindVersion))
311 .addImm(Val: 2);
312
313 return true;
314}
315
316bool X86WinEHUnwindV2::rejectCurrentFunctionInternalError(
317 const MachineFunction &MF, WinX64EHUnwindV2Mode Mode, StringRef Reason) {
318 if (Mode == WinX64EHUnwindV2Mode::Required)
319 reportFatalInternalError(reason: "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