42#define DEBUG_TYPE "x86-wineh-unwindv3"
45 "Number of functions processed by Unwind v3 pass");
47 "Number of sub-fragment splits inserted for Unwind v3");
63 "x86-wineh-unwindv3-instr-avg-size",
cl::Hidden,
65 "Average size of an instruction. This value is used in determining "
66 "split points for chained unwinder info"),
77 switch (
MI.getOpcode()) {
78 case X86::SEH_PushReg:
79 case X86::SEH_Push2Regs:
80 case X86::SEH_SaveReg:
81 case X86::SEH_SaveXMM:
82 case X86::SEH_StackAlloc:
83 case X86::SEH_StackAlign:
84 case X86::SEH_SetFrame:
85 case X86::SEH_PushFrame:
86 case X86::SEH_EndPrologue:
87 case X86::SEH_BeginEpilogue:
88 case X86::SEH_EndEpilogue:
89 case X86::SEH_SplitChained:
90 case X86::SEH_SplitChainedAtEndOfBlock:
105struct EpilogSplitPoint {
106 MachineInstr *BeginEpilog;
107 unsigned ApproxBytePos;
112 unsigned PrologOpCount = 0;
113 unsigned MaxEpilogOpCount = 0;
116 unsigned EndBytePos = 0;
126 X86WinEHUnwindV3() : MachineFunctionPass(ID) {
130 StringRef getPassName()
const override {
return "WinEH Unwind V3"; }
132 bool runOnMachineFunction(MachineFunction &MF)
override;
140 static FuncletInfo analyzeFunclet(MachineFunction &MF,
142 unsigned &ApproxBytePos);
147char X86WinEHUnwindV3::ID = 0;
150 "Capacity check and sub-fragment splitting for Win64 Unwind v3",
154 return new X86WinEHUnwindV3();
159 unsigned &ApproxBytePos) {
161 bool InEpilog =
false;
162 bool SeenProlog =
false;
163 unsigned CurrentEpilogOpCount = 0;
165 for (; Iter != MF.
end(); ++Iter) {
166 MachineBasicBlock &
MBB = *Iter;
175 unsigned MaxPadding =
A.
value() - 1;
177 MaxPadding = std::min(MaxPadding, MaxBytes);
178 ApproxBytePos += MaxPadding;
180 for (MachineInstr &
MI :
MBB) {
185 if (!
MI.isPseudo() && !
MI.isMetaInstruction())
188 switch (
MI.getOpcode()) {
189 case X86::SEH_PushReg:
190 case X86::SEH_Push2Regs:
191 case X86::SEH_StackAlloc:
192 case X86::SEH_SetFrame:
193 case X86::SEH_SaveReg:
194 case X86::SEH_SaveXMM:
195 case X86::SEH_PushFrame:
197 CurrentEpilogOpCount++;
199 Info.PrologOpCount++;
201 case X86::SEH_EndPrologue:
204 case X86::SEH_BeginEpilogue:
206 CurrentEpilogOpCount = 0;
208 <<
" begins at approx byte position " << ApproxBytePos
210 Info.Epilogs.push_back({&
MI, ApproxBytePos});
212 case X86::SEH_EndEpilogue:
214 Info.MaxEpilogOpCount =
215 std::max(
Info.MaxEpilogOpCount, CurrentEpilogOpCount);
223 Info.EndBytePos = ApproxBytePos;
225 <<
" epilog(s); ends at approx byte position "
226 << ApproxBytePos <<
"\n");
230bool X86WinEHUnwindV3::runOnMachineFunction(MachineFunction &MF) {
245 WinX64EHUnwindMode::V3;
248 unsigned ApproxBytePos = 0;
255 while (Iter != MF.
end()) {
262 MachineBasicBlock &FuncletEntry = *Iter;
265 TII->get(X86::SEH_UnwindVersion))
271 FuncletInfo
Info = analyzeFunclet(MF, Iter, ApproxBytePos);
274 Ctx.
diagnose(DiagnosticInfoResourceLimit(
275 F,
"number of unwind v3 prolog operations required",
277 Ctx.
diagnose(DiagnosticInfoGenericWithLoc(
278 "sub-fragment splitting for prolog overflow is not yet implemented",
286 Ctx.
diagnose(DiagnosticInfoResourceLimit(
287 F,
"number of unwind v3 epilog operations required",
289 Ctx.
diagnose(DiagnosticInfoGenericWithLoc(
290 "sub-fragment splitting for epilog overflow is not yet implemented",
310 auto SplitAfter = [&](
const EpilogSplitPoint &
Epilog) {
313 TII->get(X86::SEH_SplitChainedAtEndOfBlock));
318 unsigned EpilogsInFragment = 0;
319 const EpilogSplitPoint *LastEpilog =
nullptr;
320 [[maybe_unused]]
unsigned LastEpilogIdx = 0;
321 for (
unsigned Idx = 0; Idx <
Info.Epilogs.size(); ++Idx) {
322 const EpilogSplitPoint &
Epilog =
Info.Epilogs[Idx];
325 if (EpilogsInFragment > 0) {
326 bool ExceedsEpilogCount = EpilogsInFragment >=
MaxV3Epilogs;
327 bool ExceedsDistance =
328 Epilog.ApproxBytePos - LastEpilog->ApproxBytePos >=
330 if (ExceedsEpilogCount || ExceedsDistance) {
332 dbgs() <<
" splitting after epilog " << LastEpilogIdx
333 <<
" because adding epilog " << Idx <<
" would exceed the ";
334 if (ExceedsEpilogCount)
335 dbgs() <<
"7-epilog-per-fragment limit\n";
337 dbgs() <<
"epilog distance threshold (gap from previous epilog "
339 << LastEpilog->ApproxBytePos <<
" to epilog at "
340 <<
Epilog.ApproxBytePos <<
")\n";
342 SplitAfter(*LastEpilog);
343 EpilogsInFragment = 0;
353 if (LastEpilog &&
Info.EndBytePos - LastEpilog->ApproxBytePos >=
355 LLVM_DEBUG(
dbgs() <<
" splitting after last epilog " << LastEpilogIdx
356 <<
" to isolate the trailing tail (gap from epilog at "
357 << LastEpilog->ApproxBytePos <<
" to funclet end "
358 <<
Info.EndBytePos <<
")\n");
359 SplitAfter(*LastEpilog);
364 FunctionsProcessed++;
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
const HexagonInstrInfo * TII
Module.h This file contains the declarations for the Module class.
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
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 EpilogDistanceThreshold
static constexpr unsigned MaxV3EpilogOps
static cl::opt< unsigned > ApproxBytesPerInstr("x86-wineh-unwindv3-instr-avg-size", cl::Hidden, cl::desc("Average size of an instruction. This value is used in determining " "split points for chained unwinder info"), cl::init(7))
Approximate byte distance between an epilog and its fragment tail beyond which the funclet is split i...
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.
unsigned getMaxBytesForAlignment() const
Return the maximum amount of padding allowed for aligning the basic block.
bool isEHFuncletEntry() const
Returns true if this is the entry block of an EH funclet.
LLVM_ABI DebugLoc findDebugLoc(instr_iterator MBBI)
Find the next valid DebugLoc starting at MBBI, skipping any debug instructions.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
Align getAlignment() const
Return alignment of the 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
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...
virtual const TargetInstrInfo * getInstrInfo() const
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
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.
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...
void initializeX86WinEHUnwindV3Pass(PassRegistry &)
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.