LLVM 23.0.0git
X86WinEHUnwindV2.cpp
Go to the documentation of this file.
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
16#include "X86.h"
17#include "llvm/ADT/Statistic.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
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
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.
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(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 X86WinEHUnwindV2 : public MachineFunctionPass {
68public:
69 static char ID;
70
71 X86WinEHUnwindV2() : MachineFunctionPass(ID) {
73 }
74
75 StringRef getPassName() const override { return "WinEH Unwind V2"; }
76
77 bool runOnMachineFunction(MachineFunction &MF) override;
78
79private:
80 /// Rejects the current function due to an internal error within LLVM.
81 static std::nullopt_t rejectCurrentFunctionInternalError(
82 const MachineFunction &MF, WinX64EHUnwindV2Mode Mode, StringRef Reason);
83
84 // Continues running the analysis on the given function or funclet.
85 static std::optional<FrameInfo>
86 runAnalysisOnFuncOrFunclet(MachineFunction &MF,
89};
90
91enum class FunctionState {
92 InProlog,
93 HasProlog,
94 InEpilog,
95 FinishedEpilog,
96};
97
98} // end anonymous namespace
99
100char X86WinEHUnwindV2::ID = 0;
101
102INITIALIZE_PASS(X86WinEHUnwindV2, "x86-wineh-unwindv2",
103 "Analyze and emit instructions for Win64 Unwind v2", false,
104 false)
105
107 return new X86WinEHUnwindV2();
108}
109
111 for (const MachineInstr &MI : MBB)
112 if (MI.getDebugLoc())
113 return MI.getDebugLoc();
114
115 return DebugLoc::getUnknown();
116}
117
118std::optional<FrameInfo>
119X86WinEHUnwindV2::runAnalysisOnFuncOrFunclet(MachineFunction &MF,
122 const TargetFrameLowering &TFL = *MF.getSubtarget().getFrameLowering();
123
124 // Current state of processing the function. We'll assume that all functions
125 // start with a prolog.
126 FunctionState State = FunctionState::InProlog;
127
128 // Prolog information.
129 SmallVector<int64_t> PushedRegs;
130 bool HasStackAlloc = false;
131 bool HasSetFrame = false;
132 unsigned ApproximatePrologCodeCount = 0;
133
134 SmallVector<EpilogInfo> EpilogInfos;
135
136 // Unwind v2 requires that the epilog is no more than 4Kb away from the last
137 // instruction that the current unwind info covers. If we believe that we are
138 // going over that limit then we need to split the unwind info. Ideally we'd
139 // do this at the point where we actually know how far away we are from the
140 // last instruction, but that's not possible here and splitting unwind infos
141 // in MC would be difficult. However, the cost of splitting an unwind info is
142 // fairly cheap (in the other of bytes in the xdata section), so we can
143 // instead use a heuristic based on the number of MachineInstrs to decide when
144 // to split unwind infos, and allow users to tune the threshold if needed.
145 // This is not a perfect solution, but 1) it is cheap to calculate, 2) allows
146 // the common case for small functions or large functions with multiple
147 // returns at the end to have a single unwind info, and 3) allows unwind v2 to
148 // be used in large functions (that would otherwise be rejected) for a small
149 // binary size cost.
150 unsigned ApproximateInstructionCount = 0;
151
152 for (; Iter != MF.end(); ++Iter) {
153 MachineBasicBlock &MBB = *Iter;
154
155 // If we're already been processing a function, then come across a funclet
156 // then break since the funclet will get a fresh frame info.
157 if (MBB.isEHFuncletEntry() && State != FunctionState::InProlog)
158 break;
159
160 // Current epilog information. We assume that epilogs cannot cross basic
161 // block boundaries.
162 unsigned PoppedRegCount = 0;
163 bool HasStackDealloc = false;
164 bool HasSetFrameBack = false;
165 MachineInstr *UnwindV2StartLocation = nullptr;
166
167 for (MachineInstr &MI : MBB) {
168 // This is an *approximation* of the number of instructions that will be
169 // emitted. It is not the actual number of instructions, but that doesn't
170 // matter: see the comment at the declaration of
171 // ApproximateInstructionCount.
172 if (!MI.isPseudo() && !MI.isMetaInstruction())
173 ApproximateInstructionCount++;
174
175 switch (MI.getOpcode()) {
176 //
177 // Prolog handling.
178 //
179 case X86::SEH_PushReg:
180 if (State != FunctionState::InProlog)
181 llvm_unreachable("SEH_PushReg outside of prolog");
182 ApproximatePrologCodeCount++;
183 PushedRegs.push_back(MI.getOperand(0).getImm());
184 break;
185
186 case X86::SEH_StackAlloc:
187 if (State != FunctionState::InProlog)
188 llvm_unreachable("SEH_StackAlloc outside of prolog");
189 // Assume a large alloc...
190 ApproximatePrologCodeCount += 3;
191 HasStackAlloc = true;
192 break;
193
194 case X86::SEH_SetFrame:
195 if (State != FunctionState::InProlog)
196 llvm_unreachable("SEH_SetFrame outside of prolog");
197 ApproximatePrologCodeCount++;
198 HasSetFrame = true;
199 break;
200
201 case X86::SEH_SaveReg:
202 case X86::SEH_SaveXMM:
203 if (State != FunctionState::InProlog)
204 llvm_unreachable("SEH_SaveXMM or SEH_SaveReg outside of prolog");
205 // Assume a big reg...
206 ApproximatePrologCodeCount += 3;
207 break;
208
209 case X86::SEH_PushFrame:
210 if (State != FunctionState::InProlog)
211 llvm_unreachable("SEH_PushFrame outside of prolog");
212 ApproximatePrologCodeCount++;
213 break;
214
215 case X86::SEH_EndPrologue:
216 if (State != FunctionState::InProlog)
217 llvm_unreachable("SEH_EndPrologue outside of prolog");
218 State = FunctionState::HasProlog;
219 break;
220
221 //
222 // Epilog handling.
223 //
224 case X86::SEH_BeginEpilogue:
225 if (State != FunctionState::HasProlog)
226 llvm_unreachable("SEH_BeginEpilogue in prolog or another epilog");
227 State = FunctionState::InEpilog;
228 break;
229
230 case X86::SEH_EndEpilogue:
231 if (State != FunctionState::InEpilog)
232 llvm_unreachable("SEH_EndEpilogue outside of epilog");
233 if (HasStackAlloc != HasStackDealloc)
234 return rejectCurrentFunctionInternalError(
235 MF, Mode,
236 "The prolog made a stack allocation, "
237 "but the epilog did not deallocate it");
238 if (PoppedRegCount != PushedRegs.size())
239 return rejectCurrentFunctionInternalError(
240 MF, Mode,
241 "The prolog pushed more registers than "
242 "the epilog popped");
243
244 // If we didn't find the start location, then use the end of the
245 // epilog.
246 if (!UnwindV2StartLocation)
247 UnwindV2StartLocation = &MI;
248 EpilogInfos.push_back(
249 {UnwindV2StartLocation, ApproximateInstructionCount});
250 State = FunctionState::FinishedEpilog;
251 break;
252
253 case X86::MOV64rr:
254 if (State == FunctionState::InEpilog) {
255 // If the prolog contains a stack allocation, then the first
256 // instruction in the epilog must be to adjust the stack pointer.
257 if (!HasSetFrame)
258 return rejectCurrentFunctionInternalError(
259 MF, Mode,
260 "The epilog is setting frame back, but prolog did not set it");
261 if (PoppedRegCount > 0)
262 return rejectCurrentFunctionInternalError(
263 MF, Mode,
264 "The epilog is setting the frame back after popping "
265 "registers");
266 if (HasStackDealloc)
267 return rejectCurrentFunctionInternalError(
268 MF, Mode,
269 "Cannot set the frame back after the stack "
270 "allocation has been deallocated");
271 HasSetFrameBack = true;
272 } else if (State == FunctionState::FinishedEpilog)
273 return rejectCurrentFunctionInternalError(
274 MF, Mode, "Unexpected mov instruction after the epilog");
275 break;
276
277 case X86::LEA64r:
278 case X86::ADD64ri32:
279 if (State == FunctionState::InEpilog) {
280 // If the prolog contains a stack allocation, then the first
281 // instruction in the epilog must be to adjust the stack pointer.
282 if (!HasStackAlloc)
283 return rejectCurrentFunctionInternalError(
284 MF, Mode,
285 "The epilog is deallocating a stack "
286 "allocation, but the prolog did "
287 "not allocate one");
288 if (PoppedRegCount > 0)
289 return rejectCurrentFunctionInternalError(
290 MF, Mode,
291 "The epilog is deallocating a stack allocation after popping "
292 "registers");
293
294 HasStackDealloc = true;
295 } else if (State == FunctionState::FinishedEpilog)
296 return rejectCurrentFunctionInternalError(
297 MF, Mode, "Unexpected lea or add instruction after the epilog");
298 break;
299
300 case X86::POP64r:
301 if (State == FunctionState::InEpilog) {
302 Register Reg = MI.getOperand(0).getReg();
303 if (HasStackAlloc && (PoppedRegCount == 0) &&
304 !llvm::is_contained(PushedRegs, Reg)) {
305 // If this is a pop that doesn't correspond to the set of pushed
306 // registers, then assume it was used to adjust the stack pointer.
307 HasStackDealloc = true;
308 } else {
309 // Special case: no explicit stack dealloc is required if SetFrame
310 // was used and the function has a frame pointer.
311 if (PoppedRegCount == 0 && HasStackAlloc && !HasStackDealloc &&
312 HasSetFrameBack && TFL.hasFP(MF))
313 HasStackDealloc = true;
314
315 // After the stack pointer has been adjusted, the epilog must
316 // POP each register in reverse order of the PUSHes in the prolog.
317 PoppedRegCount++;
318 if (HasStackAlloc != HasStackDealloc)
319 return rejectCurrentFunctionInternalError(
320 MF, Mode,
321 "Cannot pop registers before the stack "
322 "allocation has been deallocated");
323 if (PoppedRegCount > PushedRegs.size())
324 return rejectCurrentFunctionInternalError(
325 MF, Mode,
326 "The epilog is popping more registers than the prolog "
327 "pushed");
328 if (PushedRegs[PushedRegs.size() - PoppedRegCount] != Reg.id())
329 return rejectCurrentFunctionInternalError(
330 MF, Mode,
331 "The epilog is popping a registers in "
332 "a different order than the "
333 "prolog pushed them");
334
335 // Unwind v2 records the size of the epilog not from where we place
336 // SEH_BeginEpilogue (as that contains the instruction to adjust the
337 // stack pointer) but from the first POP instruction (if there is
338 // one).
339 if (!UnwindV2StartLocation) {
340 assert(PoppedRegCount == 1);
341 UnwindV2StartLocation = &MI;
342 }
343 }
344 } else if (State == FunctionState::FinishedEpilog)
345 // Unexpected instruction after the epilog.
346 return rejectCurrentFunctionInternalError(
347 MF, Mode, "Registers are being popped after the epilog");
348 break;
349
350 default:
351 if (MI.isTerminator()) {
352 if (State == FunctionState::FinishedEpilog)
353 // Found the terminator after the epilog, we're now ready for
354 // another epilog.
355 State = FunctionState::HasProlog;
356 else if (State == FunctionState::InEpilog)
357 llvm_unreachable("Terminator in the middle of the epilog");
358 } else if (!MI.isDebugOrPseudoInstr()) {
359 if ((State == FunctionState::FinishedEpilog) ||
360 (State == FunctionState::InEpilog))
361 // Unknown instruction in or after the epilog.
362 return rejectCurrentFunctionInternalError(
363 MF, Mode, "Unexpected instruction in or after the epilog");
364 }
365 }
366 }
367 }
368
369 return FrameInfo{ApproximatePrologCodeCount, ApproximateInstructionCount,
370 EpilogInfos};
371}
372
373bool X86WinEHUnwindV2::runOnMachineFunction(MachineFunction &MF) {
375 ForceMode.getNumOccurrences()
376 ? static_cast<WinX64EHUnwindV2Mode>(ForceMode.getValue())
378
379 if (Mode == WinX64EHUnwindV2Mode::Disabled)
380 return false;
381
382 // Requested changes.
383 SmallVector<FrameInfo> FrameInfos;
385 while (Iter != MF.end()) {
386 auto FI = runAnalysisOnFuncOrFunclet(MF, Iter, Mode);
387 if (!FI)
388 return false;
389 if (!FI->EpilogInfos.empty())
390 FrameInfos.push_back(std::move(*FI));
391 }
392
393 if (FrameInfos.empty())
394 return false;
395
396 MeetsUnwindV2Criteria++;
397
398 const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
399 for (auto &FI : FrameInfos) {
400 // Walk the list of epilogs backwards and add new SEH pseudo instructions:
401 // * SEH_UnwindV2Start at the start of each epilog.
402 // * If the current instruction is too far away from where the last unwind
403 // info ended OR there are too many unwind codes in the info, then add
404 // SEH_SplitChainedAtEndOfBlock to finish the current info.
405 unsigned LastUnwindInfoEndPosition = FI.ApproximateInstructionCount;
406 unsigned UnwindCodeCount = FI.ApproximatePrologCodeCount + 1;
407 for (auto &Info : llvm::reverse(FI.EpilogInfos)) {
408 MachineBasicBlock &MBB = *Info.UnwindV2StartLocation->getParent();
409 const DebugLoc &DL = Info.UnwindV2StartLocation->getDebugLoc();
410 BuildMI(MBB, Info.UnwindV2StartLocation, DL,
411 TII->get(X86::SEH_UnwindV2Start));
412
413 if ((LastUnwindInfoEndPosition - Info.ApproximateInstructionPosition >=
415 (UnwindCodeCount >= UnwindCodeThreshold)) {
416 BuildMI(MBB, MBB.begin(), DL,
417 TII->get(X86::SEH_SplitChainedAtEndOfBlock));
418 LastUnwindInfoEndPosition = Info.ApproximateInstructionPosition;
419 // Doesn't reset to 0, as the prolog unwind codes are now in this info.
420 UnwindCodeCount = FI.ApproximatePrologCodeCount + 1;
421 }
422
423 UnwindCodeCount++;
424 }
425 }
426
427 // Note that the function is using Unwind v2.
428 MachineBasicBlock &FirstMBB = MF.front();
429 BuildMI(FirstMBB, FirstMBB.front(), findDebugLoc(FirstMBB),
430 TII->get(X86::SEH_UnwindVersion))
431 .addImm(2);
432
433 return true;
434}
435
436std::nullopt_t X86WinEHUnwindV2::rejectCurrentFunctionInternalError(
437 const MachineFunction &MF, WinX64EHUnwindV2Mode Mode, StringRef Reason) {
438 if (Mode == WinX64EHUnwindV2Mode::Required)
439 reportFatalInternalError("Windows x64 Unwind v2 is required, but LLVM has "
440 "generated incompatible code in function '" +
441 MF.getName() + "': " + Reason);
442
443 FailsUnwindV2Criteria++;
444 return std::nullopt;
445}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
Module.h This file contains the declarations for the Module class.
Register Reg
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
static cl::opt< RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode > Mode("regalloc-enable-advisor", cl::Hidden, cl::init(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default), cl::desc("Enable regalloc advisor mode"), cl::values(clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default, "default", "Default"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Release, "release", "precompiled"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Development, "development", "for training")))
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
static cl::opt< unsigned > UnwindCodeThreshold("x86-wineh-unwindv2-unwind-codes-threshold", cl::Hidden, cl::desc("Maximum number of unwind codes before " "splitting into a new unwind info."), cl::init(UINT8_MAX))
static cl::opt< unsigned > InstructionCountThreshold("x86-wineh-unwindv2-instruction-count-threshold", cl::Hidden, cl::desc("Maximum number of (approximate) instructions before splitting " "into a new unwind info."), cl::init(600))
DebugLoc findDebugLoc(const MachineBasicBlock &MBB)
static cl::opt< unsigned > ForceMode("x86-wineh-unwindv2-force-mode", cl::Hidden, cl::desc("Overwrites the Unwind v2 mode for testing purposes."))
A debug info location.
Definition DebugLoc.h:123
static DebugLoc getUnknown()
Definition DebugLoc.h:161
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
Module * getParent()
Get the module that this global value is contained inside of...
bool isEHFuncletEntry() const
Returns true if this is the entry block of an EH funclet.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
Function & getFunction()
Return the LLVM function that this machine code represents.
BasicBlockListType::iterator iterator
const MachineBasicBlock & front() const
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
Representation of each machine instruction.
WinX64EHUnwindV2Mode getWinX64EHUnwindV2Mode() const
Get how unwind v2 (epilog) information should be generated for x64 Windows.
Definition Module.cpp:937
static LLVM_ABI PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
constexpr unsigned id() const
Definition Register.h:100
void push_back(const T &Elt)
bool hasFP(const MachineFunction &MF) const
hasFP - Return true if the specified function should have a dedicated frame pointer register.
virtual const TargetFrameLowering * getFrameLowering() const
virtual const TargetInstrInfo * getInstrInfo() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
LLVM_ABI void reportFatalInternalError(Error Err)
Report a fatal error that indicates a bug in LLVM.
Definition Error.cpp:173
auto reverse(ContainerTy &&C)
Definition STLExtras.h:406
void initializeX86WinEHUnwindV2Pass(PassRegistry &)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
FunctionPass * createX86WinEHUnwindV2Pass()
// Analyzes and emits pseudos to support Win x64 Unwind V2.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1945
WinX64EHUnwindV2Mode
Definition CodeGen.h:167