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/TargetFrameLowering.h"
22#include "llvm/CodeGen/TargetInstrInfo.h"
23#include "llvm/CodeGen/TargetSubtargetInfo.h"
24#include "llvm/IR/DiagnosticInfo.h"
25#include "llvm/IR/Module.h"
26
27using namespace llvm;
28
29#define DEBUG_TYPE "x86-wineh-unwindv2"
30
31STATISTIC(MeetsUnwindV2Criteria,
32 "Number of functions that meet Unwind v2 criteria");
33STATISTIC(FailsUnwindV2Criteria,
34 "Number of functions that fail Unwind v2 criteria");
35
36static cl::opt<unsigned>
37 UnwindCodeThreshold("x86-wineh-unwindv2-unwind-codes-threshold", cl::Hidden,
38 cl::desc("Maximum number of unwind codes before "
39 "splitting into a new unwind info."),
40 cl::init(UINT8_MAX));
41
42static cl::opt<unsigned>
43 ForceMode("x86-wineh-unwindv2-force-mode", cl::Hidden,
44 cl::desc("Overwrites the Unwind v2 mode for testing purposes."));
45
46// This threshold is for the *approximate* number of instructions, see the
47// comment in runAnalysisOnFuncOrFunclet for more details.
48static cl::opt<unsigned> InstructionCountThreshold(
49 "x86-wineh-unwindv2-instruction-count-threshold", cl::Hidden,
50 cl::desc("Maximum number of (approximate) instructions before splitting "
51 "into a new unwind info."),
52 cl::init(Val: 600));
53
54namespace {
55
56struct EpilogInfo {
57 MachineInstr *UnwindV2StartLocation;
58 unsigned ApproximateInstructionPosition;
59};
60
61struct FrameInfo {
62 unsigned ApproximatePrologCodeCount;
63 unsigned ApproximateInstructionCount;
64 SmallVector<EpilogInfo> EpilogInfos;
65};
66
67class X86WinEHUnwindV2Legacy : public MachineFunctionPass {
68public:
69 static char ID;
70
71 X86WinEHUnwindV2Legacy() : MachineFunctionPass(ID) {
72 initializeX86WinEHUnwindV2LegacyPass(*PassRegistry::getPassRegistry());
73 }
74
75 StringRef getPassName() const override { return "WinEH Unwind V2"; }
76
77 bool runOnMachineFunction(MachineFunction &MF) override;
78};
79
80/// Rejects the current function due to an internal error within LLVM.
81std::nullopt_t rejectCurrentFunctionInternalError(const MachineFunction &MF,
82 WinX64EHUnwindV2Mode Mode,
83 StringRef Reason) {
84 if (Mode == WinX64EHUnwindV2Mode::Required)
85 reportFatalInternalError(reason: "Windows x64 Unwind v2 is required, but LLVM has "
86 "generated incompatible code in function '" +
87 MF.getName() + "': " + Reason);
88
89 FailsUnwindV2Criteria++;
90 return std::nullopt;
91}
92
93enum class FunctionState {
94 InProlog,
95 HasProlog,
96 InEpilog,
97 FinishedEpilog,
98};
99
100} // end anonymous namespace
101
102char X86WinEHUnwindV2Legacy::ID = 0;
103
104INITIALIZE_PASS(X86WinEHUnwindV2Legacy, "x86-wineh-unwindv2",
105 "Analyze and emit instructions for Win64 Unwind v2", false,
106 false)
107
108FunctionPass *llvm::createX86WinEHUnwindV2LegacyPass() {
109 return new X86WinEHUnwindV2Legacy();
110}
111
112DebugLoc findDebugLoc(const MachineBasicBlock &MBB) {
113 for (const MachineInstr &MI : MBB)
114 if (MI.getDebugLoc())
115 return MI.getDebugLoc();
116
117 return DebugLoc::getUnknown();
118}
119
120// Continues running the analysis on the given function or funclet.
121std::optional<FrameInfo>
122runAnalysisOnFuncOrFunclet(MachineFunction &MF, MachineFunction::iterator &Iter,
123 WinX64EHUnwindV2Mode Mode) {
124 const TargetFrameLowering &TFL = *MF.getSubtarget().getFrameLowering();
125
126 // Current state of processing the function. We'll assume that all functions
127 // start with a prolog.
128 FunctionState State = FunctionState::InProlog;
129
130 // Prolog information.
131 SmallVector<int64_t> PushedRegs;
132 bool HasStackAlloc = false;
133 bool HasSetFrame = false;
134 unsigned ApproximatePrologCodeCount = 0;
135
136 SmallVector<EpilogInfo> EpilogInfos;
137
138 // Unwind v2 requires that the epilog is no more than 4Kb away from the last
139 // instruction that the current unwind info covers. If we believe that we are
140 // going over that limit then we need to split the unwind info. Ideally we'd
141 // do this at the point where we actually know how far away we are from the
142 // last instruction, but that's not possible here and splitting unwind infos
143 // in MC would be difficult. However, the cost of splitting an unwind info is
144 // fairly cheap (in the other of bytes in the xdata section), so we can
145 // instead use a heuristic based on the number of MachineInstrs to decide when
146 // to split unwind infos, and allow users to tune the threshold if needed.
147 // This is not a perfect solution, but 1) it is cheap to calculate, 2) allows
148 // the common case for small functions or large functions with multiple
149 // returns at the end to have a single unwind info, and 3) allows unwind v2 to
150 // be used in large functions (that would otherwise be rejected) for a small
151 // binary size cost.
152 unsigned ApproximateInstructionCount = 0;
153
154 for (; Iter != MF.end(); ++Iter) {
155 MachineBasicBlock &MBB = *Iter;
156
157 // If we're already been processing a function, then come across a funclet
158 // then break since the funclet will get a fresh frame info.
159 if (MBB.isEHFuncletEntry() && State != FunctionState::InProlog)
160 break;
161
162 // Current epilog information. We assume that epilogs cannot cross basic
163 // block boundaries.
164 unsigned PoppedRegCount = 0;
165 bool HasStackDealloc = false;
166 bool HasSetFrameBack = false;
167 MachineInstr *UnwindV2StartLocation = nullptr;
168
169 for (MachineInstr &MI : MBB) {
170 // This is an *approximation* of the number of instructions that will be
171 // emitted. It is not the actual number of instructions, but that doesn't
172 // matter: see the comment at the declaration of
173 // ApproximateInstructionCount.
174 if (!MI.isPseudo() && !MI.isMetaInstruction())
175 ApproximateInstructionCount++;
176
177 switch (MI.getOpcode()) {
178 //
179 // Prolog handling.
180 //
181 case X86::SEH_PushReg:
182 if (State != FunctionState::InProlog)
183 llvm_unreachable("SEH_PushReg outside of prolog");
184 ApproximatePrologCodeCount++;
185 PushedRegs.push_back(Elt: MI.getOperand(i: 0).getImm());
186 break;
187
188 case X86::SEH_StackAlloc:
189 if (State != FunctionState::InProlog)
190 llvm_unreachable("SEH_StackAlloc outside of prolog");
191 // Assume a large alloc...
192 ApproximatePrologCodeCount += 3;
193 HasStackAlloc = true;
194 break;
195
196 case X86::SEH_SetFrame:
197 if (State != FunctionState::InProlog)
198 llvm_unreachable("SEH_SetFrame outside of prolog");
199 ApproximatePrologCodeCount++;
200 HasSetFrame = true;
201 break;
202
203 case X86::SEH_SaveReg:
204 case X86::SEH_SaveXMM:
205 if (State != FunctionState::InProlog)
206 llvm_unreachable("SEH_SaveXMM or SEH_SaveReg outside of prolog");
207 // Assume a big reg...
208 ApproximatePrologCodeCount += 3;
209 break;
210
211 case X86::SEH_PushFrame:
212 if (State != FunctionState::InProlog)
213 llvm_unreachable("SEH_PushFrame outside of prolog");
214 ApproximatePrologCodeCount++;
215 break;
216
217 case X86::SEH_EndPrologue:
218 if (State != FunctionState::InProlog)
219 llvm_unreachable("SEH_EndPrologue outside of prolog");
220 State = FunctionState::HasProlog;
221 break;
222
223 //
224 // Epilog handling.
225 //
226 case X86::SEH_BeginEpilogue:
227 if (State != FunctionState::HasProlog)
228 llvm_unreachable("SEH_BeginEpilogue in prolog or another epilog");
229 State = FunctionState::InEpilog;
230 break;
231
232 case X86::SEH_EndEpilogue:
233 if (State != FunctionState::InEpilog)
234 llvm_unreachable("SEH_EndEpilogue outside of epilog");
235 if (HasStackAlloc != HasStackDealloc)
236 return rejectCurrentFunctionInternalError(
237 MF, Mode,
238 Reason: "The prolog made a stack allocation, "
239 "but the epilog did not deallocate it");
240 if (PoppedRegCount != PushedRegs.size())
241 return rejectCurrentFunctionInternalError(
242 MF, Mode,
243 Reason: "The prolog pushed more registers than "
244 "the epilog popped");
245
246 // If we didn't find the start location, then use the end of the
247 // epilog.
248 if (!UnwindV2StartLocation)
249 UnwindV2StartLocation = &MI;
250 EpilogInfos.push_back(
251 Elt: {.UnwindV2StartLocation: UnwindV2StartLocation, .ApproximateInstructionPosition: ApproximateInstructionCount});
252 State = FunctionState::FinishedEpilog;
253 break;
254
255 case X86::MOV64rr:
256 if (State == FunctionState::InEpilog) {
257 // If the prolog contains a stack allocation, then the first
258 // instruction in the epilog must be to adjust the stack pointer.
259 if (!HasSetFrame)
260 return rejectCurrentFunctionInternalError(
261 MF, Mode,
262 Reason: "The epilog is setting frame back, but prolog did not set it");
263 if (PoppedRegCount > 0)
264 return rejectCurrentFunctionInternalError(
265 MF, Mode,
266 Reason: "The epilog is setting the frame back after popping "
267 "registers");
268 if (HasStackDealloc)
269 return rejectCurrentFunctionInternalError(
270 MF, Mode,
271 Reason: "Cannot set the frame back after the stack "
272 "allocation has been deallocated");
273 HasSetFrameBack = true;
274 } else if (State == FunctionState::FinishedEpilog)
275 return rejectCurrentFunctionInternalError(
276 MF, Mode, Reason: "Unexpected mov instruction after the epilog");
277 break;
278
279 case X86::LEA64r:
280 case X86::ADD64ri32:
281 if (State == FunctionState::InEpilog) {
282 // If the prolog contains a stack allocation, then the first
283 // instruction in the epilog must be to adjust the stack pointer.
284 if (!HasStackAlloc)
285 return rejectCurrentFunctionInternalError(
286 MF, Mode,
287 Reason: "The epilog is deallocating a stack "
288 "allocation, but the prolog did "
289 "not allocate one");
290 if (PoppedRegCount > 0)
291 return rejectCurrentFunctionInternalError(
292 MF, Mode,
293 Reason: "The epilog is deallocating a stack allocation after popping "
294 "registers");
295
296 HasStackDealloc = true;
297 } else if (State == FunctionState::FinishedEpilog)
298 return rejectCurrentFunctionInternalError(
299 MF, Mode, Reason: "Unexpected lea or add instruction after the epilog");
300 break;
301
302 case X86::POP64r:
303 if (State == FunctionState::InEpilog) {
304 Register Reg = MI.getOperand(i: 0).getReg();
305 if (HasStackAlloc && (PoppedRegCount == 0) &&
306 !llvm::is_contained(Range&: PushedRegs, Element: Reg)) {
307 // If this is a pop that doesn't correspond to the set of pushed
308 // registers, then assume it was used to adjust the stack pointer.
309 HasStackDealloc = true;
310 } else {
311 // Special case: no explicit stack dealloc is required if SetFrame
312 // was used and the function has a frame pointer.
313 if (PoppedRegCount == 0 && HasStackAlloc && !HasStackDealloc &&
314 HasSetFrameBack && TFL.hasFP(MF))
315 HasStackDealloc = true;
316
317 // After the stack pointer has been adjusted, the epilog must
318 // POP each register in reverse order of the PUSHes in the prolog.
319 PoppedRegCount++;
320 if (HasStackAlloc != HasStackDealloc)
321 return rejectCurrentFunctionInternalError(
322 MF, Mode,
323 Reason: "Cannot pop registers before the stack "
324 "allocation has been deallocated");
325 if (PoppedRegCount > PushedRegs.size())
326 return rejectCurrentFunctionInternalError(
327 MF, Mode,
328 Reason: "The epilog is popping more registers than the prolog "
329 "pushed");
330 if (PushedRegs[PushedRegs.size() - PoppedRegCount] != Reg.id())
331 return rejectCurrentFunctionInternalError(
332 MF, Mode,
333 Reason: "The epilog is popping a registers in "
334 "a different order than the "
335 "prolog pushed them");
336
337 // Unwind v2 records the size of the epilog not from where we place
338 // SEH_BeginEpilogue (as that contains the instruction to adjust the
339 // stack pointer) but from the first POP instruction (if there is
340 // one).
341 if (!UnwindV2StartLocation) {
342 assert(PoppedRegCount == 1);
343 UnwindV2StartLocation = &MI;
344 }
345 }
346 } else if (State == FunctionState::FinishedEpilog)
347 // Unexpected instruction after the epilog.
348 return rejectCurrentFunctionInternalError(
349 MF, Mode, Reason: "Registers are being popped after the epilog");
350 break;
351
352 default:
353 if (MI.isTerminator()) {
354 if (State == FunctionState::FinishedEpilog)
355 // Found the terminator after the epilog, we're now ready for
356 // another epilog.
357 State = FunctionState::HasProlog;
358 else if (State == FunctionState::InEpilog)
359 llvm_unreachable("Terminator in the middle of the epilog");
360 } else if (!MI.isDebugOrPseudoInstr()) {
361 if ((State == FunctionState::FinishedEpilog) ||
362 (State == FunctionState::InEpilog))
363 // Unknown instruction in or after the epilog.
364 return rejectCurrentFunctionInternalError(
365 MF, Mode, Reason: "Unexpected instruction in or after the epilog");
366 }
367 }
368 }
369 }
370
371 return FrameInfo{.ApproximatePrologCodeCount: ApproximatePrologCodeCount, .ApproximateInstructionCount: ApproximateInstructionCount,
372 .EpilogInfos: EpilogInfos};
373}
374
375bool runX86WinEHUnwindV2(MachineFunction &MF) {
376 WinX64EHUnwindV2Mode Mode =
377 ForceMode.getNumOccurrences()
378 ? static_cast<WinX64EHUnwindV2Mode>(ForceMode.getValue())
379 : MF.getFunction().getParent()->getWinX64EHUnwindV2Mode();
380
381 if (Mode == WinX64EHUnwindV2Mode::Disabled)
382 return false;
383
384 // Requested changes.
385 SmallVector<FrameInfo> FrameInfos;
386 MachineFunction::iterator Iter = MF.begin();
387 while (Iter != MF.end()) {
388 auto FI = runAnalysisOnFuncOrFunclet(MF, Iter, Mode);
389 if (!FI)
390 return false;
391 if (!FI->EpilogInfos.empty())
392 FrameInfos.push_back(Elt: std::move(*FI));
393 }
394
395 if (FrameInfos.empty())
396 return false;
397
398 MeetsUnwindV2Criteria++;
399
400 const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
401 for (auto &FI : FrameInfos) {
402 // Walk the list of epilogs backwards and add new SEH pseudo instructions:
403 // * SEH_UnwindV2Start at the start of each epilog.
404 // * If the current instruction is too far away from where the last unwind
405 // info ended OR there are too many unwind codes in the info, then add
406 // SEH_SplitChainedAtEndOfBlock to finish the current info.
407 unsigned LastUnwindInfoEndPosition = FI.ApproximateInstructionCount;
408 unsigned UnwindCodeCount = FI.ApproximatePrologCodeCount + 1;
409 for (auto &Info : llvm::reverse(C&: FI.EpilogInfos)) {
410 MachineBasicBlock &MBB = *Info.UnwindV2StartLocation->getParent();
411 const DebugLoc &DL = Info.UnwindV2StartLocation->getDebugLoc();
412 BuildMI(BB&: MBB, I: Info.UnwindV2StartLocation, MIMD: DL,
413 MCID: TII->get(Opcode: X86::SEH_UnwindV2Start));
414
415 if ((LastUnwindInfoEndPosition - Info.ApproximateInstructionPosition >=
416 InstructionCountThreshold) ||
417 (UnwindCodeCount >= UnwindCodeThreshold)) {
418 BuildMI(BB&: MBB, I: MBB.begin(), MIMD: DL,
419 MCID: TII->get(Opcode: X86::SEH_SplitChainedAtEndOfBlock));
420 LastUnwindInfoEndPosition = Info.ApproximateInstructionPosition;
421 // Doesn't reset to 0, as the prolog unwind codes are now in this info.
422 UnwindCodeCount = FI.ApproximatePrologCodeCount + 1;
423 }
424
425 UnwindCodeCount++;
426 }
427 }
428
429 // Note that the function is using Unwind v2.
430 MachineBasicBlock &FirstMBB = MF.front();
431 BuildMI(BB&: FirstMBB, I&: FirstMBB.front(), MIMD: findDebugLoc(MBB: FirstMBB),
432 MCID: TII->get(Opcode: X86::SEH_UnwindVersion))
433 .addImm(Val: 2);
434
435 return true;
436}
437
438PreservedAnalyses
439X86WinEHUnwindV2Pass::run(MachineFunction &MF,
440 MachineFunctionAnalysisManager &MFAM) {
441 const bool Modified = runX86WinEHUnwindV2(MF);
442 return Modified ? getMachineFunctionPassPreservedAnalyses()
443 .preserveSet<CFGAnalyses>()
444 : PreservedAnalyses::all();
445}
446
447bool X86WinEHUnwindV2Legacy::runOnMachineFunction(MachineFunction &MF) {
448 return runX86WinEHUnwindV2(MF);
449}
450