//===- X86Operand.h - Parsed X86 machine instruction ------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_TARGET_X86_ASMPARSER_X86OPERAND_H
#define LLVM_LIB_TARGET_X86_ASMPARSER_X86OPERAND_H

#include "MCTargetDesc/X86IntelInstPrinter.h"
#include "MCTargetDesc/X86MCTargetDesc.h"
#include "X86AsmParserCommon.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/SMLoc.h"
#include <cassert>
#include <memory>

namespace llvm {

/// X86Operand - Instances of this class represent a parsed X86 machine
/// instruction.
struct X86Operand final : public MCParsedAsmOperand {
  enum KindTy { Token, Register, Immediate, Memory, Prefix, DXRegister } Kind;

  SMLoc StartLoc, EndLoc;
  SMLoc OffsetOfLoc;
  StringRef SymName;
  void *OpDecl;
  bool AddressOf;

  /// This used for inline asm which may specify base reg and index reg for
  /// MemOp. e.g. ARR[eax + ecx*4], so no extra reg can be used for MemOp.
  bool UseUpRegs = false;

  struct TokOp {
    const char *Data;
    unsigned Length;
  };

  struct RegOp {
    MCRegister RegNo;
  };

  struct PrefOp {
    unsigned Prefixes;
  };

  struct ImmOp {
    const MCExpr *Val;
    bool LocalRef;
  };

  struct MemOp {
    MCRegister SegReg;
    const MCExpr *Disp;
    MCRegister BaseReg;
    MCRegister DefaultBaseReg;
    MCRegister IndexReg;
    unsigned Scale;
    unsigned Size;
    unsigned ModeSize;

    /// If the memory operand is unsized and there are multiple instruction
    /// matches, prefer the one with this size.
    unsigned FrontendSize;

    /// If false, then this operand must be a memory operand for an indirect
    /// branch instruction. Otherwise, this operand may belong to either a
    /// direct or indirect branch instruction.
    bool MaybeDirectBranchDest;
  };

  union {
    struct TokOp Tok;
    struct RegOp Reg;
    struct ImmOp Imm;
    struct MemOp Mem;
    struct PrefOp Pref;
  };

  X86Operand(KindTy K, SMLoc Start, SMLoc End)
      : Kind(K), StartLoc(Start), EndLoc(End), OpDecl(nullptr),
        AddressOf(false) {}

  StringRef getSymName() override { return SymName; }
  void *getOpDecl() override { return OpDecl; }

  /// getStartLoc - Get the location of the first token of this operand.
  SMLoc getStartLoc() const override { return StartLoc; }

  /// getEndLoc - Get the location of the last token of this operand.
  SMLoc getEndLoc() const override { return EndLoc; }

  /// getLocRange - Get the range between the first and last token of this
  /// operand.
  SMRange getLocRange() const { return SMRange(StartLoc, EndLoc); }

  /// getOffsetOfLoc - Get the location of the offset operator.
  SMLoc getOffsetOfLoc() const override { return OffsetOfLoc; }

  void print(raw_ostream &OS) const override {

    auto PrintImmValue = [&](const MCExpr *Val, const char *VName) {
      if (Val->getKind() == MCExpr::Constant) {
        if (auto Imm = cast<MCConstantExpr>(Val)->getValue())
          OS << VName << Imm;
      } else if (Val->getKind() == MCExpr::SymbolRef) {
        if (auto *SRE = dyn_cast<MCSymbolRefExpr>(Val)) {
          const MCSymbol &Sym = SRE->getSymbol();
          if (const char *SymNameStr = Sym.getName().data())
            OS << VName << SymNameStr;
        }
      }
    };

    switch (Kind) {
    case Token:
      OS << Tok.Data;
      break;
    case Register:
      OS << "Reg:" << X86IntelInstPrinter::getRegisterName(Reg.RegNo);
      break;
    case DXRegister:
      OS << "DXReg";
      break;
    case Immediate:
      PrintImmValue(Imm.Val, "Imm:");
      break;
    case Prefix:
      OS << "Prefix:" << Pref.Prefixes;
      break;
    case Memory:
      OS << "Memory: ModeSize=" << Mem.ModeSize;
      if (Mem.Size)
        OS << ",Size=" << Mem.Size;
      if (Mem.BaseReg)
        OS << ",BaseReg=" << X86IntelInstPrinter::getRegisterName(Mem.BaseReg);
      if (Mem.IndexReg)
        OS << ",IndexReg="
           << X86IntelInstPrinter::getRegisterName(Mem.IndexReg);
      if (Mem.Scale)
        OS << ",Scale=" << Mem.Scale;
      if (Mem.Disp)
        PrintImmValue(Mem.Disp, ",Disp=");
      if (Mem.SegReg)
        OS << ",SegReg=" << X86IntelInstPrinter::getRegisterName(Mem.SegReg);
      break;
    }
  }

  StringRef getToken() const {
    assert(Kind == Token && "Invalid access!");
    return StringRef(Tok.Data, Tok.Length);
  }
  void setTokenValue(StringRef Value) {
    assert(Kind == Token && "Invalid access!");
    Tok.Data = Value.data();
    Tok.Length = Value.size();
  }

  MCRegister getReg() const override {
    assert(Kind == Register && "Invalid access!");
    return Reg.RegNo;
  }

  unsigned getPrefix() const {
    assert(Kind == Prefix && "Invalid access!");
    return Pref.Prefixes;
  }

  const MCExpr *getImm() const {
    assert(Kind == Immediate && "Invalid access!");
    return Imm.Val;
  }

  const MCExpr *getMemDisp() const {
    assert(Kind == Memory && "Invalid access!");
    return Mem.Disp;
  }
  MCRegister getMemSegReg() const {
    assert(Kind == Memory && "Invalid access!");
    return Mem.SegReg;
  }
  MCRegister getMemBaseReg() const {
    assert(Kind == Memory && "Invalid access!");
    return Mem.BaseReg;
  }
  MCRegister getMemDefaultBaseReg() const {
    assert(Kind == Memory && "Invalid access!");
    return Mem.DefaultBaseReg;
  }
  MCRegister getMemIndexReg() const {
    assert(Kind == Memory && "Invalid access!");
    return Mem.IndexReg;
  }
  unsigned getMemScale() const {
    assert(Kind == Memory && "Invalid access!");
    return Mem.Scale;
  }
  unsigned getMemModeSize() const {
    assert(Kind == Memory && "Invalid access!");
    return Mem.ModeSize;
  }
  unsigned getMemFrontendSize() const {
    assert(Kind == Memory && "Invalid access!");
    return Mem.FrontendSize;
  }
  bool isMaybeDirectBranchDest() const {
    assert(Kind == Memory && "Invalid access!");
    return Mem.MaybeDirectBranchDest;
  }

  bool isToken() const override {return Kind == Token; }

  bool isImm() const override { return Kind == Immediate; }

  bool isImmSExti16i8() const {
    if (!isImm())
      return false;

    // If this isn't a constant expr, just assume it fits and let relaxation
    // handle it.
    const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
    if (!CE)
      return true;

    // Otherwise, check the value is in a range that makes sense for this
    // extension.
    return isImmSExti16i8Value(CE->getValue());
  }
  bool isImmSExti32i8() const {
    if (!isImm())
      return false;

    // If this isn't a constant expr, just assume it fits and let relaxation
    // handle it.
    const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
    if (!CE)
      return true;

    // Otherwise, check the value is in a range that makes sense for this
    // extension.
    return isImmSExti32i8Value(CE->getValue());
  }
  bool isImmSExti64i8() const {
    if (!isImm())
      return false;

    // If this isn't a constant expr, just assume it fits and let relaxation
    // handle it.
    const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
    if (!CE)
      return true;

    // Otherwise, check the value is in a range that makes sense for this
    // extension.
    return isImmSExti64i8Value(CE->getValue());
  }
  bool isImmSExti64i32() const {
    if (!isImm())
      return false;

    // If this isn't a constant expr, just assume it fits and let relaxation
    // handle it.
    const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
    if (!CE)
      return true;

    // Otherwise, check the value is in a range that makes sense for this
    // extension.
    return isImmSExti64i32Value(CE->getValue());
  }

  bool isImmUnsignedi4() const {
    if (!isImm()) return false;
    // If this isn't a constant expr, reject it. The immediate byte is shared
    // with a register encoding. We can't have it affected by a relocation.
    const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
    if (!CE) return false;
    return isImmUnsignedi4Value(CE->getValue());
  }

  bool isImmUnsignedi8() const {
    if (!isImm()) return false;
    // If this isn't a constant expr, just assume it fits and let relaxation
    // handle it.
    const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
    if (!CE) return true;
    return isImmUnsignedi8Value(CE->getValue());
  }

  bool isOffsetOfLocal() const override { return isImm() && Imm.LocalRef; }

  bool needAddressOf() const override { return AddressOf; }

  bool isMem() const override { return Kind == Memory; }
  bool isMemUnsized() const {
    return Kind == Memory && Mem.Size == 0;
  }
  bool isMem8() const {
    return Kind == Memory && (!Mem.Size || Mem.Size == 8);
  }
  bool isMem16() const {
    return Kind == Memory && (!Mem.Size || Mem.Size == 16);
  }
  bool isMem32() const {
    return Kind == Memory && (!Mem.Size || Mem.Size == 32);
  }
  bool isMem64() const {
    return Kind == Memory && (!Mem.Size || Mem.Size == 64);
  }
  bool isMem80() const {
    return Kind == Memory && (!Mem.Size || Mem.Size == 80);
  }
  bool isMem128() const {
    return Kind == Memory && (!Mem.Size || Mem.Size == 128);
  }
  bool isMem256() const {
    return Kind == Memory && (!Mem.Size || Mem.Size == 256);
  }
  bool isMem512() const {
    return Kind == Memory && (!Mem.Size || Mem.Size == 512);
  }

  bool isSibMem() const {
    return isMem() && Mem.BaseReg != X86::RIP && Mem.BaseReg != X86::EIP;
  }

  bool isMemIndexReg(unsigned LowR, unsigned HighR) const {
    assert(Kind == Memory && "Invalid access!");
    return Mem.IndexReg >= LowR && Mem.IndexReg <= HighR;
  }

  bool isMem32_RC128() const {
    return isMem32() && isMemIndexReg(X86::XMM0, X86::XMM15);
  }
  bool isMem64_RC128() const {
    return isMem64() && isMemIndexReg(X86::XMM0, X86::XMM15);
  }
  bool isMem32_RC256() const {
    return isMem32() && isMemIndexReg(X86::YMM0, X86::YMM15);
  }
  bool isMem64_RC256() const {
    return isMem64() && isMemIndexReg(X86::YMM0, X86::YMM15);
  }

  bool isMem32_RC128X() const {
    return isMem32() && X86II::isXMMReg(Mem.IndexReg);
  }
  bool isMem64_RC128X() const {
    return isMem64() && X86II::isXMMReg(Mem.IndexReg);
  }
  bool isMem32_RC256X() const {
    return isMem32() && X86II::isYMMReg(Mem.IndexReg);
  }
  bool isMem64_RC256X() const {
    return isMem64() && X86II::isYMMReg(Mem.IndexReg);
  }
  bool isMem32_RC512() const {
    return isMem32() && X86II::isZMMReg(Mem.IndexReg);
  }
  bool isMem64_RC512() const {
    return isMem64() && X86II::isZMMReg(Mem.IndexReg);
  }

  bool isMem512_GR16() const {
    if (!isMem512())
      return false;
    if (getMemBaseReg() &&
        !X86MCRegisterClasses[X86::GR16RegClassID].contains(getMemBaseReg()))
      return false;
    return true;
  }
  bool isMem512_GR32() const {
    if (!isMem512())
      return false;
    if (getMemBaseReg() &&
        !X86MCRegisterClasses[X86::GR32RegClassID].contains(getMemBaseReg()) &&
        getMemBaseReg() != X86::EIP)
      return false;
    if (getMemIndexReg() &&
        !X86MCRegisterClasses[X86::GR32RegClassID].contains(getMemIndexReg()) &&
        getMemIndexReg() != X86::EIZ)
      return false;
    return true;
  }
  bool isMem512_GR64() const {
    if (!isMem512())
      return false;
    if (getMemBaseReg() &&
        !X86MCRegisterClasses[X86::GR64RegClassID].contains(getMemBaseReg()) &&
        getMemBaseReg() != X86::RIP)
      return false;
    if (getMemIndexReg() &&
        !X86MCRegisterClasses[X86::GR64RegClassID].contains(getMemIndexReg()) &&
        getMemIndexReg() != X86::RIZ)
      return false;
    return true;
  }

  bool isAbsMem() const {
    return Kind == Memory && !getMemSegReg() && !getMemBaseReg() &&
           !getMemIndexReg() && getMemScale() == 1 && isMaybeDirectBranchDest();
  }

  bool isAVX512RC() const{
      return isImm();
  }

  bool isAbsMem16() const {
    return isAbsMem() && Mem.ModeSize == 16;
  }

  bool isMemUseUpRegs() const override { return UseUpRegs; }

  bool isSrcIdx() const {
    return !getMemIndexReg() && getMemScale() == 1 &&
      (getMemBaseReg() == X86::RSI || getMemBaseReg() == X86::ESI ||
       getMemBaseReg() == X86::SI) && isa<MCConstantExpr>(getMemDisp()) &&
      cast<MCConstantExpr>(getMemDisp())->getValue() == 0;
  }
  bool isSrcIdx8() const {
    return isMem8() && isSrcIdx();
  }
  bool isSrcIdx16() const {
    return isMem16() && isSrcIdx();
  }
  bool isSrcIdx32() const {
    return isMem32() && isSrcIdx();
  }
  bool isSrcIdx64() const {
    return isMem64() && isSrcIdx();
  }

  bool isDstIdx() const {
    return !getMemIndexReg() && getMemScale() == 1 &&
           (!getMemSegReg() || getMemSegReg() == X86::ES) &&
           (getMemBaseReg() == X86::RDI || getMemBaseReg() == X86::EDI ||
            getMemBaseReg() == X86::DI) &&
           isa<MCConstantExpr>(getMemDisp()) &&
           cast<MCConstantExpr>(getMemDisp())->getValue() == 0;
  }
  bool isDstIdx8() const {
    return isMem8() && isDstIdx();
  }
  bool isDstIdx16() const {
    return isMem16() && isDstIdx();
  }
  bool isDstIdx32() const {
    return isMem32() && isDstIdx();
  }
  bool isDstIdx64() const {
    return isMem64() && isDstIdx();
  }

  bool isMemOffs() const {
    return Kind == Memory && !getMemBaseReg() && !getMemIndexReg() &&
      getMemScale() == 1;
  }

  bool isMemOffs16_8() const {
    return isMemOffs() && Mem.ModeSize == 16 && (!Mem.Size || Mem.Size == 8);
  }
  bool isMemOffs16_16() const {
    return isMemOffs() && Mem.ModeSize == 16 && (!Mem.Size || Mem.Size == 16);
  }
  bool isMemOffs16_32() const {
    return isMemOffs() && Mem.ModeSize == 16 && (!Mem.Size || Mem.Size == 32);
  }
  bool isMemOffs32_8() const {
    return isMemOffs() && Mem.ModeSize == 32 && (!Mem.Size || Mem.Size == 8);
  }
  bool isMemOffs32_16() const {
    return isMemOffs() && Mem.ModeSize == 32 && (!Mem.Size || Mem.Size == 16);
  }
  bool isMemOffs32_32() const {
    return isMemOffs() && Mem.ModeSize == 32 && (!Mem.Size || Mem.Size == 32);
  }
  bool isMemOffs32_64() const {
    return isMemOffs() && Mem.ModeSize == 32 && (!Mem.Size || Mem.Size == 64);
  }
  bool isMemOffs64_8() const {
    return isMemOffs() && Mem.ModeSize == 64 && (!Mem.Size || Mem.Size == 8);
  }
  bool isMemOffs64_16() const {
    return isMemOffs() && Mem.ModeSize == 64 && (!Mem.Size || Mem.Size == 16);
  }
  bool isMemOffs64_32() const {
    return isMemOffs() && Mem.ModeSize == 64 && (!Mem.Size || Mem.Size == 32);
  }
  bool isMemOffs64_64() const {
    return isMemOffs() && Mem.ModeSize == 64 && (!Mem.Size || Mem.Size == 64);
  }

  bool isPrefix() const { return Kind == Prefix; }
  bool isReg() const override { return Kind == Register; }
  bool isDXReg() const { return Kind == DXRegister; }

  bool isGR32orGR64() const {
    return Kind == Register &&
      (X86MCRegisterClasses[X86::GR32RegClassID].contains(getReg()) ||
       X86MCRegisterClasses[X86::GR64RegClassID].contains(getReg()));
  }

  bool isGR16orGR32orGR64() const {
    return Kind == Register &&
      (X86MCRegisterClasses[X86::GR16RegClassID].contains(getReg()) ||
       X86MCRegisterClasses[X86::GR32RegClassID].contains(getReg()) ||
       X86MCRegisterClasses[X86::GR64RegClassID].contains(getReg()));
  }

  bool isVectorReg() const {
    return Kind == Register &&
           (X86MCRegisterClasses[X86::VR64RegClassID].contains(getReg()) ||
            X86MCRegisterClasses[X86::VR128XRegClassID].contains(getReg()) ||
            X86MCRegisterClasses[X86::VR256XRegClassID].contains(getReg()) ||
            X86MCRegisterClasses[X86::VR512RegClassID].contains(getReg()));
  }

  bool isVK1Pair() const {
    return Kind == Register &&
      X86MCRegisterClasses[X86::VK1RegClassID].contains(getReg());
  }

  bool isVK2Pair() const {
    return Kind == Register &&
      X86MCRegisterClasses[X86::VK2RegClassID].contains(getReg());
  }

  bool isVK4Pair() const {
    return Kind == Register &&
      X86MCRegisterClasses[X86::VK4RegClassID].contains(getReg());
  }

  bool isVK8Pair() const {
    return Kind == Register &&
      X86MCRegisterClasses[X86::VK8RegClassID].contains(getReg());
  }

  bool isVK16Pair() const {
    return Kind == Register &&
      X86MCRegisterClasses[X86::VK16RegClassID].contains(getReg());
  }

  void addExpr(MCInst &Inst, const MCExpr *Expr) const {
    // Add as immediates when possible.
    if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr))
      Inst.addOperand(MCOperand::createImm(CE->getValue()));
    else
      Inst.addOperand(MCOperand::createExpr(Expr));
  }

  void addRegOperands(MCInst &Inst, unsigned N) const {
    assert(N == 1 && "Invalid number of operands!");
    Inst.addOperand(MCOperand::createReg(getReg()));
  }

  void addGR32orGR64Operands(MCInst &Inst, unsigned N) const {
    assert(N == 1 && "Invalid number of operands!");
    MCRegister RegNo = getReg();
    if (X86MCRegisterClasses[X86::GR64RegClassID].contains(RegNo))
      RegNo = getX86SubSuperRegister(RegNo, 32);
    Inst.addOperand(MCOperand::createReg(RegNo));
  }

  void addGR16orGR32orGR64Operands(MCInst &Inst, unsigned N) const {
    assert(N == 1 && "Invalid number of operands!");
    MCRegister RegNo = getReg();
    if (X86MCRegisterClasses[X86::GR32RegClassID].contains(RegNo) ||
        X86MCRegisterClasses[X86::GR64RegClassID].contains(RegNo))
      RegNo = getX86SubSuperRegister(RegNo, 16);
    Inst.addOperand(MCOperand::createReg(RegNo));
  }

  void addAVX512RCOperands(MCInst &Inst, unsigned N) const {
    assert(N == 1 && "Invalid number of operands!");
    addExpr(Inst, getImm());
  }

  void addImmOperands(MCInst &Inst, unsigned N) const {
    assert(N == 1 && "Invalid number of operands!");
    addExpr(Inst, getImm());
  }

  void addMaskPairOperands(MCInst &Inst, unsigned N) const {
    assert(N == 1 && "Invalid number of operands!");
    MCRegister Reg = getReg();
    switch (Reg.id()) {
    case X86::K0:
    case X86::K1:
      Reg = X86::K0_K1;
      break;
    case X86::K2:
    case X86::K3:
      Reg = X86::K2_K3;
      break;
    case X86::K4:
    case X86::K5:
      Reg = X86::K4_K5;
      break;
    case X86::K6:
    case X86::K7:
      Reg = X86::K6_K7;
      break;
    }
    Inst.addOperand(MCOperand::createReg(Reg));
  }

  bool isTILEPair() const {
    return Kind == Register &&
           X86MCRegisterClasses[X86::TILERegClassID].contains(getReg());
  }

  void addTILEPairOperands(MCInst &Inst, unsigned N) const {
    assert(N == 1 && "Invalid number of operands!");
    unsigned Reg = getReg();
    switch (Reg) {
    default:
      llvm_unreachable("Invalid tile register!");
    case X86::TMM0:
    case X86::TMM1:
      Reg = X86::TMM0_TMM1;
      break;
    case X86::TMM2:
    case X86::TMM3:
      Reg = X86::TMM2_TMM3;
      break;
    case X86::TMM4:
    case X86::TMM5:
      Reg = X86::TMM4_TMM5;
      break;
    case X86::TMM6:
    case X86::TMM7:
      Reg = X86::TMM6_TMM7;
      break;
    }
    Inst.addOperand(MCOperand::createReg(Reg));
  }

  void addMemOperands(MCInst &Inst, unsigned N) const {
    assert((N == 5) && "Invalid number of operands!");
    if (getMemBaseReg())
      Inst.addOperand(MCOperand::createReg(getMemBaseReg()));
    else
      Inst.addOperand(MCOperand::createReg(getMemDefaultBaseReg()));
    Inst.addOperand(MCOperand::createImm(getMemScale()));
    Inst.addOperand(MCOperand::createReg(getMemIndexReg()));
    addExpr(Inst, getMemDisp());
    Inst.addOperand(MCOperand::createReg(getMemSegReg()));
  }

  void addAbsMemOperands(MCInst &Inst, unsigned N) const {
    assert((N == 1) && "Invalid number of operands!");
    // Add as immediates when possible.
    if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getMemDisp()))
      Inst.addOperand(MCOperand::createImm(CE->getValue()));
    else
      Inst.addOperand(MCOperand::createExpr(getMemDisp()));
  }

  void addSrcIdxOperands(MCInst &Inst, unsigned N) const {
    assert((N == 2) && "Invalid number of operands!");
    Inst.addOperand(MCOperand::createReg(getMemBaseReg()));
    Inst.addOperand(MCOperand::createReg(getMemSegReg()));
  }

  void addDstIdxOperands(MCInst &Inst, unsigned N) const {
    assert((N == 1) && "Invalid number of operands!");
    Inst.addOperand(MCOperand::createReg(getMemBaseReg()));
  }

  void addMemOffsOperands(MCInst &Inst, unsigned N) const {
    assert((N == 2) && "Invalid number of operands!");
    // Add as immediates when possible.
    if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getMemDisp()))
      Inst.addOperand(MCOperand::createImm(CE->getValue()));
    else
      Inst.addOperand(MCOperand::createExpr(getMemDisp()));
    Inst.addOperand(MCOperand::createReg(getMemSegReg()));
  }

  static std::unique_ptr<X86Operand> CreateToken(StringRef Str, SMLoc Loc) {
    SMLoc EndLoc = SMLoc::getFromPointer(Loc.getPointer() + Str.size());
    auto Res = std::make_unique<X86Operand>(Token, Loc, EndLoc);
    Res->Tok.Data = Str.data();
    Res->Tok.Length = Str.size();
    return Res;
  }

  static std::unique_ptr<X86Operand>
  CreateReg(MCRegister Reg, SMLoc StartLoc, SMLoc EndLoc,
            bool AddressOf = false, SMLoc OffsetOfLoc = SMLoc(),
            StringRef SymName = StringRef(), void *OpDecl = nullptr) {
    auto Res = std::make_unique<X86Operand>(Register, StartLoc, EndLoc);
    Res->Reg.RegNo = Reg;
    Res->AddressOf = AddressOf;
    Res->OffsetOfLoc = OffsetOfLoc;
    Res->SymName = SymName;
    Res->OpDecl = OpDecl;
    return Res;
  }

  static std::unique_ptr<X86Operand>
  CreateDXReg(SMLoc StartLoc, SMLoc EndLoc) {
    return std::make_unique<X86Operand>(DXRegister, StartLoc, EndLoc);
  }

  static std::unique_ptr<X86Operand>
  CreatePrefix(unsigned Prefixes, SMLoc StartLoc, SMLoc EndLoc) {
    auto Res = std::make_unique<X86Operand>(Prefix, StartLoc, EndLoc);
    Res->Pref.Prefixes = Prefixes;
    return Res;
  }

  static std::unique_ptr<X86Operand> CreateImm(const MCExpr *Val,
                                               SMLoc StartLoc, SMLoc EndLoc,
                                               StringRef SymName = StringRef(),
                                               void *OpDecl = nullptr,
                                               bool GlobalRef = true) {
    auto Res = std::make_unique<X86Operand>(Immediate, StartLoc, EndLoc);
    Res->Imm.Val      = Val;
    Res->Imm.LocalRef = !GlobalRef;
    Res->SymName      = SymName;
    Res->OpDecl       = OpDecl;
    Res->AddressOf    = true;
    return Res;
  }

  /// Create an absolute memory operand.
  static std::unique_ptr<X86Operand>
  CreateMem(unsigned ModeSize, const MCExpr *Disp, SMLoc StartLoc, SMLoc EndLoc,
            unsigned Size = 0, StringRef SymName = StringRef(),
            void *OpDecl = nullptr, unsigned FrontendSize = 0,
            bool UseUpRegs = false, bool MaybeDirectBranchDest = true) {
    auto Res = std::make_unique<X86Operand>(Memory, StartLoc, EndLoc);
    Res->Mem.SegReg = MCRegister();
    Res->Mem.Disp     = Disp;
    Res->Mem.BaseReg = MCRegister();
    Res->Mem.DefaultBaseReg = MCRegister();
    Res->Mem.IndexReg = MCRegister();
    Res->Mem.Scale    = 1;
    Res->Mem.Size     = Size;
    Res->Mem.ModeSize = ModeSize;
    Res->Mem.FrontendSize = FrontendSize;
    Res->Mem.MaybeDirectBranchDest = MaybeDirectBranchDest;
    Res->UseUpRegs = UseUpRegs;
    Res->SymName      = SymName;
    Res->OpDecl       = OpDecl;
    Res->AddressOf    = false;
    return Res;
  }

  /// Create a generalized memory operand.
  static std::unique_ptr<X86Operand>
  CreateMem(unsigned ModeSize, MCRegister SegReg, const MCExpr *Disp,
            MCRegister BaseReg, MCRegister IndexReg, unsigned Scale,
            SMLoc StartLoc, SMLoc EndLoc, unsigned Size = 0,
            MCRegister DefaultBaseReg = MCRegister(),
            StringRef SymName = StringRef(), void *OpDecl = nullptr,
            unsigned FrontendSize = 0, bool UseUpRegs = false,
            bool MaybeDirectBranchDest = true) {
    // We should never just have a displacement, that should be parsed as an
    // absolute memory operand.
    assert((SegReg || BaseReg || IndexReg || DefaultBaseReg) &&
           "Invalid memory operand!");

    // The scale should always be one of {1,2,4,8}.
    assert(((Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8)) &&
           "Invalid scale!");
    auto Res = std::make_unique<X86Operand>(Memory, StartLoc, EndLoc);
    Res->Mem.SegReg   = SegReg;
    Res->Mem.Disp     = Disp;
    Res->Mem.BaseReg  = BaseReg;
    Res->Mem.DefaultBaseReg = DefaultBaseReg;
    Res->Mem.IndexReg = IndexReg;
    Res->Mem.Scale    = Scale;
    Res->Mem.Size     = Size;
    Res->Mem.ModeSize = ModeSize;
    Res->Mem.FrontendSize = FrontendSize;
    Res->Mem.MaybeDirectBranchDest = MaybeDirectBranchDest;
    Res->UseUpRegs = UseUpRegs;
    Res->SymName      = SymName;
    Res->OpDecl       = OpDecl;
    Res->AddressOf    = false;
    return Res;
  }
};

} // end namespace llvm

#endif // LLVM_LIB_TARGET_X86_ASMPARSER_X86OPERAND_H
