[ms] [llvm-ml] Support MASM's relational operators (EQ, LT, etc.)

Support the named relational operators (EQ, LT, etc.).

Reviewed By: thakis

Differential Revision: https://reviews.llvm.org/D89733
This commit is contained in:
Eric Astor 2020-11-09 13:22:37 -05:00
parent a97e357e8e
commit d657f7cd30
4 changed files with 374 additions and 46 deletions

View File

@ -1831,13 +1831,17 @@ bool MasmParser::parseBinOpRHS(unsigned Precedence, const MCExpr *&Res,
while (true) {
AsmToken::TokenKind TokKind = Lexer.getKind();
if (Lexer.getKind() == AsmToken::Identifier) {
StringRef Identifier = Lexer.getTok().getString();
if (Identifier.equals_lower("and"))
TokKind = AsmToken::Amp;
else if (Identifier.equals_lower("not"))
TokKind = AsmToken::Exclaim;
else if (Identifier.equals_lower("or"))
TokKind = AsmToken::Pipe;
TokKind = StringSwitch<AsmToken::TokenKind>(Lexer.getTok().getString())
.CaseLower("and", AsmToken::Amp)
.CaseLower("not", AsmToken::Exclaim)
.CaseLower("or", AsmToken::Pipe)
.CaseLower("eq", AsmToken::EqualEqual)
.CaseLower("ne", AsmToken::ExclaimEqual)
.CaseLower("lt", AsmToken::Less)
.CaseLower("le", AsmToken::LessEqual)
.CaseLower("gt", AsmToken::Greater)
.CaseLower("ge", AsmToken::GreaterEqual)
.Default(TokKind);
}
MCBinaryExpr::Opcode Kind = MCBinaryExpr::Add;
unsigned TokPrec = getBinOpPrecedence(TokKind, Kind);

View File

@ -57,22 +57,28 @@ static bool checkScale(unsigned Scale, StringRef &ErrMsg) {
namespace {
static const char OpPrecedence[] = {
0, // IC_OR
1, // IC_XOR
2, // IC_AND
3, // IC_LSHIFT
3, // IC_RSHIFT
4, // IC_PLUS
4, // IC_MINUS
5, // IC_MULTIPLY
5, // IC_DIVIDE
5, // IC_MOD
6, // IC_NOT
7, // IC_NEG
8, // IC_RPAREN
9, // IC_LPAREN
0, // IC_IMM
0 // IC_REGISTER
0, // IC_OR
1, // IC_XOR
2, // IC_AND
4, // IC_LSHIFT
4, // IC_RSHIFT
5, // IC_PLUS
5, // IC_MINUS
6, // IC_MULTIPLY
6, // IC_DIVIDE
6, // IC_MOD
7, // IC_NOT
8, // IC_NEG
9, // IC_RPAREN
10, // IC_LPAREN
0, // IC_IMM
0, // IC_REGISTER
3, // IC_EQ
3, // IC_NE
3, // IC_LT
3, // IC_LE
3, // IC_GT
3 // IC_GE
};
class X86AsmParser : public MCTargetAsmParser {
@ -143,7 +149,13 @@ private:
IC_RPAREN,
IC_LPAREN,
IC_IMM,
IC_REGISTER
IC_REGISTER,
IC_EQ,
IC_NE,
IC_LT,
IC_LE,
IC_GT,
IC_GE
};
enum IntelOperatorKind {
@ -332,6 +344,44 @@ private:
Val = Op1.second >> Op2.second;
OperandStack.push_back(std::make_pair(IC_IMM, Val));
break;
case IC_EQ:
assert(Op1.first == IC_IMM && Op2.first == IC_IMM &&
"Equals operation with an immediate and a register!");
Val = (Op1.second == Op2.second) ? -1 : 0;
OperandStack.push_back(std::make_pair(IC_IMM, Val));
break;
case IC_NE:
assert(Op1.first == IC_IMM && Op2.first == IC_IMM &&
"Not-equals operation with an immediate and a register!");
Val = (Op1.second != Op2.second) ? -1 : 0;
OperandStack.push_back(std::make_pair(IC_IMM, Val));
break;
case IC_LT:
assert(Op1.first == IC_IMM && Op2.first == IC_IMM &&
"Less-than operation with an immediate and a register!");
Val = (Op1.second < Op2.second) ? -1 : 0;
OperandStack.push_back(std::make_pair(IC_IMM, Val));
break;
case IC_LE:
assert(Op1.first == IC_IMM && Op2.first == IC_IMM &&
"Less-than-or-equal operation with an immediate and a "
"register!");
Val = (Op1.second <= Op2.second) ? -1 : 0;
OperandStack.push_back(std::make_pair(IC_IMM, Val));
break;
case IC_GT:
assert(Op1.first == IC_IMM && Op2.first == IC_IMM &&
"Greater-than operation with an immediate and a register!");
Val = (Op1.second > Op2.second) ? -1 : 0;
OperandStack.push_back(std::make_pair(IC_IMM, Val));
break;
case IC_GE:
assert(Op1.first == IC_IMM && Op2.first == IC_IMM &&
"Greater-than-or-equal operation with an immediate and a "
"register!");
Val = (Op1.second >= Op2.second) ? -1 : 0;
OperandStack.push_back(std::make_pair(IC_IMM, Val));
break;
}
}
}
@ -345,6 +395,12 @@ private:
IES_OR,
IES_XOR,
IES_AND,
IES_EQ,
IES_NE,
IES_LT,
IES_LE,
IES_GT,
IES_GE,
IES_LSHIFT,
IES_RSHIFT,
IES_PLUS,
@ -461,6 +517,96 @@ private:
}
PrevState = CurrState;
}
void onEq() {
IntelExprState CurrState = State;
switch (State) {
default:
State = IES_ERROR;
break;
case IES_INTEGER:
case IES_RPAREN:
case IES_REGISTER:
State = IES_EQ;
IC.pushOperator(IC_EQ);
break;
}
PrevState = CurrState;
}
void onNE() {
IntelExprState CurrState = State;
switch (State) {
default:
State = IES_ERROR;
break;
case IES_INTEGER:
case IES_RPAREN:
case IES_REGISTER:
State = IES_NE;
IC.pushOperator(IC_NE);
break;
}
PrevState = CurrState;
}
void onLT() {
IntelExprState CurrState = State;
switch (State) {
default:
State = IES_ERROR;
break;
case IES_INTEGER:
case IES_RPAREN:
case IES_REGISTER:
State = IES_LT;
IC.pushOperator(IC_LT);
break;
}
PrevState = CurrState;
}
void onLE() {
IntelExprState CurrState = State;
switch (State) {
default:
State = IES_ERROR;
break;
case IES_INTEGER:
case IES_RPAREN:
case IES_REGISTER:
State = IES_LE;
IC.pushOperator(IC_LE);
break;
}
PrevState = CurrState;
}
void onGT() {
IntelExprState CurrState = State;
switch (State) {
default:
State = IES_ERROR;
break;
case IES_INTEGER:
case IES_RPAREN:
case IES_REGISTER:
State = IES_GT;
IC.pushOperator(IC_GT);
break;
}
PrevState = CurrState;
}
void onGE() {
IntelExprState CurrState = State;
switch (State) {
default:
State = IES_ERROR;
break;
case IES_INTEGER:
case IES_RPAREN:
case IES_REGISTER:
State = IES_GE;
IC.pushOperator(IC_GE);
break;
}
PrevState = CurrState;
}
void onLShift() {
IntelExprState CurrState = State;
switch (State) {
@ -531,6 +677,12 @@ private:
case IES_OR:
case IES_XOR:
case IES_AND:
case IES_EQ:
case IES_NE:
case IES_LT:
case IES_LE:
case IES_GT:
case IES_GE:
case IES_LSHIFT:
case IES_RSHIFT:
case IES_PLUS:
@ -586,6 +738,12 @@ private:
case IES_OR:
case IES_XOR:
case IES_AND:
case IES_EQ:
case IES_NE:
case IES_LT:
case IES_LE:
case IES_GT:
case IES_GE:
case IES_LSHIFT:
case IES_RSHIFT:
case IES_PLUS:
@ -686,6 +844,12 @@ private:
case IES_OR:
case IES_XOR:
case IES_AND:
case IES_EQ:
case IES_NE:
case IES_LT:
case IES_LE:
case IES_GT:
case IES_GE:
case IES_LSHIFT:
case IES_RSHIFT:
case IES_DIVIDE:
@ -822,6 +986,12 @@ private:
case IES_OR:
case IES_XOR:
case IES_AND:
case IES_EQ:
case IES_NE:
case IES_LT:
case IES_LE:
case IES_GT:
case IES_GE:
case IES_LSHIFT:
case IES_RSHIFT:
case IES_MULTIPLY:
@ -932,6 +1102,8 @@ private:
bool ParseRoundingModeOp(SMLoc Start, OperandVector &Operands);
bool ParseIntelNamedOperator(StringRef Name, IntelExprStateMachine &SM,
bool &ParseError, SMLoc &End);
bool ParseMasmNamedOperator(StringRef Name, IntelExprStateMachine &SM,
bool &ParseError, SMLoc &End);
void RewriteIntelExpression(IntelExprStateMachine &SM, SMLoc Start,
SMLoc End);
bool ParseIntelExpression(IntelExprStateMachine &SM, SMLoc &End);
@ -1608,8 +1780,10 @@ bool X86AsmParser::CreateMemForMSInlineAsm(
bool X86AsmParser::ParseIntelNamedOperator(StringRef Name,
IntelExprStateMachine &SM,
bool &ParseError, SMLoc &End) {
// A named operator should be either lower or upper case, but not a mix
if (Name.compare(Name.lower()) && Name.compare(Name.upper()))
// A named operator should be either lower or upper case, but not a mix...
// except in MASM, which uses full case-insensitivity.
if (Name.compare(Name.lower()) && Name.compare(Name.upper()) &&
!getParser().isParsingMasm())
return false;
if (Name.equals_lower("not")) {
SM.onNot();
@ -1645,6 +1819,27 @@ bool X86AsmParser::ParseIntelNamedOperator(StringRef Name,
End = consumeToken();
return true;
}
bool X86AsmParser::ParseMasmNamedOperator(StringRef Name,
IntelExprStateMachine &SM,
bool &ParseError, SMLoc &End) {
if (Name.equals_lower("eq")) {
SM.onEq();
} else if (Name.equals_lower("ne")) {
SM.onNE();
} else if (Name.equals_lower("lt")) {
SM.onLT();
} else if (Name.equals_lower("le")) {
SM.onLE();
} else if (Name.equals_lower("gt")) {
SM.onGT();
} else if (Name.equals_lower("ge")) {
SM.onGE();
} else {
return false;
}
End = consumeToken();
return true;
}
bool X86AsmParser::ParseIntelExpression(IntelExprStateMachine &SM, SMLoc &End) {
MCAsmParser &Parser = getParser();
@ -1787,6 +1982,12 @@ bool X86AsmParser::ParseIntelExpression(IntelExprStateMachine &SM, SMLoc &End) {
return true;
break;
}
if (Parser.isParsingMasm() &&
ParseMasmNamedOperator(Identifier, SM, ParseError, End)) {
if (ParseError)
return true;
break;
}
// Symbol reference, when parsing assembly content
InlineAsmIdentifierInfo Info;
AsmFieldInfo FieldInfo;

View File

@ -1,20 +0,0 @@
; RUN: llvm-ml -filetype=asm %s | FileCheck %s
.data
t1 BYTE NOT 1
; CHECK: t1:
; CHECK-NEXT: .byte -2
t2 BYTE 1 OR 2
; CHECK: t2:
; CHECK-NEXT: .byte 3
t3 BYTE 6 AND 10
; CHECK: t3:
; CHECK-NEXT: .byte 2
.code
xor eax, eax
END

View File

@ -0,0 +1,143 @@
; RUN: llvm-ml -filetype=asm %s | FileCheck %s
.data
t1 BYTE NOT 1
; CHECK-LABEL: t1:
; CHECK-NEXT: .byte -2
; CHECK-NOT: .byte
t2 BYTE 1 OR 2
; CHECK-LABEL: t2:
; CHECK-NEXT: .byte 3
t3 BYTE 6 AND 10
; CHECK-LABEL: t3:
; CHECK-NEXT: .byte 2
t4 BYTE 5 EQ 6
BYTE 6 EQ 6
BYTE 7 EQ 6
; CHECK-LABEL: t4:
; CHECK-NEXT: .byte 0
; CHECK: .byte -1
; CHECK: .byte 0
; CHECK-NOT: .byte
t5 BYTE 5 NE 6
BYTE 6 NE 6
BYTE 7 NE 6
; CHECK-LABEL: t5:
; CHECK-NEXT: .byte -1
; CHECK: .byte 0
; CHECK: .byte -1
; CHECK-NOT: .byte
t6 BYTE 5 LT 6
BYTE 6 LT 6
BYTE 7 LT 6
; CHECK-LABEL: t6:
; CHECK-NEXT: .byte -1
; CHECK: .byte 0
; CHECK: .byte 0
; CHECK-NOT: .byte
t7 BYTE 5 LE 6
BYTE 6 LE 6
BYTE 7 LE 6
; CHECK-LABEL: t7:
; CHECK-NEXT: .byte -1
; CHECK: .byte -1
; CHECK: .byte 0
; CHECK-NOT: .byte
t8 BYTE 5 GT 6
BYTE 6 GT 6
BYTE 7 GT 6
; CHECK-LABEL: t8:
; CHECK-NEXT: .byte 0
; CHECK: .byte 0
; CHECK: .byte -1
; CHECK-NOT: .byte
t9 BYTE 5 GE 6
BYTE 6 GE 6
BYTE 7 GE 6
; CHECK-LABEL: t9:
; CHECK-NEXT: .byte 0
; CHECK: .byte -1
; CHECK: .byte -1
; CHECK-NOT: .byte
.code
t10:
xor eax, Not 1
; CHECK-LABEL: t10:
; CHECK-NEXT: xor eax, -2
t11:
xor eax, 1 oR 2
; CHECK-LABEL: t11:
; CHECK-NEXT: xor eax, 3
t12:
xor eax, 6 ANd 10
; CHECK-LABEL: t12:
; CHECK-NEXT: xor eax, 2
t13:
xor eax, 5 Eq 6
xor eax, 6 eQ 6
xor eax, 7 eq 6
; CHECK-LABEL: t13:
; CHECK-NEXT: xor eax, 0
; CHECK-NEXT: xor eax, -1
; CHECK-NEXT: xor eax, 0
t14:
xor eax, 5 Ne 6
xor eax, 6 nE 6
xor eax, 7 ne 6
; CHECK-LABEL: t14:
; CHECK-NEXT: xor eax, -1
; CHECK-NEXT: xor eax, 0
; CHECK-NEXT: xor eax, -1
t15:
xor eax, 5 Lt 6
xor eax, 6 lT 6
xor eax, 7 lt 6
; CHECK-LABEL: t15:
; CHECK-NEXT: xor eax, -1
; CHECK-NEXT: xor eax, 0
; CHECK-NEXT: xor eax, 0
t16:
xor eax, 5 Le 6
xor eax, 6 lE 6
xor eax, 7 le 6
; CHECK-LABEL: t16:
; CHECK-NEXT: xor eax, -1
; CHECK-NEXT: xor eax, -1
; CHECK-NEXT: xor eax, 0
t17:
xor eax, 5 Gt 6
xor eax, 6 gT 6
xor eax, 7 gt 6
; CHECK-LABEL: t17:
; CHECK-NEXT: xor eax, 0
; CHECK-NEXT: xor eax, 0
; CHECK-NEXT: xor eax, -1
t18:
xor eax, 5 Ge 6
xor eax, 6 gE 6
xor eax, 7 ge 6
; CHECK-LABEL: t18:
; CHECK-NEXT: xor eax, 0
; CHECK-NEXT: xor eax, -1
; CHECK-NEXT: xor eax, -1
END