41#define DEBUG_TYPE "x86-wineh-unwindv3"
44 "Number of functions processed by Unwind v3 pass");
46 "Number of sub-fragment splits inserted for Unwind v3");
62 "x86-wineh-unwindv3-instr-avg-size",
cl::Hidden,
64 "Average size of an instruction. This value is used in determining "
65 "split points for chained unwinder info"),
76 switch (
MI.getOpcode()) {
77 case X86::SEH_PushReg:
78 case X86::SEH_Push2Regs:
79 case X86::SEH_SaveReg:
80 case X86::SEH_SaveXMM:
81 case X86::SEH_StackAlloc:
82 case X86::SEH_StackAlign:
83 case X86::SEH_SetFrame:
84 case X86::SEH_PushFrame:
85 case X86::SEH_EndPrologue:
86 case X86::SEH_BeginEpilogue:
87 case X86::SEH_EndEpilogue:
88 case X86::SEH_SplitChained:
89 case X86::SEH_SplitChainedAtEndOfBlock:
104struct EpilogSplitPoint {
105 MachineInstr *BeginEpilog;
106 unsigned ApproxBytePos;
111 unsigned PrologOpCount = 0;
112 unsigned MaxEpilogOpCount = 0;
115 unsigned EndBytePos = 0;
125 X86WinEHUnwindV3() : MachineFunctionPass(ID) {
129 StringRef getPassName()
const override {
return "WinEH Unwind V3"; }
141 unsigned &ApproxBytePos);
146char X86WinEHUnwindV3::ID = 0;
149 "Capacity check and sub-fragment splitting for Win64 Unwind v3",
153 return new X86WinEHUnwindV3();
158 unsigned &ApproxBytePos) {
160 bool InEpilog =
false;
161 bool SeenProlog =
false;
162 unsigned CurrentEpilogOpCount = 0;
164 for (; Iter != MF.
end(); ++Iter) {
165 MachineBasicBlock &
MBB = *Iter;
174 unsigned MaxPadding =
A.
value() - 1;
176 MaxPadding = std::min(MaxPadding, MaxBytes);
177 ApproxBytePos += MaxPadding;
179 for (MachineInstr &
MI :
MBB) {
184 if (!
MI.isPseudo() && !
MI.isMetaInstruction())
187 switch (
MI.getOpcode()) {
188 case X86::SEH_PushReg:
189 case X86::SEH_Push2Regs:
190 case X86::SEH_StackAlloc:
191 case X86::SEH_SetFrame:
192 case X86::SEH_SaveReg:
193 case X86::SEH_SaveXMM:
194 case X86::SEH_PushFrame:
196 CurrentEpilogOpCount++;
198 Info.PrologOpCount++;
200 case X86::SEH_EndPrologue:
203 case X86::SEH_BeginEpilogue:
205 CurrentEpilogOpCount = 0;
207 <<
" begins at approx byte position " << ApproxBytePos
209 Info.Epilogs.push_back({&
MI, ApproxBytePos});
211 case X86::SEH_EndEpilogue:
213 Info.MaxEpilogOpCount =
214 std::max(
Info.MaxEpilogOpCount, CurrentEpilogOpCount);
222 Info.EndBytePos = ApproxBytePos;
224 <<
" epilog(s); ends at approx byte position "
225 << ApproxBytePos <<
"\n");
244 WinX64EHUnwindMode::V3;
247 unsigned ApproxBytePos = 0;
254 while (Iter != MF.
end()) {
261 MachineBasicBlock &FuncletEntry = *Iter;
264 TII->get(X86::SEH_UnwindVersion))
270 FuncletInfo
Info = analyzeFunclet(MF, Iter, ApproxBytePos);
273 Ctx.
diagnose(DiagnosticInfoResourceLimit(
274 F,
"number of unwind v3 prolog operations required",
276 Ctx.
diagnose(DiagnosticInfoGenericWithLoc(
277 "sub-fragment splitting for prolog overflow is not yet implemented",
285 Ctx.
diagnose(DiagnosticInfoResourceLimit(
286 F,
"number of unwind v3 epilog operations required",
288 Ctx.
diagnose(DiagnosticInfoGenericWithLoc(
289 "sub-fragment splitting for epilog overflow is not yet implemented",
309 auto SplitAfter = [&](
const EpilogSplitPoint &
Epilog) {
312 TII->get(X86::SEH_SplitChainedAtEndOfBlock));
317 unsigned EpilogsInFragment = 0;
318 const EpilogSplitPoint *LastEpilog =
nullptr;
319 [[maybe_unused]]
unsigned LastEpilogIdx = 0;
320 for (
unsigned Idx = 0; Idx <
Info.Epilogs.size(); ++Idx) {
321 const EpilogSplitPoint &
Epilog =
Info.Epilogs[Idx];
324 if (EpilogsInFragment > 0) {
325 bool ExceedsEpilogCount = EpilogsInFragment >=
MaxV3Epilogs;
326 bool ExceedsDistance =
327 Epilog.ApproxBytePos - LastEpilog->ApproxBytePos >=
329 if (ExceedsEpilogCount || ExceedsDistance) {
331 dbgs() <<
" splitting after epilog " << LastEpilogIdx
332 <<
" because adding epilog " << Idx <<
" would exceed the ";
333 if (ExceedsEpilogCount)
334 dbgs() <<
"7-epilog-per-fragment limit\n";
336 dbgs() <<
"epilog distance threshold (gap from previous epilog "
338 << LastEpilog->ApproxBytePos <<
" to epilog at "
339 <<
Epilog.ApproxBytePos <<
")\n";
341 SplitAfter(*LastEpilog);
342 EpilogsInFragment = 0;
352 if (LastEpilog &&
Info.EndBytePos - LastEpilog->ApproxBytePos >=
354 LLVM_DEBUG(
dbgs() <<
" splitting after last epilog " << LastEpilogIdx
355 <<
" to isolate the trailing tail (gap from epilog at "
356 << LastEpilog->ApproxBytePos <<
" to funclet end "
357 <<
Info.EndBytePos <<
")\n");
358 SplitAfter(*LastEpilog);
363 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.