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."));
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;
117 unsigned PoppedRegCount = 0;
118 bool HasStackDealloc =
false;
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())
315 if (ApproximatePrologCodeCount + UnwindV2StartLocations.
size() + 1 >
317 if (Mode == WinX64EHUnwindV2Mode::Required)
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++;
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.
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
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...
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.
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...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Wrapper class representing virtual and physical registers.
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.
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.
Reg
All possible values of the reg field in the ModR/M byte.
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 &)
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.