LLVM 22.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"
24#include "llvm/IR/Module.h"
25
26using namespace llvm;
27
28#define DEBUG_TYPE "x86-wineh-unwindv2"
29
30STATISTIC(MeetsUnwindV2Criteria,
31 "Number of functions that meet Unwind v2 criteria");
32STATISTIC(FailsUnwindV2Criteria,
33 "Number of functions that fail Unwind v2 criteria");
34
36 "x86-wineh-unwindv2-max-unwind-codes", cl::Hidden,
37 cl::desc("Maximum number of unwind codes permitted in each unwind info."),
38 cl::init(UINT8_MAX));
39
41 ForceMode("x86-wineh-unwindv2-force-mode", cl::Hidden,
42 cl::desc("Overwrites the Unwind v2 mode for testing purposes."));
43
44namespace {
45
46class X86WinEHUnwindV2 : public MachineFunctionPass {
47public:
48 static char ID;
49
50 X86WinEHUnwindV2() : MachineFunctionPass(ID) {
52 }
53
54 StringRef getPassName() const override { return "WinEH Unwind V2"; }
55
56 bool runOnMachineFunction(MachineFunction &MF) override;
57
58private:
59 /// Rejects the current function due to an internal error within LLVM.
60 static bool rejectCurrentFunctionInternalError(const MachineFunction &MF,
62 StringRef Reason);
63};
64
65enum class FunctionState {
66 InProlog,
67 HasProlog,
68 InEpilog,
69 FinishedEpilog,
70};
71
72} // end anonymous namespace
73
74char X86WinEHUnwindV2::ID = 0;
75
76INITIALIZE_PASS(X86WinEHUnwindV2, "x86-wineh-unwindv2",
77 "Analyze and emit instructions for Win64 Unwind v2", false,
78 false)
79
81 return new X86WinEHUnwindV2();
82}
83
85 for (const MachineInstr &MI : MBB)
86 if (MI.getDebugLoc())
87 return MI.getDebugLoc();
88
89 return DebugLoc::getUnknown();
90}
91
92bool X86WinEHUnwindV2::runOnMachineFunction(MachineFunction &MF) {
94 ForceMode.getNumOccurrences()
95 ? static_cast<WinX64EHUnwindV2Mode>(ForceMode.getValue())
97
98 if (Mode == WinX64EHUnwindV2Mode::Disabled)
99 return false;
100
101 // Current state of processing the function. We'll assume that all functions
102 // start with a prolog.
103 FunctionState State = FunctionState::InProlog;
104
105 // Prolog information.
106 SmallVector<int64_t> PushedRegs;
107 bool HasStackAlloc = false;
108 bool HasSetFrame = false;
109 unsigned ApproximatePrologCodeCount = 0;
110
111 // Requested changes.
112 SmallVector<MachineInstr *> UnwindV2StartLocations;
113
114 for (MachineBasicBlock &MBB : MF) {
115 // Current epilog information. We assume that epilogs cannot cross basic
116 // block boundaries.
117 unsigned PoppedRegCount = 0;
118 bool HasStackDealloc = false;
119 MachineInstr *UnwindV2StartLocation = nullptr;
120
121 for (MachineInstr &MI : MBB) {
122 switch (MI.getOpcode()) {
123 //
124 // Prolog handling.
125 //
126 case X86::SEH_PushReg:
127 if (State != FunctionState::InProlog)
128 llvm_unreachable("SEH_PushReg outside of prolog");
129 ApproximatePrologCodeCount++;
130 PushedRegs.push_back(MI.getOperand(0).getImm());
131 break;
132
133 case X86::SEH_StackAlloc:
134 if (State != FunctionState::InProlog)
135 llvm_unreachable("SEH_StackAlloc outside of prolog");
136 // Assume a large alloc...
137 ApproximatePrologCodeCount += 3;
138 HasStackAlloc = true;
139 break;
140
141 case X86::SEH_SetFrame:
142 if (State != FunctionState::InProlog)
143 llvm_unreachable("SEH_SetFrame outside of prolog");
144 ApproximatePrologCodeCount++;
145 HasSetFrame = true;
146 break;
147
148 case X86::SEH_SaveReg:
149 case X86::SEH_SaveXMM:
150 if (State != FunctionState::InProlog)
151 llvm_unreachable("SEH_SaveXMM or SEH_SaveReg outside of prolog");
152 // Assume a big reg...
153 ApproximatePrologCodeCount += 3;
154 break;
155
156 case X86::SEH_PushFrame:
157 if (State != FunctionState::InProlog)
158 llvm_unreachable("SEH_PushFrame outside of prolog");
159 ApproximatePrologCodeCount++;
160 break;
161
162 case X86::SEH_EndPrologue:
163 if (State != FunctionState::InProlog)
164 llvm_unreachable("SEH_EndPrologue outside of prolog");
165 State = FunctionState::HasProlog;
166 break;
167
168 //
169 // Epilog handling.
170 //
171 case X86::SEH_BeginEpilogue:
172 if (State != FunctionState::HasProlog)
173 llvm_unreachable("SEH_BeginEpilogue in prolog or another epilog");
174 State = FunctionState::InEpilog;
175 break;
176
177 case X86::SEH_EndEpilogue:
178 if (State != FunctionState::InEpilog)
179 llvm_unreachable("SEH_EndEpilogue outside of epilog");
180 if (HasStackAlloc != HasStackDealloc)
181 return rejectCurrentFunctionInternalError(
182 MF, Mode,
183 "The prolog made a stack allocation, "
184 "but the epilog did not deallocate it");
185 if (PoppedRegCount != PushedRegs.size())
186 return rejectCurrentFunctionInternalError(
187 MF, Mode,
188 "The prolog pushed more registers than "
189 "the epilog popped");
190
191 // If we didn't find the start location, then use the end of the
192 // epilog.
193 if (!UnwindV2StartLocation)
194 UnwindV2StartLocation = &MI;
195 UnwindV2StartLocations.push_back(UnwindV2StartLocation);
196 State = FunctionState::FinishedEpilog;
197 break;
198
199 case X86::MOV64rr:
200 if (State == FunctionState::InEpilog) {
201 // If the prolog contains a stack allocation, then the first
202 // instruction in the epilog must be to adjust the stack pointer.
203 if (!HasSetFrame)
204 return rejectCurrentFunctionInternalError(
205 MF, Mode,
206 "The epilog is setting frame back, but prolog did not set it");
207 if (PoppedRegCount > 0)
208 return rejectCurrentFunctionInternalError(
209 MF, Mode,
210 "The epilog is setting the frame back after popping "
211 "registers");
212 if (HasStackDealloc)
213 return rejectCurrentFunctionInternalError(
214 MF, Mode,
215 "Cannot set the frame back after the stack "
216 "allocation has been deallocated");
217 } else if (State == FunctionState::FinishedEpilog)
218 return rejectCurrentFunctionInternalError(
219 MF, Mode, "Unexpected mov instruction after the epilog");
220 break;
221
222 case X86::LEA64r:
223 case X86::ADD64ri32:
224 if (State == FunctionState::InEpilog) {
225 // If the prolog contains a stack allocation, then the first
226 // instruction in the epilog must be to adjust the stack pointer.
227 if (!HasStackAlloc)
228 return rejectCurrentFunctionInternalError(
229 MF, Mode,
230 "The epilog is deallocating a stack "
231 "allocation, but the prolog did "
232 "not allocate one");
233 if (PoppedRegCount > 0)
234 return rejectCurrentFunctionInternalError(
235 MF, Mode,
236 "The epilog is deallocating a stack allocation after popping "
237 "registers");
238
239 HasStackDealloc = true;
240 } else if (State == FunctionState::FinishedEpilog)
241 return rejectCurrentFunctionInternalError(
242 MF, Mode, "Unexpected lea or add instruction after the epilog");
243 break;
244
245 case X86::POP64r:
246 if (State == FunctionState::InEpilog) {
247 Register Reg = MI.getOperand(0).getReg();
248 if (HasStackAlloc && (PoppedRegCount == 0) &&
249 !llvm::is_contained(PushedRegs, Reg)) {
250 // If this is a pop that doesn't correspond to the set of pushed
251 // registers, then assume it was used to adjust the stack pointer.
252 HasStackDealloc = true;
253 } else {
254 // After the stack pointer has been adjusted, the epilog must
255 // POP each register in reverse order of the PUSHes in the prolog.
256 PoppedRegCount++;
257 if (HasStackAlloc != HasStackDealloc)
258 return rejectCurrentFunctionInternalError(
259 MF, Mode,
260 "Cannot pop registers before the stack "
261 "allocation has been deallocated");
262 if (PoppedRegCount > PushedRegs.size())
263 return rejectCurrentFunctionInternalError(
264 MF, Mode,
265 "The epilog is popping more registers than the prolog "
266 "pushed");
267 if (PushedRegs[PushedRegs.size() - PoppedRegCount] != Reg.id())
268 return rejectCurrentFunctionInternalError(
269 MF, Mode,
270 "The epilog is popping a registers in "
271 "a different order than the "
272 "prolog pushed them");
273
274 // Unwind v2 records the size of the epilog not from where we place
275 // SEH_BeginEpilogue (as that contains the instruction to adjust the
276 // stack pointer) but from the first POP instruction (if there is
277 // one).
278 if (!UnwindV2StartLocation) {
279 assert(PoppedRegCount == 1);
280 UnwindV2StartLocation = &MI;
281 }
282 }
283 } else if (State == FunctionState::FinishedEpilog)
284 // Unexpected instruction after the epilog.
285 return rejectCurrentFunctionInternalError(
286 MF, Mode, "Registers are being popped after the epilog");
287 break;
288
289 default:
290 if (MI.isTerminator()) {
291 if (State == FunctionState::FinishedEpilog)
292 // Found the terminator after the epilog, we're now ready for
293 // another epilog.
294 State = FunctionState::HasProlog;
295 else if (State == FunctionState::InEpilog)
296 llvm_unreachable("Terminator in the middle of the epilog");
297 } else if (!MI.isDebugOrPseudoInstr()) {
298 if ((State == FunctionState::FinishedEpilog) ||
299 (State == FunctionState::InEpilog))
300 // Unknown instruction in or after the epilog.
301 return rejectCurrentFunctionInternalError(
302 MF, Mode, "Unexpected instruction in or after the epilog");
303 }
304 }
305 }
306 }
307
308 if (UnwindV2StartLocations.empty())
309 return false;
310
311 MachineBasicBlock &FirstMBB = MF.front();
312 // Assume +1 for the "header" UOP_Epilog that contains the epilog size, and
313 // that we won't be able to use the "last epilog at the end of function"
314 // optimization.
315 if (ApproximatePrologCodeCount + UnwindV2StartLocations.size() + 1 >
316 static_cast<unsigned>(MaximumUnwindCodes)) {
317 if (Mode == WinX64EHUnwindV2Mode::Required)
318 MF.getFunction().getContext().diagnose(DiagnosticInfoGenericWithLoc(
319 "Windows x64 Unwind v2 is required, but the function '" +
320 MF.getName() +
321 "' has too many unwind codes. Try splitting the function or "
322 "reducing the number of places where it exits early with a tail "
323 "call.",
324 MF.getFunction(), findDebugLoc(FirstMBB)));
325
326 FailsUnwindV2Criteria++;
327 return false;
328 }
329
330 MeetsUnwindV2Criteria++;
331
332 // Emit the pseudo instruction that marks the start of each epilog.
333 const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
334 for (MachineInstr *MI : UnwindV2StartLocations) {
335 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
336 TII->get(X86::SEH_UnwindV2Start));
337 }
338 // Note that the function is using Unwind v2.
339 BuildMI(FirstMBB, FirstMBB.front(), findDebugLoc(FirstMBB),
340 TII->get(X86::SEH_UnwindVersion))
341 .addImm(2);
342
343 return true;
344}
345
346bool X86WinEHUnwindV2::rejectCurrentFunctionInternalError(
347 const MachineFunction &MF, WinX64EHUnwindV2Mode Mode, StringRef Reason) {
348 if (Mode == WinX64EHUnwindV2Mode::Required)
349 reportFatalInternalError("Windows x64 Unwind v2 is required, but LLVM has "
350 "generated incompatible code in function '" +
351 MF.getName() + "': " + Reason);
352
353 FailsUnwindV2Criteria++;
354 return false;
355}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock & MBB
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
Module.h This file contains the declarations for the Module class.
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:56
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:167
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."))
static cl::opt< unsigned > MaximumUnwindCodes("x86-wineh-unwindv2-max-unwind-codes", cl::Hidden, cl::desc("Maximum number of unwind codes permitted in each unwind info."), cl::init(UINT8_MAX))
A debug info location.
Definition: DebugLoc.h:124
static DebugLoc getUnknown()
Definition: DebugLoc.h:162
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...
Definition: GlobalValue.h:663
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
Representation of each machine instruction.
Definition: MachineInstr.h:72
WinX64EHUnwindV2Mode getWinX64EHUnwindV2Mode() const
Get how unwind v2 (epilog) information should be generated for x64 Windows.
Definition: Module.cpp:925
static LLVM_ABI PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Definition: Pass.cpp:85
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
bool empty() const
Definition: SmallVector.h:82
size_t size() const
Definition: SmallVector.h:79
void push_back(const T &Elt)
Definition: SmallVector.h:414
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:55
TargetInstrInfo - Interface to description of machine instruction set.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
Reg
All possible values of the reg field in the ModR/M byte.
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:444
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
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:177
void initializeX86WinEHUnwindV2Pass(PassRegistry &)
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:1916
WinX64EHUnwindV2Mode
Definition: CodeGen.h:161