brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.9 KiB · 9bf0abb Raw
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