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