39#define DEBUG_TYPE "x86-wineh-unwindv3"
42 "Number of functions processed by Unwind v3 pass");
44 "Number of sub-fragment splits inserted for Unwind v3");
60 "x86-wineh-unwindv3-epilog-distance-threshold",
cl::Hidden,
62 "Maximum approximate instruction distance between adjacent epilogs "
63 "(or between the last epilog and the funclet end) before "
64 "splitting into a new chained unwind info for Unwind v3."),
75 switch (
MI.getOpcode()) {
76 case X86::SEH_PushReg:
77 case X86::SEH_Push2Regs:
78 case X86::SEH_SaveReg:
79 case X86::SEH_SaveXMM:
80 case X86::SEH_StackAlloc:
81 case X86::SEH_StackAlign:
82 case X86::SEH_SetFrame:
83 case X86::SEH_PushFrame:
84 case X86::SEH_EndPrologue:
85 case X86::SEH_BeginEpilogue:
86 case X86::SEH_EndEpilogue:
87 case X86::SEH_SplitChained:
88 case X86::SEH_SplitChainedAtEndOfBlock:
103struct EpilogSplitPoint {
104 MachineInstr *BeginEpilog;
105 unsigned ApproxInstrPos;
110 unsigned PrologOpCount = 0;
111 unsigned MaxEpilogOpCount = 0;
114 unsigned EndInstrPos = 0;
124 X86WinEHUnwindV3() : MachineFunctionPass(ID) {
128 StringRef getPassName()
const override {
return "WinEH Unwind V3"; }
130 bool runOnMachineFunction(MachineFunction &MF)
override;
138 static FuncletInfo analyzeFunclet(MachineFunction &MF,
140 unsigned &ApproxInstrPos);
145char X86WinEHUnwindV3::ID = 0;
148 "Capacity check and sub-fragment splitting for Win64 Unwind v3",
152 return new X86WinEHUnwindV3();
157 unsigned &ApproxInstrPos) {
159 bool InEpilog =
false;
160 bool SeenProlog =
false;
161 unsigned CurrentEpilogOpCount = 0;
163 for (; Iter != MF.
end(); ++Iter) {
164 MachineBasicBlock &
MBB = *Iter;
171 for (MachineInstr &
MI :
MBB) {
175 if (!
MI.isPseudo() && !
MI.isMetaInstruction())
178 switch (
MI.getOpcode()) {
179 case X86::SEH_PushReg:
180 case X86::SEH_Push2Regs:
181 case X86::SEH_StackAlloc:
182 case X86::SEH_SetFrame:
183 case X86::SEH_SaveReg:
184 case X86::SEH_SaveXMM:
185 case X86::SEH_PushFrame:
187 CurrentEpilogOpCount++;
189 Info.PrologOpCount++;
191 case X86::SEH_EndPrologue:
194 case X86::SEH_BeginEpilogue:
196 CurrentEpilogOpCount = 0;
198 <<
" begins at approx instruction position "
199 << ApproxInstrPos <<
"\n");
200 Info.Epilogs.push_back({&
MI, ApproxInstrPos});
202 case X86::SEH_EndEpilogue:
204 Info.MaxEpilogOpCount =
205 std::max(
Info.MaxEpilogOpCount, CurrentEpilogOpCount);
213 Info.EndInstrPos = ApproxInstrPos;
215 <<
" epilog(s); ends at approx instruction position "
216 << ApproxInstrPos <<
"\n");
220bool X86WinEHUnwindV3::runOnMachineFunction(MachineFunction &MF) {
232 if (
Mode != WinX64EHUnwindMode::V3) {
233 if (!
F.needsUnwindTableEntry())
237 Ctx.
diagnose(DiagnosticInfoUnsupported(
238 F,
"EGPR (R16-R31) requires V3 unwind info on Windows x64"));
247 unsigned ApproxInstrPos = 0;
254 while (Iter != MF.
end()) {
255 FuncletInfo
Info = analyzeFunclet(MF, Iter, ApproxInstrPos);
258 Ctx.
diagnose(DiagnosticInfoResourceLimit(
259 F,
"number of unwind v3 prolog operations required",
261 Ctx.
diagnose(DiagnosticInfoGenericWithLoc(
262 "sub-fragment splitting for prolog overflow is not yet implemented",
270 Ctx.
diagnose(DiagnosticInfoResourceLimit(
271 F,
"number of unwind v3 epilog operations required",
273 Ctx.
diagnose(DiagnosticInfoGenericWithLoc(
274 "sub-fragment splitting for epilog overflow is not yet implemented",
294 auto SplitAfter = [&](
const EpilogSplitPoint &
Epilog) {
297 TII->get(X86::SEH_SplitChainedAtEndOfBlock));
302 unsigned EpilogsInFragment = 0;
303 const EpilogSplitPoint *LastEpilog =
nullptr;
304 [[maybe_unused]]
unsigned LastEpilogIdx = 0;
305 for (
unsigned Idx = 0; Idx <
Info.Epilogs.size(); ++Idx) {
306 const EpilogSplitPoint &
Epilog =
Info.Epilogs[Idx];
309 if (EpilogsInFragment > 0) {
310 bool ExceedsEpilogCount = EpilogsInFragment >=
MaxV3Epilogs;
311 bool ExceedsDistance =
312 Epilog.ApproxInstrPos - LastEpilog->ApproxInstrPos >=
314 if (ExceedsEpilogCount || ExceedsDistance) {
316 dbgs() <<
" splitting after epilog " << LastEpilogIdx
317 <<
" because adding epilog " << Idx <<
" would exceed the ";
318 if (ExceedsEpilogCount)
319 dbgs() <<
"7-epilog-per-fragment limit\n";
321 dbgs() <<
"epilog distance threshold (gap from previous epilog "
323 << LastEpilog->ApproxInstrPos <<
" to epilog at "
324 <<
Epilog.ApproxInstrPos <<
")\n";
326 SplitAfter(*LastEpilog);
327 EpilogsInFragment = 0;
337 if (LastEpilog &&
Info.EndInstrPos - LastEpilog->ApproxInstrPos >=
339 LLVM_DEBUG(
dbgs() <<
" splitting after last epilog " << LastEpilogIdx
340 <<
" to isolate the trailing tail (gap from epilog at "
341 << LastEpilog->ApproxInstrPos <<
" to funclet end "
342 <<
Info.EndInstrPos <<
")\n");
343 SplitAfter(*LastEpilog);
348 FunctionsProcessed++;
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 constexpr unsigned MaxV3PrologOps
V3 limits from the format specification.
static constexpr unsigned MaxV3Epilogs
static constexpr unsigned MaxV3EpilogOps
static cl::opt< unsigned > EpilogDistanceThreshold("x86-wineh-unwindv3-epilog-distance-threshold", cl::Hidden, cl::desc("Maximum approximate instruction distance between adjacent epilogs " "(or between the last epilog and the funclet end) before " "splitting into a new chained unwind info for Unwind v3."), cl::init(3000))
Maximum approximate instruction distance allowed between two adjacent epilogs, and between the last e...
static void suppressWinCFI(MachineFunction &MF)
After reporting a recoverable error for MF, erase all SEH pseudo- instructions and clear the WinCFI f...
FunctionPass class - This class is used to implement most global optimizations.
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Module * getParent()
Get the module that this global value is contained inside of...
LLVM_ABI void diagnose(const DiagnosticInfo &DI)
Report a message to the currently installed diagnostic handler.
bool isEHFuncletEntry() const
Returns true if this is the entry block of an EH funclet.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void setHasWinCFI(bool v)
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
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...
virtual const TargetInstrInfo * getInstrInfo() const
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
FunctionPass * createX86WinEHUnwindV3Pass()
Capacity check and sub-fragment splitting for Win x64 Unwind V3.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
void initializeX86WinEHUnwindV3Pass(PassRegistry &)