//===- bolt/Target/X86/X86MCPlusBuilder.cpp -------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file provides X86-specific MCPlus builder.
//
//===----------------------------------------------------------------------===//

#include "MCTargetDesc/X86BaseInfo.h"
#include "MCTargetDesc/X86InstrRelaxTables.h"
#include "MCTargetDesc/X86MCTargetDesc.h"
#include "X86MCSymbolizer.h"
#include "bolt/Core/MCPlus.h"
#include "bolt/Core/MCPlusBuilder.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCFixupKindInfo.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstBuilder.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegister.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/DataExtractor.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ErrorOr.h"
#include <set>

#define DEBUG_TYPE "mcplus"

using namespace llvm;
using namespace bolt;

namespace opts {

extern cl::OptionCategory BoltOptCategory;

static cl::opt<bool> X86StripRedundantAddressSize(
    "x86-strip-redundant-address-size",
    cl::desc("Remove redundant Address-Size override prefix"), cl::init(true),
    cl::cat(BoltOptCategory));

} // namespace opts

namespace {

unsigned getShortBranchOpcode(unsigned Opcode) {
  switch (Opcode) {
  default:
    return Opcode;
  case X86::JMP_2: return X86::JMP_1;
  case X86::JMP_4: return X86::JMP_1;
  case X86::JCC_2: return X86::JCC_1;
  case X86::JCC_4: return X86::JCC_1;
  }
}

unsigned getShortArithOpcode(unsigned Opcode) {
  return X86::getShortOpcodeArith(Opcode);
}

bool isMOVSX64rm32(const MCInst &Inst) {
  return Inst.getOpcode() == X86::MOVSX64rm32;
}

bool isADD64rr(const MCInst &Inst) { return Inst.getOpcode() == X86::ADD64rr; }

bool isADDri(const MCInst &Inst) {
  return Inst.getOpcode() == X86::ADD64ri32 ||
         Inst.getOpcode() == X86::ADD64ri8;
}

#define GET_INSTRINFO_OPERAND_TYPES_ENUM
#define GET_INSTRINFO_OPERAND_TYPE
#define GET_INSTRINFO_MEM_OPERAND_SIZE
#include "X86GenInstrInfo.inc"

class X86MCPlusBuilder : public MCPlusBuilder {
public:
  X86MCPlusBuilder(const MCInstrAnalysis *Analysis, const MCInstrInfo *Info,
                   const MCRegisterInfo *RegInfo)
      : MCPlusBuilder(Analysis, Info, RegInfo) {}

  std::unique_ptr<MCSymbolizer>
  createTargetSymbolizer(BinaryFunction &Function) const override {
    return std::make_unique<X86MCSymbolizer>(Function);
  }

  bool isBranch(const MCInst &Inst) const override {
    return Analysis->isBranch(Inst) && !isTailCall(Inst);
  }

  bool isNoop(const MCInst &Inst) const override {
    return X86::isNOP(Inst.getOpcode());
  }

  unsigned getCondCode(const MCInst &Inst) const override {
    unsigned Opcode = Inst.getOpcode();
    if (X86::isJCC(Opcode))
      return Inst.getOperand(Info->get(Opcode).NumOperands - 1).getImm();
    return X86::COND_INVALID;
  }

  unsigned getInvertedCondCode(unsigned CC) const override {
    switch (CC) {
    default: return X86::COND_INVALID;
    case X86::COND_E:  return X86::COND_NE;
    case X86::COND_NE: return X86::COND_E;
    case X86::COND_L:  return X86::COND_GE;
    case X86::COND_LE: return X86::COND_G;
    case X86::COND_G:  return X86::COND_LE;
    case X86::COND_GE: return X86::COND_L;
    case X86::COND_B:  return X86::COND_AE;
    case X86::COND_BE: return X86::COND_A;
    case X86::COND_A:  return X86::COND_BE;
    case X86::COND_AE: return X86::COND_B;
    case X86::COND_S:  return X86::COND_NS;
    case X86::COND_NS: return X86::COND_S;
    case X86::COND_P:  return X86::COND_NP;
    case X86::COND_NP: return X86::COND_P;
    case X86::COND_O:  return X86::COND_NO;
    case X86::COND_NO: return X86::COND_O;
    }
  }

  unsigned getCondCodesLogicalOr(unsigned CC1, unsigned CC2) const override {
    enum DecodedCondCode : uint8_t {
      DCC_EQUAL = 0x1,
      DCC_GREATER = 0x2,
      DCC_LESSER = 0x4,
      DCC_GREATER_OR_LESSER = 0x6,
      DCC_UNSIGNED = 0x8,
      DCC_SIGNED = 0x10,
      DCC_INVALID = 0x20,
    };

    auto decodeCondCode = [&](unsigned CC) -> uint8_t {
      switch (CC) {
      default: return DCC_INVALID;
      case X86::COND_E: return DCC_EQUAL;
      case X86::COND_NE: return DCC_GREATER | DCC_LESSER;
      case X86::COND_L: return DCC_LESSER | DCC_SIGNED;
      case X86::COND_LE: return DCC_EQUAL | DCC_LESSER | DCC_SIGNED;
      case X86::COND_G: return DCC_GREATER | DCC_SIGNED;
      case X86::COND_GE: return DCC_GREATER | DCC_EQUAL | DCC_SIGNED;
      case X86::COND_B: return DCC_LESSER | DCC_UNSIGNED;
      case X86::COND_BE: return DCC_EQUAL | DCC_LESSER | DCC_UNSIGNED;
      case X86::COND_A: return DCC_GREATER | DCC_UNSIGNED;
      case X86::COND_AE: return DCC_GREATER | DCC_EQUAL | DCC_UNSIGNED;
      }
    };

    uint8_t DCC = decodeCondCode(CC1) | decodeCondCode(CC2);

    if (DCC & DCC_INVALID)
      return X86::COND_INVALID;

    if (DCC & DCC_SIGNED && DCC & DCC_UNSIGNED)
      return X86::COND_INVALID;

    switch (DCC) {
    default: return X86::COND_INVALID;
    case DCC_EQUAL | DCC_LESSER | DCC_SIGNED: return X86::COND_LE;
    case DCC_EQUAL | DCC_LESSER | DCC_UNSIGNED: return X86::COND_BE;
    case DCC_EQUAL | DCC_GREATER | DCC_SIGNED: return X86::COND_GE;
    case DCC_EQUAL | DCC_GREATER | DCC_UNSIGNED: return X86::COND_AE;
    case DCC_GREATER | DCC_LESSER | DCC_SIGNED: return X86::COND_NE;
    case DCC_GREATER | DCC_LESSER | DCC_UNSIGNED: return X86::COND_NE;
    case DCC_GREATER | DCC_LESSER: return X86::COND_NE;
    case DCC_EQUAL | DCC_SIGNED: return X86::COND_E;
    case DCC_EQUAL | DCC_UNSIGNED: return X86::COND_E;
    case DCC_EQUAL: return X86::COND_E;
    case DCC_LESSER | DCC_SIGNED: return X86::COND_L;
    case DCC_LESSER | DCC_UNSIGNED: return X86::COND_B;
    case DCC_GREATER | DCC_SIGNED: return X86::COND_G;
    case DCC_GREATER | DCC_UNSIGNED: return X86::COND_A;
    }
  }

  bool isValidCondCode(unsigned CC) const override {
    return (CC != X86::COND_INVALID);
  }

  bool isBreakpoint(const MCInst &Inst) const override {
    return Inst.getOpcode() == X86::INT3;
  }

  bool isPrefix(const MCInst &Inst) const override {
    const MCInstrDesc &Desc = Info->get(Inst.getOpcode());
    return X86II::isPrefix(Desc.TSFlags);
  }

  bool isRep(const MCInst &Inst) const override {
    return Inst.getFlags() == X86::IP_HAS_REPEAT;
  }

  bool deleteREPPrefix(MCInst &Inst) const override {
    if (Inst.getFlags() == X86::IP_HAS_REPEAT) {
      Inst.setFlags(0);
      return true;
    }
    return false;
  }

  // FIXME: For compatibility with old LLVM only!
  bool isTerminator(const MCInst &Inst) const override {
    unsigned Opcode = Inst.getOpcode();
    return Info->get(Opcode).isTerminator() || X86::isUD1(Opcode) ||
           X86::isUD2(Opcode);
  }

  bool isIndirectCall(const MCInst &Inst) const override {
    return isCall(Inst) &&
           ((getMemoryOperandNo(Inst) != -1) || Inst.getOperand(0).isReg());
  }

  bool isPop(const MCInst &Inst) const override {
    return getPopSize(Inst) == 0 ? false : true;
  }

  bool isTerminateBranch(const MCInst &Inst) const override {
    return Inst.getOpcode() == X86::ENDBR32 || Inst.getOpcode() == X86::ENDBR64;
  }

  int getPopSize(const MCInst &Inst) const override {
    switch (Inst.getOpcode()) {
    case X86::POP16r:
    case X86::POP16rmm:
    case X86::POP16rmr:
    case X86::POPF16:
    case X86::POPA16:
    case X86::POPDS16:
    case X86::POPES16:
    case X86::POPFS16:
    case X86::POPGS16:
    case X86::POPSS16:
      return 2;
    case X86::POP32r:
    case X86::POP32rmm:
    case X86::POP32rmr:
    case X86::POPA32:
    case X86::POPDS32:
    case X86::POPES32:
    case X86::POPF32:
    case X86::POPFS32:
    case X86::POPGS32:
    case X86::POPSS32:
      return 4;
    case X86::POP64r:
    case X86::POP64rmm:
    case X86::POP64rmr:
    case X86::POPF64:
    case X86::POPFS64:
    case X86::POPGS64:
      return 8;
    }
    return 0;
  }

  bool isPush(const MCInst &Inst) const override {
    return getPushSize(Inst) == 0 ? false : true;
  }

  int getPushSize(const MCInst &Inst) const override {
    switch (Inst.getOpcode()) {
    case X86::PUSH16i8:
    case X86::PUSH16r:
    case X86::PUSH16rmm:
    case X86::PUSH16rmr:
    case X86::PUSHA16:
    case X86::PUSHCS16:
    case X86::PUSHDS16:
    case X86::PUSHES16:
    case X86::PUSHF16:
    case X86::PUSHFS16:
    case X86::PUSHGS16:
    case X86::PUSHSS16:
    case X86::PUSHi16:
      return 2;
    case X86::PUSH32i8:
    case X86::PUSH32r:
    case X86::PUSH32rmm:
    case X86::PUSH32rmr:
    case X86::PUSHA32:
    case X86::PUSHCS32:
    case X86::PUSHDS32:
    case X86::PUSHES32:
    case X86::PUSHF32:
    case X86::PUSHFS32:
    case X86::PUSHGS32:
    case X86::PUSHSS32:
    case X86::PUSHi32:
      return 4;
    case X86::PUSH64i32:
    case X86::PUSH64i8:
    case X86::PUSH64r:
    case X86::PUSH64rmm:
    case X86::PUSH64rmr:
    case X86::PUSHF64:
    case X86::PUSHFS64:
    case X86::PUSHGS64:
      return 8;
    }
    return 0;
  }

  bool isSUB(const MCInst &Inst) const override {
    return X86::isSUB(Inst.getOpcode());
  }

  bool isLEA64r(const MCInst &Inst) const override {
    return Inst.getOpcode() == X86::LEA64r;
  }

  bool isLeave(const MCInst &Inst) const override {
    return Inst.getOpcode() == X86::LEAVE || Inst.getOpcode() == X86::LEAVE64;
  }

  bool isMoveMem2Reg(const MCInst &Inst) const override {
    switch (Inst.getOpcode()) {
    case X86::MOV16rm:
    case X86::MOV32rm:
    case X86::MOV64rm:
      return true;
    }
    return false;
  }

  bool isUnsupportedBranch(unsigned Opcode) const override {
    switch (Opcode) {
    default:
      return false;
    case X86::LOOP:
    case X86::LOOPE:
    case X86::LOOPNE:
    case X86::JECXZ:
    case X86::JRCXZ:
      return true;
    }
  }

  bool isLoad(const MCInst &Inst) const override {
    if (isPop(Inst))
      return true;

    int MemOpNo = getMemoryOperandNo(Inst);
    const MCInstrDesc &MCII = Info->get(Inst.getOpcode());

    if (MemOpNo == -1)
      return false;

    return MCII.mayLoad();
  }

  bool isStore(const MCInst &Inst) const override {
    if (isPush(Inst))
      return true;

    int MemOpNo = getMemoryOperandNo(Inst);
    const MCInstrDesc &MCII = Info->get(Inst.getOpcode());

    if (MemOpNo == -1)
      return false;

    return MCII.mayStore();
  }

  bool isCleanRegXOR(const MCInst &Inst) const override {
    switch (Inst.getOpcode()) {
    case X86::XOR16rr:
    case X86::XOR32rr:
    case X86::XOR64rr:
      break;
    default:
      return false;
    }
    return (Inst.getOperand(0).getReg() == Inst.getOperand(2).getReg());
  }

  bool isPacked(const MCInst &Inst) const override {
    const MCInstrDesc &Desc = Info->get(Inst.getOpcode());
    return (Desc.TSFlags & X86II::OpPrefixMask) == X86II::PD;
  }

  unsigned getTrapFillValue() const override { return 0xCC; }

  struct IndJmpMatcherFrag1 : MCInstMatcher {
    std::unique_ptr<MCInstMatcher> Base;
    std::unique_ptr<MCInstMatcher> Scale;
    std::unique_ptr<MCInstMatcher> Index;
    std::unique_ptr<MCInstMatcher> Offset;

    IndJmpMatcherFrag1(std::unique_ptr<MCInstMatcher> Base,
                       std::unique_ptr<MCInstMatcher> Scale,
                       std::unique_ptr<MCInstMatcher> Index,
                       std::unique_ptr<MCInstMatcher> Offset)
        : Base(std::move(Base)), Scale(std::move(Scale)),
          Index(std::move(Index)), Offset(std::move(Offset)) {}

    bool match(const MCRegisterInfo &MRI, MCPlusBuilder &MIB,
               MutableArrayRef<MCInst> InInstrWindow, int OpNum) override {
      if (!MCInstMatcher::match(MRI, MIB, InInstrWindow, OpNum))
        return false;

      if (CurInst->getOpcode() != X86::JMP64m)
        return false;

      int MemOpNo = MIB.getMemoryOperandNo(*CurInst);
      if (MemOpNo == -1)
        return false;

      if (!Base->match(MRI, MIB, this->InstrWindow, MemOpNo + X86::AddrBaseReg))
        return false;
      if (!Scale->match(MRI, MIB, this->InstrWindow,
                        MemOpNo + X86::AddrScaleAmt))
        return false;
      if (!Index->match(MRI, MIB, this->InstrWindow,
                        MemOpNo + X86::AddrIndexReg))
        return false;
      if (!Offset->match(MRI, MIB, this->InstrWindow, MemOpNo + X86::AddrDisp))
        return false;
      return true;
    }

    void annotate(MCPlusBuilder &MIB, StringRef Annotation) override {
      MIB.addAnnotation(*CurInst, Annotation, true);
      Base->annotate(MIB, Annotation);
      Scale->annotate(MIB, Annotation);
      Index->annotate(MIB, Annotation);
      Offset->annotate(MIB, Annotation);
    }
  };

  std::unique_ptr<MCInstMatcher>
  matchIndJmp(std::unique_ptr<MCInstMatcher> Base,
              std::unique_ptr<MCInstMatcher> Scale,
              std::unique_ptr<MCInstMatcher> Index,
              std::unique_ptr<MCInstMatcher> Offset) const override {
    return std::unique_ptr<MCInstMatcher>(
        new IndJmpMatcherFrag1(std::move(Base), std::move(Scale),
                               std::move(Index), std::move(Offset)));
  }

  struct IndJmpMatcherFrag2 : MCInstMatcher {
    std::unique_ptr<MCInstMatcher> Reg;

    IndJmpMatcherFrag2(std::unique_ptr<MCInstMatcher> Reg)
        : Reg(std::move(Reg)) {}

    bool match(const MCRegisterInfo &MRI, MCPlusBuilder &MIB,
               MutableArrayRef<MCInst> InInstrWindow, int OpNum) override {
      if (!MCInstMatcher::match(MRI, MIB, InInstrWindow, OpNum))
        return false;

      if (CurInst->getOpcode() != X86::JMP64r)
        return false;

      return Reg->match(MRI, MIB, this->InstrWindow, 0);
    }

    void annotate(MCPlusBuilder &MIB, StringRef Annotation) override {
      MIB.addAnnotation(*CurInst, Annotation, true);
      Reg->annotate(MIB, Annotation);
    }
  };

  std::unique_ptr<MCInstMatcher>
  matchIndJmp(std::unique_ptr<MCInstMatcher> Target) const override {
    return std::unique_ptr<MCInstMatcher>(
        new IndJmpMatcherFrag2(std::move(Target)));
  }

  struct LoadMatcherFrag1 : MCInstMatcher {
    std::unique_ptr<MCInstMatcher> Base;
    std::unique_ptr<MCInstMatcher> Scale;
    std::unique_ptr<MCInstMatcher> Index;
    std::unique_ptr<MCInstMatcher> Offset;

    LoadMatcherFrag1(std::unique_ptr<MCInstMatcher> Base,
                     std::unique_ptr<MCInstMatcher> Scale,
                     std::unique_ptr<MCInstMatcher> Index,
                     std::unique_ptr<MCInstMatcher> Offset)
        : Base(std::move(Base)), Scale(std::move(Scale)),
          Index(std::move(Index)), Offset(std::move(Offset)) {}

    bool match(const MCRegisterInfo &MRI, MCPlusBuilder &MIB,
               MutableArrayRef<MCInst> InInstrWindow, int OpNum) override {
      if (!MCInstMatcher::match(MRI, MIB, InInstrWindow, OpNum))
        return false;

      if (CurInst->getOpcode() != X86::MOV64rm &&
          CurInst->getOpcode() != X86::MOVSX64rm32)
        return false;

      int MemOpNo = MIB.getMemoryOperandNo(*CurInst);
      if (MemOpNo == -1)
        return false;

      if (!Base->match(MRI, MIB, this->InstrWindow, MemOpNo + X86::AddrBaseReg))
        return false;
      if (!Scale->match(MRI, MIB, this->InstrWindow,
                        MemOpNo + X86::AddrScaleAmt))
        return false;
      if (!Index->match(MRI, MIB, this->InstrWindow,
                        MemOpNo + X86::AddrIndexReg))
        return false;
      if (!Offset->match(MRI, MIB, this->InstrWindow, MemOpNo + X86::AddrDisp))
        return false;
      return true;
    }

    void annotate(MCPlusBuilder &MIB, StringRef Annotation) override {
      MIB.addAnnotation(*CurInst, Annotation, true);
      Base->annotate(MIB, Annotation);
      Scale->annotate(MIB, Annotation);
      Index->annotate(MIB, Annotation);
      Offset->annotate(MIB, Annotation);
    }
  };

  std::unique_ptr<MCInstMatcher>
  matchLoad(std::unique_ptr<MCInstMatcher> Base,
            std::unique_ptr<MCInstMatcher> Scale,
            std::unique_ptr<MCInstMatcher> Index,
            std::unique_ptr<MCInstMatcher> Offset) const override {
    return std::unique_ptr<MCInstMatcher>(
        new LoadMatcherFrag1(std::move(Base), std::move(Scale),
                             std::move(Index), std::move(Offset)));
  }

  struct AddMatcher : MCInstMatcher {
    std::unique_ptr<MCInstMatcher> A;
    std::unique_ptr<MCInstMatcher> B;

    AddMatcher(std::unique_ptr<MCInstMatcher> A,
               std::unique_ptr<MCInstMatcher> B)
        : A(std::move(A)), B(std::move(B)) {}

    bool match(const MCRegisterInfo &MRI, MCPlusBuilder &MIB,
               MutableArrayRef<MCInst> InInstrWindow, int OpNum) override {
      if (!MCInstMatcher::match(MRI, MIB, InInstrWindow, OpNum))
        return false;

      if (CurInst->getOpcode() == X86::ADD64rr ||
          CurInst->getOpcode() == X86::ADD64rr_DB ||
          CurInst->getOpcode() == X86::ADD64rr_REV) {
        if (!A->match(MRI, MIB, this->InstrWindow, 1)) {
          if (!B->match(MRI, MIB, this->InstrWindow, 1))
            return false;
          return A->match(MRI, MIB, this->InstrWindow, 2);
        }

        if (B->match(MRI, MIB, this->InstrWindow, 2))
          return true;

        if (!B->match(MRI, MIB, this->InstrWindow, 1))
          return false;
        return A->match(MRI, MIB, this->InstrWindow, 2);
      }

      return false;
    }

    void annotate(MCPlusBuilder &MIB, StringRef Annotation) override {
      MIB.addAnnotation(*CurInst, Annotation, true);
      A->annotate(MIB, Annotation);
      B->annotate(MIB, Annotation);
    }
  };

  std::unique_ptr<MCInstMatcher>
  matchAdd(std::unique_ptr<MCInstMatcher> A,
           std::unique_ptr<MCInstMatcher> B) const override {
    return std::unique_ptr<MCInstMatcher>(
        new AddMatcher(std::move(A), std::move(B)));
  }

  struct LEAMatcher : MCInstMatcher {
    std::unique_ptr<MCInstMatcher> Target;

    LEAMatcher(std::unique_ptr<MCInstMatcher> Target)
        : Target(std::move(Target)) {}

    bool match(const MCRegisterInfo &MRI, MCPlusBuilder &MIB,
               MutableArrayRef<MCInst> InInstrWindow, int OpNum) override {
      if (!MCInstMatcher::match(MRI, MIB, InInstrWindow, OpNum))
        return false;

      if (CurInst->getOpcode() != X86::LEA64r)
        return false;

      if (CurInst->getOperand(1 + X86::AddrScaleAmt).getImm() != 1 ||
          CurInst->getOperand(1 + X86::AddrIndexReg).getReg() !=
              X86::NoRegister ||
          (CurInst->getOperand(1 + X86::AddrBaseReg).getReg() !=
               X86::NoRegister &&
           CurInst->getOperand(1 + X86::AddrBaseReg).getReg() != X86::RIP))
        return false;

      return Target->match(MRI, MIB, this->InstrWindow, 1 + X86::AddrDisp);
    }

    void annotate(MCPlusBuilder &MIB, StringRef Annotation) override {
      MIB.addAnnotation(*CurInst, Annotation, true);
      Target->annotate(MIB, Annotation);
    }
  };

  std::unique_ptr<MCInstMatcher>
  matchLoadAddr(std::unique_ptr<MCInstMatcher> Target) const override {
    return std::unique_ptr<MCInstMatcher>(new LEAMatcher(std::move(Target)));
  }

  bool hasPCRelOperand(const MCInst &Inst) const override {
    for (const MCOperand &Operand : Inst)
      if (Operand.isReg() && Operand.getReg() == X86::RIP)
        return true;
    return false;
  }

  int getMemoryOperandNo(const MCInst &Inst) const override {
    unsigned Opcode = Inst.getOpcode();
    const MCInstrDesc &Desc = Info->get(Opcode);
    int MemOpNo = X86II::getMemoryOperandNo(Desc.TSFlags);
    if (MemOpNo >= 0)
      MemOpNo += X86II::getOperandBias(Desc);
    return MemOpNo;
  }

  bool hasEVEXEncoding(const MCInst &Inst) const override {
    const MCInstrDesc &Desc = Info->get(Inst.getOpcode());
    return (Desc.TSFlags & X86II::EncodingMask) == X86II::EVEX;
  }

  bool isMacroOpFusionPair(ArrayRef<MCInst> Insts) const override {
    const auto *I = Insts.begin();
    while (I != Insts.end() && isPrefix(*I))
      ++I;
    if (I == Insts.end())
      return false;

    const MCInst &FirstInst = *I;
    ++I;
    while (I != Insts.end() && isPrefix(*I))
      ++I;
    if (I == Insts.end())
      return false;
    const MCInst &SecondInst = *I;

    if (!isConditionalBranch(SecondInst))
      return false;
    // Cannot fuse if the first instruction uses RIP-relative memory.
    if (hasPCRelOperand(FirstInst))
      return false;

    const X86::FirstMacroFusionInstKind CmpKind =
        X86::classifyFirstOpcodeInMacroFusion(FirstInst.getOpcode());
    if (CmpKind == X86::FirstMacroFusionInstKind::Invalid)
      return false;

    X86::CondCode CC = static_cast<X86::CondCode>(getCondCode(SecondInst));
    X86::SecondMacroFusionInstKind BranchKind =
        X86::classifySecondCondCodeInMacroFusion(CC);
    if (BranchKind == X86::SecondMacroFusionInstKind::Invalid)
      return false;
    return X86::isMacroFused(CmpKind, BranchKind);
  }

  bool
  evaluateX86MemoryOperand(const MCInst &Inst, unsigned *BaseRegNum,
                           int64_t *ScaleImm, unsigned *IndexRegNum,
                           int64_t *DispImm, unsigned *SegmentRegNum,
                           const MCExpr **DispExpr = nullptr) const override {
    assert(BaseRegNum && ScaleImm && IndexRegNum && SegmentRegNum &&
           "one of the input pointers is null");
    int MemOpNo = getMemoryOperandNo(Inst);
    if (MemOpNo < 0)
      return false;
    unsigned MemOpOffset = static_cast<unsigned>(MemOpNo);

    if (MemOpOffset + X86::AddrSegmentReg >= MCPlus::getNumPrimeOperands(Inst))
      return false;

    const MCOperand &Base = Inst.getOperand(MemOpOffset + X86::AddrBaseReg);
    const MCOperand &Scale = Inst.getOperand(MemOpOffset + X86::AddrScaleAmt);
    const MCOperand &Index = Inst.getOperand(MemOpOffset + X86::AddrIndexReg);
    const MCOperand &Disp = Inst.getOperand(MemOpOffset + X86::AddrDisp);
    const MCOperand &Segment =
        Inst.getOperand(MemOpOffset + X86::AddrSegmentReg);

    // Make sure it is a well-formed memory operand.
    if (!Base.isReg() || !Scale.isImm() || !Index.isReg() ||
        (!Disp.isImm() && !Disp.isExpr()) || !Segment.isReg())
      return false;

    *BaseRegNum = Base.getReg();
    *ScaleImm = Scale.getImm();
    *IndexRegNum = Index.getReg();
    if (Disp.isImm()) {
      assert(DispImm && "DispImm needs to be set");
      *DispImm = Disp.getImm();
      if (DispExpr)
        *DispExpr = nullptr;
    } else {
      assert(DispExpr && "DispExpr needs to be set");
      *DispExpr = Disp.getExpr();
      if (DispImm)
        *DispImm = 0;
    }
    *SegmentRegNum = Segment.getReg();
    return true;
  }

  bool evaluateMemOperandTarget(const MCInst &Inst, uint64_t &Target,
                                uint64_t Address,
                                uint64_t Size) const override {
    unsigned      BaseRegNum;
    int64_t       ScaleValue;
    unsigned      IndexRegNum;
    int64_t       DispValue;
    unsigned      SegRegNum;
    const MCExpr *DispExpr = nullptr;
    if (!evaluateX86MemoryOperand(Inst, &BaseRegNum, &ScaleValue, &IndexRegNum,
                                  &DispValue, &SegRegNum, &DispExpr))
      return false;

    // Make sure it's a well-formed addressing we can statically evaluate.
    if ((BaseRegNum != X86::RIP && BaseRegNum != X86::NoRegister) ||
        IndexRegNum != X86::NoRegister || SegRegNum != X86::NoRegister ||
        DispExpr)
      return false;

    Target = DispValue;
    if (BaseRegNum == X86::RIP) {
      assert(Size != 0 && "instruction size required in order to statically "
                          "evaluate RIP-relative address");
      Target += Address + Size;
    }
    return true;
  }

  MCInst::iterator getMemOperandDisp(MCInst &Inst) const override {
    int MemOpNo = getMemoryOperandNo(Inst);
    if (MemOpNo < 0)
      return Inst.end();
    return Inst.begin() + (MemOpNo + X86::AddrDisp);
  }

  bool replaceMemOperandDisp(MCInst &Inst, MCOperand Operand) const override {
    MCOperand *OI = getMemOperandDisp(Inst);
    if (OI == Inst.end())
      return false;
    *OI = Operand;
    return true;
  }

  /// Get the registers used as function parameters.
  /// This function is specific to the x86_64 abi on Linux.
  BitVector getRegsUsedAsParams() const override {
    BitVector Regs = BitVector(RegInfo->getNumRegs(), false);
    Regs |= getAliases(X86::RSI);
    Regs |= getAliases(X86::RDI);
    Regs |= getAliases(X86::RDX);
    Regs |= getAliases(X86::RCX);
    Regs |= getAliases(X86::R8);
    Regs |= getAliases(X86::R9);
    return Regs;
  }

  void getCalleeSavedRegs(BitVector &Regs) const override {
    Regs |= getAliases(X86::RBX);
    Regs |= getAliases(X86::RBP);
    Regs |= getAliases(X86::R12);
    Regs |= getAliases(X86::R13);
    Regs |= getAliases(X86::R14);
    Regs |= getAliases(X86::R15);
  }

  void getDefaultDefIn(BitVector &Regs) const override {
    assert(Regs.size() >= RegInfo->getNumRegs() &&
           "The size of BitVector is less than RegInfo->getNumRegs().");
    Regs.set(X86::RAX);
    Regs.set(X86::RCX);
    Regs.set(X86::RDX);
    Regs.set(X86::RSI);
    Regs.set(X86::RDI);
    Regs.set(X86::R8);
    Regs.set(X86::R9);
    Regs.set(X86::XMM0);
    Regs.set(X86::XMM1);
    Regs.set(X86::XMM2);
    Regs.set(X86::XMM3);
    Regs.set(X86::XMM4);
    Regs.set(X86::XMM5);
    Regs.set(X86::XMM6);
    Regs.set(X86::XMM7);
  }

  void getDefaultLiveOut(BitVector &Regs) const override {
    assert(Regs.size() >= RegInfo->getNumRegs() &&
           "The size of BitVector is less than RegInfo->getNumRegs().");
    Regs |= getAliases(X86::RAX);
    Regs |= getAliases(X86::RDX);
    Regs |= getAliases(X86::RCX);
    Regs |= getAliases(X86::XMM0);
    Regs |= getAliases(X86::XMM1);
  }

  void getGPRegs(BitVector &Regs, bool IncludeAlias) const override {
    if (IncludeAlias) {
      Regs |= getAliases(X86::RAX);
      Regs |= getAliases(X86::RBX);
      Regs |= getAliases(X86::RBP);
      Regs |= getAliases(X86::RSI);
      Regs |= getAliases(X86::RDI);
      Regs |= getAliases(X86::RDX);
      Regs |= getAliases(X86::RCX);
      Regs |= getAliases(X86::R8);
      Regs |= getAliases(X86::R9);
      Regs |= getAliases(X86::R10);
      Regs |= getAliases(X86::R11);
      Regs |= getAliases(X86::R12);
      Regs |= getAliases(X86::R13);
      Regs |= getAliases(X86::R14);
      Regs |= getAliases(X86::R15);
      return;
    }
    Regs.set(X86::RAX);
    Regs.set(X86::RBX);
    Regs.set(X86::RBP);
    Regs.set(X86::RSI);
    Regs.set(X86::RDI);
    Regs.set(X86::RDX);
    Regs.set(X86::RCX);
    Regs.set(X86::R8);
    Regs.set(X86::R9);
    Regs.set(X86::R10);
    Regs.set(X86::R11);
    Regs.set(X86::R12);
    Regs.set(X86::R13);
    Regs.set(X86::R14);
    Regs.set(X86::R15);
  }

  void getClassicGPRegs(BitVector &Regs) const override {
    Regs |= getAliases(X86::RAX);
    Regs |= getAliases(X86::RBX);
    Regs |= getAliases(X86::RBP);
    Regs |= getAliases(X86::RSI);
    Regs |= getAliases(X86::RDI);
    Regs |= getAliases(X86::RDX);
    Regs |= getAliases(X86::RCX);
  }

  void getRepRegs(BitVector &Regs) const override {
    Regs |= getAliases(X86::RCX);
  }

  MCPhysReg getAliasSized(MCPhysReg Reg, uint8_t Size) const override {
    switch (Reg) {
    case X86::RAX: case X86::EAX: case X86::AX: case X86::AL: case X86::AH:
      switch (Size) {
      case 8: return X86::RAX;       case 4: return X86::EAX;
      case 2: return X86::AX;        case 1: return X86::AL;
      default: llvm_unreachable("Unexpected size");
      }
    case X86::RBX: case X86::EBX: case X86::BX: case X86::BL: case X86::BH:
      switch (Size) {
      case 8: return X86::RBX;       case 4: return X86::EBX;
      case 2: return X86::BX;        case 1: return X86::BL;
      default: llvm_unreachable("Unexpected size");
      }
    case X86::RDX: case X86::EDX: case X86::DX: case X86::DL: case X86::DH:
      switch (Size) {
      case 8: return X86::RDX;       case 4: return X86::EDX;
      case 2: return X86::DX;        case 1: return X86::DL;
      default: llvm_unreachable("Unexpected size");
      }
    case X86::RDI: case X86::EDI: case X86::DI: case X86::DIL:
      switch (Size) {
      case 8: return X86::RDI;       case 4: return X86::EDI;
      case 2: return X86::DI;        case 1: return X86::DIL;
      default: llvm_unreachable("Unexpected size");
      }
    case X86::RSI: case X86::ESI: case X86::SI: case X86::SIL:
      switch (Size) {
      case 8: return X86::RSI;       case 4: return X86::ESI;
      case 2: return X86::SI;        case 1: return X86::SIL;
      default: llvm_unreachable("Unexpected size");
      }
    case X86::RCX: case X86::ECX: case X86::CX: case X86::CL: case X86::CH:
      switch (Size) {
      case 8: return X86::RCX;       case 4: return X86::ECX;
      case 2: return X86::CX;        case 1: return X86::CL;
      default: llvm_unreachable("Unexpected size");
      }
    case X86::RSP: case X86::ESP: case X86::SP: case X86::SPL:
      switch (Size) {
      case 8: return X86::RSP;       case 4: return X86::ESP;
      case 2: return X86::SP;        case 1: return X86::SPL;
      default: llvm_unreachable("Unexpected size");
      }
    case X86::RBP: case X86::EBP: case X86::BP: case X86::BPL:
      switch (Size) {
      case 8: return X86::RBP;       case 4: return X86::EBP;
      case 2: return X86::BP;        case 1: return X86::BPL;
      default: llvm_unreachable("Unexpected size");
      }
  case X86::R8: case X86::R8D: case X86::R8W: case X86::R8B:
      switch (Size) {
      case 8: return X86::R8;        case 4: return X86::R8D;
      case 2: return X86::R8W;       case 1: return X86::R8B;
      default: llvm_unreachable("Unexpected size");
      }
    case X86::R9: case X86::R9D: case X86::R9W: case X86::R9B:
      switch (Size) {
      case 8: return X86::R9;        case 4: return X86::R9D;
      case 2: return X86::R9W;       case 1: return X86::R9B;
      default: llvm_unreachable("Unexpected size");
      }
    case X86::R10: case X86::R10D: case X86::R10W: case X86::R10B:
      switch (Size) {
      case 8: return X86::R10;        case 4: return X86::R10D;
      case 2: return X86::R10W;       case 1: return X86::R10B;
      default: llvm_unreachable("Unexpected size");
      }
    case X86::R11: case X86::R11D: case X86::R11W: case X86::R11B:
      switch (Size) {
      case 8: return X86::R11;        case 4: return X86::R11D;
      case 2: return X86::R11W;       case 1: return X86::R11B;
      default: llvm_unreachable("Unexpected size");
      }
    case X86::R12: case X86::R12D: case X86::R12W: case X86::R12B:
      switch (Size) {
      case 8: return X86::R12;        case 4: return X86::R12D;
      case 2: return X86::R12W;       case 1: return X86::R12B;
      default: llvm_unreachable("Unexpected size");
      }
    case X86::R13: case X86::R13D: case X86::R13W: case X86::R13B:
      switch (Size) {
      case 8: return X86::R13;        case 4: return X86::R13D;
      case 2: return X86::R13W;       case 1: return X86::R13B;
      default: llvm_unreachable("Unexpected size");
      }
    case X86::R14: case X86::R14D: case X86::R14W: case X86::R14B:
      switch (Size) {
      case 8: return X86::R14;        case 4: return X86::R14D;
      case 2: return X86::R14W;       case 1: return X86::R14B;
      default: llvm_unreachable("Unexpected size");
      }
    case X86::R15: case X86::R15D: case X86::R15W: case X86::R15B:
      switch (Size) {
      case 8: return X86::R15;        case 4: return X86::R15D;
      case 2: return X86::R15W;       case 1: return X86::R15B;
      default: llvm_unreachable("Unexpected size");
      }
    default:
      dbgs() << Reg << " (get alias sized)\n";
      llvm_unreachable("Unexpected reg number");
      break;
    }
  }

  bool isUpper8BitReg(MCPhysReg Reg) const override {
    switch (Reg) {
    case X86::AH:
    case X86::BH:
    case X86::CH:
    case X86::DH:
      return true;
    default:
      return false;
    }
  }

  bool cannotUseREX(const MCInst &Inst) const override {
    switch (Inst.getOpcode()) {
    case X86::MOV8mr_NOREX:
    case X86::MOV8rm_NOREX:
    case X86::MOV8rr_NOREX:
    case X86::MOVSX32rm8_NOREX:
    case X86::MOVSX32rr8_NOREX:
    case X86::MOVZX32rm8_NOREX:
    case X86::MOVZX32rr8_NOREX:
    case X86::MOV8mr:
    case X86::MOV8rm:
    case X86::MOV8rr:
    case X86::MOVSX32rm8:
    case X86::MOVSX32rr8:
    case X86::MOVZX32rm8:
    case X86::MOVZX32rr8:
    case X86::TEST8ri:
      for (const MCOperand &Operand : MCPlus::primeOperands(Inst)) {
        if (!Operand.isReg())
          continue;
        if (isUpper8BitReg(Operand.getReg()))
          return true;
      }
      [[fallthrough]];
    default:
      return false;
    }
  }

  static uint8_t getMemDataSize(const MCInst &Inst, int MemOpNo) {
    using namespace llvm::X86;
    int OpType = getOperandType(Inst.getOpcode(), MemOpNo);
    return getMemOperandSize(OpType) / 8;
  }

  /// Classifying a stack access as *not* "SIMPLE" here means we don't know how
  /// to change this instruction memory access. It will disable any changes to
  /// the stack layout, so we can't do the most aggressive form of shrink
  /// wrapping. We must do so in a way that keeps the original stack layout.
  /// Otherwise you need to adjust the offset of all instructions accessing the
  /// stack: we can't do that anymore because there is one instruction that is
  /// not simple. There are other implications as well. We have heuristics to
  /// detect when a register is callee-saved and thus eligible for shrink
  /// wrapping. If you are restoring a register using a non-simple stack access,
  /// then it is classified as NOT callee-saved, and it disables shrink wrapping
  /// for *that* register (but not for others).
  ///
  /// Classifying a stack access as "size 0" or detecting an indexed memory
  /// access (to address a vector, for example) here means we know there is a
  /// stack access, but we can't quite understand how wide is the access in
  /// bytes. This is very serious because we can't understand how memory
  /// accesses alias with each other for this function. This will essentially
  /// disable not only shrink wrapping but all frame analysis, it will fail it
  /// as "we don't understand this function and we give up on it".
  bool isStackAccess(const MCInst &Inst, bool &IsLoad, bool &IsStore,
                     bool &IsStoreFromReg, MCPhysReg &Reg, int32_t &SrcImm,
                     uint16_t &StackPtrReg, int64_t &StackOffset, uint8_t &Size,
                     bool &IsSimple, bool &IsIndexed) const override {
    // Detect simple push/pop cases first
    if (int Sz = getPushSize(Inst)) {
      IsLoad = false;
      IsStore = true;
      IsStoreFromReg = true;
      StackPtrReg = X86::RSP;
      StackOffset = -Sz;
      Size = Sz;
      IsSimple = true;
      if (Inst.getOperand(0).isImm())
        SrcImm = Inst.getOperand(0).getImm();
      else if (Inst.getOperand(0).isReg())
        Reg = Inst.getOperand(0).getReg();
      else
        IsSimple = false;

      return true;
    }
    if (int Sz = getPopSize(Inst)) {
      IsLoad = true;
      IsStore = false;
      if (Inst.getNumOperands() == 0 || !Inst.getOperand(0).isReg()) {
        IsSimple = false;
      } else {
        Reg = Inst.getOperand(0).getReg();
        IsSimple = true;
      }
      StackPtrReg = X86::RSP;
      StackOffset = 0;
      Size = Sz;
      return true;
    }

    struct InstInfo {
      // Size in bytes that Inst loads from memory.
      uint8_t DataSize;
      bool IsLoad;
      bool IsStore;
      bool StoreFromReg;
      bool Simple;
    };

    InstInfo I;
    int MemOpNo = getMemoryOperandNo(Inst);
    const MCInstrDesc &MCII = Info->get(Inst.getOpcode());
    // If it is not dealing with a memory operand, we discard it
    if (MemOpNo == -1 || MCII.isCall())
      return false;

    switch (Inst.getOpcode()) {
    default: {
      bool IsLoad = MCII.mayLoad();
      bool IsStore = MCII.mayStore();
      // Is it LEA? (deals with memory but is not loading nor storing)
      if (!IsLoad && !IsStore) {
        I = {0, IsLoad, IsStore, false, false};
        break;
      }
      uint8_t Sz = getMemDataSize(Inst, MemOpNo);
      I = {Sz, IsLoad, IsStore, false, false};
      break;
    }
    // Report simple stack accesses
    case X86::MOV8rm: I = {1, true, false, false, true}; break;
    case X86::MOV16rm: I = {2, true, false, false, true}; break;
    case X86::MOV32rm: I = {4, true, false, false, true}; break;
    case X86::MOV64rm: I = {8, true, false, false, true}; break;
    case X86::MOV8mr: I = {1, false, true, true, true};  break;
    case X86::MOV16mr: I = {2, false, true, true, true};  break;
    case X86::MOV32mr: I = {4, false, true, true, true};  break;
    case X86::MOV64mr: I = {8, false, true, true, true};  break;
    case X86::MOV8mi: I = {1, false, true, false, true}; break;
    case X86::MOV16mi: I = {2, false, true, false, true}; break;
    case X86::MOV32mi: I = {4, false, true, false, true}; break;
    } // end switch (Inst.getOpcode())

    unsigned BaseRegNum;
    int64_t ScaleValue;
    unsigned IndexRegNum;
    int64_t DispValue;
    unsigned SegRegNum;
    const MCExpr *DispExpr;
    if (!evaluateX86MemoryOperand(Inst, &BaseRegNum, &ScaleValue, &IndexRegNum,
                                  &DispValue, &SegRegNum, &DispExpr)) {
      LLVM_DEBUG(dbgs() << "Evaluate failed on ");
      LLVM_DEBUG(Inst.dump());
      return false;
    }

    // Make sure it's a stack access
    if (BaseRegNum != X86::RBP && BaseRegNum != X86::RSP)
      return false;

    IsLoad = I.IsLoad;
    IsStore = I.IsStore;
    IsStoreFromReg = I.StoreFromReg;
    Size = I.DataSize;
    IsSimple = I.Simple;
    StackPtrReg = BaseRegNum;
    StackOffset = DispValue;
    IsIndexed = IndexRegNum != X86::NoRegister || SegRegNum != X86::NoRegister;

    if (!I.Simple)
      return true;

    // Retrieve related register in simple MOV from/to stack operations.
    unsigned MemOpOffset = static_cast<unsigned>(MemOpNo);
    if (I.IsLoad) {
      MCOperand RegOpnd = Inst.getOperand(0);
      assert(RegOpnd.isReg() && "unexpected destination operand");
      Reg = RegOpnd.getReg();
    } else if (I.IsStore) {
      MCOperand SrcOpnd =
          Inst.getOperand(MemOpOffset + X86::AddrSegmentReg + 1);
      if (I.StoreFromReg) {
        assert(SrcOpnd.isReg() && "unexpected source operand");
        Reg = SrcOpnd.getReg();
      } else {
        assert(SrcOpnd.isImm() && "unexpected source operand");
        SrcImm = SrcOpnd.getImm();
      }
    }

    return true;
  }

  void changeToPushOrPop(MCInst &Inst) const override {
    assert(!isPush(Inst) && !isPop(Inst));

    struct InstInfo {
      // Size in bytes that Inst loads from memory.
      uint8_t DataSize;
      bool IsLoad;
      bool StoreFromReg;
    };

    InstInfo I;
    switch (Inst.getOpcode()) {
    default: {
      llvm_unreachable("Unhandled opcode");
      return;
    }
    case X86::MOV16rm: I = {2, true, false}; break;
    case X86::MOV32rm: I = {4, true, false}; break;
    case X86::MOV64rm: I = {8, true, false}; break;
    case X86::MOV16mr: I = {2, false, true};  break;
    case X86::MOV32mr: I = {4, false, true};  break;
    case X86::MOV64mr: I = {8, false, true};  break;
    case X86::MOV16mi: I = {2, false, false}; break;
    case X86::MOV32mi: I = {4, false, false}; break;
    } // end switch (Inst.getOpcode())

    unsigned BaseRegNum;
    int64_t ScaleValue;
    unsigned IndexRegNum;
    int64_t DispValue;
    unsigned SegRegNum;
    const MCExpr *DispExpr;
    if (!evaluateX86MemoryOperand(Inst, &BaseRegNum, &ScaleValue, &IndexRegNum,
                                  &DispValue, &SegRegNum, &DispExpr)) {
      llvm_unreachable("Evaluate failed");
      return;
    }
    // Make sure it's a stack access
    if (BaseRegNum != X86::RBP && BaseRegNum != X86::RSP) {
      llvm_unreachable("Not a stack access");
      return;
    }

    unsigned MemOpOffset = getMemoryOperandNo(Inst);
    unsigned NewOpcode = 0;
    if (I.IsLoad) {
      switch (I.DataSize) {
      case 2: NewOpcode = X86::POP16r; break;
      case 4: NewOpcode = X86::POP32r; break;
      case 8: NewOpcode = X86::POP64r; break;
      default:
        llvm_unreachable("Unexpected size");
      }
      unsigned RegOpndNum = Inst.getOperand(0).getReg();
      Inst.clear();
      Inst.setOpcode(NewOpcode);
      Inst.addOperand(MCOperand::createReg(RegOpndNum));
    } else {
      MCOperand SrcOpnd =
          Inst.getOperand(MemOpOffset + X86::AddrSegmentReg + 1);
      if (I.StoreFromReg) {
        switch (I.DataSize) {
        case 2: NewOpcode = X86::PUSH16r; break;
        case 4: NewOpcode = X86::PUSH32r; break;
        case 8: NewOpcode = X86::PUSH64r; break;
        default:
          llvm_unreachable("Unexpected size");
        }
        assert(SrcOpnd.isReg() && "Unexpected source operand");
        unsigned RegOpndNum = SrcOpnd.getReg();
        Inst.clear();
        Inst.setOpcode(NewOpcode);
        Inst.addOperand(MCOperand::createReg(RegOpndNum));
      } else {
        switch (I.DataSize) {
        case 2: NewOpcode = X86::PUSH16i8; break;
        case 4: NewOpcode = X86::PUSH32i8; break;
        case 8: NewOpcode = X86::PUSH64i32; break;
        default:
          llvm_unreachable("Unexpected size");
        }
        assert(SrcOpnd.isImm() && "Unexpected source operand");
        int64_t SrcImm = SrcOpnd.getImm();
        Inst.clear();
        Inst.setOpcode(NewOpcode);
        Inst.addOperand(MCOperand::createImm(SrcImm));
      }
    }
  }

  bool isStackAdjustment(const MCInst &Inst) const override {
    switch (Inst.getOpcode()) {
    default:
      return false;
    case X86::SUB64ri32:
    case X86::SUB64ri8:
    case X86::ADD64ri32:
    case X86::ADD64ri8:
    case X86::LEA64r:
      break;
    }

    const MCInstrDesc &MCII = Info->get(Inst.getOpcode());
    for (int I = 0, E = MCII.getNumDefs(); I != E; ++I) {
      const MCOperand &Operand = Inst.getOperand(I);
      if (Operand.isReg() && Operand.getReg() == X86::RSP)
        return true;
    }
    return false;
  }

  bool
  evaluateStackOffsetExpr(const MCInst &Inst, int64_t &Output,
                          std::pair<MCPhysReg, int64_t> Input1,
                          std::pair<MCPhysReg, int64_t> Input2) const override {

    auto getOperandVal = [&](MCPhysReg Reg) -> ErrorOr<int64_t> {
      if (Reg == Input1.first)
        return Input1.second;
      if (Reg == Input2.first)
        return Input2.second;
      return make_error_code(errc::result_out_of_range);
    };

    switch (Inst.getOpcode()) {
    default:
      return false;

    case X86::SUB64ri32:
    case X86::SUB64ri8:
      if (!Inst.getOperand(2).isImm())
        return false;
      if (ErrorOr<int64_t> InputVal =
              getOperandVal(Inst.getOperand(1).getReg()))
        Output = *InputVal - Inst.getOperand(2).getImm();
      else
        return false;
      break;
    case X86::ADD64ri32:
    case X86::ADD64ri8:
      if (!Inst.getOperand(2).isImm())
        return false;
      if (ErrorOr<int64_t> InputVal =
              getOperandVal(Inst.getOperand(1).getReg()))
        Output = *InputVal + Inst.getOperand(2).getImm();
      else
        return false;
      break;
    case X86::ADD64i32:
      if (!Inst.getOperand(0).isImm())
        return false;
      if (ErrorOr<int64_t> InputVal = getOperandVal(X86::RAX))
        Output = *InputVal + Inst.getOperand(0).getImm();
      else
        return false;
      break;

    case X86::LEA64r: {
      unsigned BaseRegNum;
      int64_t ScaleValue;
      unsigned IndexRegNum;
      int64_t DispValue;
      unsigned SegRegNum;
      const MCExpr *DispExpr = nullptr;
      if (!evaluateX86MemoryOperand(Inst, &BaseRegNum, &ScaleValue,
                                    &IndexRegNum, &DispValue, &SegRegNum,
                                    &DispExpr))
        return false;

      if (BaseRegNum == X86::NoRegister || IndexRegNum != X86::NoRegister ||
          SegRegNum != X86::NoRegister || DispExpr)
        return false;

      if (ErrorOr<int64_t> InputVal = getOperandVal(BaseRegNum))
        Output = *InputVal + DispValue;
      else
        return false;

      break;
    }
    }
    return true;
  }

  bool isRegToRegMove(const MCInst &Inst, MCPhysReg &From,
                      MCPhysReg &To) const override {
    switch (Inst.getOpcode()) {
    default:
      return false;
    case X86::LEAVE:
    case X86::LEAVE64:
      To = getStackPointer();
      From = getFramePointer();
      return true;
    case X86::MOV64rr:
      To = Inst.getOperand(0).getReg();
      From = Inst.getOperand(1).getReg();
      return true;
    }
  }

  MCPhysReg getStackPointer() const override { return X86::RSP; }
  MCPhysReg getFramePointer() const override { return X86::RBP; }
  MCPhysReg getFlagsReg() const override { return X86::EFLAGS; }

  bool escapesVariable(const MCInst &Inst,
                       bool HasFramePointer) const override {
    int MemOpNo = getMemoryOperandNo(Inst);
    const MCInstrDesc &MCII = Info->get(Inst.getOpcode());
    const unsigned NumDefs = MCII.getNumDefs();
    static BitVector SPBPAliases(BitVector(getAliases(X86::RSP)) |=
                                 getAliases(X86::RBP));
    static BitVector SPAliases(getAliases(X86::RSP));

    // FIXME: PUSH can be technically a leak, but let's ignore this for now
    // because a lot of harmless prologue code will spill SP to the stack.
    // Unless push is clearly pushing an object address to the stack as
    // demonstrated by having a MemOp.
    bool IsPush = isPush(Inst);
    if (IsPush && MemOpNo == -1)
      return false;

    // We use this to detect LEA (has memop but does not access mem)
    bool AccessMem = MCII.mayLoad() || MCII.mayStore();
    bool DoesLeak = false;
    for (int I = 0, E = MCPlus::getNumPrimeOperands(Inst); I != E; ++I) {
      // Ignore if SP/BP is used to dereference memory -- that's fine
      if (MemOpNo != -1 && !IsPush && AccessMem && I >= MemOpNo &&
          I <= MemOpNo + 5)
        continue;
      // Ignore if someone is writing to SP/BP
      if (I < static_cast<int>(NumDefs))
        continue;

      const MCOperand &Operand = Inst.getOperand(I);
      if (HasFramePointer && Operand.isReg() && SPBPAliases[Operand.getReg()]) {
        DoesLeak = true;
        break;
      }
      if (!HasFramePointer && Operand.isReg() && SPAliases[Operand.getReg()]) {
        DoesLeak = true;
        break;
      }
    }

    // If potential leak, check if it is not just writing to itself/sp/bp
    if (DoesLeak) {
      for (int I = 0, E = NumDefs; I != E; ++I) {
        const MCOperand &Operand = Inst.getOperand(I);
        if (HasFramePointer && Operand.isReg() &&
            SPBPAliases[Operand.getReg()]) {
          DoesLeak = false;
          break;
        }
        if (!HasFramePointer && Operand.isReg() &&
            SPAliases[Operand.getReg()]) {
          DoesLeak = false;
          break;
        }
      }
    }
    return DoesLeak;
  }

  bool addToImm(MCInst &Inst, int64_t &Amt, MCContext *Ctx) const override {
    unsigned ImmOpNo = -1U;
    int MemOpNo = getMemoryOperandNo(Inst);
    if (MemOpNo != -1)
      ImmOpNo = MemOpNo + X86::AddrDisp;
    else
      for (unsigned Index = 0; Index < MCPlus::getNumPrimeOperands(Inst);
           ++Index)
        if (Inst.getOperand(Index).isImm())
          ImmOpNo = Index;
    if (ImmOpNo == -1U)
      return false;

    MCOperand &Operand = Inst.getOperand(ImmOpNo);
    Amt += Operand.getImm();
    Operand.setImm(Amt);
    // Check for the need for relaxation
    if (int64_t(Amt) == int64_t(int8_t(Amt)))
      return true;

    // Relax instruction
    switch (Inst.getOpcode()) {
    case X86::SUB64ri8:
      Inst.setOpcode(X86::SUB64ri32);
      break;
    case X86::ADD64ri8:
      Inst.setOpcode(X86::ADD64ri32);
      break;
    default:
      // No need for relaxation
      break;
    }
    return true;
  }

  /// TODO: this implementation currently works for the most common opcodes that
  /// load from memory. It can be extended to work with memory store opcodes as
  /// well as more memory load opcodes.
  bool replaceMemOperandWithImm(MCInst &Inst, StringRef ConstantData,
                                uint64_t Offset) const override {
    enum CheckSignExt : uint8_t {
      NOCHECK = 0,
      CHECK8,
      CHECK32,
    };

    using CheckList = std::vector<std::pair<CheckSignExt, unsigned>>;
    struct InstInfo {
      // Size in bytes that Inst loads from memory.
      uint8_t DataSize;

      // True when the target operand has to be duplicated because the opcode
      // expects a LHS operand.
      bool HasLHS;

      // List of checks and corresponding opcodes to be used. We try to use the
      // smallest possible immediate value when various sizes are available,
      // hence we may need to check whether a larger constant fits in a smaller
      // immediate.
      CheckList Checks;
    };

    InstInfo I;

    switch (Inst.getOpcode()) {
    default: {
      switch (getPopSize(Inst)) {
      case 2:            I = {2, false, {{NOCHECK, X86::MOV16ri}}};  break;
      case 4:            I = {4, false, {{NOCHECK, X86::MOV32ri}}};  break;
      case 8:            I = {8, false, {{CHECK32, X86::MOV64ri32},
                                         {NOCHECK, X86::MOV64rm}}};  break;
      default:           return false;
      }
      break;
    }

    // MOV
    case X86::MOV8rm:      I = {1, false, {{NOCHECK, X86::MOV8ri}}};   break;
    case X86::MOV16rm:     I = {2, false, {{NOCHECK, X86::MOV16ri}}};  break;
    case X86::MOV32rm:     I = {4, false, {{NOCHECK, X86::MOV32ri}}};  break;
    case X86::MOV64rm:     I = {8, false, {{CHECK32, X86::MOV64ri32},
                                           {NOCHECK, X86::MOV64rm}}};  break;

    // MOVZX
    case X86::MOVZX16rm8:  I = {1, false, {{NOCHECK, X86::MOV16ri}}};  break;
    case X86::MOVZX32rm8:  I = {1, false, {{NOCHECK, X86::MOV32ri}}};  break;
    case X86::MOVZX32rm16: I = {2, false, {{NOCHECK, X86::MOV32ri}}};  break;

    // CMP
    case X86::CMP8rm:      I = {1, false, {{NOCHECK, X86::CMP8ri}}};   break;
    case X86::CMP16rm:     I = {2, false, {{CHECK8,  X86::CMP16ri8},
                                           {NOCHECK, X86::CMP16ri}}};  break;
    case X86::CMP32rm:     I = {4, false, {{CHECK8,  X86::CMP32ri8},
                                           {NOCHECK, X86::CMP32ri}}};  break;
    case X86::CMP64rm:     I = {8, false, {{CHECK8,  X86::CMP64ri8},
                                           {CHECK32, X86::CMP64ri32},
                                           {NOCHECK, X86::CMP64rm}}};  break;

    // TEST
    case X86::TEST8mr:     I = {1, false, {{NOCHECK, X86::TEST8ri}}};  break;
    case X86::TEST16mr:    I = {2, false, {{NOCHECK, X86::TEST16ri}}}; break;
    case X86::TEST32mr:    I = {4, false, {{NOCHECK, X86::TEST32ri}}}; break;
    case X86::TEST64mr:    I = {8, false, {{CHECK32, X86::TEST64ri32},
                                           {NOCHECK, X86::TEST64mr}}}; break;

    // ADD
    case X86::ADD8rm:      I = {1, true,  {{NOCHECK, X86::ADD8ri}}};   break;
    case X86::ADD16rm:     I = {2, true,  {{CHECK8,  X86::ADD16ri8},
                                           {NOCHECK, X86::ADD16ri}}};  break;
    case X86::ADD32rm:     I = {4, true,  {{CHECK8,  X86::ADD32ri8},
                                           {NOCHECK, X86::ADD32ri}}};  break;
    case X86::ADD64rm:     I = {8, true,  {{CHECK8,  X86::ADD64ri8},
                                           {CHECK32, X86::ADD64ri32},
                                           {NOCHECK, X86::ADD64rm}}};  break;

    // SUB
    case X86::SUB8rm:      I = {1, true,  {{NOCHECK, X86::SUB8ri}}};   break;
    case X86::SUB16rm:     I = {2, true,  {{CHECK8,  X86::SUB16ri8},
                                           {NOCHECK, X86::SUB16ri}}};  break;
    case X86::SUB32rm:     I = {4, true,  {{CHECK8,  X86::SUB32ri8},
                                           {NOCHECK, X86::SUB32ri}}};  break;
    case X86::SUB64rm:     I = {8, true,  {{CHECK8,  X86::SUB64ri8},
                                           {CHECK32, X86::SUB64ri32},
                                           {NOCHECK, X86::SUB64rm}}};  break;

    // AND
    case X86::AND8rm:      I = {1, true,  {{NOCHECK, X86::AND8ri}}};   break;
    case X86::AND16rm:     I = {2, true,  {{CHECK8,  X86::AND16ri8},
                                           {NOCHECK, X86::AND16ri}}};  break;
    case X86::AND32rm:     I = {4, true,  {{CHECK8,  X86::AND32ri8},
                                           {NOCHECK, X86::AND32ri}}};  break;
    case X86::AND64rm:     I = {8, true,  {{CHECK8,  X86::AND64ri8},
                                           {CHECK32, X86::AND64ri32},
                                           {NOCHECK, X86::AND64rm}}};  break;

    // OR
    case X86::OR8rm:       I = {1, true,  {{NOCHECK, X86::OR8ri}}};    break;
    case X86::OR16rm:      I = {2, true,  {{CHECK8,  X86::OR16ri8},
                                           {NOCHECK, X86::OR16ri}}};   break;
    case X86::OR32rm:      I = {4, true,  {{CHECK8,  X86::OR32ri8},
                                           {NOCHECK, X86::OR32ri}}};   break;
    case X86::OR64rm:      I = {8, true,  {{CHECK8,  X86::OR64ri8},
                                           {CHECK32, X86::OR64ri32},
                                           {NOCHECK, X86::OR64rm}}};   break;

    // XOR
    case X86::XOR8rm:      I = {1, true,  {{NOCHECK, X86::XOR8ri}}};   break;
    case X86::XOR16rm:     I = {2, true,  {{CHECK8,  X86::XOR16ri8},
                                           {NOCHECK, X86::XOR16ri}}};  break;
    case X86::XOR32rm:     I = {4, true,  {{CHECK8,  X86::XOR32ri8},
                                           {NOCHECK, X86::XOR32ri}}};  break;
    case X86::XOR64rm:     I = {8, true,  {{CHECK8,  X86::XOR64ri8},
                                           {CHECK32, X86::XOR64ri32},
                                           {NOCHECK, X86::XOR64rm}}};  break;
    }

    // Compute the immediate value.
    assert(Offset + I.DataSize <= ConstantData.size() &&
           "invalid offset for given constant data");
    int64_t ImmVal =
        DataExtractor(ConstantData, true, 8).getSigned(&Offset, I.DataSize);

    // Compute the new opcode.
    unsigned NewOpcode = 0;
    for (const std::pair<CheckSignExt, unsigned> &Check : I.Checks) {
      NewOpcode = Check.second;
      if (Check.first == NOCHECK)
        break;
      if (Check.first == CHECK8 && isInt<8>(ImmVal))
        break;
      if (Check.first == CHECK32 && isInt<32>(ImmVal))
        break;
    }
    if (NewOpcode == Inst.getOpcode())
      return false;

    // Modify the instruction.
    MCOperand ImmOp = MCOperand::createImm(ImmVal);
    uint32_t TargetOpNum = 0;
    // Test instruction does not follow the regular pattern of putting the
    // memory reference of a load (5 MCOperands) last in the list of operands.
    // Since it is not modifying the register operand, it is not treated as
    // a destination operand and it is not the first operand as it is in the
    // other instructions we treat here.
    if (NewOpcode == X86::TEST8ri || NewOpcode == X86::TEST16ri ||
        NewOpcode == X86::TEST32ri || NewOpcode == X86::TEST64ri32)
      TargetOpNum = getMemoryOperandNo(Inst) + X86::AddrNumOperands;

    MCOperand TargetOp = Inst.getOperand(TargetOpNum);
    Inst.clear();
    Inst.setOpcode(NewOpcode);
    Inst.addOperand(TargetOp);
    if (I.HasLHS)
      Inst.addOperand(TargetOp);
    Inst.addOperand(ImmOp);

    return true;
  }

  /// TODO: this implementation currently works for the most common opcodes that
  /// load from memory. It can be extended to work with memory store opcodes as
  /// well as more memory load opcodes.
  bool replaceMemOperandWithReg(MCInst &Inst, MCPhysReg RegNum) const override {
    unsigned NewOpcode;

    switch (Inst.getOpcode()) {
    default: {
      switch (getPopSize(Inst)) {
      case 2:            NewOpcode = X86::MOV16rr; break;
      case 4:            NewOpcode = X86::MOV32rr; break;
      case 8:            NewOpcode = X86::MOV64rr; break;
      default:           return false;
      }
      break;
    }

    // MOV
    case X86::MOV8rm:      NewOpcode = X86::MOV8rr;   break;
    case X86::MOV16rm:     NewOpcode = X86::MOV16rr;  break;
    case X86::MOV32rm:     NewOpcode = X86::MOV32rr;  break;
    case X86::MOV64rm:     NewOpcode = X86::MOV64rr;  break;
    }

    // Modify the instruction.
    MCOperand RegOp = MCOperand::createReg(RegNum);
    MCOperand TargetOp = Inst.getOperand(0);
    Inst.clear();
    Inst.setOpcode(NewOpcode);
    Inst.addOperand(TargetOp);
    Inst.addOperand(RegOp);

    return true;
  }

  bool isRedundantMove(const MCInst &Inst) const override {
    switch (Inst.getOpcode()) {
    default:
      return false;

    // MOV
    case X86::MOV8rr:
    case X86::MOV16rr:
    case X86::MOV32rr:
    case X86::MOV64rr:
      break;
    }

    assert(Inst.getOperand(0).isReg() && Inst.getOperand(1).isReg());
    return Inst.getOperand(0).getReg() == Inst.getOperand(1).getReg();
  }

  bool requiresAlignedAddress(const MCInst &Inst) const override {
    const MCInstrDesc &Desc = Info->get(Inst.getOpcode());
    for (unsigned int I = 0; I < Desc.getNumOperands(); ++I) {
      const MCOperandInfo &Op = Desc.OpInfo[I];
      if (Op.OperandType != MCOI::OPERAND_REGISTER)
        continue;
      if (Op.RegClass == X86::VR128RegClassID)
        return true;
    }
    return false;
  }

  bool convertJmpToTailCall(MCInst &Inst) override {
    if (isTailCall(Inst))
      return false;

    int NewOpcode;
    switch (Inst.getOpcode()) {
    default:
      return false;
    case X86::JMP_1:
    case X86::JMP_2:
    case X86::JMP_4:
      NewOpcode = X86::JMP_4;
      break;
    case X86::JMP16m:
    case X86::JMP32m:
    case X86::JMP64m:
      NewOpcode = X86::JMP32m;
      break;
    case X86::JMP16r:
    case X86::JMP32r:
    case X86::JMP64r:
      NewOpcode = X86::JMP32r;
      break;
    }

    Inst.setOpcode(NewOpcode);
    setTailCall(Inst);
    return true;
  }

  bool convertTailCallToJmp(MCInst &Inst) override {
    int NewOpcode;
    switch (Inst.getOpcode()) {
    default:
      return false;
    case X86::JMP_4:
      NewOpcode = X86::JMP_1;
      break;
    case X86::JMP32m:
      NewOpcode = X86::JMP64m;
      break;
    case X86::JMP32r:
      NewOpcode = X86::JMP64r;
      break;
    }

    Inst.setOpcode(NewOpcode);
    removeAnnotation(Inst, MCPlus::MCAnnotation::kTailCall);
    clearOffset(Inst);
    return true;
  }

  bool convertTailCallToCall(MCInst &Inst) override {
    int NewOpcode;
    switch (Inst.getOpcode()) {
    default:
      return false;
    case X86::JMP_4:
      NewOpcode = X86::CALL64pcrel32;
      break;
    case X86::JMP32m:
      NewOpcode = X86::CALL64m;
      break;
    case X86::JMP32r:
      NewOpcode = X86::CALL64r;
      break;
    }

    Inst.setOpcode(NewOpcode);
    removeAnnotation(Inst, MCPlus::MCAnnotation::kTailCall);
    return true;
  }

  bool convertCallToIndirectCall(MCInst &Inst, const MCSymbol *TargetLocation,
                                 MCContext *Ctx) override {
    assert((Inst.getOpcode() == X86::CALL64pcrel32 ||
            (Inst.getOpcode() == X86::JMP_4 && isTailCall(Inst))) &&
           "64-bit direct (tail) call instruction expected");
    const auto NewOpcode =
        (Inst.getOpcode() == X86::CALL64pcrel32) ? X86::CALL64m : X86::JMP32m;
    Inst.setOpcode(NewOpcode);

    // Replace the first operand and preserve auxiliary operands of
    // the instruction.
    Inst.erase(Inst.begin());
    Inst.insert(Inst.begin(),
                MCOperand::createReg(X86::NoRegister)); // AddrSegmentReg
    Inst.insert(Inst.begin(),
                MCOperand::createExpr(                  // Displacement
                    MCSymbolRefExpr::create(TargetLocation,
                                            MCSymbolRefExpr::VK_None, *Ctx)));
    Inst.insert(Inst.begin(),
                MCOperand::createReg(X86::NoRegister)); // IndexReg
    Inst.insert(Inst.begin(),
                MCOperand::createImm(1));               // ScaleAmt
    Inst.insert(Inst.begin(),
                MCOperand::createReg(X86::RIP));        // BaseReg

    return true;
  }

  void convertIndirectCallToLoad(MCInst &Inst, MCPhysReg Reg) override {
    bool IsTailCall = isTailCall(Inst);
    if (IsTailCall)
      removeAnnotation(Inst, MCPlus::MCAnnotation::kTailCall);
    if (Inst.getOpcode() == X86::CALL64m ||
        (Inst.getOpcode() == X86::JMP32m && IsTailCall)) {
      Inst.setOpcode(X86::MOV64rm);
      Inst.insert(Inst.begin(), MCOperand::createReg(Reg));
      return;
    }
    if (Inst.getOpcode() == X86::CALL64r ||
        (Inst.getOpcode() == X86::JMP32r && IsTailCall)) {
      Inst.setOpcode(X86::MOV64rr);
      Inst.insert(Inst.begin(), MCOperand::createReg(Reg));
      return;
    }
    LLVM_DEBUG(Inst.dump());
    llvm_unreachable("not implemented");
  }

  bool shortenInstruction(MCInst &Inst,
                          const MCSubtargetInfo &STI) const override {
    unsigned OldOpcode = Inst.getOpcode();
    unsigned NewOpcode = OldOpcode;

    int MemOpNo = getMemoryOperandNo(Inst);

    // Check and remove redundant Address-Size override prefix.
    if (opts::X86StripRedundantAddressSize) {
      uint64_t TSFlags = Info->get(OldOpcode).TSFlags;
      unsigned Flags = Inst.getFlags();

      if (!X86_MC::needsAddressSizeOverride(Inst, STI, MemOpNo, TSFlags) &&
          Flags & X86::IP_HAS_AD_SIZE)
        Inst.setFlags(Flags ^ X86::IP_HAS_AD_SIZE);
    }

    // Check and remove EIZ/RIZ. These cases represent ambiguous cases where
    // SIB byte is present, but no index is used and modrm alone should have
    // been enough. Converting to NoRegister effectively removes the SIB byte.
    if (MemOpNo >= 0) {
      MCOperand &IndexOp =
          Inst.getOperand(static_cast<unsigned>(MemOpNo) + X86::AddrIndexReg);
      if (IndexOp.getReg() == X86::EIZ || IndexOp.getReg() == X86::RIZ)
        IndexOp = MCOperand::createReg(X86::NoRegister);
    }

    if (isBranch(Inst)) {
      NewOpcode = getShortBranchOpcode(OldOpcode);
    } else if (OldOpcode == X86::MOV64ri) {
      if (Inst.getOperand(MCPlus::getNumPrimeOperands(Inst) - 1).isImm()) {
        const int64_t Imm =
            Inst.getOperand(MCPlus::getNumPrimeOperands(Inst) - 1).getImm();
        if (int64_t(Imm) == int64_t(int32_t(Imm)))
          NewOpcode = X86::MOV64ri32;
      }
    } else {
      // If it's arithmetic instruction check if signed operand fits in 1 byte.
      const unsigned ShortOpcode = getShortArithOpcode(OldOpcode);
      if (ShortOpcode != OldOpcode &&
          Inst.getOperand(MCPlus::getNumPrimeOperands(Inst) - 1).isImm()) {
        int64_t Imm =
            Inst.getOperand(MCPlus::getNumPrimeOperands(Inst) - 1).getImm();
        if (int64_t(Imm) == int64_t(int8_t(Imm)))
          NewOpcode = ShortOpcode;
      }
    }

    if (NewOpcode == OldOpcode)
      return false;

    Inst.setOpcode(NewOpcode);
    return true;
  }

  bool
  convertMoveToConditionalMove(MCInst &Inst, unsigned CC, bool AllowStackMemOp,
                               bool AllowBasePtrStackMemOp) const override {
    // - Register-register moves are OK
    // - Stores are filtered out by opcode (no store CMOV)
    // - Non-stack loads are prohibited (generally unsafe)
    // - Stack loads are OK if AllowStackMemOp is true
    // - Stack loads with RBP are OK if AllowBasePtrStackMemOp is true
    if (isLoad(Inst)) {
      // If stack memory operands are not allowed, no loads are allowed
      if (!AllowStackMemOp)
        return false;

      // If stack memory operands are allowed, check if it's a load from stack
      bool IsLoad, IsStore, IsStoreFromReg, IsSimple, IsIndexed;
      MCPhysReg Reg;
      int32_t SrcImm;
      uint16_t StackPtrReg;
      int64_t StackOffset;
      uint8_t Size;
      bool IsStackAccess =
          isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, Reg, SrcImm,
                        StackPtrReg, StackOffset, Size, IsSimple, IsIndexed);
      // Prohibit non-stack-based loads
      if (!IsStackAccess)
        return false;
      // If stack memory operands are allowed, check if it's RBP-based
      if (!AllowBasePtrStackMemOp &&
          RegInfo->isSubRegisterEq(X86::RBP, StackPtrReg))
        return false;
    }

    unsigned NewOpcode = 0;
    switch (Inst.getOpcode()) {
    case X86::MOV16rr:
      NewOpcode = X86::CMOV16rr;
      break;
    case X86::MOV16rm:
      NewOpcode = X86::CMOV16rm;
      break;
    case X86::MOV32rr:
      NewOpcode = X86::CMOV32rr;
      break;
    case X86::MOV32rm:
      NewOpcode = X86::CMOV32rm;
      break;
    case X86::MOV64rr:
      NewOpcode = X86::CMOV64rr;
      break;
    case X86::MOV64rm:
      NewOpcode = X86::CMOV64rm;
      break;
    default:
      return false;
    }
    Inst.setOpcode(NewOpcode);
    // Insert CC at the end of prime operands, before annotations
    Inst.insert(Inst.begin() + MCPlus::getNumPrimeOperands(Inst),
                MCOperand::createImm(CC));
    // CMOV is a 3-operand MCInst, so duplicate the destination as src1
    Inst.insert(Inst.begin(), Inst.getOperand(0));
    return true;
  }

  bool lowerTailCall(MCInst &Inst) override {
    if (Inst.getOpcode() == X86::JMP_4 && isTailCall(Inst)) {
      Inst.setOpcode(X86::JMP_1);
      removeAnnotation(Inst, MCPlus::MCAnnotation::kTailCall);
      return true;
    }
    return false;
  }

  const MCSymbol *getTargetSymbol(const MCInst &Inst,
                                  unsigned OpNum = 0) const override {
    if (OpNum >= MCPlus::getNumPrimeOperands(Inst))
      return nullptr;

    const MCOperand &Op = Inst.getOperand(OpNum);
    if (!Op.isExpr())
      return nullptr;

    auto *SymExpr = dyn_cast<MCSymbolRefExpr>(Op.getExpr());
    if (!SymExpr || SymExpr->getKind() != MCSymbolRefExpr::VK_None)
      return nullptr;

    return &SymExpr->getSymbol();
  }

  // This is the same as the base class, but since we are overriding one of
  // getTargetSymbol's signatures above, we need to override all of them.
  const MCSymbol *getTargetSymbol(const MCExpr *Expr) const override {
    return &cast<const MCSymbolRefExpr>(Expr)->getSymbol();
  }

  bool analyzeBranch(InstructionIterator Begin, InstructionIterator End,
                     const MCSymbol *&TBB, const MCSymbol *&FBB,
                     MCInst *&CondBranch,
                     MCInst *&UncondBranch) const override {
    auto I = End;

    // Bottom-up analysis
    while (I != Begin) {
      --I;

      // Ignore nops and CFIs
      if (isPseudo(*I))
        continue;

      // Stop when we find the first non-terminator
      if (!isTerminator(*I))
        break;

      if (!isBranch(*I))
        break;

      // Handle unconditional branches.
      if ((I->getOpcode() == X86::JMP_1 || I->getOpcode() == X86::JMP_2 ||
           I->getOpcode() == X86::JMP_4) &&
          !isTailCall(*I)) {
        // If any code was seen after this unconditional branch, we've seen
        // unreachable code. Ignore them.
        CondBranch = nullptr;
        UncondBranch = &*I;
        const MCSymbol *Sym = getTargetSymbol(*I);
        assert(Sym != nullptr &&
               "Couldn't extract BB symbol from jump operand");
        TBB = Sym;
        continue;
      }

      // Handle conditional branches and ignore indirect branches
      if (!isUnsupportedBranch(I->getOpcode()) &&
          getCondCode(*I) == X86::COND_INVALID) {
        // Indirect branch
        return false;
      }

      if (CondBranch == nullptr) {
        const MCSymbol *TargetBB = getTargetSymbol(*I);
        if (TargetBB == nullptr) {
          // Unrecognized branch target
          return false;
        }
        FBB = TBB;
        TBB = TargetBB;
        CondBranch = &*I;
        continue;
      }

      llvm_unreachable("multiple conditional branches in one BB");
    }
    return true;
  }

  template <typename Itr>
  std::pair<IndirectBranchType, MCInst *>
  analyzePICJumpTable(Itr II, Itr IE, MCPhysReg R1, MCPhysReg R2) const {
    // Analyze PIC-style jump table code template:
    //
    //    lea PIC_JUMP_TABLE(%rip), {%r1|%r2}     <- MemLocInstr
    //    mov ({%r1|%r2}, %index, 4), {%r2|%r1}
    //    add %r2, %r1
    //    jmp *%r1
    //
    // (with any irrelevant instructions in-between)
    //
    // When we call this helper we've already determined %r1 and %r2, and
    // reverse instruction iterator \p II is pointing to the ADD instruction.
    //
    // PIC jump table looks like following:
    //
    //   JT:  ----------
    //    E1:| L1 - JT  |
    //       |----------|
    //    E2:| L2 - JT  |
    //       |----------|
    //       |          |
    //          ......
    //    En:| Ln - JT  |
    //        ----------
    //
    // Where L1, L2, ..., Ln represent labels in the function.
    //
    // The actual relocations in the table will be of the form:
    //
    //   Ln - JT
    //    = (Ln - En) + (En - JT)
    //    = R_X86_64_PC32(Ln) + En - JT
    //    = R_X86_64_PC32(Ln + offsetof(En))
    //
    LLVM_DEBUG(dbgs() << "Checking for PIC jump table\n");
    MCInst *MemLocInstr = nullptr;
    const MCInst *MovInstr = nullptr;
    while (++II != IE) {
      MCInst &Instr = *II;
      const MCInstrDesc &InstrDesc = Info->get(Instr.getOpcode());
      if (!InstrDesc.hasDefOfPhysReg(Instr, R1, *RegInfo) &&
          !InstrDesc.hasDefOfPhysReg(Instr, R2, *RegInfo)) {
        // Ignore instructions that don't affect R1, R2 registers.
        continue;
      }
      if (!MovInstr) {
        // Expect to see MOV instruction.
        if (!isMOVSX64rm32(Instr)) {
          LLVM_DEBUG(dbgs() << "MOV instruction expected.\n");
          break;
        }

        // Check if it's setting %r1 or %r2. In canonical form it sets %r2.
        // If it sets %r1 - rename the registers so we have to only check
        // a single form.
        unsigned MovDestReg = Instr.getOperand(0).getReg();
        if (MovDestReg != R2)
          std::swap(R1, R2);
        if (MovDestReg != R2) {
          LLVM_DEBUG(dbgs() << "MOV instruction expected to set %r2\n");
          break;
        }

        // Verify operands for MOV.
        unsigned  BaseRegNum;
        int64_t   ScaleValue;
        unsigned  IndexRegNum;
        int64_t   DispValue;
        unsigned  SegRegNum;
        if (!evaluateX86MemoryOperand(Instr, &BaseRegNum, &ScaleValue,
                                      &IndexRegNum, &DispValue, &SegRegNum))
          break;
        if (BaseRegNum != R1 || ScaleValue != 4 ||
            IndexRegNum == X86::NoRegister || DispValue != 0 ||
            SegRegNum != X86::NoRegister)
          break;
        MovInstr = &Instr;
      } else {
        if (!InstrDesc.hasDefOfPhysReg(Instr, R1, *RegInfo))
          continue;
        if (!isLEA64r(Instr)) {
          LLVM_DEBUG(dbgs() << "LEA instruction expected\n");
          break;
        }
        if (Instr.getOperand(0).getReg() != R1) {
          LLVM_DEBUG(dbgs() << "LEA instruction expected to set %r1\n");
          break;
        }

        // Verify operands for LEA.
        unsigned      BaseRegNum;
        int64_t       ScaleValue;
        unsigned      IndexRegNum;
        const MCExpr *DispExpr = nullptr;
        int64_t       DispValue;
        unsigned      SegRegNum;
        if (!evaluateX86MemoryOperand(Instr, &BaseRegNum, &ScaleValue,
                                      &IndexRegNum, &DispValue, &SegRegNum,
                                      &DispExpr))
          break;
        if (BaseRegNum != RegInfo->getProgramCounter() ||
            IndexRegNum != X86::NoRegister || SegRegNum != X86::NoRegister ||
            DispExpr == nullptr)
          break;
        MemLocInstr = &Instr;
        break;
      }
    }

    if (!MemLocInstr)
      return std::make_pair(IndirectBranchType::UNKNOWN, nullptr);

    LLVM_DEBUG(dbgs() << "checking potential PIC jump table\n");
    return std::make_pair(IndirectBranchType::POSSIBLE_PIC_JUMP_TABLE,
                          MemLocInstr);
  }

  IndirectBranchType analyzeIndirectBranch(
      MCInst &Instruction, InstructionIterator Begin, InstructionIterator End,
      const unsigned PtrSize, MCInst *&MemLocInstrOut, unsigned &BaseRegNumOut,
      unsigned &IndexRegNumOut, int64_t &DispValueOut,
      const MCExpr *&DispExprOut, MCInst *&PCRelBaseOut) const override {
    // Try to find a (base) memory location from where the address for
    // the indirect branch is loaded. For X86-64 the memory will be specified
    // in the following format:
    //
    //   {%rip}/{%basereg} + Imm + IndexReg * Scale
    //
    // We are interested in the cases where Scale == sizeof(uintptr_t) and
    // the contents of the memory are presumably an array of pointers to code.
    //
    // Normal jump table:
    //
    //    jmp *(JUMP_TABLE, %index, Scale)        <- MemLocInstr
    //
    //    or
    //
    //    mov (JUMP_TABLE, %index, Scale), %r1    <- MemLocInstr
    //    ...
    //    jmp %r1
    //
    // We handle PIC-style jump tables separately.
    //
    MemLocInstrOut = nullptr;
    BaseRegNumOut = X86::NoRegister;
    IndexRegNumOut = X86::NoRegister;
    DispValueOut = 0;
    DispExprOut = nullptr;

    std::reverse_iterator<InstructionIterator> II(End);
    std::reverse_iterator<InstructionIterator> IE(Begin);

    IndirectBranchType Type = IndirectBranchType::UNKNOWN;

    // An instruction referencing memory used by jump instruction (directly or
    // via register). This location could be an array of function pointers
    // in case of indirect tail call, or a jump table.
    MCInst *MemLocInstr = nullptr;

    if (MCPlus::getNumPrimeOperands(Instruction) == 1) {
      // If the indirect jump is on register - try to detect if the
      // register value is loaded from a memory location.
      assert(Instruction.getOperand(0).isReg() && "register operand expected");
      const unsigned R1 = Instruction.getOperand(0).getReg();
      // Check if one of the previous instructions defines the jump-on register.
      for (auto PrevII = II; PrevII != IE; ++PrevII) {
        MCInst &PrevInstr = *PrevII;
        const MCInstrDesc &PrevInstrDesc = Info->get(PrevInstr.getOpcode());

        if (!PrevInstrDesc.hasDefOfPhysReg(PrevInstr, R1, *RegInfo))
          continue;

        if (isMoveMem2Reg(PrevInstr)) {
          MemLocInstr = &PrevInstr;
          break;
        }
        if (isADD64rr(PrevInstr)) {
          unsigned R2 = PrevInstr.getOperand(2).getReg();
          if (R1 == R2)
            return IndirectBranchType::UNKNOWN;
          std::tie(Type, MemLocInstr) = analyzePICJumpTable(PrevII, IE, R1, R2);
          break;
        }
        return IndirectBranchType::UNKNOWN;
      }
      if (!MemLocInstr) {
        // No definition seen for the register in this function so far. Could be
        // an input parameter - which means it is an external code reference.
        // It also could be that the definition happens to be in the code that
        // we haven't processed yet. Since we have to be conservative, return
        // as UNKNOWN case.
        return IndirectBranchType::UNKNOWN;
      }
    } else {
      MemLocInstr = &Instruction;
    }

    const MCRegister RIPRegister = RegInfo->getProgramCounter();

    // Analyze the memory location.
    unsigned BaseRegNum, IndexRegNum, SegRegNum;
    int64_t ScaleValue, DispValue;
    const MCExpr *DispExpr;

    if (!evaluateX86MemoryOperand(*MemLocInstr, &BaseRegNum, &ScaleValue,
                                  &IndexRegNum, &DispValue, &SegRegNum,
                                  &DispExpr))
      return IndirectBranchType::UNKNOWN;

    BaseRegNumOut = BaseRegNum;
    IndexRegNumOut = IndexRegNum;
    DispValueOut = DispValue;
    DispExprOut = DispExpr;

    if ((BaseRegNum != X86::NoRegister && BaseRegNum != RIPRegister) ||
        SegRegNum != X86::NoRegister)
      return IndirectBranchType::UNKNOWN;

    if (MemLocInstr == &Instruction &&
        (!ScaleValue || IndexRegNum == X86::NoRegister)) {
      MemLocInstrOut = MemLocInstr;
      return IndirectBranchType::POSSIBLE_FIXED_BRANCH;
    }

    if (Type == IndirectBranchType::POSSIBLE_PIC_JUMP_TABLE &&
        (ScaleValue != 1 || BaseRegNum != RIPRegister))
      return IndirectBranchType::UNKNOWN;

    if (Type != IndirectBranchType::POSSIBLE_PIC_JUMP_TABLE &&
        ScaleValue != PtrSize)
      return IndirectBranchType::UNKNOWN;

    MemLocInstrOut = MemLocInstr;

    return Type;
  }

  /// Analyze a callsite to see if it could be a virtual method call.  This only
  /// checks to see if the overall pattern is satisfied, it does not guarantee
  /// that the callsite is a true virtual method call.
  /// The format of virtual method calls that are recognized is one of the
  /// following:
  ///
  ///  Form 1: (found in debug code)
  ///    add METHOD_OFFSET, %VtableReg
  ///    mov (%VtableReg), %MethodReg
  ///    ...
  ///    call or jmp *%MethodReg
  ///
  ///  Form 2:
  ///    mov METHOD_OFFSET(%VtableReg), %MethodReg
  ///    ...
  ///    call or jmp *%MethodReg
  ///
  ///  Form 3:
  ///    ...
  ///    call or jmp *METHOD_OFFSET(%VtableReg)
  ///
  bool analyzeVirtualMethodCall(InstructionIterator ForwardBegin,
                                InstructionIterator ForwardEnd,
                                std::vector<MCInst *> &MethodFetchInsns,
                                unsigned &VtableRegNum, unsigned &MethodRegNum,
                                uint64_t &MethodOffset) const override {
    VtableRegNum = X86::NoRegister;
    MethodRegNum = X86::NoRegister;
    MethodOffset = 0;

    std::reverse_iterator<InstructionIterator> Itr(ForwardEnd);
    std::reverse_iterator<InstructionIterator> End(ForwardBegin);

    MCInst &CallInst = *Itr++;
    assert(isIndirectBranch(CallInst) || isCall(CallInst));

    unsigned BaseReg, IndexReg, SegmentReg;
    int64_t Scale, Disp;
    const MCExpr *DispExpr;

    // The call can just be jmp offset(reg)
    if (evaluateX86MemoryOperand(CallInst, &BaseReg, &Scale, &IndexReg, &Disp,
                                 &SegmentReg, &DispExpr)) {
      if (!DispExpr && BaseReg != X86::RIP && BaseReg != X86::RBP &&
          BaseReg != X86::NoRegister) {
        MethodRegNum = BaseReg;
        if (Scale == 1 && IndexReg == X86::NoRegister &&
            SegmentReg == X86::NoRegister) {
          VtableRegNum = MethodRegNum;
          MethodOffset = Disp;
          MethodFetchInsns.push_back(&CallInst);
          return true;
        }
      }
      return false;
    }
    if (CallInst.getOperand(0).isReg())
      MethodRegNum = CallInst.getOperand(0).getReg();
    else
      return false;

    if (MethodRegNum == X86::RIP || MethodRegNum == X86::RBP) {
      VtableRegNum = X86::NoRegister;
      MethodRegNum = X86::NoRegister;
      return false;
    }

    // find load from vtable, this may or may not include the method offset
    while (Itr != End) {
      MCInst &CurInst = *Itr++;
      const MCInstrDesc &Desc = Info->get(CurInst.getOpcode());
      if (Desc.hasDefOfPhysReg(CurInst, MethodRegNum, *RegInfo)) {
        if (isLoad(CurInst) &&
            evaluateX86MemoryOperand(CurInst, &BaseReg, &Scale, &IndexReg,
                                     &Disp, &SegmentReg, &DispExpr)) {
          if (!DispExpr && Scale == 1 && BaseReg != X86::RIP &&
              BaseReg != X86::RBP && BaseReg != X86::NoRegister &&
              IndexReg == X86::NoRegister && SegmentReg == X86::NoRegister &&
              BaseReg != X86::RIP) {
            VtableRegNum = BaseReg;
            MethodOffset = Disp;
            MethodFetchInsns.push_back(&CurInst);
            if (MethodOffset != 0)
              return true;
            break;
          }
        }
        return false;
      }
    }

    if (!VtableRegNum)
      return false;

    // look for any adds affecting the method register.
    while (Itr != End) {
      MCInst &CurInst = *Itr++;
      const MCInstrDesc &Desc = Info->get(CurInst.getOpcode());
      if (Desc.hasDefOfPhysReg(CurInst, VtableRegNum, *RegInfo)) {
        if (isADDri(CurInst)) {
          assert(!MethodOffset);
          MethodOffset = CurInst.getOperand(2).getImm();
          MethodFetchInsns.insert(MethodFetchInsns.begin(), &CurInst);
          break;
        }
      }
    }

    return true;
  }

  bool createStackPointerIncrement(MCInst &Inst, int Size,
                                   bool NoFlagsClobber) const override {
    if (NoFlagsClobber) {
      Inst.setOpcode(X86::LEA64r);
      Inst.clear();
      Inst.addOperand(MCOperand::createReg(X86::RSP));
      Inst.addOperand(MCOperand::createReg(X86::RSP));        // BaseReg
      Inst.addOperand(MCOperand::createImm(1));               // ScaleAmt
      Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // IndexReg
      Inst.addOperand(MCOperand::createImm(-Size));           // Displacement
      Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // AddrSegmentReg
      return true;
    }
    Inst.setOpcode(X86::SUB64ri8);
    Inst.clear();
    Inst.addOperand(MCOperand::createReg(X86::RSP));
    Inst.addOperand(MCOperand::createReg(X86::RSP));
    Inst.addOperand(MCOperand::createImm(Size));
    return true;
  }

  bool createStackPointerDecrement(MCInst &Inst, int Size,
                                   bool NoFlagsClobber) const override {
    if (NoFlagsClobber) {
      Inst.setOpcode(X86::LEA64r);
      Inst.clear();
      Inst.addOperand(MCOperand::createReg(X86::RSP));
      Inst.addOperand(MCOperand::createReg(X86::RSP));        // BaseReg
      Inst.addOperand(MCOperand::createImm(1));               // ScaleAmt
      Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // IndexReg
      Inst.addOperand(MCOperand::createImm(Size));            // Displacement
      Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // AddrSegmentReg
      return true;
    }
    Inst.setOpcode(X86::ADD64ri8);
    Inst.clear();
    Inst.addOperand(MCOperand::createReg(X86::RSP));
    Inst.addOperand(MCOperand::createReg(X86::RSP));
    Inst.addOperand(MCOperand::createImm(Size));
    return true;
  }

  bool createSaveToStack(MCInst &Inst, const MCPhysReg &StackReg, int Offset,
                         const MCPhysReg &SrcReg, int Size) const override {
    unsigned NewOpcode;
    switch (Size) {
    default:
      return false;
    case 2:      NewOpcode = X86::MOV16mr; break;
    case 4:      NewOpcode = X86::MOV32mr; break;
    case 8:      NewOpcode = X86::MOV64mr; break;
    }
    Inst.setOpcode(NewOpcode);
    Inst.clear();
    Inst.addOperand(MCOperand::createReg(StackReg));        // BaseReg
    Inst.addOperand(MCOperand::createImm(1));               // ScaleAmt
    Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // IndexReg
    Inst.addOperand(MCOperand::createImm(Offset));          // Displacement
    Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // AddrSegmentReg
    Inst.addOperand(MCOperand::createReg(SrcReg));
    return true;
  }

  bool createRestoreFromStack(MCInst &Inst, const MCPhysReg &StackReg,
                              int Offset, const MCPhysReg &DstReg,
                              int Size) const override {
    return createLoad(Inst, StackReg, /*Scale=*/1, /*IndexReg=*/X86::NoRegister,
                      Offset, nullptr, /*AddrSegmentReg=*/X86::NoRegister,
                      DstReg, Size);
  }

  bool createLoad(MCInst &Inst, const MCPhysReg &BaseReg, int64_t Scale,
                  const MCPhysReg &IndexReg, int64_t Offset,
                  const MCExpr *OffsetExpr, const MCPhysReg &AddrSegmentReg,
                  const MCPhysReg &DstReg, int Size) const override {
    unsigned NewOpcode;
    switch (Size) {
    default:
      return false;
    case 2:      NewOpcode = X86::MOV16rm; break;
    case 4:      NewOpcode = X86::MOV32rm; break;
    case 8:      NewOpcode = X86::MOV64rm; break;
    }
    Inst.setOpcode(NewOpcode);
    Inst.clear();
    Inst.addOperand(MCOperand::createReg(DstReg));
    Inst.addOperand(MCOperand::createReg(BaseReg));
    Inst.addOperand(MCOperand::createImm(Scale));
    Inst.addOperand(MCOperand::createReg(IndexReg));
    if (OffsetExpr)
      Inst.addOperand(MCOperand::createExpr(OffsetExpr)); // Displacement
    else
      Inst.addOperand(MCOperand::createImm(Offset)); // Displacement
    Inst.addOperand(MCOperand::createReg(AddrSegmentReg)); // AddrSegmentReg
    return true;
  }

  void createLoadImmediate(MCInst &Inst, const MCPhysReg Dest,
                           uint32_t Imm) const override {
    Inst.setOpcode(X86::MOV64ri32);
    Inst.clear();
    Inst.addOperand(MCOperand::createReg(Dest));
    Inst.addOperand(MCOperand::createImm(Imm));
  }

  bool createIncMemory(MCInst &Inst, const MCSymbol *Target,
                       MCContext *Ctx) const override {

    Inst.setOpcode(X86::LOCK_INC64m);
    Inst.clear();
    Inst.addOperand(MCOperand::createReg(X86::RIP));        // BaseReg
    Inst.addOperand(MCOperand::createImm(1));               // ScaleAmt
    Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // IndexReg

    Inst.addOperand(MCOperand::createExpr(
        MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None,
                                *Ctx)));                    // Displacement
    Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // AddrSegmentReg
    return true;
  }

  bool createIJmp32Frag(SmallVectorImpl<MCInst> &Insts,
                        const MCOperand &BaseReg, const MCOperand &Scale,
                        const MCOperand &IndexReg, const MCOperand &Offset,
                        const MCOperand &TmpReg) const override {
    // The code fragment we emit here is:
    //
    //  mov32 (%base, %index, scale), %tmpreg
    //  ijmp *(%tmpreg)
    //
    MCInst IJmp;
    IJmp.setOpcode(X86::JMP64r);
    IJmp.addOperand(TmpReg);

    MCInst Load;
    Load.setOpcode(X86::MOV32rm);
    Load.addOperand(TmpReg);
    Load.addOperand(BaseReg);
    Load.addOperand(Scale);
    Load.addOperand(IndexReg);
    Load.addOperand(Offset);
    Load.addOperand(MCOperand::createReg(X86::NoRegister));

    Insts.push_back(Load);
    Insts.push_back(IJmp);
    return true;
  }

  bool createNoop(MCInst &Inst) const override {
    Inst.setOpcode(X86::NOOP);
    return true;
  }

  bool createReturn(MCInst &Inst) const override {
    Inst.setOpcode(X86::RET64);
    return true;
  }

  InstructionListType createInlineMemcpy(bool ReturnEnd) const override {
    InstructionListType Code;
    if (ReturnEnd)
      Code.emplace_back(MCInstBuilder(X86::LEA64r)
                            .addReg(X86::RAX)
                            .addReg(X86::RDI)
                            .addImm(1)
                            .addReg(X86::RDX)
                            .addImm(0)
                            .addReg(X86::NoRegister));
    else
      Code.emplace_back(MCInstBuilder(X86::MOV64rr)
                            .addReg(X86::RAX)
                            .addReg(X86::RDI));

    Code.emplace_back(MCInstBuilder(X86::MOV32rr)
                          .addReg(X86::ECX)
                          .addReg(X86::EDX));
    Code.emplace_back(MCInstBuilder(X86::REP_MOVSB_64));

    return Code;
  }

  InstructionListType createOneByteMemcpy() const override {
    InstructionListType Code;
    Code.emplace_back(MCInstBuilder(X86::MOV8rm)
                          .addReg(X86::CL)
                          .addReg(X86::RSI)
                          .addImm(0)
                          .addReg(X86::NoRegister)
                          .addImm(0)
                          .addReg(X86::NoRegister));
    Code.emplace_back(MCInstBuilder(X86::MOV8mr)
                          .addReg(X86::RDI)
                          .addImm(0)
                          .addReg(X86::NoRegister)
                          .addImm(0)
                          .addReg(X86::NoRegister)
                          .addReg(X86::CL));
    Code.emplace_back(MCInstBuilder(X86::MOV64rr)
                          .addReg(X86::RAX)
                          .addReg(X86::RDI));
    return Code;
  }

  InstructionListType createCmpJE(MCPhysReg RegNo, int64_t Imm,
                                  const MCSymbol *Target,
                                  MCContext *Ctx) const override {
    InstructionListType Code;
    Code.emplace_back(MCInstBuilder(X86::CMP64ri8)
                          .addReg(RegNo)
                          .addImm(Imm));
    Code.emplace_back(MCInstBuilder(X86::JCC_1)
                          .addExpr(MCSymbolRefExpr::create(
                              Target, MCSymbolRefExpr::VK_None, *Ctx))
                          .addImm(X86::COND_E));
    return Code;
  }

  std::optional<Relocation>
  createRelocation(const MCFixup &Fixup,
                   const MCAsmBackend &MAB) const override {
    const MCFixupKindInfo &FKI = MAB.getFixupKindInfo(Fixup.getKind());

    assert(FKI.TargetOffset == 0 && "0-bit relocation offset expected");
    const uint64_t RelOffset = Fixup.getOffset();

    uint64_t RelType;
    if (FKI.Flags & MCFixupKindInfo::FKF_IsPCRel) {
      switch (FKI.TargetSize) {
      default:
        return std::nullopt;
      case  8: RelType = ELF::R_X86_64_PC8; break;
      case 16: RelType = ELF::R_X86_64_PC16; break;
      case 32: RelType = ELF::R_X86_64_PC32; break;
      case 64: RelType = ELF::R_X86_64_PC64; break;
      }
    } else {
      switch (FKI.TargetSize) {
      default:
        return std::nullopt;
      case  8: RelType = ELF::R_X86_64_8; break;
      case 16: RelType = ELF::R_X86_64_16; break;
      case 32: RelType = ELF::R_X86_64_32; break;
      case 64: RelType = ELF::R_X86_64_64; break;
      }
    }

    // Extract a symbol and an addend out of the fixup value expression.
    //
    // Only the following limited expression types are supported:
    //   Symbol + Addend
    //   Symbol
    uint64_t Addend = 0;
    MCSymbol *Symbol = nullptr;
    const MCExpr *ValueExpr = Fixup.getValue();
    if (ValueExpr->getKind() == MCExpr::Binary) {
      const auto *BinaryExpr = cast<MCBinaryExpr>(ValueExpr);
      assert(BinaryExpr->getOpcode() == MCBinaryExpr::Add &&
             "unexpected binary expression");
      const MCExpr *LHS = BinaryExpr->getLHS();
      assert(LHS->getKind() == MCExpr::SymbolRef && "unexpected LHS");
      Symbol = const_cast<MCSymbol *>(this->getTargetSymbol(LHS));
      const MCExpr *RHS = BinaryExpr->getRHS();
      assert(RHS->getKind() == MCExpr::Constant && "unexpected RHS");
      Addend = cast<MCConstantExpr>(RHS)->getValue();
    } else {
      assert(ValueExpr->getKind() == MCExpr::SymbolRef && "unexpected value");
      Symbol = const_cast<MCSymbol *>(this->getTargetSymbol(ValueExpr));
    }

    return Relocation({RelOffset, Symbol, RelType, Addend, 0});
  }

  bool replaceImmWithSymbolRef(MCInst &Inst, const MCSymbol *Symbol,
                               int64_t Addend, MCContext *Ctx, int64_t &Value,
                               uint64_t RelType) const override {
    unsigned ImmOpNo = -1U;

    for (unsigned Index = 0; Index < MCPlus::getNumPrimeOperands(Inst);
         ++Index) {
      if (Inst.getOperand(Index).isImm()) {
        ImmOpNo = Index;
        // TODO: this is a bit hacky.  It finds the correct operand by
        // searching for a specific immediate value.  If no value is
        // provided it defaults to the last immediate operand found.
        // This could lead to unexpected results if the instruction
        // has more than one immediate with the same value.
        if (Inst.getOperand(ImmOpNo).getImm() == Value)
          break;
      }
    }

    if (ImmOpNo == -1U)
      return false;

    Value = Inst.getOperand(ImmOpNo).getImm();

    setOperandToSymbolRef(Inst, ImmOpNo, Symbol, Addend, Ctx, RelType);

    return true;
  }

  bool replaceRegWithImm(MCInst &Inst, unsigned Register,
                         int64_t Imm) const override {

    enum CheckSignExt : uint8_t {
      NOCHECK = 0,
      CHECK8,
      CHECK32,
    };

    using CheckList = std::vector<std::pair<CheckSignExt, unsigned>>;
    struct InstInfo {
      // Size in bytes that Inst loads from memory.
      uint8_t DataSize;

      // True when the target operand has to be duplicated because the opcode
      // expects a LHS operand.
      bool HasLHS;

      // List of checks and corresponding opcodes to be used. We try to use the
      // smallest possible immediate value when various sizes are available,
      // hence we may need to check whether a larger constant fits in a smaller
      // immediate.
      CheckList Checks;
    };

    InstInfo I;

    switch (Inst.getOpcode()) {
    default: {
      switch (getPushSize(Inst)) {

      case 2: I = {2, false, {{CHECK8, X86::PUSH16i8}, {NOCHECK, X86::PUSHi16}}}; break;
      case 4: I = {4, false, {{CHECK8, X86::PUSH32i8}, {NOCHECK, X86::PUSHi32}}}; break;
      case 8: I = {8, false, {{CHECK8, X86::PUSH64i8},
                              {CHECK32, X86::PUSH64i32},
                              {NOCHECK, Inst.getOpcode()}}}; break;
      default: return false;
      }
      break;
    }

    // MOV
    case X86::MOV8rr:       I = {1, false, {{NOCHECK, X86::MOV8ri}}}; break;
    case X86::MOV16rr:      I = {2, false, {{NOCHECK, X86::MOV16ri}}}; break;
    case X86::MOV32rr:      I = {4, false, {{NOCHECK, X86::MOV32ri}}}; break;
    case X86::MOV64rr:      I = {8, false, {{CHECK32, X86::MOV64ri32},
                                            {NOCHECK, X86::MOV64ri}}}; break;

    case X86::MOV8mr:       I = {1, false, {{NOCHECK, X86::MOV8mi}}}; break;
    case X86::MOV16mr:      I = {2, false, {{NOCHECK, X86::MOV16mi}}}; break;
    case X86::MOV32mr:      I = {4, false, {{NOCHECK, X86::MOV32mi}}}; break;
    case X86::MOV64mr:      I = {8, false, {{CHECK32, X86::MOV64mi32},
                                            {NOCHECK, X86::MOV64mr}}}; break;

    // MOVZX
    case X86::MOVZX16rr8:   I = {1, false, {{NOCHECK, X86::MOV16ri}}}; break;
    case X86::MOVZX32rr8:   I = {1, false, {{NOCHECK, X86::MOV32ri}}}; break;
    case X86::MOVZX32rr16:  I = {2, false, {{NOCHECK, X86::MOV32ri}}}; break;

    // CMP
    case X86::CMP8rr:       I = {1, false, {{NOCHECK, X86::CMP8ri}}}; break;
    case X86::CMP16rr:      I = {2, false, {{CHECK8, X86::CMP16ri8},
                                            {NOCHECK, X86::CMP16ri}}}; break;
    case X86::CMP32rr:      I = {4, false, {{CHECK8, X86::CMP32ri8},
                                            {NOCHECK, X86::CMP32ri}}}; break;
    case X86::CMP64rr:      I = {8, false, {{CHECK8, X86::CMP64ri8},
                                            {CHECK32, X86::CMP64ri32},
                                            {NOCHECK, X86::CMP64rr}}}; break;

    // TEST
    case X86::TEST8rr:      I = {1, false, {{NOCHECK, X86::TEST8ri}}}; break;
    case X86::TEST16rr:     I = {2, false, {{NOCHECK, X86::TEST16ri}}}; break;
    case X86::TEST32rr:     I = {4, false, {{NOCHECK, X86::TEST32ri}}}; break;
    case X86::TEST64rr:     I = {8, false, {{CHECK32, X86::TEST64ri32},
                                            {NOCHECK, X86::TEST64rr}}}; break;

    // ADD
    case X86::ADD8rr:       I = {1, true, {{NOCHECK, X86::ADD8ri}}}; break;
    case X86::ADD16rr:      I = {2, true, {{CHECK8, X86::ADD16ri8},
                                           {NOCHECK, X86::ADD16ri}}}; break;
    case X86::ADD32rr:      I = {4, true, {{CHECK8, X86::ADD32ri8},
                                           {NOCHECK, X86::ADD32ri}}}; break;
    case X86::ADD64rr:      I = {8, true, {{CHECK8, X86::ADD64ri8},
                                           {CHECK32, X86::ADD64ri32},
                                           {NOCHECK, X86::ADD64rr}}}; break;

    // SUB
    case X86::SUB8rr:       I = {1, true, {{NOCHECK, X86::SUB8ri}}}; break;
    case X86::SUB16rr:      I = {2, true, {{CHECK8, X86::SUB16ri8},
                                           {NOCHECK, X86::SUB16ri}}}; break;
    case X86::SUB32rr:      I = {4, true, {{CHECK8, X86::SUB32ri8},
                                           {NOCHECK, X86::SUB32ri}}}; break;
    case X86::SUB64rr:      I = {8, true, {{CHECK8, X86::SUB64ri8},
                                           {CHECK32, X86::SUB64ri32},
                                           {NOCHECK, X86::SUB64rr}}}; break;

    // AND
    case X86::AND8rr:       I = {1, true, {{NOCHECK, X86::AND8ri}}}; break;
    case X86::AND16rr:      I = {2, true, {{CHECK8, X86::AND16ri8},
                                           {NOCHECK, X86::AND16ri}}}; break;
    case X86::AND32rr:      I = {4, true, {{CHECK8, X86::AND32ri8},
                                           {NOCHECK, X86::AND32ri}}}; break;
    case X86::AND64rr:      I = {8, true, {{CHECK8, X86::AND64ri8},
                                           {CHECK32, X86::AND64ri32},
                                           {NOCHECK, X86::AND64rr}}}; break;

    // OR
    case X86::OR8rr:        I = {1, true, {{NOCHECK, X86::OR8ri}}}; break;
    case X86::OR16rr:       I = {2, true, {{CHECK8, X86::OR16ri8},
                                           {NOCHECK, X86::OR16ri}}}; break;
    case X86::OR32rr:       I = {4, true, {{CHECK8, X86::OR32ri8},
                                           {NOCHECK, X86::OR32ri}}}; break;
    case X86::OR64rr:       I = {8, true, {{CHECK8, X86::OR64ri8},
                                           {CHECK32, X86::OR64ri32},
                                           {NOCHECK, X86::OR64rr}}}; break;

    // XOR
    case X86::XOR8rr:       I = {1, true, {{NOCHECK, X86::XOR8ri}}}; break;
    case X86::XOR16rr:      I = {2, true, {{CHECK8, X86::XOR16ri8},
                                           {NOCHECK, X86::XOR16ri}}}; break;
    case X86::XOR32rr:      I = {4, true, {{CHECK8, X86::XOR32ri8},
                                           {NOCHECK, X86::XOR32ri}}}; break;
    case X86::XOR64rr:      I = {8, true, {{CHECK8, X86::XOR64ri8},
                                           {CHECK32, X86::XOR64ri32},
                                           {NOCHECK, X86::XOR64rr}}}; break;
    }

    // Compute the new opcode.
    unsigned NewOpcode = 0;
    for (const std::pair<CheckSignExt, unsigned> &Check : I.Checks) {
      NewOpcode = Check.second;
      if (Check.first == NOCHECK)
        break;
      if (Check.first == CHECK8 && isInt<8>(Imm))
        break;
      if (Check.first == CHECK32 && isInt<32>(Imm))
        break;
    }
    if (NewOpcode == Inst.getOpcode())
      return false;

    const MCInstrDesc &InstDesc = Info->get(Inst.getOpcode());

    unsigned NumFound = 0;
    for (unsigned Index = InstDesc.getNumDefs() + (I.HasLHS ? 1 : 0),
                  E = InstDesc.getNumOperands();
         Index != E; ++Index)
      if (Inst.getOperand(Index).isReg() &&
          Inst.getOperand(Index).getReg() == Register)
        NumFound++;

    if (NumFound != 1)
      return false;

    MCOperand TargetOp = Inst.getOperand(0);
    Inst.clear();
    Inst.setOpcode(NewOpcode);
    Inst.addOperand(TargetOp);
    if (I.HasLHS)
      Inst.addOperand(TargetOp);
    Inst.addOperand(MCOperand::createImm(Imm));

    return true;
  }

  bool replaceRegWithReg(MCInst &Inst, unsigned ToReplace,
                         unsigned ReplaceWith) const override {

    // Get the HasLHS value so that iteration can be done
    bool HasLHS;
    if (X86::isAND(Inst.getOpcode()) || X86::isADD(Inst.getOpcode()) ||
        X86::isSUB(Inst.getOpcode())) {
      HasLHS = true;
    } else if (isPop(Inst) || isPush(Inst) || X86::isCMP(Inst.getOpcode()) ||
               X86::isTEST(Inst.getOpcode())) {
      HasLHS = false;
    } else {
      switch (Inst.getOpcode()) {
      case X86::MOV8rr:
      case X86::MOV8rm:
      case X86::MOV8mr:
      case X86::MOV8ri:
      case X86::MOV16rr:
      case X86::MOV16rm:
      case X86::MOV16mr:
      case X86::MOV16ri:
      case X86::MOV32rr:
      case X86::MOV32rm:
      case X86::MOV32mr:
      case X86::MOV32ri:
      case X86::MOV64rr:
      case X86::MOV64rm:
      case X86::MOV64mr:
      case X86::MOV64ri:
      case X86::MOVZX16rr8:
      case X86::MOVZX32rr8:
      case X86::MOVZX32rr16:
      case X86::MOVSX32rm8:
      case X86::MOVSX32rr8:
      case X86::MOVSX64rm32:
      case X86::LEA64r:
        HasLHS = false;
        break;
      default:
        return false;
      }
    }

    const MCInstrDesc &InstDesc = Info->get(Inst.getOpcode());

    bool FoundOne = false;

    // Iterate only through src operands that arent also dest operands
    for (unsigned Index = InstDesc.getNumDefs() + (HasLHS ? 1 : 0),
                  E = InstDesc.getNumOperands();
         Index != E; ++Index) {
      BitVector RegAliases = getAliases(ToReplace, true);
      if (!Inst.getOperand(Index).isReg() ||
          !RegAliases.test(Inst.getOperand(Index).getReg()))
        continue;
      // Resize register if needed
      unsigned SizedReplaceWith = getAliasSized(
          ReplaceWith, getRegSize(Inst.getOperand(Index).getReg()));
      MCOperand NewOperand = MCOperand::createReg(SizedReplaceWith);
      Inst.getOperand(Index) = NewOperand;
      FoundOne = true;
    }

    // Return true if at least one operand was replaced
    return FoundOne;
  }

  bool createUncondBranch(MCInst &Inst, const MCSymbol *TBB,
                          MCContext *Ctx) const override {
    Inst.setOpcode(X86::JMP_1);
    Inst.addOperand(MCOperand::createExpr(
        MCSymbolRefExpr::create(TBB, MCSymbolRefExpr::VK_None, *Ctx)));
    return true;
  }

  bool createCall(MCInst &Inst, const MCSymbol *Target,
                  MCContext *Ctx) override {
    Inst.setOpcode(X86::CALL64pcrel32);
    Inst.addOperand(MCOperand::createExpr(
        MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx)));
    return true;
  }

  bool createTailCall(MCInst &Inst, const MCSymbol *Target,
                      MCContext *Ctx) override {
    return createDirectCall(Inst, Target, Ctx, /*IsTailCall*/ true);
  }

  void createLongTailCall(InstructionListType &Seq, const MCSymbol *Target,
                          MCContext *Ctx) override {
    Seq.clear();
    Seq.emplace_back();
    createDirectCall(Seq.back(), Target, Ctx, /*IsTailCall*/ true);
  }

  bool createTrap(MCInst &Inst) const override {
    Inst.clear();
    Inst.setOpcode(X86::TRAP);
    return true;
  }

  bool reverseBranchCondition(MCInst &Inst, const MCSymbol *TBB,
                              MCContext *Ctx) const override {
    unsigned InvCC = getInvertedCondCode(getCondCode(Inst));
    assert(InvCC != X86::COND_INVALID && "invalid branch instruction");
    Inst.getOperand(Info->get(Inst.getOpcode()).NumOperands - 1).setImm(InvCC);
    Inst.getOperand(0) = MCOperand::createExpr(
        MCSymbolRefExpr::create(TBB, MCSymbolRefExpr::VK_None, *Ctx));
    return true;
  }

  bool replaceBranchCondition(MCInst &Inst, const MCSymbol *TBB, MCContext *Ctx,
                              unsigned CC) const override {
    if (CC == X86::COND_INVALID)
      return false;
    Inst.getOperand(Info->get(Inst.getOpcode()).NumOperands - 1).setImm(CC);
    Inst.getOperand(0) = MCOperand::createExpr(
        MCSymbolRefExpr::create(TBB, MCSymbolRefExpr::VK_None, *Ctx));
    return true;
  }

  unsigned getCanonicalBranchCondCode(unsigned CC) const override {
    switch (CC) {
    default:           return X86::COND_INVALID;

    case X86::COND_E:  return X86::COND_E;
    case X86::COND_NE: return X86::COND_E;

    case X86::COND_L:  return X86::COND_L;
    case X86::COND_GE: return X86::COND_L;

    case X86::COND_LE: return X86::COND_G;
    case X86::COND_G:  return X86::COND_G;

    case X86::COND_B:  return X86::COND_B;
    case X86::COND_AE: return X86::COND_B;

    case X86::COND_BE: return X86::COND_A;
    case X86::COND_A:  return X86::COND_A;

    case X86::COND_S:  return X86::COND_S;
    case X86::COND_NS: return X86::COND_S;

    case X86::COND_P:  return X86::COND_P;
    case X86::COND_NP: return X86::COND_P;

    case X86::COND_O:  return X86::COND_O;
    case X86::COND_NO: return X86::COND_O;
    }
  }

  bool replaceBranchTarget(MCInst &Inst, const MCSymbol *TBB,
                           MCContext *Ctx) const override {
    assert((isCall(Inst) || isBranch(Inst)) && !isIndirectBranch(Inst) &&
           "Invalid instruction");
    Inst.getOperand(0) = MCOperand::createExpr(
        MCSymbolRefExpr::create(TBB, MCSymbolRefExpr::VK_None, *Ctx));
    return true;
  }

  MCPhysReg getX86R11() const override { return X86::R11; }

  MCPhysReg getIntArgRegister(unsigned ArgNo) const override {
    // FIXME: this should depend on the calling convention.
    switch (ArgNo) {
    case 0:   return X86::RDI;
    case 1:   return X86::RSI;
    case 2:   return X86::RDX;
    case 3:   return X86::RCX;
    case 4:   return X86::R8;
    case 5:   return X86::R9;
    default:  return getNoRegister();
    }
  }

  void createPause(MCInst &Inst) const override {
    Inst.clear();
    Inst.setOpcode(X86::PAUSE);
  }

  void createLfence(MCInst &Inst) const override {
    Inst.clear();
    Inst.setOpcode(X86::LFENCE);
  }

  bool createDirectCall(MCInst &Inst, const MCSymbol *Target, MCContext *Ctx,
                        bool IsTailCall) override {
    Inst.clear();
    Inst.setOpcode(IsTailCall ? X86::JMP_4 : X86::CALL64pcrel32);
    Inst.addOperand(MCOperand::createExpr(
        MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx)));
    if (IsTailCall)
      setTailCall(Inst);
    return true;
  }

  void createShortJmp(InstructionListType &Seq, const MCSymbol *Target,
                      MCContext *Ctx, bool IsTailCall) override {
    Seq.clear();
    MCInst Inst;
    Inst.setOpcode(X86::JMP_1);
    Inst.addOperand(MCOperand::createExpr(
        MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx)));
    if (IsTailCall)
      setTailCall(Inst);
    Seq.emplace_back(Inst);
  }

  bool isConditionalMove(const MCInst &Inst) const override {
    unsigned OpCode = Inst.getOpcode();
    return (OpCode == X86::CMOV16rr || OpCode == X86::CMOV32rr ||
            OpCode == X86::CMOV64rr);
  }

  bool isBranchOnMem(const MCInst &Inst) const override {
    unsigned OpCode = Inst.getOpcode();
    if (OpCode == X86::CALL64m || (OpCode == X86::JMP32m && isTailCall(Inst)) ||
        OpCode == X86::JMP64m)
      return true;

    return false;
  }

  bool isBranchOnReg(const MCInst &Inst) const override {
    unsigned OpCode = Inst.getOpcode();
    if (OpCode == X86::CALL64r || (OpCode == X86::JMP32r && isTailCall(Inst)) ||
        OpCode == X86::JMP64r)
      return true;

    return false;
  }

  void createPushRegister(MCInst &Inst, MCPhysReg Reg,
                          unsigned Size) const override {
    Inst.clear();
    unsigned NewOpcode = 0;
    if (Reg == X86::EFLAGS) {
      switch (Size) {
      case 2: NewOpcode = X86::PUSHF16;  break;
      case 4: NewOpcode = X86::PUSHF32;  break;
      case 8: NewOpcode = X86::PUSHF64;  break;
      default:
        llvm_unreachable("Unexpected size");
      }
      Inst.setOpcode(NewOpcode);
      return;
    }
    switch (Size) {
    case 2: NewOpcode = X86::PUSH16r;  break;
    case 4: NewOpcode = X86::PUSH32r;  break;
    case 8: NewOpcode = X86::PUSH64r;  break;
    default:
      llvm_unreachable("Unexpected size");
    }
    Inst.setOpcode(NewOpcode);
    Inst.addOperand(MCOperand::createReg(Reg));
  }

  void createPopRegister(MCInst &Inst, MCPhysReg Reg,
                         unsigned Size) const override {
    Inst.clear();
    unsigned NewOpcode = 0;
    if (Reg == X86::EFLAGS) {
      switch (Size) {
      case 2: NewOpcode = X86::POPF16;  break;
      case 4: NewOpcode = X86::POPF32;  break;
      case 8: NewOpcode = X86::POPF64;  break;
      default:
        llvm_unreachable("Unexpected size");
      }
      Inst.setOpcode(NewOpcode);
      return;
    }
    switch (Size) {
    case 2: NewOpcode = X86::POP16r;  break;
    case 4: NewOpcode = X86::POP32r;  break;
    case 8: NewOpcode = X86::POP64r;  break;
    default:
      llvm_unreachable("Unexpected size");
    }
    Inst.setOpcode(NewOpcode);
    Inst.addOperand(MCOperand::createReg(Reg));
  }

  void createPushFlags(MCInst &Inst, unsigned Size) const override {
    return createPushRegister(Inst, X86::EFLAGS, Size);
  }

  void createPopFlags(MCInst &Inst, unsigned Size) const override {
    return createPopRegister(Inst, X86::EFLAGS, Size);
  }

  void createAddRegImm(MCInst &Inst, MCPhysReg Reg, int64_t Value,
                       unsigned Size) const {
    unsigned int Opcode;
    switch (Size) {
    case 1: Opcode = X86::ADD8ri; break;
    case 2: Opcode = X86::ADD16ri; break;
    case 4: Opcode = X86::ADD32ri; break;
    default:
      llvm_unreachable("Unexpected size");
    }
    Inst.setOpcode(Opcode);
    Inst.clear();
    Inst.addOperand(MCOperand::createReg(Reg));
    Inst.addOperand(MCOperand::createReg(Reg));
    Inst.addOperand(MCOperand::createImm(Value));
  }

  void createClearRegWithNoEFlagsUpdate(MCInst &Inst, MCPhysReg Reg,
                                        unsigned Size) const {
    unsigned int Opcode;
    switch (Size) {
    case 1: Opcode = X86::MOV8ri; break;
    case 2: Opcode = X86::MOV16ri; break;
    case 4: Opcode = X86::MOV32ri; break;
    // Writing to a 32-bit register always zeros the upper 32 bits of the
    // full-width register
    case 8:
      Opcode = X86::MOV32ri;
      Reg = getAliasSized(Reg, 4);
      break;
    default:
      llvm_unreachable("Unexpected size");
    }
    Inst.setOpcode(Opcode);
    Inst.clear();
    Inst.addOperand(MCOperand::createReg(Reg));
    Inst.addOperand(MCOperand::createImm(0));
  }

  void createX86SaveOVFlagToRegister(MCInst &Inst, MCPhysReg Reg) const {
    Inst.setOpcode(X86::SETCCr);
    Inst.clear();
    Inst.addOperand(MCOperand::createReg(Reg));
    Inst.addOperand(MCOperand::createImm(X86::COND_O));
  }

  void createX86Lahf(MCInst &Inst) const {
    Inst.setOpcode(X86::LAHF);
    Inst.clear();
  }

  void createX86Sahf(MCInst &Inst) const {
    Inst.setOpcode(X86::SAHF);
    Inst.clear();
  }

  void createInstrIncMemory(InstructionListType &Instrs, const MCSymbol *Target,
                            MCContext *Ctx, bool IsLeaf) const override {
    unsigned int I = 0;

    Instrs.resize(IsLeaf ? 13 : 11);
    // Don't clobber application red zone (ABI dependent)
    if (IsLeaf)
      createStackPointerIncrement(Instrs[I++], 128,
                                  /*NoFlagsClobber=*/true);

    // Performance improvements based on the optimization discussed at
    // https://reviews.llvm.org/D6629
    // LAHF/SAHF are used instead of PUSHF/POPF
    // PUSHF
    createPushRegister(Instrs[I++], X86::RAX, 8);
    createClearRegWithNoEFlagsUpdate(Instrs[I++], X86::RAX, 8);
    createX86Lahf(Instrs[I++]);
    createPushRegister(Instrs[I++], X86::RAX, 8);
    createClearRegWithNoEFlagsUpdate(Instrs[I++], X86::RAX, 8);
    createX86SaveOVFlagToRegister(Instrs[I++], X86::AL);
    // LOCK INC
    createIncMemory(Instrs[I++], Target, Ctx);
    // POPF
    createAddRegImm(Instrs[I++], X86::AL, 127, 1);
    createPopRegister(Instrs[I++], X86::RAX, 8);
    createX86Sahf(Instrs[I++]);
    createPopRegister(Instrs[I++], X86::RAX, 8);

    if (IsLeaf)
      createStackPointerDecrement(Instrs[I], 128,
                                  /*NoFlagsClobber=*/true);
  }

  void createSwap(MCInst &Inst, MCPhysReg Source, MCPhysReg MemBaseReg,
                  int64_t Disp) const {
    Inst.setOpcode(X86::XCHG64rm);
    Inst.addOperand(MCOperand::createReg(Source));
    Inst.addOperand(MCOperand::createReg(Source));
    Inst.addOperand(MCOperand::createReg(MemBaseReg));      // BaseReg
    Inst.addOperand(MCOperand::createImm(1));               // ScaleAmt
    Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // IndexReg
    Inst.addOperand(MCOperand::createImm(Disp));            // Displacement
    Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // AddrSegmentReg
  }

  void createIndirectBranch(MCInst &Inst, MCPhysReg MemBaseReg,
                            int64_t Disp) const {
    Inst.setOpcode(X86::JMP64m);
    Inst.addOperand(MCOperand::createReg(MemBaseReg));      // BaseReg
    Inst.addOperand(MCOperand::createImm(1));               // ScaleAmt
    Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // IndexReg
    Inst.addOperand(MCOperand::createImm(Disp));            // Displacement
    Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // AddrSegmentReg
  }

  InstructionListType createInstrumentedIndirectCall(const MCInst &CallInst,
                                                     bool TailCall,
                                                     MCSymbol *HandlerFuncAddr,
                                                     int CallSiteID,
                                                     MCContext *Ctx) override {
    // Check if the target address expression used in the original indirect call
    // uses the stack pointer, which we are going to clobber.
    static BitVector SPAliases(getAliases(X86::RSP));
    bool UsesSP = false;
    // Skip defs.
    for (unsigned I = Info->get(CallInst.getOpcode()).getNumDefs(),
                  E = MCPlus::getNumPrimeOperands(CallInst);
         I != E; ++I) {
      const MCOperand &Operand = CallInst.getOperand(I);
      if (Operand.isReg() && SPAliases[Operand.getReg()]) {
        UsesSP = true;
        break;
      }
    }

    InstructionListType Insts;
    MCPhysReg TempReg = getIntArgRegister(0);
    // Code sequence used to enter indirect call instrumentation helper:
    //   push %rdi
    //   add $8, %rsp       ;; $rsp may be used in target, so fix it to prev val
    //   movq target, %rdi  ;; via convertIndirectCallTargetToLoad
    //   sub $8, %rsp       ;; restore correct stack value
    //   push %rdi
    //   movq $CallSiteID, %rdi
    //   push %rdi
    //   callq/jmp HandlerFuncAddr
    Insts.emplace_back();
    createPushRegister(Insts.back(), TempReg, 8);
    if (UsesSP) { // Only adjust SP if we really need to
      Insts.emplace_back();
      createStackPointerDecrement(Insts.back(), 8, /*NoFlagsClobber=*/false);
    }
    Insts.emplace_back(CallInst);
    // Insts.back() and CallInst now share the same annotation instruction.
    // Strip it from Insts.back(), only preserving tail call annotation.
    stripAnnotations(Insts.back(), /*KeepTC=*/true);
    convertIndirectCallToLoad(Insts.back(), TempReg);
    if (UsesSP) {
      Insts.emplace_back();
      createStackPointerIncrement(Insts.back(), 8, /*NoFlagsClobber=*/false);
    }
    Insts.emplace_back();
    createPushRegister(Insts.back(), TempReg, 8);
    Insts.emplace_back();
    createLoadImmediate(Insts.back(), TempReg, CallSiteID);
    Insts.emplace_back();
    createPushRegister(Insts.back(), TempReg, 8);
    Insts.emplace_back();
    createDirectCall(Insts.back(), HandlerFuncAddr, Ctx,
                     /*TailCall=*/TailCall);
    // Carry over metadata
    for (int I = MCPlus::getNumPrimeOperands(CallInst),
             E = CallInst.getNumOperands();
         I != E; ++I)
      Insts.back().addOperand(CallInst.getOperand(I));

    return Insts;
  }

  InstructionListType createInstrumentedIndCallHandlerExitBB() const override {
    const MCPhysReg TempReg = getIntArgRegister(0);
    // We just need to undo the sequence created for every ind call in
    // instrumentIndirectTarget(), which can be accomplished minimally with:
    //   popfq
    //   pop %rdi
    //   add $16, %rsp
    //   xchg (%rsp), %rdi
    //   jmp *-8(%rsp)
    InstructionListType Insts(5);
    createPopFlags(Insts[0], 8);
    createPopRegister(Insts[1], TempReg, 8);
    createStackPointerDecrement(Insts[2], 16, /*NoFlagsClobber=*/false);
    createSwap(Insts[3], TempReg, X86::RSP, 0);
    createIndirectBranch(Insts[4], X86::RSP, -8);
    return Insts;
  }

  InstructionListType
  createInstrumentedIndTailCallHandlerExitBB() const override {
    const MCPhysReg TempReg = getIntArgRegister(0);
    // Same thing as above, but for tail calls
    //   popfq
    //   add $16, %rsp
    //   pop %rdi
    //   jmp *-16(%rsp)
    InstructionListType Insts(4);
    createPopFlags(Insts[0], 8);
    createStackPointerDecrement(Insts[1], 16, /*NoFlagsClobber=*/false);
    createPopRegister(Insts[2], TempReg, 8);
    createIndirectBranch(Insts[3], X86::RSP, -16);
    return Insts;
  }

  InstructionListType
  createInstrumentedIndCallHandlerEntryBB(const MCSymbol *InstrTrampoline,
                                          const MCSymbol *IndCallHandler,
                                          MCContext *Ctx) override {
    const MCPhysReg TempReg = getIntArgRegister(0);
    // Code sequence used to check whether InstrTampoline was initialized
    // and call it if so, returns via IndCallHandler.
    //   pushfq
    //   mov    InstrTrampoline,%rdi
    //   cmp    $0x0,%rdi
    //   je     IndCallHandler
    //   callq  *%rdi
    //   jmpq   IndCallHandler
    InstructionListType Insts;
    Insts.emplace_back();
    createPushFlags(Insts.back(), 8);
    Insts.emplace_back();
    createMove(Insts.back(), InstrTrampoline, TempReg, Ctx);
    InstructionListType cmpJmp = createCmpJE(TempReg, 0, IndCallHandler, Ctx);
    Insts.insert(Insts.end(), cmpJmp.begin(), cmpJmp.end());
    Insts.emplace_back();
    Insts.back().setOpcode(X86::CALL64r);
    Insts.back().addOperand(MCOperand::createReg(TempReg));
    Insts.emplace_back();
    createDirectCall(Insts.back(), IndCallHandler, Ctx, /*IsTailCall*/ true);
    return Insts;
  }

  InstructionListType createNumCountersGetter(MCContext *Ctx) const override {
    InstructionListType Insts(2);
    MCSymbol *NumLocs = Ctx->getOrCreateSymbol("__bolt_num_counters");
    createMove(Insts[0], NumLocs, X86::EAX, Ctx);
    createReturn(Insts[1]);
    return Insts;
  }

  InstructionListType
  createInstrLocationsGetter(MCContext *Ctx) const override {
    InstructionListType Insts(2);
    MCSymbol *Locs = Ctx->getOrCreateSymbol("__bolt_instr_locations");
    createLea(Insts[0], Locs, X86::EAX, Ctx);
    createReturn(Insts[1]);
    return Insts;
  }

  InstructionListType createInstrTablesGetter(MCContext *Ctx) const override {
    InstructionListType Insts(2);
    MCSymbol *Locs = Ctx->getOrCreateSymbol("__bolt_instr_tables");
    createLea(Insts[0], Locs, X86::EAX, Ctx);
    createReturn(Insts[1]);
    return Insts;
  }

  InstructionListType createInstrNumFuncsGetter(MCContext *Ctx) const override {
    InstructionListType Insts(2);
    MCSymbol *NumFuncs = Ctx->getOrCreateSymbol("__bolt_instr_num_funcs");
    createMove(Insts[0], NumFuncs, X86::EAX, Ctx);
    createReturn(Insts[1]);
    return Insts;
  }

  InstructionListType createSymbolTrampoline(const MCSymbol *TgtSym,
                                             MCContext *Ctx) const override {
    InstructionListType Insts(1);
    createUncondBranch(Insts[0], TgtSym, Ctx);
    return Insts;
  }

  InstructionListType createDummyReturnFunction(MCContext *Ctx) const override {
    InstructionListType Insts(1);
    createReturn(Insts[0]);
    return Insts;
  }

  BlocksVectorTy indirectCallPromotion(
      const MCInst &CallInst,
      const std::vector<std::pair<MCSymbol *, uint64_t>> &Targets,
      const std::vector<std::pair<MCSymbol *, uint64_t>> &VtableSyms,
      const std::vector<MCInst *> &MethodFetchInsns,
      const bool MinimizeCodeSize, MCContext *Ctx) override {
    const bool IsTailCall = isTailCall(CallInst);
    const bool IsJumpTable = getJumpTable(CallInst) != 0;
    BlocksVectorTy Results;

    // Label for the current code block.
    MCSymbol *NextTarget = nullptr;

    // The join block which contains all the instructions following CallInst.
    // MergeBlock remains null if CallInst is a tail call.
    MCSymbol *MergeBlock = nullptr;

    unsigned FuncAddrReg = X86::R10;

    const bool LoadElim = !VtableSyms.empty();
    assert((!LoadElim || VtableSyms.size() == Targets.size()) &&
           "There must be a vtable entry for every method "
           "in the targets vector.");

    if (MinimizeCodeSize && !LoadElim) {
      std::set<unsigned> UsedRegs;

      for (unsigned int I = 0; I < MCPlus::getNumPrimeOperands(CallInst); ++I) {
        const MCOperand &Op = CallInst.getOperand(I);
        if (Op.isReg())
          UsedRegs.insert(Op.getReg());
      }

      if (UsedRegs.count(X86::R10) == 0)
        FuncAddrReg = X86::R10;
      else if (UsedRegs.count(X86::R11) == 0)
        FuncAddrReg = X86::R11;
      else
        return Results;
    }

    const auto jumpToMergeBlock = [&](InstructionListType &NewCall) {
      assert(MergeBlock);
      NewCall.push_back(CallInst);
      MCInst &Merge = NewCall.back();
      Merge.clear();
      createUncondBranch(Merge, MergeBlock, Ctx);
    };

    for (unsigned int i = 0; i < Targets.size(); ++i) {
      Results.emplace_back(NextTarget, InstructionListType());
      InstructionListType *NewCall = &Results.back().second;

      if (MinimizeCodeSize && !LoadElim) {
        // Load the call target into FuncAddrReg.
        NewCall->push_back(CallInst); // Copy CallInst in order to get SMLoc
        MCInst &Target = NewCall->back();
        Target.clear();
        Target.setOpcode(X86::MOV64ri32);
        Target.addOperand(MCOperand::createReg(FuncAddrReg));
        if (Targets[i].first) {
          // Is this OK?
          Target.addOperand(MCOperand::createExpr(MCSymbolRefExpr::create(
              Targets[i].first, MCSymbolRefExpr::VK_None, *Ctx)));
        } else {
          const uint64_t Addr = Targets[i].second;
          // Immediate address is out of sign extended 32 bit range.
          if (int64_t(Addr) != int64_t(int32_t(Addr)))
            return BlocksVectorTy();

          Target.addOperand(MCOperand::createImm(Addr));
        }

        // Compare current call target to a specific address.
        NewCall->push_back(CallInst);
        MCInst &Compare = NewCall->back();
        Compare.clear();
        if (isBranchOnReg(CallInst))
          Compare.setOpcode(X86::CMP64rr);
        else if (CallInst.getOpcode() == X86::CALL64pcrel32)
          Compare.setOpcode(X86::CMP64ri32);
        else
          Compare.setOpcode(X86::CMP64rm);

        Compare.addOperand(MCOperand::createReg(FuncAddrReg));

        // TODO: Would be preferable to only load this value once.
        for (unsigned i = 0;
             i < Info->get(CallInst.getOpcode()).getNumOperands(); ++i)
          if (!CallInst.getOperand(i).isInst())
            Compare.addOperand(CallInst.getOperand(i));
      } else {
        // Compare current call target to a specific address.
        NewCall->push_back(CallInst);
        MCInst &Compare = NewCall->back();
        Compare.clear();
        if (isBranchOnReg(CallInst))
          Compare.setOpcode(X86::CMP64ri32);
        else
          Compare.setOpcode(X86::CMP64mi32);

        // Original call address.
        for (unsigned i = 0;
             i < Info->get(CallInst.getOpcode()).getNumOperands(); ++i)
          if (!CallInst.getOperand(i).isInst())
            Compare.addOperand(CallInst.getOperand(i));

        // Target address.
        if (Targets[i].first || LoadElim) {
          const MCSymbol *Sym =
              LoadElim ? VtableSyms[i].first : Targets[i].first;
          const uint64_t Addend = LoadElim ? VtableSyms[i].second : 0;
          const MCExpr *Expr = MCSymbolRefExpr::create(Sym, *Ctx);
          if (Addend)
            Expr = MCBinaryExpr::createAdd(
                Expr, MCConstantExpr::create(Addend, *Ctx), *Ctx);
          Compare.addOperand(MCOperand::createExpr(Expr));
        } else {
          const uint64_t Addr = Targets[i].second;
          // Immediate address is out of sign extended 32 bit range.
          if (int64_t(Addr) != int64_t(int32_t(Addr)))
            return BlocksVectorTy();

          Compare.addOperand(MCOperand::createImm(Addr));
        }
      }

      // jump to next target compare.
      NextTarget =
          Ctx->createNamedTempSymbol(); // generate label for the next block
      NewCall->push_back(CallInst);

      if (IsJumpTable) {
        MCInst &Je = NewCall->back();

        // Jump to next compare if target addresses don't match.
        Je.clear();
        Je.setOpcode(X86::JCC_1);
        if (Targets[i].first)
          Je.addOperand(MCOperand::createExpr(MCSymbolRefExpr::create(
              Targets[i].first, MCSymbolRefExpr::VK_None, *Ctx)));
        else
          Je.addOperand(MCOperand::createImm(Targets[i].second));

        Je.addOperand(MCOperand::createImm(X86::COND_E));
        assert(!isInvoke(CallInst));
      } else {
        MCInst &Jne = NewCall->back();

        // Jump to next compare if target addresses don't match.
        Jne.clear();
        Jne.setOpcode(X86::JCC_1);
        Jne.addOperand(MCOperand::createExpr(MCSymbolRefExpr::create(
            NextTarget, MCSymbolRefExpr::VK_None, *Ctx)));
        Jne.addOperand(MCOperand::createImm(X86::COND_NE));

        // Call specific target directly.
        Results.emplace_back(Ctx->createNamedTempSymbol(),
                             InstructionListType());
        NewCall = &Results.back().second;
        NewCall->push_back(CallInst);
        MCInst &CallOrJmp = NewCall->back();

        CallOrJmp.clear();

        if (MinimizeCodeSize && !LoadElim) {
          CallOrJmp.setOpcode(IsTailCall ? X86::JMP32r : X86::CALL64r);
          CallOrJmp.addOperand(MCOperand::createReg(FuncAddrReg));
        } else {
          CallOrJmp.setOpcode(IsTailCall ? X86::JMP_4 : X86::CALL64pcrel32);

          if (Targets[i].first)
            CallOrJmp.addOperand(MCOperand::createExpr(MCSymbolRefExpr::create(
                Targets[i].first, MCSymbolRefExpr::VK_None, *Ctx)));
          else
            CallOrJmp.addOperand(MCOperand::createImm(Targets[i].second));
        }
        if (IsTailCall)
          setTailCall(CallOrJmp);

        if (CallOrJmp.getOpcode() == X86::CALL64r ||
            CallOrJmp.getOpcode() == X86::CALL64pcrel32) {
          if (std::optional<uint32_t> Offset = getOffset(CallInst))
            // Annotated as duplicated call
            setOffset(CallOrJmp, *Offset);
        }

        if (isInvoke(CallInst) && !isInvoke(CallOrJmp)) {
          // Copy over any EH or GNU args size information from the original
          // call.
          std::optional<MCPlus::MCLandingPad> EHInfo = getEHInfo(CallInst);
          if (EHInfo)
            addEHInfo(CallOrJmp, *EHInfo);
          int64_t GnuArgsSize = getGnuArgsSize(CallInst);
          if (GnuArgsSize >= 0)
            addGnuArgsSize(CallOrJmp, GnuArgsSize);
        }

        if (!IsTailCall) {
          // The fallthrough block for the most common target should be
          // the merge block.
          if (i == 0) {
            // Fallthrough to merge block.
            MergeBlock = Ctx->createNamedTempSymbol();
          } else {
            // Insert jump to the merge block if we are not doing a fallthrough.
            jumpToMergeBlock(*NewCall);
          }
        }
      }
    }

    // Cold call block.
    Results.emplace_back(NextTarget, InstructionListType());
    InstructionListType &NewCall = Results.back().second;
    for (const MCInst *Inst : MethodFetchInsns)
      if (Inst != &CallInst)
        NewCall.push_back(*Inst);
    NewCall.push_back(CallInst);

    // Jump to merge block from cold call block
    if (!IsTailCall && !IsJumpTable) {
      jumpToMergeBlock(NewCall);

      // Record merge block
      Results.emplace_back(MergeBlock, InstructionListType());
    }

    return Results;
  }

  BlocksVectorTy jumpTablePromotion(
      const MCInst &IJmpInst,
      const std::vector<std::pair<MCSymbol *, uint64_t>> &Targets,
      const std::vector<MCInst *> &TargetFetchInsns,
      MCContext *Ctx) const override {
    assert(getJumpTable(IJmpInst) != 0);
    uint16_t IndexReg = getAnnotationAs<uint16_t>(IJmpInst, "JTIndexReg");
    if (IndexReg == 0)
      return BlocksVectorTy();

    BlocksVectorTy Results;

    // Label for the current code block.
    MCSymbol *NextTarget = nullptr;

    for (unsigned int i = 0; i < Targets.size(); ++i) {
      Results.emplace_back(NextTarget, InstructionListType());
      InstructionListType *CurBB = &Results.back().second;

      // Compare current index to a specific index.
      CurBB->emplace_back(MCInst());
      MCInst &CompareInst = CurBB->back();
      CompareInst.setLoc(IJmpInst.getLoc());
      CompareInst.setOpcode(X86::CMP64ri32);
      CompareInst.addOperand(MCOperand::createReg(IndexReg));

      const uint64_t CaseIdx = Targets[i].second;
      // Immediate address is out of sign extended 32 bit range.
      if (int64_t(CaseIdx) != int64_t(int32_t(CaseIdx)))
        return BlocksVectorTy();

      CompareInst.addOperand(MCOperand::createImm(CaseIdx));
      shortenInstruction(CompareInst, *Ctx->getSubtargetInfo());

      // jump to next target compare.
      NextTarget =
          Ctx->createNamedTempSymbol(); // generate label for the next block
      CurBB->push_back(MCInst());

      MCInst &JEInst = CurBB->back();
      JEInst.setLoc(IJmpInst.getLoc());

      // Jump to target if indices match
      JEInst.setOpcode(X86::JCC_1);
      JEInst.addOperand(MCOperand::createExpr(MCSymbolRefExpr::create(
          Targets[i].first, MCSymbolRefExpr::VK_None, *Ctx)));
      JEInst.addOperand(MCOperand::createImm(X86::COND_E));
    }

    // Cold call block.
    Results.emplace_back(NextTarget, InstructionListType());
    InstructionListType &CurBB = Results.back().second;
    for (const MCInst *Inst : TargetFetchInsns)
      if (Inst != &IJmpInst)
        CurBB.push_back(*Inst);

    CurBB.push_back(IJmpInst);

    return Results;
  }

private:
  bool createMove(MCInst &Inst, const MCSymbol *Src, unsigned Reg,
                  MCContext *Ctx) const {
    Inst.setOpcode(X86::MOV64rm);
    Inst.addOperand(MCOperand::createReg(Reg));
    Inst.addOperand(MCOperand::createReg(X86::RIP));        // BaseReg
    Inst.addOperand(MCOperand::createImm(1));               // ScaleAmt
    Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // IndexReg
    Inst.addOperand(MCOperand::createExpr(
        MCSymbolRefExpr::create(Src, MCSymbolRefExpr::VK_None,
                                *Ctx)));                    // Displacement
    Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // AddrSegmentReg

    return true;
  }

  bool createLea(MCInst &Inst, const MCSymbol *Src, unsigned Reg,
                 MCContext *Ctx) const {
    Inst.setOpcode(X86::LEA64r);
    Inst.addOperand(MCOperand::createReg(Reg));
    Inst.addOperand(MCOperand::createReg(X86::RIP));        // BaseReg
    Inst.addOperand(MCOperand::createImm(1));               // ScaleAmt
    Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // IndexReg
    Inst.addOperand(MCOperand::createExpr(
        MCSymbolRefExpr::create(Src, MCSymbolRefExpr::VK_None,
                                *Ctx)));                    // Displacement
    Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // AddrSegmentReg
    return true;
  }
};

} // namespace

namespace llvm {
namespace bolt {

MCPlusBuilder *createX86MCPlusBuilder(const MCInstrAnalysis *Analysis,
                                      const MCInstrInfo *Info,
                                      const MCRegisterInfo *RegInfo) {
  return new X86MCPlusBuilder(Analysis, Info, RegInfo);
}

} // namespace bolt
} // namespace llvm
