30#define DEBUG_TYPE "x86-wineh-unwindv2"
33 "Number of functions that meet Unwind v2 criteria");
35 "Number of functions that fail Unwind v2 criteria");
41 unsigned ApproximateInstructionPosition;
45 unsigned ApproximatePrologCodeCount;
46 unsigned ApproximateInstructionCount;
54 X86WinEHUnwindV2Legacy() : MachineFunctionPass(ID) {
58 StringRef getPassName()
const override {
return "WinEH Unwind V2"; }
64std::nullopt_t rejectCurrentFunctionInternalError(
const MachineFunction &MF,
69 "generated incompatible code in function '" +
72 FailsUnwindV2Criteria++;
76enum class FunctionState {
85char X86WinEHUnwindV2Legacy::ID = 0;
88 "Analyze and emit instructions for Win64 Unwind v2",
false,
92 return new X86WinEHUnwindV2Legacy();
98 return MI.getDebugLoc();
104std::optional<FrameInfo>
111 FunctionState State = FunctionState::InProlog;
115 bool HasStackAlloc =
false;
116 bool HasSetFrame =
false;
117 unsigned ApproximatePrologCodeCount = 0;
135 unsigned ApproximateInstructionCount = 0;
137 for (; Iter != MF.
end(); ++Iter) {
142 if (
MBB.isEHFuncletEntry() && State != FunctionState::InProlog)
147 unsigned PoppedRegCount = 0;
148 bool HasStackDealloc =
false;
149 bool HasSetFrameBack =
false;
157 if (!
MI.isPseudo() && !
MI.isMetaInstruction())
158 ApproximateInstructionCount++;
160 switch (
MI.getOpcode()) {
164 case X86::SEH_PushReg:
165 if (State != FunctionState::InProlog)
167 ApproximatePrologCodeCount++;
171 case X86::SEH_StackAlloc:
172 if (State != FunctionState::InProlog)
175 ApproximatePrologCodeCount += 3;
176 HasStackAlloc =
true;
179 case X86::SEH_SetFrame:
180 if (State != FunctionState::InProlog)
182 ApproximatePrologCodeCount++;
186 case X86::SEH_SaveReg:
187 case X86::SEH_SaveXMM:
188 if (State != FunctionState::InProlog)
191 ApproximatePrologCodeCount += 3;
194 case X86::SEH_PushFrame:
195 if (State != FunctionState::InProlog)
197 ApproximatePrologCodeCount++;
200 case X86::SEH_EndPrologue:
201 if (State != FunctionState::InProlog)
203 State = FunctionState::HasProlog;
209 case X86::SEH_BeginEpilogue:
210 if (State != FunctionState::HasProlog)
212 State = FunctionState::InEpilog;
215 case X86::SEH_EndEpilogue:
216 if (State != FunctionState::InEpilog)
218 if (HasStackAlloc != HasStackDealloc)
219 return rejectCurrentFunctionInternalError(
221 "The prolog made a stack allocation, "
222 "but the epilog did not deallocate it");
223 if (PoppedRegCount != PushedRegs.
size())
224 return rejectCurrentFunctionInternalError(
226 "The prolog pushed more registers than "
227 "the epilog popped");
231 if (!UnwindV2StartLocation)
232 UnwindV2StartLocation = &
MI;
234 {UnwindV2StartLocation, ApproximateInstructionCount});
235 State = FunctionState::FinishedEpilog;
239 if (State == FunctionState::InEpilog) {
243 return rejectCurrentFunctionInternalError(
245 "The epilog is setting frame back, but prolog did not set it");
246 if (PoppedRegCount > 0)
247 return rejectCurrentFunctionInternalError(
249 "The epilog is setting the frame back after popping "
252 return rejectCurrentFunctionInternalError(
254 "Cannot set the frame back after the stack "
255 "allocation has been deallocated");
256 HasSetFrameBack =
true;
257 }
else if (State == FunctionState::FinishedEpilog)
258 return rejectCurrentFunctionInternalError(
259 MF,
Mode,
"Unexpected mov instruction after the epilog");
264 if (State == FunctionState::InEpilog) {
268 return rejectCurrentFunctionInternalError(
270 "The epilog is deallocating a stack "
271 "allocation, but the prolog did "
273 if (PoppedRegCount > 0)
274 return rejectCurrentFunctionInternalError(
276 "The epilog is deallocating a stack allocation after popping "
279 HasStackDealloc =
true;
280 }
else if (State == FunctionState::FinishedEpilog)
281 return rejectCurrentFunctionInternalError(
282 MF,
Mode,
"Unexpected lea or add instruction after the epilog");
286 if (State == FunctionState::InEpilog) {
288 if (HasStackAlloc && (PoppedRegCount == 0) &&
292 HasStackDealloc =
true;
296 if (PoppedRegCount == 0 && HasStackAlloc && !HasStackDealloc &&
297 HasSetFrameBack && TFL.
hasFP(MF))
298 HasStackDealloc =
true;
303 if (HasStackAlloc != HasStackDealloc)
304 return rejectCurrentFunctionInternalError(
306 "Cannot pop registers before the stack "
307 "allocation has been deallocated");
308 if (PoppedRegCount > PushedRegs.
size())
309 return rejectCurrentFunctionInternalError(
311 "The epilog is popping more registers than the prolog "
313 if (PushedRegs[PushedRegs.
size() - PoppedRegCount] !=
Reg.id())
314 return rejectCurrentFunctionInternalError(
316 "The epilog is popping a registers in "
317 "a different order than the "
318 "prolog pushed them");
324 if (!UnwindV2StartLocation) {
325 assert(PoppedRegCount == 1);
326 UnwindV2StartLocation = &
MI;
329 }
else if (State == FunctionState::FinishedEpilog)
331 return rejectCurrentFunctionInternalError(
332 MF,
Mode,
"Registers are being popped after the epilog");
336 if (
MI.isTerminator()) {
337 if (State == FunctionState::FinishedEpilog)
340 State = FunctionState::HasProlog;
341 else if (State == FunctionState::InEpilog)
343 }
else if (!
MI.isDebugOrPseudoInstr()) {
344 if ((State == FunctionState::FinishedEpilog) ||
345 (State == FunctionState::InEpilog))
347 return rejectCurrentFunctionInternalError(
348 MF,
Mode,
"Unexpected instruction in or after the epilog");
354 return FrameInfo{ApproximatePrologCodeCount, ApproximateInstructionCount,
360 std::optional<unsigned> ForceMode = CLOpts.wineh_unwindv2_force_mode;
379 while (Iter != MF.
end()) {
383 if (!FI->EpilogInfos.empty())
387 if (FrameInfos.
empty())
390 MeetsUnwindV2Criteria++;
393 for (
auto &FI : FrameInfos) {
399 unsigned LastUnwindInfoEndPosition = FI.ApproximateInstructionCount;
400 unsigned UnwindCodeCount = FI.ApproximatePrologCodeCount + 1;
403 const DebugLoc &
DL = Info.UnwindV2StartLocation->getDebugLoc();
405 TII->get(X86::SEH_UnwindV2Start))
408 if ((LastUnwindInfoEndPosition - Info.ApproximateInstructionPosition >=
409 CLOpts.wineh_unwindv2_instruction_count_threshold) ||
410 (UnwindCodeCount >= CLOpts.wineh_unwindv2_unwind_codes_threshold)) {
412 TII->get(X86::SEH_SplitChainedAtEndOfBlock))
414 LastUnwindInfoEndPosition = Info.ApproximateInstructionPosition;
416 UnwindCodeCount = FI.ApproximatePrologCodeCount + 1;
426 TII->get(X86::SEH_UnwindVersion))
442bool 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 &)