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