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