Skip to content

Commit 344708c

Browse files
authored
[ms] [llvm-ml] Allow PTR casting of registers to their own size (llvm#132751)
MASM allows no-op casts on register operands; for example, `DWORD PTR eax` is a legal expression. Any other cast is an error. Fixes llvm#132084
1 parent 40edc34 commit 344708c

File tree

3 files changed

+113
-6
lines changed

3 files changed

+113
-6
lines changed

llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515
#include "MCTargetDesc/X86TargetStreamer.h"
1616
#include "TargetInfo/X86TargetInfo.h"
1717
#include "X86Operand.h"
18+
#include "X86RegisterInfo.h"
1819
#include "llvm-c/Visibility.h"
1920
#include "llvm/ADT/STLExtras.h"
2021
#include "llvm/ADT/SmallString.h"
2122
#include "llvm/ADT/SmallVector.h"
23+
#include "llvm/ADT/StringRef.h"
2224
#include "llvm/ADT/StringSwitch.h"
2325
#include "llvm/ADT/Twine.h"
2426
#include "llvm/MC/MCContext.h"
@@ -29,6 +31,7 @@
2931
#include "llvm/MC/MCParser/MCAsmParser.h"
3032
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
3133
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
34+
#include "llvm/MC/MCRegister.h"
3235
#include "llvm/MC/MCRegisterInfo.h"
3336
#include "llvm/MC/MCSection.h"
3437
#include "llvm/MC/MCStreamer.h"
@@ -40,6 +43,7 @@
4043
#include "llvm/Support/SourceMgr.h"
4144
#include "llvm/Support/raw_ostream.h"
4245
#include <algorithm>
46+
#include <cstdint>
4347
#include <memory>
4448

4549
using namespace llvm;
@@ -1172,7 +1176,7 @@ class X86AsmParser : public MCTargetAsmParser {
11721176

11731177
X86::CondCode ParseConditionCode(StringRef CCode);
11741178

1175-
bool ParseIntelMemoryOperandSize(unsigned &Size);
1179+
bool ParseIntelMemoryOperandSize(unsigned &Size, StringRef *SizeStr);
11761180
bool CreateMemForMSInlineAsm(MCRegister SegReg, const MCExpr *Disp,
11771181
MCRegister BaseReg, MCRegister IndexReg,
11781182
unsigned Scale, bool NonAbsMem, SMLoc Start,
@@ -2574,7 +2578,8 @@ bool X86AsmParser::ParseMasmOperator(unsigned OpKind, int64_t &Val) {
25742578
return false;
25752579
}
25762580

2577-
bool X86AsmParser::ParseIntelMemoryOperandSize(unsigned &Size) {
2581+
bool X86AsmParser::ParseIntelMemoryOperandSize(unsigned &Size,
2582+
StringRef *SizeStr) {
25782583
Size = StringSwitch<unsigned>(getTok().getString())
25792584
.Cases("BYTE", "byte", 8)
25802585
.Cases("WORD", "word", 16)
@@ -2592,6 +2597,8 @@ bool X86AsmParser::ParseIntelMemoryOperandSize(unsigned &Size) {
25922597
.Cases("ZMMWORD", "zmmword", 512)
25932598
.Default(0);
25942599
if (Size) {
2600+
if (SizeStr)
2601+
*SizeStr = getTok().getString();
25952602
const AsmToken &Tok = Lex(); // Eat operand size (e.g., byte, word).
25962603
if (!(Tok.getString() == "PTR" || Tok.getString() == "ptr"))
25972604
return Error(Tok.getLoc(), "Expected 'PTR' or 'ptr' token!");
@@ -2600,14 +2607,28 @@ bool X86AsmParser::ParseIntelMemoryOperandSize(unsigned &Size) {
26002607
return false;
26012608
}
26022609

2610+
uint16_t RegSizeInBits(const MCRegisterInfo &MRI, MCRegister RegNo) {
2611+
if (X86MCRegisterClasses[X86::GR8RegClassID].contains(RegNo))
2612+
return 8;
2613+
if (X86MCRegisterClasses[X86::GR16RegClassID].contains(RegNo))
2614+
return 16;
2615+
if (X86MCRegisterClasses[X86::GR32RegClassID].contains(RegNo))
2616+
return 32;
2617+
if (X86MCRegisterClasses[X86::GR64RegClassID].contains(RegNo))
2618+
return 64;
2619+
// Unknown register size
2620+
return 0;
2621+
}
2622+
26032623
bool X86AsmParser::parseIntelOperand(OperandVector &Operands, StringRef Name) {
26042624
MCAsmParser &Parser = getParser();
26052625
const AsmToken &Tok = Parser.getTok();
26062626
SMLoc Start, End;
26072627

26082628
// Parse optional Size directive.
26092629
unsigned Size;
2610-
if (ParseIntelMemoryOperandSize(Size))
2630+
StringRef SizeStr;
2631+
if (ParseIntelMemoryOperandSize(Size, &SizeStr))
26112632
return true;
26122633
bool PtrInOperand = bool(Size);
26132634

@@ -2624,9 +2645,29 @@ bool X86AsmParser::parseIntelOperand(OperandVector &Operands, StringRef Name) {
26242645
return Error(Start, "rip can only be used as a base register");
26252646
// A Register followed by ':' is considered a segment override
26262647
if (Tok.isNot(AsmToken::Colon)) {
2627-
if (PtrInOperand)
2628-
return Error(Start, "expected memory operand after 'ptr', "
2629-
"found register operand instead");
2648+
if (PtrInOperand) {
2649+
if (!Parser.isParsingMasm())
2650+
return Error(Start, "expected memory operand after 'ptr', "
2651+
"found register operand instead");
2652+
2653+
// If we are parsing MASM, we are allowed to cast registers to their own
2654+
// sizes, but not to other types.
2655+
uint16_t RegSize =
2656+
RegSizeInBits(*getContext().getRegisterInfo(), RegNo);
2657+
if (RegSize == 0)
2658+
return Error(
2659+
Start,
2660+
"cannot cast register '" +
2661+
StringRef(getContext().getRegisterInfo()->getName(RegNo)) +
2662+
"'; its size is not easily defined.");
2663+
if (RegSize != Size)
2664+
return Error(
2665+
Start,
2666+
std::to_string(RegSize) + "-bit register '" +
2667+
StringRef(getContext().getRegisterInfo()->getName(RegNo)) +
2668+
"' cannot be used as a " + std::to_string(Size) + "-bit " +
2669+
SizeStr.upper());
2670+
}
26302671
Operands.push_back(X86Operand::CreateReg(RegNo, Start, End));
26312672
return false;
26322673
}

llvm/test/tools/llvm-ml/cast.asm

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
; RUN: llvm-ml -m64 -filetype=s %s /Fo - | FileCheck %s
2+
3+
.code
4+
5+
mov byte ptr al, al
6+
mov al, byte ptr al
7+
; CHECK: mov al, al
8+
; CHECK-NEXT: mov al, al
9+
10+
mov word ptr ax, ax
11+
mov ax, word ptr ax
12+
; CHECK: mov ax, ax
13+
; CHECK-NEXT: mov ax, ax
14+
15+
mov dword ptr eax, eax
16+
mov eax, dword ptr eax
17+
; CHECK: mov eax, eax
18+
; CHECK-NEXT: mov eax, eax
19+
20+
mov qword ptr rax, rax
21+
mov rax, qword ptr rax
22+
; CHECK: mov rax, rax
23+
; CHECK-NEXT: mov rax, rax
24+
25+
END
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
; RUN: not llvm-ml -m64 -filetype=s %s /Fo /dev/null 2>&1 | FileCheck %s
2+
3+
.code
4+
5+
mov word ptr al, ax
6+
; CHECK: [[#@LINE-1]]:14: error: 8-bit register 'AL' cannot be used as a 16-bit WORD
7+
8+
mov dword ptr al, eax
9+
; CHECK: [[#@LINE-1]]:15: error: 8-bit register 'AL' cannot be used as a 32-bit DWORD
10+
11+
mov qword ptr al, rax
12+
; CHECK: [[#@LINE-1]]:15: error: 8-bit register 'AL' cannot be used as a 64-bit QWORD
13+
14+
mov byte ptr ax, al
15+
; CHECK: [[#@LINE-1]]:14: error: 16-bit register 'AX' cannot be used as a 8-bit BYTE
16+
17+
mov dword ptr ax, eax
18+
; CHECK: [[#@LINE-1]]:15: error: 16-bit register 'AX' cannot be used as a 32-bit DWORD
19+
20+
mov qword ptr ax, rax
21+
; CHECK: [[#@LINE-1]]:15: error: 16-bit register 'AX' cannot be used as a 64-bit QWORD
22+
23+
mov byte ptr eax, al
24+
; CHECK: [[#@LINE-1]]:14: error: 32-bit register 'EAX' cannot be used as a 8-bit BYTE
25+
26+
mov word ptr eax, ax
27+
; CHECK: [[#@LINE-1]]:14: error: 32-bit register 'EAX' cannot be used as a 16-bit WORD
28+
29+
mov qword ptr eax, rax
30+
; CHECK: [[#@LINE-1]]:15: error: 32-bit register 'EAX' cannot be used as a 64-bit QWORD
31+
32+
mov byte ptr rax, al
33+
; CHECK: [[#@LINE-1]]:14: error: 64-bit register 'RAX' cannot be used as a 8-bit BYTE
34+
35+
mov word ptr rax, ax
36+
; CHECK: [[#@LINE-1]]:14: error: 64-bit register 'RAX' cannot be used as a 16-bit WORD
37+
38+
mov dword ptr rax, eax
39+
; CHECK: [[#@LINE-1]]:15: error: 64-bit register 'RAX' cannot be used as a 32-bit DWORD
40+
41+
END

0 commit comments

Comments
 (0)