std::unique_ptr<llvm::MCParsedAsmOperand> &&Dst);
bool VerifyAndAdjustOperands(OperandVector &OrigOperands,
OperandVector &FinalOperands);
- bool ParseOperand(OperandVector &Operands);
- bool ParseATTOperand(OperandVector &Operands);
- bool ParseIntelOperand(OperandVector &Operands);
+ bool parseOperand(OperandVector &Operands, StringRef Name);
+ bool parseATTOperand(OperandVector &Operands);
+ bool parseIntelOperand(OperandVector &Operands, StringRef Name);
bool ParseIntelOffsetOperator(const MCExpr *&Val, StringRef &ID,
InlineAsmIdentifierInfo &Info, SMLoc &End);
bool ParseIntelDotOperator(IntelExprStateMachine &SM, SMLoc &End);
return false;
}
-bool X86AsmParser::ParseOperand(OperandVector &Operands) {
+bool X86AsmParser::parseOperand(OperandVector &Operands, StringRef Name) {
if (isParsingIntelSyntax())
- return ParseIntelOperand(Operands);
+ return parseIntelOperand(Operands, Name);
- return ParseATTOperand(Operands);
+ return parseATTOperand(Operands);
}
bool X86AsmParser::CreateMemForMSInlineAsm(
return false;
}
-bool X86AsmParser::ParseIntelOperand(OperandVector &Operands) {
+bool X86AsmParser::parseIntelOperand(OperandVector &Operands, StringRef Name) {
MCAsmParser &Parser = getParser();
const AsmToken &Tok = Parser.getTok();
SMLoc Start, End;
// When parsing x64 MS-style assembly, all non-absolute references to a named
// variable default to RIP-relative.
- if (Parser.isParsingMasm() && is64BitMode() && SM.getElementSize() > 0) {
- Operands.push_back(X86Operand::CreateMem(getPointerWidth(), RegNo, Disp,
- BaseReg, IndexReg, Scale, Start,
- End, Size,
- /*DefaultBaseReg=*/X86::RIP));
- return false;
+ unsigned DefaultBaseReg = X86::NoRegister;
+ bool MaybeDirectBranchDest = true;
+
+ if (Parser.isParsingMasm()) {
+ bool IsUnconditionalBranch =
+ Name.equals_insensitive("jmp") || Name.equals_insensitive("call");
+ if (is64BitMode() && SM.getElementSize() > 0) {
+ DefaultBaseReg = X86::RIP;
+ }
+ if (IsUnconditionalBranch) {
+ if (PtrInOperand) {
+ MaybeDirectBranchDest = false;
+ if (is64BitMode())
+ DefaultBaseReg = X86::RIP;
+ } else if (!BaseReg && !IndexReg && Disp &&
+ Disp->getKind() == MCExpr::SymbolRef) {
+ if (is64BitMode()) {
+ if (SM.getSize() == 8) {
+ MaybeDirectBranchDest = false;
+ DefaultBaseReg = X86::RIP;
+ }
+ } else {
+ if (SM.getSize() == 4 || SM.getSize() == 2)
+ MaybeDirectBranchDest = false;
+ }
+ }
+ }
}
- if ((BaseReg || IndexReg || RegNo))
- Operands.push_back(X86Operand::CreateMem(getPointerWidth(), RegNo, Disp,
- BaseReg, IndexReg, Scale, Start,
- End, Size));
+ if ((BaseReg || IndexReg || RegNo || DefaultBaseReg != X86::NoRegister))
+ Operands.push_back(X86Operand::CreateMem(
+ getPointerWidth(), RegNo, Disp, BaseReg, IndexReg, Scale, Start, End,
+ Size, DefaultBaseReg, /*SymName=*/StringRef(), /*OpDecl=*/nullptr,
+ /*FrontendSize=*/0, /*UseUpRegs=*/false, MaybeDirectBranchDest));
else
- Operands.push_back(
- X86Operand::CreateMem(getPointerWidth(), Disp, Start, End, Size));
+ Operands.push_back(X86Operand::CreateMem(
+ getPointerWidth(), Disp, Start, End, Size, /*SymName=*/StringRef(),
+ /*OpDecl=*/nullptr, /*FrontendSize=*/0, /*UseUpRegs=*/false,
+ MaybeDirectBranchDest));
return false;
}
-bool X86AsmParser::ParseATTOperand(OperandVector &Operands) {
+bool X86AsmParser::parseATTOperand(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
switch (getLexer().getKind()) {
case AsmToken::Dollar: {
// Read the operands.
while (true) {
- if (ParseOperand(Operands))
+ if (parseOperand(Operands, Name))
return true;
if (HandleAVX512Operand(Operands))
return true;
/// 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 {
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 isAbsMem() const {
return Kind == Memory && !getMemSegReg() && !getMemBaseReg() &&
- !getMemIndexReg() && getMemScale() == 1;
+ !getMemIndexReg() && getMemScale() == 1 && isMaybeDirectBranchDest();
}
+
bool isAVX512RC() const{
return isImm();
}
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 UseUpRegs = false, bool MaybeDirectBranchDest = true) {
auto Res = std::make_unique<X86Operand>(Memory, StartLoc, EndLoc);
Res->Mem.SegReg = 0;
Res->Mem.Disp = Disp;
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;
SMLoc EndLoc, unsigned Size = 0,
unsigned DefaultBaseReg = X86::NoRegister,
StringRef SymName = StringRef(), void *OpDecl = nullptr,
- unsigned FrontendSize = 0, bool UseUpRegs = false) {
+ 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) &&
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;
--- /dev/null
+; RUN: llvm-ml -m64 -filetype=s %s /Fo - | FileCheck %s --check-prefixes=CHECK-64,CHECK
+; RUN: llvm-ml -m32 -filetype=s %s /Fo - | FileCheck %s --check-prefixes=CHECK-32,CHECK
+
+.data
+
+ifdef rax
+ fn_ref qword 1
+else
+ fn_ref dword 1
+endif
+
+fn_ref_word word 2
+fn PROC
+
+BranchTargetStruc struc
+ member0 dword ?
+ ifdef rax
+ member1 dword ?
+ endif
+BranchTargetStruc ends
+
+
+ifdef rax
+ fn_ref_struc BranchTargetStruc {3, 3}
+else
+ fn_ref_struc BranchTargetStruc {3}
+endif
+
+.code
+
+t0:
+call fn_ref
+jmp fn_ref
+; CHECK-LABEL: t0:
+; CHECK-64: call qword ptr [rip + fn_ref]
+; CHECK-64: jmp qword ptr [rip + fn_ref]
+; CHECK-32: call dword ptr [fn_ref]
+; CHECK-32: jmp dword ptr [fn_ref]
+
+t1:
+call [fn_ref]
+jmp [fn_ref]
+; CHECK-LABEL: t1:
+; CHECK-64: call qword ptr [rip + fn_ref]
+; CHECK-64: jmp qword ptr [rip + fn_ref]
+; CHECK-32: call dword ptr [fn_ref]
+; CHECK-32: jmp dword ptr [fn_ref]
+
+ifdef rax
+ t2:
+ call qword ptr [fn_ref]
+ jmp qword ptr [fn_ref]
+ ; CHECK-64-LABEL: t2:
+ ; CHECK-64: call qword ptr [rip + fn_ref]
+ ; CHECK-64: jmp qword ptr [rip + fn_ref]
+else
+ t2:
+ call dword ptr [fn_ref]
+ jmp dword ptr [fn_ref]
+ ; CHECK-32-LABEL: t2:
+ ; CHECK-32: call dword ptr [fn_ref]
+ ; CHECK-32: jmp dword ptr [fn_ref]
+
+ t3:
+ call fn_ref_word
+ jmp fn_ref_word
+ ; CHECK-32-LABEL: t3:
+ ; CHECK-32: call word ptr [fn_ref_word]
+ ; CHECK-32-NEXT: jmp word ptr [fn_ref_word]
+
+ t4:
+ call [fn_ref_word]
+ jmp [fn_ref_word]
+ ; CHECK-32-LABEL: t4:
+ ; CHECK-32: call word ptr [fn_ref_word]
+ ; CHECK-32-NEXT: jmp word ptr [fn_ref_word]
+
+ t5:
+ call word ptr [fn_ref_word]
+ jmp word ptr [fn_ref_word]
+ ; CHECK-32-LABEL: t5:
+ ; CHECK-32: call word ptr [fn_ref_word]
+ ; CHECK-32-NEXT: jmp word ptr [fn_ref_word]
+endif
+
+t6:
+call t6
+jmp t6
+; CHECK-LABEL: t6:
+; CHECK: call t6
+; CHECK-NEXT: jmp t6
+
+t7:
+call [t7]
+jmp [t7]
+; CHECK-LABEL: t7:
+; CHECK: call t7
+; CHECK-NEXT: jmp t7
+
+ifdef rax
+ t8:
+ call qword ptr [t8]
+ jmp qword ptr [t8]
+ ; CHECK-64-LABEL: t8:
+ ; CHECK-64: call qword ptr [rip + t8]
+ ; CHECK-64-NEXT: jmp qword ptr [rip + t8]
+else
+ t8:
+ call dword ptr [t8]
+ jmp dword ptr [t8]
+ ; CHECK-32-LABEL: t8:
+ ; CHECK-32: call dword ptr [t8]
+ ; CHECK-32-NEXT: jmp dword ptr [t8]
+endif
+
+t9:
+call fn
+jmp fn
+; CHECK-LABEL: t9:
+; CHECK: call fn
+; CHECK-NEXT: jmp fn
+
+t10:
+call [fn]
+jmp [fn]
+; CHECK-LABEL: t10:
+; CHECK: call fn
+; CHECK-NEXT: jmp fn
+
+ifdef rax
+ t11:
+ call qword ptr [fn]
+ jmp qword ptr [fn]
+ ; CHECK-64-LABEL: t11:
+ ; CHECK-64: call qword ptr [rip + fn]
+ ; CHECK-64-NEXT: jmp qword ptr [rip + fn]
+else
+ t11:
+ call dword ptr [fn]
+ jmp dword ptr [fn]
+ ; CHECK-32-LABEL: t11:
+ ; CHECK-32: call dword ptr [fn]
+ ; CHECK-32-NEXT: jmp dword ptr [fn]
+endif
+
+t12:
+call fn_ref_struc
+jmp fn_ref_struc
+; CHECK-LABEL: t12:
+; CHECK-64: call qword ptr [rip + fn_ref_struc]
+; CHECK-64: jmp qword ptr [rip + fn_ref_struc]
+; CHECK-32: call dword ptr [fn_ref_struc]
+; CHECK-32: jmp dword ptr [fn_ref_struc]
+
+t13:
+call [fn_ref_struc]
+jmp [fn_ref_struc]
+; CHECK-LABEL: t13:
+; CHECK-64: call qword ptr [rip + fn_ref_struc]
+; CHECK-64: jmp qword ptr [rip + fn_ref_struc]
+; CHECK-32: call dword ptr [fn_ref_struc]
+; CHECK-32: jmp dword ptr [fn_ref_struc]
+
+ifdef rax
+ t14:
+ call qword ptr [fn_ref_struc]
+ jmp qword ptr [fn_ref_struc]
+ ; CHECK-64-LABEL: t14:
+ ; CHECK-64: call qword ptr [rip + fn_ref_struc]
+ ; CHECK-64: jmp qword ptr [rip + fn_ref_struc]
+else
+ t14:
+ call dword ptr [fn_ref_struc]
+ jmp dword ptr [fn_ref_struc]
+ ; CHECK-32-LABEL: t14:
+ ; CHECK-32: call dword ptr [fn_ref_struc]
+ ; CHECK-32: jmp dword ptr [fn_ref_struc]
+endif
+
+t15:
+je t15
+; CHECK-LABEL: t15:
+; CHECK: je t15
+
+t16:
+je [t16];
+; CHECK-LABEL: t16:
+; CHECK: je t16