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 X86WinEHUnwindV2Legacy : public MachineFunctionPass {
68public:
69 static char ID;
70
71 X86WinEHUnwindV2Legacy() : MachineFunctionPass(ID) {
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,
83 StringRef Reason) {
85 reportFatalInternalError("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
109 return new X86WinEHUnwindV2Legacy();
110}
111
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>
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(MI.getOperand(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 "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 "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 {UnwindV2StartLocation, 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 "The epilog is setting frame back, but prolog did not set it");
263 if (PoppedRegCount > 0)
264 return rejectCurrentFunctionInternalError(
265 MF, Mode,
266 "The epilog is setting the frame back after popping "
267 "registers");
268 if (HasStackDealloc)
269 return rejectCurrentFunctionInternalError(
270 MF, Mode,
271 "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, "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 "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 "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, "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(0).getReg();
305 if (HasStackAlloc && (PoppedRegCount == 0) &&
306 !llvm::is_contained(PushedRegs, 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 "Cannot pop registers before the stack "
324 "allocation has been deallocated");
325 if (PoppedRegCount > PushedRegs.size())
326 return rejectCurrentFunctionInternalError(
327 MF, Mode,
328 "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 "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, "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, "Unexpected instruction in or after the epilog");
366 }
367 }
368 }
369 }
370
371 return FrameInfo{ApproximatePrologCodeCount, ApproximateInstructionCount,
372 EpilogInfos};
373}
374
377 ForceMode.getNumOccurrences()
378 ? static_cast<WinX64EHUnwindV2Mode>(ForceMode.getValue())
380
382 return false;
383
384 // Requested changes.
385 SmallVector<FrameInfo> FrameInfos;
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(std::move(*FI));
393 }
394
395 if (FrameInfos.empty())
396 return false;
397
398 MeetsUnwindV2Criteria++;
399
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(FI.EpilogInfos)) {
410 MachineBasicBlock &MBB = *Info.UnwindV2StartLocation->getParent();
411 const DebugLoc &DL = Info.UnwindV2StartLocation->getDebugLoc();
412 BuildMI(MBB, Info.UnwindV2StartLocation, DL,
413 TII->get(X86::SEH_UnwindV2Start));
414
415 if ((LastUnwindInfoEndPosition - Info.ApproximateInstructionPosition >=
417 (UnwindCodeCount >= UnwindCodeThreshold)) {
418 BuildMI(MBB, MBB.begin(), DL,
419 TII->get(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(FirstMBB, FirstMBB.front(), findDebugLoc(FirstMBB),
432 TII->get(X86::SEH_UnwindVersion))
433 .addImm(2);
434
435 return true;
436}
437
446
447bool X86WinEHUnwindV2Legacy::runOnMachineFunction(MachineFunction &MF) {
448 return runX86WinEHUnwindV2(MF);
449}
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
#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))
std::optional< FrameInfo > runAnalysisOnFuncOrFunclet(MachineFunction &MF, MachineFunction::iterator &Iter, WinX64EHUnwindV2Mode Mode)
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."))
bool runX86WinEHUnwindV2(MachineFunction &MF)
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
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...
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...
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Definition Analysis.h:151
Wrapper class representing virtual and physical registers.
Definition Register.h:20
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
Information about stack frame layout on the target.
bool hasFP(const MachineFunction &MF) const
hasFP - Return true if the specified function should have a dedicated frame pointer register.
TargetInstrInfo - Interface to description of machine instruction set.
virtual const TargetFrameLowering * getFrameLowering() const
virtual const TargetInstrInfo * getInstrInfo() const
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
#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.
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI void reportFatalInternalError(Error Err)
Report a fatal error that indicates a bug in LLVM.
Definition Error.cpp:173
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
auto reverse(ContainerTy &&C)
Definition STLExtras.h:408
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1947
FunctionPass * createX86WinEHUnwindV2LegacyPass()
WinX64EHUnwindV2Mode
Definition CodeGen.h:167
void initializeX86WinEHUnwindV2LegacyPass(PassRegistry &)