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-instr-avg-size",
cl::Hidden,
62 "Average size of an instruction. This value is used in determining "
63 "split points for chained unwinder info"),
74 switch (
MI.getOpcode()) {
75 case X86::SEH_PushReg:
76 case X86::SEH_Push2Regs:
77 case X86::SEH_SaveReg:
78 case X86::SEH_SaveXMM:
79 case X86::SEH_StackAlloc:
80 case X86::SEH_StackAlign:
81 case X86::SEH_SetFrame:
82 case X86::SEH_PushFrame:
83 case X86::SEH_EndPrologue:
84 case X86::SEH_BeginEpilogue:
85 case X86::SEH_EndEpilogue:
86 case X86::SEH_SplitChained:
87 case X86::SEH_SplitChainedAtEndOfBlock:
102struct EpilogSplitPoint {
103 MachineInstr *BeginEpilog;
104 unsigned ApproxBytePos;
109 unsigned PrologOpCount = 0;
110 unsigned MaxEpilogOpCount = 0;
113 unsigned EndBytePos = 0;
123 X86WinEHUnwindV3() : MachineFunctionPass(ID) {
127 StringRef getPassName()
const override {
return "WinEH Unwind V3"; }
129 bool runOnMachineFunction(MachineFunction &MF)
override;
137 static FuncletInfo analyzeFunclet(MachineFunction &MF,
139 unsigned &ApproxBytePos);
144char X86WinEHUnwindV3::ID = 0;
147 "Capacity check and sub-fragment splitting for Win64 Unwind v3",
151 return new X86WinEHUnwindV3();
156 unsigned &ApproxBytePos) {
158 bool InEpilog =
false;
159 bool SeenProlog =
false;
160 unsigned CurrentEpilogOpCount = 0;
162 for (; Iter != MF.
end(); ++Iter) {
163 MachineBasicBlock &
MBB = *Iter;
172 unsigned MaxPadding =
A.
value() - 1;
174 MaxPadding = std::min(MaxPadding, MaxBytes);
175 ApproxBytePos += MaxPadding;
177 for (MachineInstr &
MI :
MBB) {
182 if (!
MI.isPseudo() && !
MI.isMetaInstruction())
185 switch (
MI.getOpcode()) {
186 case X86::SEH_PushReg:
187 case X86::SEH_Push2Regs:
188 case X86::SEH_StackAlloc:
189 case X86::SEH_SetFrame:
190 case X86::SEH_SaveReg:
191 case X86::SEH_SaveXMM:
192 case X86::SEH_PushFrame:
194 CurrentEpilogOpCount++;
196 Info.PrologOpCount++;
198 case X86::SEH_EndPrologue:
201 case X86::SEH_BeginEpilogue:
203 CurrentEpilogOpCount = 0;
205 <<
" begins at approx byte position " << ApproxBytePos
207 Info.Epilogs.push_back({&
MI, ApproxBytePos});
209 case X86::SEH_EndEpilogue:
211 Info.MaxEpilogOpCount =
212 std::max(
Info.MaxEpilogOpCount, CurrentEpilogOpCount);
220 Info.EndBytePos = ApproxBytePos;
222 <<
" epilog(s); ends at approx byte position "
223 << ApproxBytePos <<
"\n");
227bool X86WinEHUnwindV3::runOnMachineFunction(MachineFunction &MF) {
239 if (
Mode != WinX64EHUnwindMode::V3) {
240 if (!
F.needsUnwindTableEntry())
244 Ctx.
diagnose(DiagnosticInfoUnsupported(
245 F,
"EGPR (R16-R31) requires V3 unwind info on Windows x64"));
254 unsigned ApproxBytePos = 0;
261 while (Iter != MF.
end()) {
262 FuncletInfo
Info = analyzeFunclet(MF, Iter, ApproxBytePos);
265 Ctx.
diagnose(DiagnosticInfoResourceLimit(
266 F,
"number of unwind v3 prolog operations required",
268 Ctx.
diagnose(DiagnosticInfoGenericWithLoc(
269 "sub-fragment splitting for prolog overflow is not yet implemented",
277 Ctx.
diagnose(DiagnosticInfoResourceLimit(
278 F,
"number of unwind v3 epilog operations required",
280 Ctx.
diagnose(DiagnosticInfoGenericWithLoc(
281 "sub-fragment splitting for epilog overflow is not yet implemented",
301 auto SplitAfter = [&](
const EpilogSplitPoint &
Epilog) {
304 TII->get(X86::SEH_SplitChainedAtEndOfBlock));
309 unsigned EpilogsInFragment = 0;
310 const EpilogSplitPoint *LastEpilog =
nullptr;
311 [[maybe_unused]]
unsigned LastEpilogIdx = 0;
312 for (
unsigned Idx = 0; Idx <
Info.Epilogs.size(); ++Idx) {
313 const EpilogSplitPoint &
Epilog =
Info.Epilogs[Idx];
316 if (EpilogsInFragment > 0) {
317 bool ExceedsEpilogCount = EpilogsInFragment >=
MaxV3Epilogs;
318 bool ExceedsDistance =
319 Epilog.ApproxBytePos - LastEpilog->ApproxBytePos >=
321 if (ExceedsEpilogCount || ExceedsDistance) {
323 dbgs() <<
" splitting after epilog " << LastEpilogIdx
324 <<
" because adding epilog " << Idx <<
" would exceed the ";
325 if (ExceedsEpilogCount)
326 dbgs() <<
"7-epilog-per-fragment limit\n";
328 dbgs() <<
"epilog distance threshold (gap from previous epilog "
330 << LastEpilog->ApproxBytePos <<
" to epilog at "
331 <<
Epilog.ApproxBytePos <<
")\n";
333 SplitAfter(*LastEpilog);
334 EpilogsInFragment = 0;
344 if (LastEpilog &&
Info.EndBytePos - LastEpilog->ApproxBytePos >=
346 LLVM_DEBUG(
dbgs() <<
" splitting after last epilog " << LastEpilogIdx
347 <<
" to isolate the trailing tail (gap from epilog at "
348 << LastEpilog->ApproxBytePos <<
" to funclet end "
349 <<
Info.EndBytePos <<
")\n");
350 SplitAfter(*LastEpilog);
355 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)
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 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.
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
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.
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.