diff --git a/llvm/include/llvm/MC/MCParser/MCAsmParser.h b/llvm/include/llvm/MC/MCParser/MCAsmParser.h --- a/llvm/include/llvm/MC/MCParser/MCAsmParser.h +++ b/llvm/include/llvm/MC/MCParser/MCAsmParser.h @@ -201,6 +201,10 @@ return true; } + virtual bool lookUpData(StringRef name, AsmTypeInfo &Info) const { + return true; + } + /// Parse MS-style inline assembly. virtual bool parseMSInlineAsm( std::string &AsmString, unsigned &NumOutputs, unsigned &NumInputs, diff --git a/llvm/lib/MC/MCParser/MasmParser.cpp b/llvm/lib/MC/MCParser/MasmParser.cpp --- a/llvm/lib/MC/MCParser/MasmParser.cpp +++ b/llvm/lib/MC/MCParser/MasmParser.cpp @@ -517,6 +517,8 @@ bool lookUpType(StringRef Name, AsmTypeInfo &Info) const override; + bool lookUpData(StringRef name, AsmTypeInfo &Info) const override; + bool parseMSInlineAsm(std::string &AsmString, unsigned &NumOutputs, unsigned &NumInputs, SmallVectorImpl> &OpDecls, @@ -7375,6 +7377,15 @@ return true; } +bool MasmParser::lookUpData(StringRef Name, AsmTypeInfo &Info) const { + auto it = KnownType.find(Name.lower()); + if (it != KnownType.end()) { + Info = it->second; + return false; + } + return true; +} + bool MasmParser::parseMSInlineAsm( std::string &AsmString, unsigned &NumOutputs, unsigned &NumInputs, SmallVectorImpl> &OpDecls, diff --git a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp --- a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -1107,9 +1107,9 @@ std::unique_ptr &&Dst); bool VerifyAndAdjustOperands(OperandVector &OrigOperands, OperandVector &FinalOperands); - bool ParseOperand(OperandVector &Operands); + bool ParseOperand(OperandVector &Operands, StringRef Name); bool ParseATTOperand(OperandVector &Operands); - bool ParseIntelOperand(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); @@ -1736,9 +1736,9 @@ 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); } @@ -2513,7 +2513,7 @@ 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; @@ -2635,21 +2635,48 @@ // 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 || IsUnconditionalBranch)) { + DefaultBaseReg = X86::RIP; + } + if (IsUnconditionalBranch) { + if (PtrInOperand) { + MaybeDirectBranchDest = false; + } else if (!BaseReg && !IndexReg && Disp && + Disp->getKind() == MCExpr::SymbolRef) { + const auto *SRE = cast(Disp); + AsmTypeInfo ATI; + StringRef DispName = SRE->getSymbol().getName(); + if (!Parser.lookUpData(DispName, ATI)) { + StringRef TypeName = ATI.Name; + if (is64BitMode()) { + if (TypeName.equals_insensitive("QWORD")) + MaybeDirectBranchDest = false; + } else { + if (TypeName.equals_insensitive("DWORD") || + TypeName.equals_insensitive("WORD")) + 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; } @@ -3409,7 +3436,7 @@ // Read the operands. while (true) { - if (ParseOperand(Operands)) + if (ParseOperand(Operands, Name)) return true; if (HandleAVX512Operand(Operands)) return true; @@ -4689,9 +4716,9 @@ // operation. There shouldn't be any ambiguity in our mnemonic table, so try // matching with the unsized operand. if (Match.empty()) { - Match.push_back(MatchInstruction( - Operands, Inst, ErrorInfo, MissingFeatures, MatchingInlineAsm, - isParsingIntelSyntax())); + unsigned MI = MatchInstruction(Operands, Inst, ErrorInfo, MissingFeatures, + MatchingInlineAsm, isParsingIntelSyntax()); + Match.push_back(MI); // If this returned as a missing feature failure, remember that. if (Match.back() == Match_MissingFeature) ErrorInfoMissingFeatures = MissingFeatures; diff --git a/llvm/lib/Target/X86/AsmParser/X86Operand.h b/llvm/lib/Target/X86/AsmParser/X86Operand.h --- a/llvm/lib/Target/X86/AsmParser/X86Operand.h +++ b/llvm/lib/Target/X86/AsmParser/X86Operand.h @@ -72,6 +72,8 @@ /// If the memory operand is unsized and there are multiple instruction /// matches, prefer the one with this size. unsigned FrontendSize; + + bool MaybeDirectBranchDest; }; union { @@ -209,6 +211,10 @@ 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; } @@ -374,8 +380,9 @@ bool isAbsMem() const { return Kind == Memory && !getMemSegReg() && !getMemBaseReg() && - !getMemIndexReg() && getMemScale() == 1; + !getMemIndexReg() && getMemScale() == 1 && isMaybeDirectBranchDest(); } + bool isAVX512RC() const{ return isImm(); } @@ -672,7 +679,7 @@ 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(Memory, StartLoc, EndLoc); Res->Mem.SegReg = 0; Res->Mem.Disp = Disp; @@ -683,6 +690,7 @@ 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; @@ -697,7 +705,8 @@ 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) && @@ -716,6 +725,7 @@ 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; diff --git a/llvm/test/tools/llvm-ml/unconditional_branch_x64.asm b/llvm/test/tools/llvm-ml/unconditional_branch_x64.asm new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-ml/unconditional_branch_x64.asm @@ -0,0 +1,69 @@ +; RUN: llvm-ml -m64 -filetype=s %s /Fo - | FileCheck %s + +.data + +fn_ref QWORD 28 +fn PROC + +t0: +call fn_ref +jmp fn_ref +; CHECK-LABEL: t0 +; CHECK: call qword ptr [rip + fn_ref] +; CHECK: jmp qword ptr [rip + fn_ref] + +t1: +call [fn_ref] +jmp [fn_ref] +; CHECK-LABEL: t1 +; CHECK: call qword ptr [rip + fn_ref] +; CHECK: jmp qword ptr [rip + fn_ref] + +t2: +call qword ptr [fn_ref] +jmp qword ptr [fn_ref] +; CHECK-LABEL: t2 +; CHECK: call qword ptr [rip + fn_ref] +; CHECK: jmp qword ptr [rip + fn_ref] + +t3: +call t3 +jmp t3 +; CHECK-LABEL: t3 +; CHECK: call t3 +; CHECK: jmp t3 + +t4: +call [t4] +jmp [t4] +; CHECK-LABEL: t4 +; CHECK: call t4 +; CHECK: jmp t4 + +t5: +call qword ptr [t5] +jmp qword ptr [t5] +; CHECK-LABEL: t5 +; CHECK: call qword ptr [rip + t5] +; CHECK: jmp qword ptr [rip + t5] + +t6: +call fn +jmp fn +; CHECK-LABEL: t6 +; CHECK: call fn +; CHECK: jmp fn + +t7: +call [fn] +jmp [fn] +; CHECK-LABEL: t7 +; CHECK: call fn +; CHECK: jmp fn + +t8: +call qword ptr [fn] +jmp qword ptr [fn] +; CHECK-LABEL: t8 +; CHECK: call qword ptr [rip + fn] +; CHECK: jmp qword ptr [rip + fn] \ No newline at end of file diff --git a/llvm/test/tools/llvm-ml/unconditional_branch_x86.asm b/llvm/test/tools/llvm-ml/unconditional_branch_x86.asm new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-ml/unconditional_branch_x86.asm @@ -0,0 +1,69 @@ +; RUN: llvm-ml -m32 -filetype=s %s /Fo - | FileCheck %s + +.data + +fn_ref DWORD 28 +fn PROC + +t0: +call fn_ref +jmp fn_ref +; CHECK-LABEL: t0 +; CHECK: call dword ptr [fn_ref] +; CHECK: jmp dword ptr [fn_ref] + +t1: +call [fn_ref] +jmp [fn_ref] +; CHECK-LABEL: t1 +; CHECK: call dword ptr [fn_ref] +; CHECK: jmp dword ptr [fn_ref] + +t2: +call dword ptr [fn_ref] +jmp dword ptr [fn_ref] +; CHECK-LABEL: t2 +; CHECK: call dword ptr [fn_ref] +; CHECK: jmp dword ptr [fn_ref] + +t3: +call t3 +jmp t3 +; CHECK-LABEL: t3 +; CHECK: call t3 +; CHECK: jmp t3 + +t4: +call [t4] +jmp [t4] +; CHECK-LABEL: t4 +; CHECK: call t4 +; CHECK: jmp t4 + +t5: +call dword ptr [t5] +jmp dword ptr [t5] +; CHECK-LABEL: t5 +; CHECK: call dword ptr [t5] +; CHECK: jmp dword ptr [t5] + +t6: +call fn +jmp fn +; CHECK-LABEL: t6 +; CHECK: call fn +; CHECK: jmp fn + +t7: +call [fn] +jmp [fn] +; CHECK-LABEL: t7 +; CHECK: call fn +; CHECK: jmp fn + +t8: +call dword ptr [fn] +jmp dword ptr [fn] +; CHECK-LABEL: t8 +; CHECK: call dword ptr [fn] +; CHECK: jmp dword ptr [fn] \ No newline at end of file