diff --git a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp index d7671ed19589b..ce5e92135f706 100644 --- a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -15,10 +15,12 @@ #include "MCTargetDesc/X86TargetStreamer.h" #include "TargetInfo/X86TargetInfo.h" #include "X86Operand.h" +#include "X86RegisterInfo.h" #include "llvm-c/Visibility.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "llvm/MC/MCContext.h" @@ -29,6 +31,7 @@ #include "llvm/MC/MCParser/MCAsmParser.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" #include "llvm/MC/MCParser/MCTargetAsmParser.h" +#include "llvm/MC/MCRegister.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCStreamer.h" @@ -40,6 +43,7 @@ #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" #include +#include #include using namespace llvm; @@ -1172,7 +1176,7 @@ class X86AsmParser : public MCTargetAsmParser { X86::CondCode ParseConditionCode(StringRef CCode); - bool ParseIntelMemoryOperandSize(unsigned &Size); + bool ParseIntelMemoryOperandSize(unsigned &Size, StringRef *SizeStr); bool CreateMemForMSInlineAsm(MCRegister SegReg, const MCExpr *Disp, MCRegister BaseReg, MCRegister IndexReg, unsigned Scale, bool NonAbsMem, SMLoc Start, @@ -2574,7 +2578,8 @@ bool X86AsmParser::ParseMasmOperator(unsigned OpKind, int64_t &Val) { return false; } -bool X86AsmParser::ParseIntelMemoryOperandSize(unsigned &Size) { +bool X86AsmParser::ParseIntelMemoryOperandSize(unsigned &Size, + StringRef *SizeStr) { Size = StringSwitch(getTok().getString()) .Cases("BYTE", "byte", 8) .Cases("WORD", "word", 16) @@ -2592,6 +2597,8 @@ bool X86AsmParser::ParseIntelMemoryOperandSize(unsigned &Size) { .Cases("ZMMWORD", "zmmword", 512) .Default(0); if (Size) { + if (SizeStr) + *SizeStr = getTok().getString(); const AsmToken &Tok = Lex(); // Eat operand size (e.g., byte, word). if (!(Tok.getString() == "PTR" || Tok.getString() == "ptr")) return Error(Tok.getLoc(), "Expected 'PTR' or 'ptr' token!"); @@ -2600,6 +2607,19 @@ bool X86AsmParser::ParseIntelMemoryOperandSize(unsigned &Size) { return false; } +uint16_t RegSizeInBits(const MCRegisterInfo &MRI, MCRegister RegNo) { + if (X86MCRegisterClasses[X86::GR8RegClassID].contains(RegNo)) + return 8; + if (X86MCRegisterClasses[X86::GR16RegClassID].contains(RegNo)) + return 16; + if (X86MCRegisterClasses[X86::GR32RegClassID].contains(RegNo)) + return 32; + if (X86MCRegisterClasses[X86::GR64RegClassID].contains(RegNo)) + return 64; + // Unknown register size + return 0; +} + bool X86AsmParser::parseIntelOperand(OperandVector &Operands, StringRef Name) { MCAsmParser &Parser = getParser(); const AsmToken &Tok = Parser.getTok(); @@ -2607,7 +2627,8 @@ bool X86AsmParser::parseIntelOperand(OperandVector &Operands, StringRef Name) { // Parse optional Size directive. unsigned Size; - if (ParseIntelMemoryOperandSize(Size)) + StringRef SizeStr; + if (ParseIntelMemoryOperandSize(Size, &SizeStr)) return true; bool PtrInOperand = bool(Size); @@ -2624,9 +2645,29 @@ bool X86AsmParser::parseIntelOperand(OperandVector &Operands, StringRef Name) { return Error(Start, "rip can only be used as a base register"); // A Register followed by ':' is considered a segment override if (Tok.isNot(AsmToken::Colon)) { - if (PtrInOperand) - return Error(Start, "expected memory operand after 'ptr', " - "found register operand instead"); + if (PtrInOperand) { + if (!Parser.isParsingMasm()) + return Error(Start, "expected memory operand after 'ptr', " + "found register operand instead"); + + // If we are parsing MASM, we are allowed to cast registers to their own + // sizes, but not to other types. + uint16_t RegSize = + RegSizeInBits(*getContext().getRegisterInfo(), RegNo); + if (RegSize == 0) + return Error( + Start, + "cannot cast register '" + + StringRef(getContext().getRegisterInfo()->getName(RegNo)) + + "'; its size is not easily defined."); + if (RegSize != Size) + return Error( + Start, + std::to_string(RegSize) + "-bit register '" + + StringRef(getContext().getRegisterInfo()->getName(RegNo)) + + "' cannot be used as a " + std::to_string(Size) + "-bit " + + SizeStr.upper()); + } Operands.push_back(X86Operand::CreateReg(RegNo, Start, End)); return false; } diff --git a/llvm/test/tools/llvm-ml/cast.asm b/llvm/test/tools/llvm-ml/cast.asm new file mode 100644 index 0000000000000..2b4aaae88866e --- /dev/null +++ b/llvm/test/tools/llvm-ml/cast.asm @@ -0,0 +1,25 @@ +; RUN: llvm-ml -m64 -filetype=s %s /Fo - | FileCheck %s + +.code + +mov byte ptr al, al +mov al, byte ptr al +; CHECK: mov al, al +; CHECK-NEXT: mov al, al + +mov word ptr ax, ax +mov ax, word ptr ax +; CHECK: mov ax, ax +; CHECK-NEXT: mov ax, ax + +mov dword ptr eax, eax +mov eax, dword ptr eax +; CHECK: mov eax, eax +; CHECK-NEXT: mov eax, eax + +mov qword ptr rax, rax +mov rax, qword ptr rax +; CHECK: mov rax, rax +; CHECK-NEXT: mov rax, rax + +END diff --git a/llvm/test/tools/llvm-ml/cast_errors.asm b/llvm/test/tools/llvm-ml/cast_errors.asm new file mode 100644 index 0000000000000..ca51648236573 --- /dev/null +++ b/llvm/test/tools/llvm-ml/cast_errors.asm @@ -0,0 +1,41 @@ +; RUN: not llvm-ml -m64 -filetype=s %s /Fo /dev/null 2>&1 | FileCheck %s + +.code + +mov word ptr al, ax +; CHECK: [[#@LINE-1]]:14: error: 8-bit register 'AL' cannot be used as a 16-bit WORD + +mov dword ptr al, eax +; CHECK: [[#@LINE-1]]:15: error: 8-bit register 'AL' cannot be used as a 32-bit DWORD + +mov qword ptr al, rax +; CHECK: [[#@LINE-1]]:15: error: 8-bit register 'AL' cannot be used as a 64-bit QWORD + +mov byte ptr ax, al +; CHECK: [[#@LINE-1]]:14: error: 16-bit register 'AX' cannot be used as a 8-bit BYTE + +mov dword ptr ax, eax +; CHECK: [[#@LINE-1]]:15: error: 16-bit register 'AX' cannot be used as a 32-bit DWORD + +mov qword ptr ax, rax +; CHECK: [[#@LINE-1]]:15: error: 16-bit register 'AX' cannot be used as a 64-bit QWORD + +mov byte ptr eax, al +; CHECK: [[#@LINE-1]]:14: error: 32-bit register 'EAX' cannot be used as a 8-bit BYTE + +mov word ptr eax, ax +; CHECK: [[#@LINE-1]]:14: error: 32-bit register 'EAX' cannot be used as a 16-bit WORD + +mov qword ptr eax, rax +; CHECK: [[#@LINE-1]]:15: error: 32-bit register 'EAX' cannot be used as a 64-bit QWORD + +mov byte ptr rax, al +; CHECK: [[#@LINE-1]]:14: error: 64-bit register 'RAX' cannot be used as a 8-bit BYTE + +mov word ptr rax, ax +; CHECK: [[#@LINE-1]]:14: error: 64-bit register 'RAX' cannot be used as a 16-bit WORD + +mov dword ptr rax, eax +; CHECK: [[#@LINE-1]]:15: error: 64-bit register 'RAX' cannot be used as a 32-bit DWORD + +END