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");
40 unsigned ApproximateInstructionPosition;
44 unsigned ApproximatePrologCodeCount;
45 unsigned ApproximateInstructionCount;
53 X86WinEHUnwindV2Legacy() : MachineFunctionPass(ID) {
57 StringRef getPassName()
const override {
return "WinEH Unwind V2"; }
63std::nullopt_t rejectCurrentFunctionInternalError(
const MachineFunction &MF,
68 "generated incompatible code in function '" +
71 FailsUnwindV2Criteria++;
75enum class FunctionState {
84char X86WinEHUnwindV2Legacy::ID = 0;
87 "Analyze and emit instructions for Win64 Unwind v2",
false,
91 return new X86WinEHUnwindV2Legacy();
97 return MI.getDebugLoc();
103std::optional<FrameInfo>
110 FunctionState State = FunctionState::InProlog;
114 bool HasStackAlloc =
false;
115 bool HasSetFrame =
false;
116 unsigned ApproximatePrologCodeCount = 0;
134 unsigned ApproximateInstructionCount = 0;
136 for (; Iter != MF.
end(); ++Iter) {
141 if (
MBB.isEHFuncletEntry() && State != FunctionState::InProlog)
146 unsigned PoppedRegCount = 0;
147 bool HasStackDealloc =
false;
148 bool HasSetFrameBack =
false;
156 if (!
MI.isPseudo() && !
MI.isMetaInstruction())
157 ApproximateInstructionCount++;
159 switch (
MI.getOpcode()) {
163 case X86::SEH_PushReg:
164 if (State != FunctionState::InProlog)
166 ApproximatePrologCodeCount++;
170 case X86::SEH_StackAlloc:
171 if (State != FunctionState::InProlog)
174 ApproximatePrologCodeCount += 3;
175 HasStackAlloc =
true;
178 case X86::SEH_SetFrame:
179 if (State != FunctionState::InProlog)
181 ApproximatePrologCodeCount++;
185 case X86::SEH_SaveReg:
186 case X86::SEH_SaveXMM:
187 if (State != FunctionState::InProlog)
190 ApproximatePrologCodeCount += 3;
193 case X86::SEH_PushFrame:
194 if (State != FunctionState::InProlog)
196 ApproximatePrologCodeCount++;
199 case X86::SEH_EndPrologue:
200 if (State != FunctionState::InProlog)
202 State = FunctionState::HasProlog;
208 case X86::SEH_BeginEpilogue:
209 if (State != FunctionState::HasProlog)
211 State = FunctionState::InEpilog;
214 case X86::SEH_EndEpilogue:
215 if (State != FunctionState::InEpilog)
217 if (HasStackAlloc != HasStackDealloc)
218 return rejectCurrentFunctionInternalError(
220 "The prolog made a stack allocation, "
221 "but the epilog did not deallocate it");
222 if (PoppedRegCount != PushedRegs.
size())
223 return rejectCurrentFunctionInternalError(
225 "The prolog pushed more registers than "
226 "the epilog popped");
230 if (!UnwindV2StartLocation)
231 UnwindV2StartLocation = &
MI;
233 {UnwindV2StartLocation, ApproximateInstructionCount});
234 State = FunctionState::FinishedEpilog;
238 if (State == FunctionState::InEpilog) {
242 return rejectCurrentFunctionInternalError(
244 "The epilog is setting frame back, but prolog did not set it");
245 if (PoppedRegCount > 0)
246 return rejectCurrentFunctionInternalError(
248 "The epilog is setting the frame back after popping "
251 return rejectCurrentFunctionInternalError(
253 "Cannot set the frame back after the stack "
254 "allocation has been deallocated");
255 HasSetFrameBack =
true;
256 }
else if (State == FunctionState::FinishedEpilog)
257 return rejectCurrentFunctionInternalError(
258 MF,
Mode,
"Unexpected mov instruction after the epilog");
263 if (State == FunctionState::InEpilog) {
267 return rejectCurrentFunctionInternalError(
269 "The epilog is deallocating a stack "
270 "allocation, but the prolog did "
272 if (PoppedRegCount > 0)
273 return rejectCurrentFunctionInternalError(
275 "The epilog is deallocating a stack allocation after popping "
278 HasStackDealloc =
true;
279 }
else if (State == FunctionState::FinishedEpilog)
280 return rejectCurrentFunctionInternalError(
281 MF,
Mode,
"Unexpected lea or add instruction after the epilog");
285 if (State == FunctionState::InEpilog) {
287 if (HasStackAlloc && (PoppedRegCount == 0) &&
291 HasStackDealloc =
true;
295 if (PoppedRegCount == 0 && HasStackAlloc && !HasStackDealloc &&
296 HasSetFrameBack && TFL.
hasFP(MF))
297 HasStackDealloc =
true;
302 if (HasStackAlloc != HasStackDealloc)
303 return rejectCurrentFunctionInternalError(
305 "Cannot pop registers before the stack "
306 "allocation has been deallocated");
307 if (PoppedRegCount > PushedRegs.
size())
308 return rejectCurrentFunctionInternalError(
310 "The epilog is popping more registers than the prolog "
312 if (PushedRegs[PushedRegs.
size() - PoppedRegCount] !=
Reg.id())
313 return rejectCurrentFunctionInternalError(
315 "The epilog is popping a registers in "
316 "a different order than the "
317 "prolog pushed them");
323 if (!UnwindV2StartLocation) {
324 assert(PoppedRegCount == 1);
325 UnwindV2StartLocation = &
MI;
328 }
else if (State == FunctionState::FinishedEpilog)
330 return rejectCurrentFunctionInternalError(
331 MF,
Mode,
"Registers are being popped after the epilog");
335 if (
MI.isTerminator()) {
336 if (State == FunctionState::FinishedEpilog)
339 State = FunctionState::HasProlog;
340 else if (State == FunctionState::InEpilog)
342 }
else if (!
MI.isDebugOrPseudoInstr()) {
343 if ((State == FunctionState::FinishedEpilog) ||
344 (State == FunctionState::InEpilog))
346 return rejectCurrentFunctionInternalError(
347 MF,
Mode,
"Unexpected instruction in or after the epilog");
353 return FrameInfo{ApproximatePrologCodeCount, ApproximateInstructionCount,
359 std::optional<unsigned> ForceMode = CLOpts.wineh_unwindv2_force_mode;
378 while (Iter != MF.
end()) {
382 if (!FI->EpilogInfos.empty())
386 if (FrameInfos.
empty())
389 MeetsUnwindV2Criteria++;
392 for (
auto &FI : FrameInfos) {
398 unsigned LastUnwindInfoEndPosition = FI.ApproximateInstructionCount;
399 unsigned UnwindCodeCount = FI.ApproximatePrologCodeCount + 1;
402 const DebugLoc &
DL = Info.UnwindV2StartLocation->getDebugLoc();
404 TII->get(X86::SEH_UnwindV2Start))
407 if ((LastUnwindInfoEndPosition - Info.ApproximateInstructionPosition >=
408 CLOpts.wineh_unwindv2_instruction_count_threshold) ||
409 (UnwindCodeCount >= CLOpts.wineh_unwindv2_unwind_codes_threshold)) {
411 TII->get(X86::SEH_SplitChainedAtEndOfBlock))
413 LastUnwindInfoEndPosition = Info.ApproximateInstructionPosition;
415 UnwindCodeCount = FI.ApproximatePrologCodeCount + 1;
425 TII->get(X86::SEH_UnwindVersion))
441bool 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)
DebugLoc findDebugLoc(const MachineBasicBlock &MBB)
std::optional< FrameInfo > runAnalysisOnFuncOrFunclet(MachineFunction &MF, MachineFunction::iterator &Iter, WinX64EHUnwindMode Mode)
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 & setMIFlag(MachineInstr::MIFlag Flag) const
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
Representation of each machine instruction.
WinX64EHUnwindMode getWinX64EHUnwindMode() const
Get how unwind 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.
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.
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)
bool requireWinX64UnwindV3(const MachineFunction &MF)
Returns true when MF must use Windows x64 Unwind V3: the module is in V3 mode, or the function needs ...
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 &)