1*700637cbSDimitry Andric //===-- X86WinEHUnwindV2.cpp - Win x64 Unwind v2 ----------------*- C++ -*-===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric ///
9*700637cbSDimitry Andric /// Implements the analysis required to detect if a function can use Unwind v2
10*700637cbSDimitry Andric /// information, and emits the neccesary pseudo instructions used by MC to
11*700637cbSDimitry Andric /// generate the unwind info.
12*700637cbSDimitry Andric ///
13*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
14*700637cbSDimitry Andric
15*700637cbSDimitry Andric #include "MCTargetDesc/X86BaseInfo.h"
16*700637cbSDimitry Andric #include "X86.h"
17*700637cbSDimitry Andric #include "llvm/ADT/Statistic.h"
18*700637cbSDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
19*700637cbSDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
20*700637cbSDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
21*700637cbSDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
22*700637cbSDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
23*700637cbSDimitry Andric #include "llvm/IR/DiagnosticInfo.h"
24*700637cbSDimitry Andric #include "llvm/IR/Module.h"
25*700637cbSDimitry Andric
26*700637cbSDimitry Andric using namespace llvm;
27*700637cbSDimitry Andric
28*700637cbSDimitry Andric #define DEBUG_TYPE "x86-wineh-unwindv2"
29*700637cbSDimitry Andric
30*700637cbSDimitry Andric STATISTIC(MeetsUnwindV2Criteria,
31*700637cbSDimitry Andric "Number of functions that meet Unwind v2 criteria");
32*700637cbSDimitry Andric STATISTIC(FailsUnwindV2Criteria,
33*700637cbSDimitry Andric "Number of functions that fail Unwind v2 criteria");
34*700637cbSDimitry Andric
35*700637cbSDimitry Andric static cl::opt<unsigned> MaximumUnwindCodes(
36*700637cbSDimitry Andric "x86-wineh-unwindv2-max-unwind-codes", cl::Hidden,
37*700637cbSDimitry Andric cl::desc("Maximum number of unwind codes permitted in each unwind info."),
38*700637cbSDimitry Andric cl::init(UINT8_MAX));
39*700637cbSDimitry Andric
40*700637cbSDimitry Andric static cl::opt<unsigned>
41*700637cbSDimitry Andric ForceMode("x86-wineh-unwindv2-force-mode", cl::Hidden,
42*700637cbSDimitry Andric cl::desc("Overwrites the Unwind v2 mode for testing purposes."));
43*700637cbSDimitry Andric
44*700637cbSDimitry Andric namespace {
45*700637cbSDimitry Andric
46*700637cbSDimitry Andric class X86WinEHUnwindV2 : public MachineFunctionPass {
47*700637cbSDimitry Andric public:
48*700637cbSDimitry Andric static char ID;
49*700637cbSDimitry Andric
X86WinEHUnwindV2()50*700637cbSDimitry Andric X86WinEHUnwindV2() : MachineFunctionPass(ID) {
51*700637cbSDimitry Andric initializeX86WinEHUnwindV2Pass(*PassRegistry::getPassRegistry());
52*700637cbSDimitry Andric }
53*700637cbSDimitry Andric
getPassName() const54*700637cbSDimitry Andric StringRef getPassName() const override { return "WinEH Unwind V2"; }
55*700637cbSDimitry Andric
56*700637cbSDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override;
57*700637cbSDimitry Andric
58*700637cbSDimitry Andric private:
59*700637cbSDimitry Andric /// Rejects the current function due to an internal error within LLVM.
60*700637cbSDimitry Andric static bool rejectCurrentFunctionInternalError(const MachineFunction &MF,
61*700637cbSDimitry Andric WinX64EHUnwindV2Mode Mode,
62*700637cbSDimitry Andric StringRef Reason);
63*700637cbSDimitry Andric };
64*700637cbSDimitry Andric
65*700637cbSDimitry Andric enum class FunctionState {
66*700637cbSDimitry Andric InProlog,
67*700637cbSDimitry Andric HasProlog,
68*700637cbSDimitry Andric InEpilog,
69*700637cbSDimitry Andric FinishedEpilog,
70*700637cbSDimitry Andric };
71*700637cbSDimitry Andric
72*700637cbSDimitry Andric } // end anonymous namespace
73*700637cbSDimitry Andric
74*700637cbSDimitry Andric char X86WinEHUnwindV2::ID = 0;
75*700637cbSDimitry Andric
76*700637cbSDimitry Andric INITIALIZE_PASS(X86WinEHUnwindV2, "x86-wineh-unwindv2",
77*700637cbSDimitry Andric "Analyze and emit instructions for Win64 Unwind v2", false,
78*700637cbSDimitry Andric false)
79*700637cbSDimitry Andric
createX86WinEHUnwindV2Pass()80*700637cbSDimitry Andric FunctionPass *llvm::createX86WinEHUnwindV2Pass() {
81*700637cbSDimitry Andric return new X86WinEHUnwindV2();
82*700637cbSDimitry Andric }
83*700637cbSDimitry Andric
findDebugLoc(const MachineBasicBlock & MBB)84*700637cbSDimitry Andric DebugLoc findDebugLoc(const MachineBasicBlock &MBB) {
85*700637cbSDimitry Andric for (const MachineInstr &MI : MBB)
86*700637cbSDimitry Andric if (MI.getDebugLoc())
87*700637cbSDimitry Andric return MI.getDebugLoc();
88*700637cbSDimitry Andric
89*700637cbSDimitry Andric return DebugLoc::getUnknown();
90*700637cbSDimitry Andric }
91*700637cbSDimitry Andric
runOnMachineFunction(MachineFunction & MF)92*700637cbSDimitry Andric bool X86WinEHUnwindV2::runOnMachineFunction(MachineFunction &MF) {
93*700637cbSDimitry Andric WinX64EHUnwindV2Mode Mode =
94*700637cbSDimitry Andric ForceMode.getNumOccurrences()
95*700637cbSDimitry Andric ? static_cast<WinX64EHUnwindV2Mode>(ForceMode.getValue())
96*700637cbSDimitry Andric : MF.getFunction().getParent()->getWinX64EHUnwindV2Mode();
97*700637cbSDimitry Andric
98*700637cbSDimitry Andric if (Mode == WinX64EHUnwindV2Mode::Disabled)
99*700637cbSDimitry Andric return false;
100*700637cbSDimitry Andric
101*700637cbSDimitry Andric // Current state of processing the function. We'll assume that all functions
102*700637cbSDimitry Andric // start with a prolog.
103*700637cbSDimitry Andric FunctionState State = FunctionState::InProlog;
104*700637cbSDimitry Andric
105*700637cbSDimitry Andric // Prolog information.
106*700637cbSDimitry Andric SmallVector<int64_t> PushedRegs;
107*700637cbSDimitry Andric bool HasStackAlloc = false;
108*700637cbSDimitry Andric unsigned ApproximatePrologCodeCount = 0;
109*700637cbSDimitry Andric
110*700637cbSDimitry Andric // Requested changes.
111*700637cbSDimitry Andric SmallVector<MachineInstr *> UnwindV2StartLocations;
112*700637cbSDimitry Andric
113*700637cbSDimitry Andric for (MachineBasicBlock &MBB : MF) {
114*700637cbSDimitry Andric // Current epilog information. We assume that epilogs cannot cross basic
115*700637cbSDimitry Andric // block boundaries.
116*700637cbSDimitry Andric unsigned PoppedRegCount = 0;
117*700637cbSDimitry Andric bool HasStackDealloc = false;
118*700637cbSDimitry Andric MachineInstr *UnwindV2StartLocation = nullptr;
119*700637cbSDimitry Andric
120*700637cbSDimitry Andric for (MachineInstr &MI : MBB) {
121*700637cbSDimitry Andric switch (MI.getOpcode()) {
122*700637cbSDimitry Andric //
123*700637cbSDimitry Andric // Prolog handling.
124*700637cbSDimitry Andric //
125*700637cbSDimitry Andric case X86::SEH_PushReg:
126*700637cbSDimitry Andric if (State != FunctionState::InProlog)
127*700637cbSDimitry Andric llvm_unreachable("SEH_PushReg outside of prolog");
128*700637cbSDimitry Andric ApproximatePrologCodeCount++;
129*700637cbSDimitry Andric PushedRegs.push_back(MI.getOperand(0).getImm());
130*700637cbSDimitry Andric break;
131*700637cbSDimitry Andric
132*700637cbSDimitry Andric case X86::SEH_StackAlloc:
133*700637cbSDimitry Andric case X86::SEH_SetFrame:
134*700637cbSDimitry Andric if (State != FunctionState::InProlog)
135*700637cbSDimitry Andric llvm_unreachable("SEH_StackAlloc or SEH_SetFrame outside of prolog");
136*700637cbSDimitry Andric // Assume a large alloc...
137*700637cbSDimitry Andric ApproximatePrologCodeCount +=
138*700637cbSDimitry Andric (MI.getOpcode() == X86::SEH_StackAlloc) ? 3 : 1;
139*700637cbSDimitry Andric HasStackAlloc = true;
140*700637cbSDimitry Andric break;
141*700637cbSDimitry Andric
142*700637cbSDimitry Andric case X86::SEH_SaveReg:
143*700637cbSDimitry Andric case X86::SEH_SaveXMM:
144*700637cbSDimitry Andric if (State != FunctionState::InProlog)
145*700637cbSDimitry Andric llvm_unreachable("SEH_SaveXMM or SEH_SaveReg outside of prolog");
146*700637cbSDimitry Andric // Assume a big reg...
147*700637cbSDimitry Andric ApproximatePrologCodeCount += 3;
148*700637cbSDimitry Andric break;
149*700637cbSDimitry Andric
150*700637cbSDimitry Andric case X86::SEH_PushFrame:
151*700637cbSDimitry Andric if (State != FunctionState::InProlog)
152*700637cbSDimitry Andric llvm_unreachable("SEH_PushFrame outside of prolog");
153*700637cbSDimitry Andric ApproximatePrologCodeCount++;
154*700637cbSDimitry Andric break;
155*700637cbSDimitry Andric
156*700637cbSDimitry Andric case X86::SEH_EndPrologue:
157*700637cbSDimitry Andric if (State != FunctionState::InProlog)
158*700637cbSDimitry Andric llvm_unreachable("SEH_EndPrologue outside of prolog");
159*700637cbSDimitry Andric State = FunctionState::HasProlog;
160*700637cbSDimitry Andric break;
161*700637cbSDimitry Andric
162*700637cbSDimitry Andric //
163*700637cbSDimitry Andric // Epilog handling.
164*700637cbSDimitry Andric //
165*700637cbSDimitry Andric case X86::SEH_BeginEpilogue:
166*700637cbSDimitry Andric if (State != FunctionState::HasProlog)
167*700637cbSDimitry Andric llvm_unreachable("SEH_BeginEpilogue in prolog or another epilog");
168*700637cbSDimitry Andric State = FunctionState::InEpilog;
169*700637cbSDimitry Andric break;
170*700637cbSDimitry Andric
171*700637cbSDimitry Andric case X86::SEH_EndEpilogue:
172*700637cbSDimitry Andric if (State != FunctionState::InEpilog)
173*700637cbSDimitry Andric llvm_unreachable("SEH_EndEpilogue outside of epilog");
174*700637cbSDimitry Andric if (HasStackAlloc != HasStackDealloc)
175*700637cbSDimitry Andric return rejectCurrentFunctionInternalError(
176*700637cbSDimitry Andric MF, Mode,
177*700637cbSDimitry Andric "The prolog made a stack allocation, "
178*700637cbSDimitry Andric "but the epilog did not deallocate it");
179*700637cbSDimitry Andric if (PoppedRegCount != PushedRegs.size())
180*700637cbSDimitry Andric return rejectCurrentFunctionInternalError(
181*700637cbSDimitry Andric MF, Mode,
182*700637cbSDimitry Andric "The prolog pushed more registers than "
183*700637cbSDimitry Andric "the epilog popped");
184*700637cbSDimitry Andric
185*700637cbSDimitry Andric // If we didn't find the start location, then use the end of the
186*700637cbSDimitry Andric // epilog.
187*700637cbSDimitry Andric if (!UnwindV2StartLocation)
188*700637cbSDimitry Andric UnwindV2StartLocation = &MI;
189*700637cbSDimitry Andric UnwindV2StartLocations.push_back(UnwindV2StartLocation);
190*700637cbSDimitry Andric State = FunctionState::FinishedEpilog;
191*700637cbSDimitry Andric break;
192*700637cbSDimitry Andric
193*700637cbSDimitry Andric case X86::MOV64rr:
194*700637cbSDimitry Andric case X86::ADD64ri32:
195*700637cbSDimitry Andric if (State == FunctionState::InEpilog) {
196*700637cbSDimitry Andric // If the prolog contains a stack allocation, then the first
197*700637cbSDimitry Andric // instruction in the epilog must be to adjust the stack pointer.
198*700637cbSDimitry Andric if (!HasStackAlloc)
199*700637cbSDimitry Andric return rejectCurrentFunctionInternalError(
200*700637cbSDimitry Andric MF, Mode,
201*700637cbSDimitry Andric "The epilog is deallocating a stack "
202*700637cbSDimitry Andric "allocation, but the prolog did "
203*700637cbSDimitry Andric "not allocate one");
204*700637cbSDimitry Andric if (HasStackDealloc)
205*700637cbSDimitry Andric return rejectCurrentFunctionInternalError(
206*700637cbSDimitry Andric MF, Mode,
207*700637cbSDimitry Andric "The epilog is deallocating the stack "
208*700637cbSDimitry Andric "allocation more than once");
209*700637cbSDimitry Andric if (PoppedRegCount > 0)
210*700637cbSDimitry Andric llvm_unreachable(
211*700637cbSDimitry Andric "Should have raised an error: either popping before "
212*700637cbSDimitry Andric "deallocating or deallocating without an allocation");
213*700637cbSDimitry Andric
214*700637cbSDimitry Andric HasStackDealloc = true;
215*700637cbSDimitry Andric } else if (State == FunctionState::FinishedEpilog)
216*700637cbSDimitry Andric return rejectCurrentFunctionInternalError(
217*700637cbSDimitry Andric MF, Mode, "Unexpected mov or add instruction after the epilog");
218*700637cbSDimitry Andric break;
219*700637cbSDimitry Andric
220*700637cbSDimitry Andric case X86::POP64r:
221*700637cbSDimitry Andric if (State == FunctionState::InEpilog) {
222*700637cbSDimitry Andric // After the stack pointer has been adjusted, the epilog must
223*700637cbSDimitry Andric // POP each register in reverse order of the PUSHes in the prolog.
224*700637cbSDimitry Andric PoppedRegCount++;
225*700637cbSDimitry Andric if (HasStackAlloc != HasStackDealloc)
226*700637cbSDimitry Andric return rejectCurrentFunctionInternalError(
227*700637cbSDimitry Andric MF, Mode,
228*700637cbSDimitry Andric "Cannot pop registers before the stack "
229*700637cbSDimitry Andric "allocation has been deallocated");
230*700637cbSDimitry Andric if (PoppedRegCount > PushedRegs.size())
231*700637cbSDimitry Andric return rejectCurrentFunctionInternalError(
232*700637cbSDimitry Andric MF, Mode,
233*700637cbSDimitry Andric "The epilog is popping more registers than the prolog pushed");
234*700637cbSDimitry Andric if (PushedRegs[PushedRegs.size() - PoppedRegCount] !=
235*700637cbSDimitry Andric MI.getOperand(0).getReg())
236*700637cbSDimitry Andric return rejectCurrentFunctionInternalError(
237*700637cbSDimitry Andric MF, Mode,
238*700637cbSDimitry Andric "The epilog is popping a registers in "
239*700637cbSDimitry Andric "a different order than the "
240*700637cbSDimitry Andric "prolog pushed them");
241*700637cbSDimitry Andric
242*700637cbSDimitry Andric // Unwind v2 records the size of the epilog not from where we place
243*700637cbSDimitry Andric // SEH_BeginEpilogue (as that contains the instruction to adjust the
244*700637cbSDimitry Andric // stack pointer) but from the first POP instruction (if there is
245*700637cbSDimitry Andric // one).
246*700637cbSDimitry Andric if (!UnwindV2StartLocation) {
247*700637cbSDimitry Andric assert(PoppedRegCount == 1);
248*700637cbSDimitry Andric UnwindV2StartLocation = &MI;
249*700637cbSDimitry Andric }
250*700637cbSDimitry Andric } else if (State == FunctionState::FinishedEpilog)
251*700637cbSDimitry Andric // Unexpected instruction after the epilog.
252*700637cbSDimitry Andric return rejectCurrentFunctionInternalError(
253*700637cbSDimitry Andric MF, Mode, "Registers are being popped after the epilog");
254*700637cbSDimitry Andric break;
255*700637cbSDimitry Andric
256*700637cbSDimitry Andric default:
257*700637cbSDimitry Andric if (MI.isTerminator()) {
258*700637cbSDimitry Andric if (State == FunctionState::FinishedEpilog)
259*700637cbSDimitry Andric // Found the terminator after the epilog, we're now ready for
260*700637cbSDimitry Andric // another epilog.
261*700637cbSDimitry Andric State = FunctionState::HasProlog;
262*700637cbSDimitry Andric else if (State == FunctionState::InEpilog)
263*700637cbSDimitry Andric llvm_unreachable("Terminator in the middle of the epilog");
264*700637cbSDimitry Andric } else if (!MI.isDebugOrPseudoInstr()) {
265*700637cbSDimitry Andric if ((State == FunctionState::FinishedEpilog) ||
266*700637cbSDimitry Andric (State == FunctionState::InEpilog))
267*700637cbSDimitry Andric // Unknown instruction in or after the epilog.
268*700637cbSDimitry Andric return rejectCurrentFunctionInternalError(
269*700637cbSDimitry Andric MF, Mode, "Unexpected instruction in or after the epilog");
270*700637cbSDimitry Andric }
271*700637cbSDimitry Andric }
272*700637cbSDimitry Andric }
273*700637cbSDimitry Andric }
274*700637cbSDimitry Andric
275*700637cbSDimitry Andric if (UnwindV2StartLocations.empty()) {
276*700637cbSDimitry Andric assert(State == FunctionState::InProlog &&
277*700637cbSDimitry Andric "If there are no epilogs, then there should be no prolog");
278*700637cbSDimitry Andric return false;
279*700637cbSDimitry Andric }
280*700637cbSDimitry Andric
281*700637cbSDimitry Andric MachineBasicBlock &FirstMBB = MF.front();
282*700637cbSDimitry Andric // Assume +1 for the "header" UOP_Epilog that contains the epilog size, and
283*700637cbSDimitry Andric // that we won't be able to use the "last epilog at the end of function"
284*700637cbSDimitry Andric // optimization.
285*700637cbSDimitry Andric if (ApproximatePrologCodeCount + UnwindV2StartLocations.size() + 1 >
286*700637cbSDimitry Andric static_cast<unsigned>(MaximumUnwindCodes)) {
287*700637cbSDimitry Andric if (Mode == WinX64EHUnwindV2Mode::Required)
288*700637cbSDimitry Andric MF.getFunction().getContext().diagnose(DiagnosticInfoGenericWithLoc(
289*700637cbSDimitry Andric "Windows x64 Unwind v2 is required, but the function '" +
290*700637cbSDimitry Andric MF.getName() +
291*700637cbSDimitry Andric "' has too many unwind codes. Try splitting the function or "
292*700637cbSDimitry Andric "reducing the number of places where it exits early with a tail "
293*700637cbSDimitry Andric "call.",
294*700637cbSDimitry Andric MF.getFunction(), findDebugLoc(FirstMBB)));
295*700637cbSDimitry Andric
296*700637cbSDimitry Andric FailsUnwindV2Criteria++;
297*700637cbSDimitry Andric return false;
298*700637cbSDimitry Andric }
299*700637cbSDimitry Andric
300*700637cbSDimitry Andric MeetsUnwindV2Criteria++;
301*700637cbSDimitry Andric
302*700637cbSDimitry Andric // Emit the pseudo instruction that marks the start of each epilog.
303*700637cbSDimitry Andric const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
304*700637cbSDimitry Andric for (MachineInstr *MI : UnwindV2StartLocations) {
305*700637cbSDimitry Andric BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
306*700637cbSDimitry Andric TII->get(X86::SEH_UnwindV2Start));
307*700637cbSDimitry Andric }
308*700637cbSDimitry Andric // Note that the function is using Unwind v2.
309*700637cbSDimitry Andric BuildMI(FirstMBB, FirstMBB.front(), findDebugLoc(FirstMBB),
310*700637cbSDimitry Andric TII->get(X86::SEH_UnwindVersion))
311*700637cbSDimitry Andric .addImm(2);
312*700637cbSDimitry Andric
313*700637cbSDimitry Andric return true;
314*700637cbSDimitry Andric }
315*700637cbSDimitry Andric
rejectCurrentFunctionInternalError(const MachineFunction & MF,WinX64EHUnwindV2Mode Mode,StringRef Reason)316*700637cbSDimitry Andric bool X86WinEHUnwindV2::rejectCurrentFunctionInternalError(
317*700637cbSDimitry Andric const MachineFunction &MF, WinX64EHUnwindV2Mode Mode, StringRef Reason) {
318*700637cbSDimitry Andric if (Mode == WinX64EHUnwindV2Mode::Required)
319*700637cbSDimitry Andric reportFatalInternalError("Windows x64 Unwind v2 is required, but LLVM has "
320*700637cbSDimitry Andric "generated incompatible code in function '" +
321*700637cbSDimitry Andric MF.getName() + "': " + Reason);
322*700637cbSDimitry Andric
323*700637cbSDimitry Andric FailsUnwindV2Criteria++;
324*700637cbSDimitry Andric return false;
325*700637cbSDimitry Andric }
326