28#define DEBUG_TYPE "x86-wineh-unwindv2"
31 "Number of functions that meet Unwind v2 criteria");
33 "Number of functions that fail Unwind v2 criteria");
36 "x86-wineh-unwindv2-max-unwind-codes",
cl::Hidden,
37 cl::desc(
"Maximum number of unwind codes permitted in each unwind info."),
42 cl::desc(
"Overwrites the Unwind v2 mode for testing purposes."));
54 StringRef getPassName()
const override {
return "WinEH Unwind V2"; }
56 bool runOnMachineFunction(MachineFunction &MF)
override;
60 static bool rejectCurrentFunctionInternalError(
const MachineFunction &MF,
65enum class FunctionState {
74char X86WinEHUnwindV2::ID = 0;
77 "Analyze and emit instructions for Win64 Unwind v2",
false,
81 return new X86WinEHUnwindV2();
87 return MI.getDebugLoc();
98 if (
Mode == WinX64EHUnwindV2Mode::Disabled)
103 FunctionState State = FunctionState::InProlog;
107 bool HasStackAlloc =
false;
108 bool HasSetFrame =
false;
109 unsigned ApproximatePrologCodeCount = 0;
114 for (MachineBasicBlock &
MBB : MF) {
117 unsigned PoppedRegCount = 0;
118 bool HasStackDealloc =
false;
119 MachineInstr *UnwindV2StartLocation =
nullptr;
121 for (MachineInstr &
MI :
MBB) {
122 switch (
MI.getOpcode()) {
126 case X86::SEH_PushReg:
127 if (State != FunctionState::InProlog)
129 ApproximatePrologCodeCount++;
133 case X86::SEH_StackAlloc:
134 if (State != FunctionState::InProlog)
137 ApproximatePrologCodeCount += 3;
138 HasStackAlloc =
true;
141 case X86::SEH_SetFrame:
142 if (State != FunctionState::InProlog)
144 ApproximatePrologCodeCount++;
148 case X86::SEH_SaveReg:
149 case X86::SEH_SaveXMM:
150 if (State != FunctionState::InProlog)
153 ApproximatePrologCodeCount += 3;
156 case X86::SEH_PushFrame:
157 if (State != FunctionState::InProlog)
159 ApproximatePrologCodeCount++;
162 case X86::SEH_EndPrologue:
163 if (State != FunctionState::InProlog)
165 State = FunctionState::HasProlog;
171 case X86::SEH_BeginEpilogue:
172 if (State != FunctionState::HasProlog)
174 State = FunctionState::InEpilog;
177 case X86::SEH_EndEpilogue:
178 if (State != FunctionState::InEpilog)
180 if (HasStackAlloc != HasStackDealloc)
181 return rejectCurrentFunctionInternalError(
183 "The prolog made a stack allocation, "
184 "but the epilog did not deallocate it");
185 if (PoppedRegCount != PushedRegs.
size())
186 return rejectCurrentFunctionInternalError(
188 "The prolog pushed more registers than "
189 "the epilog popped");
193 if (!UnwindV2StartLocation)
194 UnwindV2StartLocation = &
MI;
195 UnwindV2StartLocations.
push_back(UnwindV2StartLocation);
196 State = FunctionState::FinishedEpilog;
200 if (State == FunctionState::InEpilog) {
204 return rejectCurrentFunctionInternalError(
206 "The epilog is setting frame back, but prolog did not set it");
207 if (PoppedRegCount > 0)
208 return rejectCurrentFunctionInternalError(
210 "The epilog is setting the frame back after popping "
213 return rejectCurrentFunctionInternalError(
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");
224 if (State == FunctionState::InEpilog) {
228 return rejectCurrentFunctionInternalError(
230 "The epilog is deallocating a stack "
231 "allocation, but the prolog did "
233 if (PoppedRegCount > 0)
234 return rejectCurrentFunctionInternalError(
236 "The epilog is deallocating a stack allocation after popping "
239 HasStackDealloc =
true;
240 }
else if (State == FunctionState::FinishedEpilog)
241 return rejectCurrentFunctionInternalError(
242 MF,
Mode,
"Unexpected lea or add instruction after the epilog");
246 if (State == FunctionState::InEpilog) {
248 if (HasStackAlloc && (PoppedRegCount == 0) &&
252 HasStackDealloc =
true;
257 if (HasStackAlloc != HasStackDealloc)
258 return rejectCurrentFunctionInternalError(
260 "Cannot pop registers before the stack "
261 "allocation has been deallocated");
262 if (PoppedRegCount > PushedRegs.
size())
263 return rejectCurrentFunctionInternalError(
265 "The epilog is popping more registers than the prolog "
267 if (PushedRegs[PushedRegs.
size() - PoppedRegCount] !=
Reg.
id())
268 return rejectCurrentFunctionInternalError(
270 "The epilog is popping a registers in "
271 "a different order than the "
272 "prolog pushed them");
278 if (!UnwindV2StartLocation) {
279 assert(PoppedRegCount == 1);
280 UnwindV2StartLocation = &
MI;
283 }
else if (State == FunctionState::FinishedEpilog)
285 return rejectCurrentFunctionInternalError(
286 MF,
Mode,
"Registers are being popped after the epilog");
290 if (
MI.isTerminator()) {
291 if (State == FunctionState::FinishedEpilog)
294 State = FunctionState::HasProlog;
295 else if (State == FunctionState::InEpilog)
297 }
else if (!
MI.isDebugOrPseudoInstr()) {
298 if ((State == FunctionState::FinishedEpilog) ||
299 (State == FunctionState::InEpilog))
301 return rejectCurrentFunctionInternalError(
302 MF,
Mode,
"Unexpected instruction in or after the epilog");
308 if (UnwindV2StartLocations.
empty())
311 MachineBasicBlock &FirstMBB = MF.front();
315 if (ApproximatePrologCodeCount + UnwindV2StartLocations.
size() + 1 >
317 if (
Mode == WinX64EHUnwindV2Mode::Required)
318 MF.getFunction().getContext().diagnose(DiagnosticInfoGenericWithLoc(
319 "Windows x64 Unwind v2 is required, but the function '" +
321 "' has too many unwind codes. Try splitting the function or "
322 "reducing the number of places where it exits early with a tail "
326 FailsUnwindV2Criteria++;
330 MeetsUnwindV2Criteria++;
333 const TargetInstrInfo *
TII = MF.getSubtarget().getInstrInfo();
334 for (MachineInstr *
MI : UnwindV2StartLocations) {
336 TII->get(X86::SEH_UnwindV2Start));
340 TII->get(X86::SEH_UnwindVersion))
346bool X86WinEHUnwindV2::rejectCurrentFunctionInternalError(
348 if (
Mode == WinX64EHUnwindV2Mode::Required)
350 "generated incompatible code in function '" +
351 MF.
getName() +
"': " + Reason);
353 FailsUnwindV2Criteria++;
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
const HexagonInstrInfo * TII
Module.h This file contains the declarations for the Module class.
Promote Memory to Register
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
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)
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))
static DebugLoc getUnknown()
FunctionPass class - This class is used to implement most global optimizations.
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...
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.
WinX64EHUnwindV2Mode getWinX64EHUnwindV2Mode() const
Get how unwind v2 (epilog) information should be generated for x64 Windows.
static LLVM_ABI PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
constexpr unsigned id() const
void push_back(const T &Elt)
#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.
initializer< Ty > init(const Ty &Val)
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.
LLVM_ABI void reportFatalInternalError(Error Err)
Report a fatal error that indicates a bug in LLVM.
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.