29#define DEBUG_TYPE "x86-wineh-unwindv2"
32 "Number of functions that meet Unwind v2 criteria");
34 "Number of functions that fail Unwind v2 criteria");
38 cl::desc(
"Maximum number of unwind codes before "
39 "splitting into a new unwind info."),
44 cl::desc(
"Overwrites the Unwind v2 mode for testing purposes."));
49 "x86-wineh-unwindv2-instruction-count-threshold",
cl::Hidden,
50 cl::desc(
"Maximum number of (approximate) instructions before splitting "
51 "into a new unwind info."),
58 unsigned ApproximateInstructionPosition;
62 unsigned ApproximatePrologCodeCount;
63 unsigned ApproximateInstructionCount;
71 X86WinEHUnwindV2() : MachineFunctionPass(ID) {
75 StringRef getPassName()
const override {
return "WinEH Unwind V2"; }
77 bool runOnMachineFunction(MachineFunction &MF)
override;
81 static std::nullopt_t rejectCurrentFunctionInternalError(
85 static std::optional<FrameInfo>
86 runAnalysisOnFuncOrFunclet(MachineFunction &MF,
91enum class FunctionState {
100char X86WinEHUnwindV2::ID = 0;
103 "Analyze and emit instructions for Win64 Unwind v2",
false,
107 return new X86WinEHUnwindV2();
112 if (
MI.getDebugLoc())
113 return MI.getDebugLoc();
118std::optional<FrameInfo>
126 FunctionState State = FunctionState::InProlog;
130 bool HasStackAlloc =
false;
131 bool HasSetFrame =
false;
132 unsigned ApproximatePrologCodeCount = 0;
150 unsigned ApproximateInstructionCount = 0;
152 for (; Iter != MF.
end(); ++Iter) {
153 MachineBasicBlock &
MBB = *Iter;
162 unsigned PoppedRegCount = 0;
163 bool HasStackDealloc =
false;
164 bool HasSetFrameBack =
false;
165 MachineInstr *UnwindV2StartLocation =
nullptr;
167 for (MachineInstr &
MI :
MBB) {
172 if (!
MI.isPseudo() && !
MI.isMetaInstruction())
173 ApproximateInstructionCount++;
175 switch (
MI.getOpcode()) {
179 case X86::SEH_PushReg:
180 if (State != FunctionState::InProlog)
182 ApproximatePrologCodeCount++;
186 case X86::SEH_StackAlloc:
187 if (State != FunctionState::InProlog)
190 ApproximatePrologCodeCount += 3;
191 HasStackAlloc =
true;
194 case X86::SEH_SetFrame:
195 if (State != FunctionState::InProlog)
197 ApproximatePrologCodeCount++;
201 case X86::SEH_SaveReg:
202 case X86::SEH_SaveXMM:
203 if (State != FunctionState::InProlog)
206 ApproximatePrologCodeCount += 3;
209 case X86::SEH_PushFrame:
210 if (State != FunctionState::InProlog)
212 ApproximatePrologCodeCount++;
215 case X86::SEH_EndPrologue:
216 if (State != FunctionState::InProlog)
218 State = FunctionState::HasProlog;
224 case X86::SEH_BeginEpilogue:
225 if (State != FunctionState::HasProlog)
227 State = FunctionState::InEpilog;
230 case X86::SEH_EndEpilogue:
231 if (State != FunctionState::InEpilog)
233 if (HasStackAlloc != HasStackDealloc)
234 return rejectCurrentFunctionInternalError(
236 "The prolog made a stack allocation, "
237 "but the epilog did not deallocate it");
238 if (PoppedRegCount != PushedRegs.
size())
239 return rejectCurrentFunctionInternalError(
241 "The prolog pushed more registers than "
242 "the epilog popped");
246 if (!UnwindV2StartLocation)
247 UnwindV2StartLocation = &
MI;
249 {UnwindV2StartLocation, ApproximateInstructionCount});
250 State = FunctionState::FinishedEpilog;
254 if (State == FunctionState::InEpilog) {
258 return rejectCurrentFunctionInternalError(
260 "The epilog is setting frame back, but prolog did not set it");
261 if (PoppedRegCount > 0)
262 return rejectCurrentFunctionInternalError(
264 "The epilog is setting the frame back after popping "
267 return rejectCurrentFunctionInternalError(
269 "Cannot set the frame back after the stack "
270 "allocation has been deallocated");
271 HasSetFrameBack =
true;
272 }
else if (State == FunctionState::FinishedEpilog)
273 return rejectCurrentFunctionInternalError(
274 MF,
Mode,
"Unexpected mov instruction after the epilog");
279 if (State == FunctionState::InEpilog) {
283 return rejectCurrentFunctionInternalError(
285 "The epilog is deallocating a stack "
286 "allocation, but the prolog did "
288 if (PoppedRegCount > 0)
289 return rejectCurrentFunctionInternalError(
291 "The epilog is deallocating a stack allocation after popping "
294 HasStackDealloc =
true;
295 }
else if (State == FunctionState::FinishedEpilog)
296 return rejectCurrentFunctionInternalError(
297 MF,
Mode,
"Unexpected lea or add instruction after the epilog");
301 if (State == FunctionState::InEpilog) {
303 if (HasStackAlloc && (PoppedRegCount == 0) &&
307 HasStackDealloc =
true;
311 if (PoppedRegCount == 0 && HasStackAlloc && !HasStackDealloc &&
312 HasSetFrameBack && TFL.
hasFP(MF))
313 HasStackDealloc =
true;
318 if (HasStackAlloc != HasStackDealloc)
319 return rejectCurrentFunctionInternalError(
321 "Cannot pop registers before the stack "
322 "allocation has been deallocated");
323 if (PoppedRegCount > PushedRegs.
size())
324 return rejectCurrentFunctionInternalError(
326 "The epilog is popping more registers than the prolog "
328 if (PushedRegs[PushedRegs.
size() - PoppedRegCount] !=
Reg.
id())
329 return rejectCurrentFunctionInternalError(
331 "The epilog is popping a registers in "
332 "a different order than the "
333 "prolog pushed them");
339 if (!UnwindV2StartLocation) {
340 assert(PoppedRegCount == 1);
341 UnwindV2StartLocation = &
MI;
344 }
else if (State == FunctionState::FinishedEpilog)
346 return rejectCurrentFunctionInternalError(
347 MF,
Mode,
"Registers are being popped after the epilog");
351 if (
MI.isTerminator()) {
352 if (State == FunctionState::FinishedEpilog)
355 State = FunctionState::HasProlog;
356 else if (State == FunctionState::InEpilog)
358 }
else if (!
MI.isDebugOrPseudoInstr()) {
359 if ((State == FunctionState::FinishedEpilog) ||
360 (State == FunctionState::InEpilog))
362 return rejectCurrentFunctionInternalError(
363 MF,
Mode,
"Unexpected instruction in or after the epilog");
369 return FrameInfo{ApproximatePrologCodeCount, ApproximateInstructionCount,
373bool X86WinEHUnwindV2::runOnMachineFunction(MachineFunction &MF) {
379 if (
Mode == WinX64EHUnwindV2Mode::Disabled)
385 while (Iter != MF.
end()) {
386 auto FI = runAnalysisOnFuncOrFunclet(MF, Iter,
Mode);
389 if (!FI->EpilogInfos.empty())
393 if (FrameInfos.
empty())
396 MeetsUnwindV2Criteria++;
399 for (
auto &FI : FrameInfos) {
405 unsigned LastUnwindInfoEndPosition = FI.ApproximateInstructionCount;
406 unsigned UnwindCodeCount = FI.ApproximatePrologCodeCount + 1;
408 MachineBasicBlock &
MBB = *
Info.UnwindV2StartLocation->getParent();
411 TII->get(X86::SEH_UnwindV2Start));
413 if ((LastUnwindInfoEndPosition -
Info.ApproximateInstructionPosition >=
417 TII->get(X86::SEH_SplitChainedAtEndOfBlock));
418 LastUnwindInfoEndPosition =
Info.ApproximateInstructionPosition;
420 UnwindCodeCount = FI.ApproximatePrologCodeCount + 1;
428 MachineBasicBlock &FirstMBB = MF.
front();
430 TII->get(X86::SEH_UnwindVersion))
436std::nullopt_t X86WinEHUnwindV2::rejectCurrentFunctionInternalError(
438 if (
Mode == WinX64EHUnwindV2Mode::Required)
440 "generated incompatible code in function '" +
441 MF.
getName() +
"': " + Reason);
443 FailsUnwindV2Criteria++;
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
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)
static cl::opt< unsigned > UnwindCodeThreshold("x86-wineh-unwindv2-unwind-codes-threshold", cl::Hidden, cl::desc("Maximum number of unwind codes before " "splitting into a new unwind info."), cl::init(UINT8_MAX))
static cl::opt< unsigned > InstructionCountThreshold("x86-wineh-unwindv2-instruction-count-threshold", cl::Hidden, cl::desc("Maximum number of (approximate) instructions before splitting " "into a new unwind info."), cl::init(600))
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 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...
bool isEHFuncletEntry() const
Returns true if this is the entry block of an EH funclet.
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 & 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)
bool hasFP(const MachineFunction &MF) const
hasFP - Return true if the specified function should have a dedicated frame pointer register.
virtual const TargetFrameLowering * getFrameLowering() const
virtual const TargetInstrInfo * getInstrInfo() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
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.
auto reverse(ContainerTy &&C)
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.