40#define DEBUG_TYPE "x86-wineh-unwindv3"
43 "Number of functions processed by Unwind v3 pass");
45 "Number of sub-fragment splits inserted for Unwind v3");
69 switch (
MI.getOpcode()) {
70 case X86::SEH_PushReg:
71 case X86::SEH_Push2Regs:
72 case X86::SEH_SaveReg:
73 case X86::SEH_SaveXMM:
74 case X86::SEH_StackAlloc:
75 case X86::SEH_StackAlign:
76 case X86::SEH_SetFrame:
77 case X86::SEH_PushFrame:
78 case X86::SEH_EndPrologue:
79 case X86::SEH_BeginEpilogue:
80 case X86::SEH_EndEpilogue:
81 case X86::SEH_SplitChained:
82 case X86::SEH_SplitChainedAtEndOfBlock:
97struct EpilogSplitPoint {
98 MachineInstr *BeginEpilog;
99 unsigned ApproxBytePos;
104 unsigned PrologOpCount = 0;
105 unsigned MaxEpilogOpCount = 0;
108 unsigned EndBytePos = 0;
118 X86WinEHUnwindV3() : MachineFunctionPass(ID) {
122 StringRef getPassName()
const override {
return "WinEH Unwind V3"; }
134 unsigned &ApproxBytePos);
139char X86WinEHUnwindV3::ID = 0;
142 "Capacity check and sub-fragment splitting for Win64 Unwind v3",
146 return new X86WinEHUnwindV3();
151 unsigned &ApproxBytePos) {
153 bool InEpilog =
false;
154 bool SeenProlog =
false;
155 unsigned CurrentEpilogOpCount = 0;
156 const unsigned ApproxBytesPerInstr =
157 MF.
getSubtarget<X86Subtarget>().getCLOpts().wineh_unwindv3_instr_avg_size;
159 for (; Iter != MF.
end(); ++Iter) {
160 MachineBasicBlock &
MBB = *Iter;
169 unsigned MaxPadding =
A.
value() - 1;
171 MaxPadding = std::min(MaxPadding, MaxBytes);
172 ApproxBytePos += MaxPadding;
174 for (MachineInstr &
MI :
MBB) {
179 if (!
MI.isPseudo() && !
MI.isMetaInstruction())
180 ApproxBytePos += ApproxBytesPerInstr;
182 switch (
MI.getOpcode()) {
183 case X86::SEH_PushReg:
184 case X86::SEH_Push2Regs:
185 case X86::SEH_StackAlloc:
186 case X86::SEH_SetFrame:
187 case X86::SEH_SaveReg:
188 case X86::SEH_SaveXMM:
189 case X86::SEH_PushFrame:
191 CurrentEpilogOpCount++;
193 Info.PrologOpCount++;
195 case X86::SEH_EndPrologue:
198 case X86::SEH_BeginEpilogue:
200 CurrentEpilogOpCount = 0;
202 <<
" begins at approx byte position " << ApproxBytePos
204 Info.Epilogs.push_back({&
MI, ApproxBytePos});
206 case X86::SEH_EndEpilogue:
208 Info.MaxEpilogOpCount =
209 std::max(
Info.MaxEpilogOpCount, CurrentEpilogOpCount);
217 Info.EndBytePos = ApproxBytePos;
219 <<
" epilog(s); ends at approx byte position "
220 << ApproxBytePos <<
"\n");
239 WinX64EHUnwindMode::V3;
242 unsigned ApproxBytePos = 0;
249 while (Iter != MF.
end()) {
256 MachineBasicBlock &FuncletEntry = *Iter;
259 TII->get(X86::SEH_UnwindVersion))
265 FuncletInfo
Info = analyzeFunclet(MF, Iter, ApproxBytePos);
268 Ctx.
diagnose(DiagnosticInfoResourceLimit(
269 F,
"number of unwind v3 prolog operations required",
271 Ctx.
diagnose(DiagnosticInfoGenericWithLoc(
272 "sub-fragment splitting for prolog overflow is not yet implemented",
280 Ctx.
diagnose(DiagnosticInfoResourceLimit(
281 F,
"number of unwind v3 epilog operations required",
283 Ctx.
diagnose(DiagnosticInfoGenericWithLoc(
284 "sub-fragment splitting for epilog overflow is not yet implemented",
304 auto SplitAfter = [&](
const EpilogSplitPoint &
Epilog) {
307 TII->get(X86::SEH_SplitChainedAtEndOfBlock))
313 unsigned EpilogsInFragment = 0;
314 const EpilogSplitPoint *LastEpilog =
nullptr;
315 [[maybe_unused]]
unsigned LastEpilogIdx = 0;
316 for (
unsigned Idx = 0;
Idx <
Info.Epilogs.size(); ++
Idx) {
320 if (EpilogsInFragment > 0) {
321 bool ExceedsEpilogCount = EpilogsInFragment >=
MaxV3Epilogs;
322 bool ExceedsDistance =
323 Epilog.ApproxBytePos - LastEpilog->ApproxBytePos >=
325 if (ExceedsEpilogCount || ExceedsDistance) {
327 dbgs() <<
" splitting after epilog " << LastEpilogIdx
328 <<
" because adding epilog " <<
Idx <<
" would exceed the ";
329 if (ExceedsEpilogCount)
330 dbgs() <<
"7-epilog-per-fragment limit\n";
332 dbgs() <<
"epilog distance threshold (gap from previous epilog "
334 << LastEpilog->ApproxBytePos <<
" to epilog at "
335 <<
Epilog.ApproxBytePos <<
")\n";
337 SplitAfter(*LastEpilog);
338 EpilogsInFragment = 0;
348 if (LastEpilog &&
Info.EndBytePos - LastEpilog->ApproxBytePos >=
350 LLVM_DEBUG(
dbgs() <<
" splitting after last epilog " << LastEpilogIdx
351 <<
" to isolate the trailing tail (gap from epilog at "
352 << LastEpilog->ApproxBytePos <<
" to funclet end "
353 <<
Info.EndBytePos <<
")\n");
354 SplitAfter(*LastEpilog);
359 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
Approximate byte distance between an epilog and its fragment tail beyond which the funclet is split i...
static constexpr unsigned MaxV3EpilogOps
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.
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.