| //===- 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/Support/Casting.h" | |
| #include "llvm/Support/ErrorHandling.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; | |
| bool CallOperand; | |
| struct TokOp { | |
| const char *Data; | |
| unsigned Length; | |
| }; | |
| struct RegOp { | |
| unsigned RegNo; | |
| }; | |
| struct PrefOp { | |
| unsigned Prefixes; | |
| }; | |
| struct ImmOp { | |
| const MCExpr *Val; | |
| bool LocalRef; | |
| }; | |
| struct MemOp { | |
| unsigned SegReg; | |
| const MCExpr *Disp; | |
| unsigned BaseReg; | |
| unsigned 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; | |
| }; | |
| 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), CallOperand(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(); | |
| } | |
| unsigned 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; | |
| } | |
| unsigned getMemSegReg() const { | |
| assert(Kind == Memory && "Invalid access!"); | |
| return Mem.SegReg; | |
| } | |
| unsigned getMemBaseReg() const { | |
| assert(Kind == Memory && "Invalid access!"); | |
| return Mem.BaseReg; | |
| } | |
| unsigned 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 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 isMemIndexReg(unsigned LowR, unsigned HighR) const { | |
| assert(Kind == Memory && "Invalid access!"); | |
| return Mem.IndexReg >= LowR && Mem.IndexReg <= HighR; | |
| } | |
| bool isMem64_RC128() const { | |
| return isMem64() && isMemIndexReg(X86::XMM0, X86::XMM15); | |
| } | |
| bool isMem128_RC128() const { | |
| return isMem128() && isMemIndexReg(X86::XMM0, X86::XMM15); | |
| } | |
| bool isMem128_RC256() const { | |
| return isMem128() && isMemIndexReg(X86::YMM0, X86::YMM15); | |
| } | |
| bool isMem256_RC128() const { | |
| return isMem256() && isMemIndexReg(X86::XMM0, X86::XMM15); | |
| } | |
| bool isMem256_RC256() const { | |
| return isMem256() && isMemIndexReg(X86::YMM0, X86::YMM15); | |
| } | |
| bool isMem64_RC128X() const { | |
| return isMem64() && isMemIndexReg(X86::XMM0, X86::XMM31); | |
| } | |
| bool isMem128_RC128X() const { | |
| return isMem128() && isMemIndexReg(X86::XMM0, X86::XMM31); | |
| } | |
| bool isMem128_RC256X() const { | |
| return isMem128() && isMemIndexReg(X86::YMM0, X86::YMM31); | |
| } | |
| bool isMem256_RC128X() const { | |
| return isMem256() && isMemIndexReg(X86::XMM0, X86::XMM31); | |
| } | |
| bool isMem256_RC256X() const { | |
| return isMem256() && isMemIndexReg(X86::YMM0, X86::YMM31); | |
| } | |
| bool isMem256_RC512() const { | |
| return isMem256() && isMemIndexReg(X86::ZMM0, X86::ZMM31); | |
| } | |
| bool isMem512_RC256X() const { | |
| return isMem512() && isMemIndexReg(X86::YMM0, X86::YMM31); | |
| } | |
| bool isMem512_RC512() const { | |
| return isMem512() && isMemIndexReg(X86::ZMM0, X86::ZMM31); | |
| } | |
| bool isAbsMem() const { | |
| return Kind == Memory && !getMemSegReg() && !getMemBaseReg() && | |
| !getMemIndexReg() && getMemScale() == 1; | |
| } | |
| bool isAVX512RC() const{ | |
| return isImm(); | |
| } | |
| bool isAbsMem16() const { | |
| return isAbsMem() && Mem.ModeSize == 16; | |
| } | |
| 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() == 0 || 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 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 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!"); | |
| unsigned Reg = getReg(); | |
| switch (Reg) { | |
| 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)); | |
| } | |
| void addMemOperands(MCInst &Inst, unsigned N) const { | |
| assert((N == 5) && "Invalid number of operands!"); | |
| Inst.addOperand(MCOperand::createReg(getMemBaseReg())); | |
| 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(unsigned RegNo, 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 = RegNo; | |
| 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) { | |
| auto Res = std::make_unique<X86Operand>(Memory, StartLoc, EndLoc); | |
| Res->Mem.SegReg = 0; | |
| Res->Mem.Disp = Disp; | |
| Res->Mem.BaseReg = 0; | |
| Res->Mem.IndexReg = 0; | |
| Res->Mem.Scale = 1; | |
| Res->Mem.Size = Size; | |
| Res->Mem.ModeSize = ModeSize; | |
| Res->Mem.FrontendSize = FrontendSize; | |
| Res->SymName = SymName; | |
| Res->OpDecl = OpDecl; | |
| Res->AddressOf = false; | |
| return Res; | |
| } | |
| /// Create a generalized memory operand. | |
| static std::unique_ptr<X86Operand> | |
| CreateMem(unsigned ModeSize, unsigned SegReg, const MCExpr *Disp, | |
| unsigned BaseReg, unsigned IndexReg, unsigned Scale, SMLoc StartLoc, | |
| SMLoc EndLoc, unsigned Size = 0, StringRef SymName = StringRef(), | |
| void *OpDecl = nullptr, unsigned FrontendSize = 0) { | |
| // We should never just have a displacement, that should be parsed as an | |
| // absolute memory operand. | |
| assert((SegReg || BaseReg || IndexReg) && "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.IndexReg = IndexReg; | |
| Res->Mem.Scale = Scale; | |
| Res->Mem.Size = Size; | |
| Res->Mem.ModeSize = ModeSize; | |
| Res->Mem.FrontendSize = FrontendSize; | |
| Res->SymName = SymName; | |
| Res->OpDecl = OpDecl; | |
| Res->AddressOf = false; | |
| return Res; | |
| } | |
| }; | |
| } // end namespace llvm | |
| #endif // LLVM_LIB_TARGET_X86_ASMPARSER_X86OPERAND_H |