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 X86WinEHUnwindV2Legacy() : MachineFunctionPass(ID) {
75 StringRef getPassName()
const override {
return "WinEH Unwind V2"; }
77 bool runOnMachineFunction(MachineFunction &MF)
override;
81std::nullopt_t rejectCurrentFunctionInternalError(
const MachineFunction &MF,
86 "generated incompatible code in function '" +
89 FailsUnwindV2Criteria++;
93enum class FunctionState {
102char X86WinEHUnwindV2Legacy::ID = 0;
105 "Analyze and emit instructions for Win64 Unwind v2",
false,
109 return new X86WinEHUnwindV2Legacy();
114 if (
MI.getDebugLoc())
115 return MI.getDebugLoc();
121std::optional<FrameInfo>
128 FunctionState State = FunctionState::InProlog;
132 bool HasStackAlloc =
false;
133 bool HasSetFrame =
false;
134 unsigned ApproximatePrologCodeCount = 0;
152 unsigned ApproximateInstructionCount = 0;
154 for (; Iter != MF.
end(); ++Iter) {
159 if (
MBB.isEHFuncletEntry() && State != FunctionState::InProlog)
164 unsigned PoppedRegCount = 0;
165 bool HasStackDealloc =
false;
166 bool HasSetFrameBack =
false;
174 if (!
MI.isPseudo() && !
MI.isMetaInstruction())
175 ApproximateInstructionCount++;
177 switch (
MI.getOpcode()) {
181 case X86::SEH_PushReg:
182 if (State != FunctionState::InProlog)
184 ApproximatePrologCodeCount++;
188 case X86::SEH_StackAlloc:
189 if (State != FunctionState::InProlog)
192 ApproximatePrologCodeCount += 3;
193 HasStackAlloc =
true;
196 case X86::SEH_SetFrame:
197 if (State != FunctionState::InProlog)
199 ApproximatePrologCodeCount++;
203 case X86::SEH_SaveReg:
204 case X86::SEH_SaveXMM:
205 if (State != FunctionState::InProlog)
208 ApproximatePrologCodeCount += 3;
211 case X86::SEH_PushFrame:
212 if (State != FunctionState::InProlog)
214 ApproximatePrologCodeCount++;
217 case X86::SEH_EndPrologue:
218 if (State != FunctionState::InProlog)
220 State = FunctionState::HasProlog;
226 case X86::SEH_BeginEpilogue:
227 if (State != FunctionState::HasProlog)
229 State = FunctionState::InEpilog;
232 case X86::SEH_EndEpilogue:
233 if (State != FunctionState::InEpilog)
235 if (HasStackAlloc != HasStackDealloc)
236 return rejectCurrentFunctionInternalError(
238 "The prolog made a stack allocation, "
239 "but the epilog did not deallocate it");
240 if (PoppedRegCount != PushedRegs.
size())
241 return rejectCurrentFunctionInternalError(
243 "The prolog pushed more registers than "
244 "the epilog popped");
248 if (!UnwindV2StartLocation)
249 UnwindV2StartLocation = &
MI;
251 {UnwindV2StartLocation, ApproximateInstructionCount});
252 State = FunctionState::FinishedEpilog;
256 if (State == FunctionState::InEpilog) {
260 return rejectCurrentFunctionInternalError(
262 "The epilog is setting frame back, but prolog did not set it");
263 if (PoppedRegCount > 0)
264 return rejectCurrentFunctionInternalError(
266 "The epilog is setting the frame back after popping "
269 return rejectCurrentFunctionInternalError(
271 "Cannot set the frame back after the stack "
272 "allocation has been deallocated");
273 HasSetFrameBack =
true;
274 }
else if (State == FunctionState::FinishedEpilog)
275 return rejectCurrentFunctionInternalError(
276 MF,
Mode,
"Unexpected mov instruction after the epilog");
281 if (State == FunctionState::InEpilog) {
285 return rejectCurrentFunctionInternalError(
287 "The epilog is deallocating a stack "
288 "allocation, but the prolog did "
290 if (PoppedRegCount > 0)
291 return rejectCurrentFunctionInternalError(
293 "The epilog is deallocating a stack allocation after popping "
296 HasStackDealloc =
true;
297 }
else if (State == FunctionState::FinishedEpilog)
298 return rejectCurrentFunctionInternalError(
299 MF,
Mode,
"Unexpected lea or add instruction after the epilog");
303 if (State == FunctionState::InEpilog) {
305 if (HasStackAlloc && (PoppedRegCount == 0) &&
309 HasStackDealloc =
true;
313 if (PoppedRegCount == 0 && HasStackAlloc && !HasStackDealloc &&
314 HasSetFrameBack && TFL.
hasFP(MF))
315 HasStackDealloc =
true;
320 if (HasStackAlloc != HasStackDealloc)
321 return rejectCurrentFunctionInternalError(
323 "Cannot pop registers before the stack "
324 "allocation has been deallocated");
325 if (PoppedRegCount > PushedRegs.
size())
326 return rejectCurrentFunctionInternalError(
328 "The epilog is popping more registers than the prolog "
330 if (PushedRegs[PushedRegs.
size() - PoppedRegCount] !=
Reg.id())
331 return rejectCurrentFunctionInternalError(
333 "The epilog is popping a registers in "
334 "a different order than the "
335 "prolog pushed them");
341 if (!UnwindV2StartLocation) {
342 assert(PoppedRegCount == 1);
343 UnwindV2StartLocation = &
MI;
346 }
else if (State == FunctionState::FinishedEpilog)
348 return rejectCurrentFunctionInternalError(
349 MF,
Mode,
"Registers are being popped after the epilog");
353 if (
MI.isTerminator()) {
354 if (State == FunctionState::FinishedEpilog)
357 State = FunctionState::HasProlog;
358 else if (State == FunctionState::InEpilog)
360 }
else if (!
MI.isDebugOrPseudoInstr()) {
361 if ((State == FunctionState::FinishedEpilog) ||
362 (State == FunctionState::InEpilog))
364 return rejectCurrentFunctionInternalError(
365 MF,
Mode,
"Unexpected instruction in or after the epilog");
371 return FrameInfo{ApproximatePrologCodeCount, ApproximateInstructionCount,
387 while (Iter != MF.
end()) {
391 if (!FI->EpilogInfos.empty())
395 if (FrameInfos.
empty())
398 MeetsUnwindV2Criteria++;
401 for (
auto &FI : FrameInfos) {
407 unsigned LastUnwindInfoEndPosition = FI.ApproximateInstructionCount;
408 unsigned UnwindCodeCount = FI.ApproximatePrologCodeCount + 1;
411 const DebugLoc &
DL = Info.UnwindV2StartLocation->getDebugLoc();
413 TII->get(X86::SEH_UnwindV2Start));
415 if ((LastUnwindInfoEndPosition - Info.ApproximateInstructionPosition >=
419 TII->get(X86::SEH_SplitChainedAtEndOfBlock));
420 LastUnwindInfoEndPosition = Info.ApproximateInstructionPosition;
422 UnwindCodeCount = FI.ApproximatePrologCodeCount + 1;
432 TII->get(X86::SEH_UnwindVersion))
447bool X86WinEHUnwindV2Legacy::runOnMachineFunction(
MachineFunction &MF) {
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.
#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))
std::optional< FrameInfo > runAnalysisOnFuncOrFunclet(MachineFunction &MF, MachineFunction::iterator &Iter, WinX64EHUnwindV2Mode Mode)
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."))
bool runX86WinEHUnwindV2(MachineFunction &MF)
Represents analyses that only rely on functions' control flow.
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...
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...
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
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.
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.
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.
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI void reportFatalInternalError(Error Err)
Report a fatal error that indicates a bug in LLVM.
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
auto reverse(ContainerTy &&C)
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.
FunctionPass * createX86WinEHUnwindV2LegacyPass()
void initializeX86WinEHUnwindV2LegacyPass(PassRegistry &)