2009-07-18 04:42:00 +08:00
|
|
|
//===-- X86AsmParser.cpp - Parse X86 assembly to MCInst instructions ------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
[codeview] Implement FPO data assembler directives
Summary:
This adds a set of new directives that describe 32-bit x86 prologues.
The directives are limited and do not expose the full complexity of
codeview FPO data. They are merely a convenience for the compiler to
generate more readable assembly so we don't need to generate tons of
labels in CodeGen. If our prologue emission changes in the future, we
can change the set of available directives to suit our needs. These are
modelled after the .seh_ directives, which use a different format that
interacts with exception handling.
The directives are:
.cv_fpo_proc _foo
.cv_fpo_pushreg ebp/ebx/etc
.cv_fpo_setframe ebp/esi/etc
.cv_fpo_stackalloc 200
.cv_fpo_endprologue
.cv_fpo_endproc
.cv_fpo_data _foo
I tried to follow the implementation of ARM EHABI CFI directives by
sinking most directives out of MCStreamer and into X86TargetStreamer.
This helps avoid polluting non-X86 code with WinCOFF specific logic.
I used cdb to confirm that this can show locals in parent CSRs in a few
cases, most importantly the one where we use ESI as a frame pointer,
i.e. the one in http://crbug.com/756153#c28
Once we have cdb integration in debuginfo-tests, we can add integration
tests there.
Reviewers: majnemer, hans
Subscribers: aemerson, mgorny, kristof.beyls, llvm-commits, hiraditya
Differential Revision: https://reviews.llvm.org/D38776
llvm-svn: 315513
2017-10-12 05:24:33 +08:00
|
|
|
#include "InstPrinter/X86IntelInstPrinter.h"
|
2011-07-26 08:24:13 +08:00
|
|
|
#include "MCTargetDesc/X86BaseInfo.h"
|
[codeview] Implement FPO data assembler directives
Summary:
This adds a set of new directives that describe 32-bit x86 prologues.
The directives are limited and do not expose the full complexity of
codeview FPO data. They are merely a convenience for the compiler to
generate more readable assembly so we don't need to generate tons of
labels in CodeGen. If our prologue emission changes in the future, we
can change the set of available directives to suit our needs. These are
modelled after the .seh_ directives, which use a different format that
interacts with exception handling.
The directives are:
.cv_fpo_proc _foo
.cv_fpo_pushreg ebp/ebx/etc
.cv_fpo_setframe ebp/esi/etc
.cv_fpo_stackalloc 200
.cv_fpo_endprologue
.cv_fpo_endproc
.cv_fpo_data _foo
I tried to follow the implementation of ARM EHABI CFI directives by
sinking most directives out of MCStreamer and into X86TargetStreamer.
This helps avoid polluting non-X86 code with WinCOFF specific logic.
I used cdb to confirm that this can show locals in parent CSRs in a few
cases, most importantly the one where we use ESI as a frame pointer,
i.e. the one in http://crbug.com/756153#c28
Once we have cdb integration in debuginfo-tests, we can add integration
tests there.
Reviewers: majnemer, hans
Subscribers: aemerson, mgorny, kristof.beyls, llvm-commits, hiraditya
Differential Revision: https://reviews.llvm.org/D38776
llvm-svn: 315513
2017-10-12 05:24:33 +08:00
|
|
|
#include "MCTargetDesc/X86TargetStreamer.h"
|
2014-03-14 16:58:04 +08:00
|
|
|
#include "X86AsmInstrumentation.h"
|
2014-02-28 20:28:07 +08:00
|
|
|
#include "X86AsmParserCommon.h"
|
|
|
|
#include "X86Operand.h"
|
2013-07-24 15:33:14 +08:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2010-09-22 12:11:10 +08:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
|
|
#include "llvm/ADT/StringSwitch.h"
|
|
|
|
#include "llvm/ADT/Twine.h"
|
2013-04-03 04:02:33 +08:00
|
|
|
#include "llvm/MC/MCContext.h"
|
2012-12-04 00:50:05 +08:00
|
|
|
#include "llvm/MC/MCExpr.h"
|
|
|
|
#include "llvm/MC/MCInst.h"
|
2014-04-24 21:29:34 +08:00
|
|
|
#include "llvm/MC/MCInstrInfo.h"
|
2012-12-04 00:50:05 +08:00
|
|
|
#include "llvm/MC/MCParser/MCAsmLexer.h"
|
|
|
|
#include "llvm/MC/MCParser/MCAsmParser.h"
|
|
|
|
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
|
2016-01-27 18:01:28 +08:00
|
|
|
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
|
2012-12-04 00:50:05 +08:00
|
|
|
#include "llvm/MC/MCRegisterInfo.h"
|
2015-12-14 01:07:23 +08:00
|
|
|
#include "llvm/MC/MCSection.h"
|
2012-12-04 00:50:05 +08:00
|
|
|
#include "llvm/MC/MCStreamer.h"
|
|
|
|
#include "llvm/MC/MCSubtargetInfo.h"
|
|
|
|
#include "llvm/MC/MCSymbol.h"
|
2009-07-29 06:40:46 +08:00
|
|
|
#include "llvm/Support/SourceMgr.h"
|
2011-08-25 02:08:43 +08:00
|
|
|
#include "llvm/Support/TargetRegistry.h"
|
2010-08-12 08:55:42 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2014-07-31 06:23:11 +08:00
|
|
|
#include <algorithm>
|
2014-03-14 16:58:04 +08:00
|
|
|
#include <memory>
|
2011-07-08 09:53:10 +08:00
|
|
|
|
2009-07-18 04:42:00 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
2017-07-25 21:05:12 +08:00
|
|
|
static bool checkScale(unsigned Scale, StringRef &ErrMsg) {
|
|
|
|
if (Scale != 1 && Scale != 2 && Scale != 4 && Scale != 8) {
|
|
|
|
ErrMsg = "scale factor in address must be 1, 2, 4 or 8";
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-07-18 04:42:00 +08:00
|
|
|
namespace {
|
|
|
|
|
2013-04-17 02:15:40 +08:00
|
|
|
static const char OpPrecedence[] = {
|
2014-01-16 03:05:24 +08:00
|
|
|
0, // IC_OR
|
2015-06-14 20:59:45 +08:00
|
|
|
1, // IC_XOR
|
|
|
|
2, // IC_AND
|
|
|
|
3, // IC_LSHIFT
|
|
|
|
3, // IC_RSHIFT
|
|
|
|
4, // IC_PLUS
|
|
|
|
4, // IC_MINUS
|
|
|
|
5, // IC_MULTIPLY
|
|
|
|
5, // IC_DIVIDE
|
2017-06-28 00:58:27 +08:00
|
|
|
5, // IC_MOD
|
|
|
|
6, // IC_NOT
|
|
|
|
7, // IC_NEG
|
|
|
|
8, // IC_RPAREN
|
|
|
|
9, // IC_LPAREN
|
2013-04-17 02:15:40 +08:00
|
|
|
0, // IC_IMM
|
|
|
|
0 // IC_REGISTER
|
|
|
|
};
|
|
|
|
|
2012-01-13 02:03:40 +08:00
|
|
|
class X86AsmParser : public MCTargetAsmParser {
|
2012-10-26 04:41:34 +08:00
|
|
|
ParseInstructionInfo *InstInfo;
|
2014-03-14 16:58:04 +08:00
|
|
|
std::unique_ptr<X86AsmInstrumentation> Instrumentation;
|
2016-09-27 03:33:36 +08:00
|
|
|
bool Code16GCC;
|
2015-09-22 19:14:39 +08:00
|
|
|
|
2009-07-29 06:40:46 +08:00
|
|
|
private:
|
2013-12-03 00:06:06 +08:00
|
|
|
SMLoc consumeToken() {
|
2014-11-11 13:18:41 +08:00
|
|
|
MCAsmParser &Parser = getParser();
|
2013-12-03 00:06:06 +08:00
|
|
|
SMLoc Result = Parser.getTok().getLoc();
|
|
|
|
Parser.Lex();
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
[codeview] Implement FPO data assembler directives
Summary:
This adds a set of new directives that describe 32-bit x86 prologues.
The directives are limited and do not expose the full complexity of
codeview FPO data. They are merely a convenience for the compiler to
generate more readable assembly so we don't need to generate tons of
labels in CodeGen. If our prologue emission changes in the future, we
can change the set of available directives to suit our needs. These are
modelled after the .seh_ directives, which use a different format that
interacts with exception handling.
The directives are:
.cv_fpo_proc _foo
.cv_fpo_pushreg ebp/ebx/etc
.cv_fpo_setframe ebp/esi/etc
.cv_fpo_stackalloc 200
.cv_fpo_endprologue
.cv_fpo_endproc
.cv_fpo_data _foo
I tried to follow the implementation of ARM EHABI CFI directives by
sinking most directives out of MCStreamer and into X86TargetStreamer.
This helps avoid polluting non-X86 code with WinCOFF specific logic.
I used cdb to confirm that this can show locals in parent CSRs in a few
cases, most importantly the one where we use ESI as a frame pointer,
i.e. the one in http://crbug.com/756153#c28
Once we have cdb integration in debuginfo-tests, we can add integration
tests there.
Reviewers: majnemer, hans
Subscribers: aemerson, mgorny, kristof.beyls, llvm-commits, hiraditya
Differential Revision: https://reviews.llvm.org/D38776
llvm-svn: 315513
2017-10-12 05:24:33 +08:00
|
|
|
X86TargetStreamer &getTargetStreamer() {
|
|
|
|
assert(getParser().getStreamer().getTargetStreamer() &&
|
|
|
|
"do not have a target streamer");
|
|
|
|
MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer();
|
|
|
|
return static_cast<X86TargetStreamer &>(TS);
|
|
|
|
}
|
|
|
|
|
2016-09-27 03:33:36 +08:00
|
|
|
unsigned MatchInstruction(const OperandVector &Operands, MCInst &Inst,
|
|
|
|
uint64_t &ErrorInfo, bool matchingInlineAsm,
|
|
|
|
unsigned VariantID = 0) {
|
|
|
|
// In Code16GCC mode, match as 32-bit.
|
|
|
|
if (Code16GCC)
|
|
|
|
SwitchMode(X86::Mode32Bit);
|
|
|
|
unsigned rv = MatchInstructionImpl(Operands, Inst, ErrorInfo,
|
|
|
|
matchingInlineAsm, VariantID);
|
|
|
|
if (Code16GCC)
|
|
|
|
SwitchMode(X86::Mode16Bit);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2013-04-17 02:15:40 +08:00
|
|
|
enum InfixCalculatorTok {
|
2014-01-16 03:05:24 +08:00
|
|
|
IC_OR = 0,
|
2015-06-14 20:59:45 +08:00
|
|
|
IC_XOR,
|
2014-01-16 03:05:24 +08:00
|
|
|
IC_AND,
|
2014-02-06 09:21:15 +08:00
|
|
|
IC_LSHIFT,
|
|
|
|
IC_RSHIFT,
|
2014-01-16 03:05:24 +08:00
|
|
|
IC_PLUS,
|
2013-04-17 02:15:40 +08:00
|
|
|
IC_MINUS,
|
|
|
|
IC_MULTIPLY,
|
|
|
|
IC_DIVIDE,
|
2017-06-28 00:58:27 +08:00
|
|
|
IC_MOD,
|
|
|
|
IC_NOT,
|
|
|
|
IC_NEG,
|
2013-04-17 02:15:40 +08:00
|
|
|
IC_RPAREN,
|
|
|
|
IC_LPAREN,
|
|
|
|
IC_IMM,
|
|
|
|
IC_REGISTER
|
|
|
|
};
|
|
|
|
|
2017-03-22 03:31:55 +08:00
|
|
|
enum IntelOperatorKind {
|
|
|
|
IOK_INVALID = 0,
|
|
|
|
IOK_LENGTH,
|
|
|
|
IOK_SIZE,
|
|
|
|
IOK_TYPE,
|
|
|
|
IOK_OFFSET
|
|
|
|
};
|
|
|
|
|
2013-04-17 02:15:40 +08:00
|
|
|
class InfixCalculator {
|
|
|
|
typedef std::pair< InfixCalculatorTok, int64_t > ICToken;
|
|
|
|
SmallVector<InfixCalculatorTok, 4> InfixOperatorStack;
|
|
|
|
SmallVector<ICToken, 4> PostfixStack;
|
2014-12-04 13:20:33 +08:00
|
|
|
|
2017-06-28 00:58:27 +08:00
|
|
|
bool isUnaryOperator(const InfixCalculatorTok Op) {
|
|
|
|
return Op == IC_NEG || Op == IC_NOT;
|
|
|
|
}
|
|
|
|
|
2013-04-17 02:15:40 +08:00
|
|
|
public:
|
|
|
|
int64_t popOperand() {
|
|
|
|
assert (!PostfixStack.empty() && "Poped an empty stack!");
|
|
|
|
ICToken Op = PostfixStack.pop_back_val();
|
2017-07-25 21:05:12 +08:00
|
|
|
if (!(Op.first == IC_IMM || Op.first == IC_REGISTER))
|
|
|
|
return -1; // The invalid Scale value will be caught later by checkScale
|
2013-04-17 02:15:40 +08:00
|
|
|
return Op.second;
|
|
|
|
}
|
|
|
|
void pushOperand(InfixCalculatorTok Op, int64_t Val = 0) {
|
|
|
|
assert ((Op == IC_IMM || Op == IC_REGISTER) &&
|
|
|
|
"Unexpected operand!");
|
|
|
|
PostfixStack.push_back(std::make_pair(Op, Val));
|
|
|
|
}
|
2014-12-04 13:20:33 +08:00
|
|
|
|
2013-08-08 23:48:46 +08:00
|
|
|
void popOperator() { InfixOperatorStack.pop_back(); }
|
2013-04-17 02:15:40 +08:00
|
|
|
void pushOperator(InfixCalculatorTok Op) {
|
|
|
|
// Push the new operator if the stack is empty.
|
|
|
|
if (InfixOperatorStack.empty()) {
|
|
|
|
InfixOperatorStack.push_back(Op);
|
|
|
|
return;
|
|
|
|
}
|
2014-12-04 13:20:33 +08:00
|
|
|
|
2013-04-17 02:15:40 +08:00
|
|
|
// Push the new operator if it has a higher precedence than the operator
|
|
|
|
// on the top of the stack or the operator on the top of the stack is a
|
|
|
|
// left parentheses.
|
|
|
|
unsigned Idx = InfixOperatorStack.size() - 1;
|
|
|
|
InfixCalculatorTok StackOp = InfixOperatorStack[Idx];
|
|
|
|
if (OpPrecedence[Op] > OpPrecedence[StackOp] || StackOp == IC_LPAREN) {
|
|
|
|
InfixOperatorStack.push_back(Op);
|
|
|
|
return;
|
|
|
|
}
|
2014-12-04 13:20:33 +08:00
|
|
|
|
2013-04-17 02:15:40 +08:00
|
|
|
// The operator on the top of the stack has higher precedence than the
|
|
|
|
// new operator.
|
|
|
|
unsigned ParenCount = 0;
|
2017-01-19 00:34:25 +08:00
|
|
|
while (1) {
|
2013-04-17 02:15:40 +08:00
|
|
|
// Nothing to process.
|
|
|
|
if (InfixOperatorStack.empty())
|
|
|
|
break;
|
2014-12-04 13:20:33 +08:00
|
|
|
|
2013-04-17 02:15:40 +08:00
|
|
|
Idx = InfixOperatorStack.size() - 1;
|
|
|
|
StackOp = InfixOperatorStack[Idx];
|
|
|
|
if (!(OpPrecedence[StackOp] >= OpPrecedence[Op] || ParenCount))
|
|
|
|
break;
|
2014-12-04 13:20:33 +08:00
|
|
|
|
2013-04-17 02:15:40 +08:00
|
|
|
// If we have an even parentheses count and we see a left parentheses,
|
|
|
|
// then stop processing.
|
|
|
|
if (!ParenCount && StackOp == IC_LPAREN)
|
|
|
|
break;
|
2014-12-04 13:20:33 +08:00
|
|
|
|
2013-04-17 02:15:40 +08:00
|
|
|
if (StackOp == IC_RPAREN) {
|
|
|
|
++ParenCount;
|
2013-08-08 23:48:46 +08:00
|
|
|
InfixOperatorStack.pop_back();
|
2013-04-17 02:15:40 +08:00
|
|
|
} else if (StackOp == IC_LPAREN) {
|
|
|
|
--ParenCount;
|
2013-08-08 23:48:46 +08:00
|
|
|
InfixOperatorStack.pop_back();
|
2013-04-17 02:15:40 +08:00
|
|
|
} else {
|
2013-08-08 23:48:46 +08:00
|
|
|
InfixOperatorStack.pop_back();
|
2013-04-17 02:15:40 +08:00
|
|
|
PostfixStack.push_back(std::make_pair(StackOp, 0));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Push the new operator.
|
|
|
|
InfixOperatorStack.push_back(Op);
|
|
|
|
}
|
2015-08-10 19:33:10 +08:00
|
|
|
|
2013-04-17 02:15:40 +08:00
|
|
|
int64_t execute() {
|
|
|
|
// Push any remaining operators onto the postfix stack.
|
|
|
|
while (!InfixOperatorStack.empty()) {
|
|
|
|
InfixCalculatorTok StackOp = InfixOperatorStack.pop_back_val();
|
|
|
|
if (StackOp != IC_LPAREN && StackOp != IC_RPAREN)
|
|
|
|
PostfixStack.push_back(std::make_pair(StackOp, 0));
|
|
|
|
}
|
2014-12-04 13:20:33 +08:00
|
|
|
|
2013-04-17 02:15:40 +08:00
|
|
|
if (PostfixStack.empty())
|
|
|
|
return 0;
|
2014-12-04 13:20:33 +08:00
|
|
|
|
2013-04-17 02:15:40 +08:00
|
|
|
SmallVector<ICToken, 16> OperandStack;
|
|
|
|
for (unsigned i = 0, e = PostfixStack.size(); i != e; ++i) {
|
|
|
|
ICToken Op = PostfixStack[i];
|
|
|
|
if (Op.first == IC_IMM || Op.first == IC_REGISTER) {
|
|
|
|
OperandStack.push_back(Op);
|
2017-06-28 00:58:27 +08:00
|
|
|
} else if (isUnaryOperator(Op.first)) {
|
|
|
|
assert (OperandStack.size() > 0 && "Too few operands.");
|
|
|
|
ICToken Operand = OperandStack.pop_back_val();
|
|
|
|
assert (Operand.first == IC_IMM &&
|
|
|
|
"Unary operation with a register!");
|
|
|
|
switch (Op.first) {
|
|
|
|
default:
|
|
|
|
report_fatal_error("Unexpected operator!");
|
|
|
|
break;
|
|
|
|
case IC_NEG:
|
|
|
|
OperandStack.push_back(std::make_pair(IC_IMM, -Operand.second));
|
|
|
|
break;
|
|
|
|
case IC_NOT:
|
|
|
|
OperandStack.push_back(std::make_pair(IC_IMM, ~Operand.second));
|
|
|
|
break;
|
|
|
|
}
|
2013-04-17 02:15:40 +08:00
|
|
|
} else {
|
|
|
|
assert (OperandStack.size() > 1 && "Too few operands.");
|
|
|
|
int64_t Val;
|
|
|
|
ICToken Op2 = OperandStack.pop_back_val();
|
|
|
|
ICToken Op1 = OperandStack.pop_back_val();
|
|
|
|
switch (Op.first) {
|
|
|
|
default:
|
|
|
|
report_fatal_error("Unexpected operator!");
|
|
|
|
break;
|
|
|
|
case IC_PLUS:
|
|
|
|
Val = Op1.second + Op2.second;
|
|
|
|
OperandStack.push_back(std::make_pair(IC_IMM, Val));
|
|
|
|
break;
|
|
|
|
case IC_MINUS:
|
|
|
|
Val = Op1.second - Op2.second;
|
|
|
|
OperandStack.push_back(std::make_pair(IC_IMM, Val));
|
|
|
|
break;
|
|
|
|
case IC_MULTIPLY:
|
|
|
|
assert (Op1.first == IC_IMM && Op2.first == IC_IMM &&
|
|
|
|
"Multiply operation with an immediate and a register!");
|
|
|
|
Val = Op1.second * Op2.second;
|
|
|
|
OperandStack.push_back(std::make_pair(IC_IMM, Val));
|
|
|
|
break;
|
|
|
|
case IC_DIVIDE:
|
|
|
|
assert (Op1.first == IC_IMM && Op2.first == IC_IMM &&
|
|
|
|
"Divide operation with an immediate and a register!");
|
|
|
|
assert (Op2.second != 0 && "Division by zero!");
|
|
|
|
Val = Op1.second / Op2.second;
|
|
|
|
OperandStack.push_back(std::make_pair(IC_IMM, Val));
|
|
|
|
break;
|
2017-06-28 00:58:27 +08:00
|
|
|
case IC_MOD:
|
|
|
|
assert (Op1.first == IC_IMM && Op2.first == IC_IMM &&
|
|
|
|
"Modulo operation with an immediate and a register!");
|
|
|
|
Val = Op1.second % Op2.second;
|
|
|
|
OperandStack.push_back(std::make_pair(IC_IMM, Val));
|
|
|
|
break;
|
2014-01-16 03:05:24 +08:00
|
|
|
case IC_OR:
|
|
|
|
assert (Op1.first == IC_IMM && Op2.first == IC_IMM &&
|
|
|
|
"Or operation with an immediate and a register!");
|
|
|
|
Val = Op1.second | Op2.second;
|
|
|
|
OperandStack.push_back(std::make_pair(IC_IMM, Val));
|
|
|
|
break;
|
2015-06-14 20:59:45 +08:00
|
|
|
case IC_XOR:
|
|
|
|
assert(Op1.first == IC_IMM && Op2.first == IC_IMM &&
|
|
|
|
"Xor operation with an immediate and a register!");
|
|
|
|
Val = Op1.second ^ Op2.second;
|
|
|
|
OperandStack.push_back(std::make_pair(IC_IMM, Val));
|
|
|
|
break;
|
2014-01-16 03:05:24 +08:00
|
|
|
case IC_AND:
|
|
|
|
assert (Op1.first == IC_IMM && Op2.first == IC_IMM &&
|
|
|
|
"And operation with an immediate and a register!");
|
|
|
|
Val = Op1.second & Op2.second;
|
|
|
|
OperandStack.push_back(std::make_pair(IC_IMM, Val));
|
|
|
|
break;
|
2014-02-06 09:21:15 +08:00
|
|
|
case IC_LSHIFT:
|
|
|
|
assert (Op1.first == IC_IMM && Op2.first == IC_IMM &&
|
|
|
|
"Left shift operation with an immediate and a register!");
|
|
|
|
Val = Op1.second << Op2.second;
|
|
|
|
OperandStack.push_back(std::make_pair(IC_IMM, Val));
|
|
|
|
break;
|
|
|
|
case IC_RSHIFT:
|
|
|
|
assert (Op1.first == IC_IMM && Op2.first == IC_IMM &&
|
|
|
|
"Right shift operation with an immediate and a register!");
|
|
|
|
Val = Op1.second >> Op2.second;
|
|
|
|
OperandStack.push_back(std::make_pair(IC_IMM, Val));
|
|
|
|
break;
|
2013-04-17 02:15:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert (OperandStack.size() == 1 && "Expected a single result.");
|
|
|
|
return OperandStack.pop_back_val().second;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
enum IntelExprState {
|
2017-08-24 16:46:25 +08:00
|
|
|
IES_INIT,
|
2014-01-16 03:05:24 +08:00
|
|
|
IES_OR,
|
2015-06-14 20:59:45 +08:00
|
|
|
IES_XOR,
|
2014-01-16 03:05:24 +08:00
|
|
|
IES_AND,
|
2014-02-06 09:21:15 +08:00
|
|
|
IES_LSHIFT,
|
|
|
|
IES_RSHIFT,
|
2013-04-17 02:15:40 +08:00
|
|
|
IES_PLUS,
|
|
|
|
IES_MINUS,
|
2014-07-05 03:13:05 +08:00
|
|
|
IES_NOT,
|
2013-04-17 02:15:40 +08:00
|
|
|
IES_MULTIPLY,
|
|
|
|
IES_DIVIDE,
|
2017-06-28 00:58:27 +08:00
|
|
|
IES_MOD,
|
2013-04-17 02:15:40 +08:00
|
|
|
IES_LBRAC,
|
|
|
|
IES_RBRAC,
|
|
|
|
IES_LPAREN,
|
|
|
|
IES_RPAREN,
|
|
|
|
IES_REGISTER,
|
|
|
|
IES_INTEGER,
|
|
|
|
IES_IDENTIFIER,
|
|
|
|
IES_ERROR
|
|
|
|
};
|
|
|
|
|
|
|
|
class IntelExprStateMachine {
|
2013-04-18 05:01:45 +08:00
|
|
|
IntelExprState State, PrevState;
|
2013-04-17 02:15:40 +08:00
|
|
|
unsigned BaseReg, IndexReg, TmpReg, Scale;
|
2013-04-17 08:11:46 +08:00
|
|
|
int64_t Imm;
|
2013-04-17 02:15:40 +08:00
|
|
|
const MCExpr *Sym;
|
|
|
|
StringRef SymName;
|
|
|
|
InfixCalculator IC;
|
2013-04-23 03:42:15 +08:00
|
|
|
InlineAsmIdentifierInfo Info;
|
2017-08-24 16:46:25 +08:00
|
|
|
short BracCount;
|
|
|
|
bool MemExpr;
|
2015-09-22 19:14:39 +08:00
|
|
|
|
2013-04-17 02:15:40 +08:00
|
|
|
public:
|
2017-08-24 16:46:25 +08:00
|
|
|
IntelExprStateMachine()
|
|
|
|
: State(IES_INIT), PrevState(IES_ERROR), BaseReg(0), IndexReg(0),
|
|
|
|
TmpReg(0), Scale(1), Imm(0), Sym(nullptr), BracCount(0),
|
2017-09-29 15:02:46 +08:00
|
|
|
MemExpr(false) {}
|
2014-12-04 13:20:33 +08:00
|
|
|
|
2017-08-24 16:46:25 +08:00
|
|
|
void addImm(int64_t imm) { Imm += imm; }
|
|
|
|
short getBracCount() { return BracCount; }
|
|
|
|
bool isMemExpr() { return MemExpr; }
|
2013-04-17 02:15:40 +08:00
|
|
|
unsigned getBaseReg() { return BaseReg; }
|
|
|
|
unsigned getIndexReg() { return IndexReg; }
|
|
|
|
unsigned getScale() { return Scale; }
|
|
|
|
const MCExpr *getSym() { return Sym; }
|
|
|
|
StringRef getSymName() { return SymName; }
|
2013-04-17 08:11:46 +08:00
|
|
|
int64_t getImm() { return Imm + IC.execute(); }
|
2013-05-10 07:48:53 +08:00
|
|
|
bool isValidEndState() {
|
|
|
|
return State == IES_RBRAC || State == IES_INTEGER;
|
|
|
|
}
|
2013-04-18 05:01:45 +08:00
|
|
|
bool hadError() { return State == IES_ERROR; }
|
2017-08-24 16:46:25 +08:00
|
|
|
InlineAsmIdentifierInfo &getIdentifierInfo() { return Info; }
|
2013-04-23 03:42:15 +08:00
|
|
|
|
2014-01-16 03:05:24 +08:00
|
|
|
void onOr() {
|
|
|
|
IntelExprState CurrState = State;
|
|
|
|
switch (State) {
|
|
|
|
default:
|
|
|
|
State = IES_ERROR;
|
|
|
|
break;
|
|
|
|
case IES_INTEGER:
|
|
|
|
case IES_RPAREN:
|
|
|
|
case IES_REGISTER:
|
|
|
|
State = IES_OR;
|
|
|
|
IC.pushOperator(IC_OR);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
PrevState = CurrState;
|
|
|
|
}
|
2015-06-14 20:59:45 +08:00
|
|
|
void onXor() {
|
|
|
|
IntelExprState CurrState = State;
|
|
|
|
switch (State) {
|
|
|
|
default:
|
|
|
|
State = IES_ERROR;
|
|
|
|
break;
|
|
|
|
case IES_INTEGER:
|
|
|
|
case IES_RPAREN:
|
|
|
|
case IES_REGISTER:
|
|
|
|
State = IES_XOR;
|
|
|
|
IC.pushOperator(IC_XOR);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
PrevState = CurrState;
|
|
|
|
}
|
2014-01-16 03:05:24 +08:00
|
|
|
void onAnd() {
|
|
|
|
IntelExprState CurrState = State;
|
|
|
|
switch (State) {
|
|
|
|
default:
|
|
|
|
State = IES_ERROR;
|
|
|
|
break;
|
|
|
|
case IES_INTEGER:
|
|
|
|
case IES_RPAREN:
|
|
|
|
case IES_REGISTER:
|
|
|
|
State = IES_AND;
|
|
|
|
IC.pushOperator(IC_AND);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
PrevState = CurrState;
|
|
|
|
}
|
2014-02-06 09:21:15 +08:00
|
|
|
void onLShift() {
|
|
|
|
IntelExprState CurrState = State;
|
|
|
|
switch (State) {
|
|
|
|
default:
|
|
|
|
State = IES_ERROR;
|
|
|
|
break;
|
|
|
|
case IES_INTEGER:
|
|
|
|
case IES_RPAREN:
|
|
|
|
case IES_REGISTER:
|
|
|
|
State = IES_LSHIFT;
|
|
|
|
IC.pushOperator(IC_LSHIFT);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
PrevState = CurrState;
|
|
|
|
}
|
|
|
|
void onRShift() {
|
|
|
|
IntelExprState CurrState = State;
|
|
|
|
switch (State) {
|
|
|
|
default:
|
|
|
|
State = IES_ERROR;
|
|
|
|
break;
|
|
|
|
case IES_INTEGER:
|
|
|
|
case IES_RPAREN:
|
|
|
|
case IES_REGISTER:
|
|
|
|
State = IES_RSHIFT;
|
|
|
|
IC.pushOperator(IC_RSHIFT);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
PrevState = CurrState;
|
|
|
|
}
|
2017-07-25 21:05:12 +08:00
|
|
|
bool onPlus(StringRef &ErrMsg) {
|
2013-04-18 05:01:45 +08:00
|
|
|
IntelExprState CurrState = State;
|
2013-04-17 02:15:40 +08:00
|
|
|
switch (State) {
|
|
|
|
default:
|
|
|
|
State = IES_ERROR;
|
|
|
|
break;
|
|
|
|
case IES_INTEGER:
|
|
|
|
case IES_RPAREN:
|
|
|
|
case IES_REGISTER:
|
|
|
|
State = IES_PLUS;
|
|
|
|
IC.pushOperator(IC_PLUS);
|
2013-04-18 05:01:45 +08:00
|
|
|
if (CurrState == IES_REGISTER && PrevState != IES_MULTIPLY) {
|
|
|
|
// If we already have a BaseReg, then assume this is the IndexReg with
|
|
|
|
// a scale of 1.
|
|
|
|
if (!BaseReg) {
|
|
|
|
BaseReg = TmpReg;
|
|
|
|
} else {
|
2017-07-25 21:05:12 +08:00
|
|
|
if (IndexReg) {
|
|
|
|
ErrMsg = "BaseReg/IndexReg already set!";
|
|
|
|
return true;
|
|
|
|
}
|
2013-04-18 05:01:45 +08:00
|
|
|
IndexReg = TmpReg;
|
|
|
|
Scale = 1;
|
|
|
|
}
|
|
|
|
}
|
2013-04-17 02:15:40 +08:00
|
|
|
break;
|
|
|
|
}
|
2013-04-18 05:01:45 +08:00
|
|
|
PrevState = CurrState;
|
2017-07-25 21:05:12 +08:00
|
|
|
return false;
|
2013-04-17 02:15:40 +08:00
|
|
|
}
|
2017-07-25 21:05:12 +08:00
|
|
|
bool onMinus(StringRef &ErrMsg) {
|
2013-04-18 05:01:45 +08:00
|
|
|
IntelExprState CurrState = State;
|
2013-04-17 02:15:40 +08:00
|
|
|
switch (State) {
|
|
|
|
default:
|
|
|
|
State = IES_ERROR;
|
|
|
|
break;
|
2017-06-28 00:58:27 +08:00
|
|
|
case IES_OR:
|
|
|
|
case IES_XOR:
|
|
|
|
case IES_AND:
|
|
|
|
case IES_LSHIFT:
|
|
|
|
case IES_RSHIFT:
|
2013-04-17 02:15:40 +08:00
|
|
|
case IES_PLUS:
|
2014-07-05 03:13:05 +08:00
|
|
|
case IES_NOT:
|
2013-04-18 05:01:45 +08:00
|
|
|
case IES_MULTIPLY:
|
|
|
|
case IES_DIVIDE:
|
2017-06-28 00:58:27 +08:00
|
|
|
case IES_MOD:
|
2013-04-17 02:15:40 +08:00
|
|
|
case IES_LPAREN:
|
|
|
|
case IES_RPAREN:
|
2013-04-18 05:01:45 +08:00
|
|
|
case IES_LBRAC:
|
|
|
|
case IES_RBRAC:
|
|
|
|
case IES_INTEGER:
|
2013-04-17 02:15:40 +08:00
|
|
|
case IES_REGISTER:
|
2017-08-24 16:46:25 +08:00
|
|
|
case IES_INIT:
|
2013-04-17 02:15:40 +08:00
|
|
|
State = IES_MINUS;
|
2017-06-28 00:58:27 +08:00
|
|
|
// push minus operator if it is not a negate operator
|
|
|
|
if (CurrState == IES_REGISTER || CurrState == IES_RPAREN ||
|
|
|
|
CurrState == IES_INTEGER || CurrState == IES_RBRAC)
|
2013-04-18 05:01:45 +08:00
|
|
|
IC.pushOperator(IC_MINUS);
|
2017-07-25 21:05:12 +08:00
|
|
|
else if (PrevState == IES_REGISTER && CurrState == IES_MULTIPLY) {
|
|
|
|
// We have negate operator for Scale: it's illegal
|
|
|
|
ErrMsg = "Scale can't be negative";
|
|
|
|
return true;
|
|
|
|
} else
|
2017-06-28 00:58:27 +08:00
|
|
|
IC.pushOperator(IC_NEG);
|
2013-04-18 05:01:45 +08:00
|
|
|
if (CurrState == IES_REGISTER && PrevState != IES_MULTIPLY) {
|
|
|
|
// If we already have a BaseReg, then assume this is the IndexReg with
|
|
|
|
// a scale of 1.
|
|
|
|
if (!BaseReg) {
|
|
|
|
BaseReg = TmpReg;
|
|
|
|
} else {
|
2017-07-25 21:05:12 +08:00
|
|
|
if (IndexReg) {
|
|
|
|
ErrMsg = "BaseReg/IndexReg already set!";
|
|
|
|
return true;
|
|
|
|
}
|
2013-04-18 05:01:45 +08:00
|
|
|
IndexReg = TmpReg;
|
|
|
|
Scale = 1;
|
|
|
|
}
|
2013-04-17 02:15:40 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2013-04-18 05:01:45 +08:00
|
|
|
PrevState = CurrState;
|
2017-07-25 21:05:12 +08:00
|
|
|
return false;
|
2013-04-17 02:15:40 +08:00
|
|
|
}
|
2014-07-05 03:13:05 +08:00
|
|
|
void onNot() {
|
|
|
|
IntelExprState CurrState = State;
|
|
|
|
switch (State) {
|
|
|
|
default:
|
|
|
|
State = IES_ERROR;
|
|
|
|
break;
|
2017-06-28 00:58:27 +08:00
|
|
|
case IES_OR:
|
|
|
|
case IES_XOR:
|
|
|
|
case IES_AND:
|
|
|
|
case IES_LSHIFT:
|
|
|
|
case IES_RSHIFT:
|
2014-07-05 03:13:05 +08:00
|
|
|
case IES_PLUS:
|
2017-06-28 00:58:27 +08:00
|
|
|
case IES_MINUS:
|
2014-07-05 03:13:05 +08:00
|
|
|
case IES_NOT:
|
2017-06-28 00:58:27 +08:00
|
|
|
case IES_MULTIPLY:
|
|
|
|
case IES_DIVIDE:
|
|
|
|
case IES_MOD:
|
|
|
|
case IES_LPAREN:
|
|
|
|
case IES_LBRAC:
|
2017-08-24 16:46:25 +08:00
|
|
|
case IES_INIT:
|
2014-07-05 03:13:05 +08:00
|
|
|
State = IES_NOT;
|
2017-06-28 00:58:27 +08:00
|
|
|
IC.pushOperator(IC_NOT);
|
2014-07-05 03:13:05 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
PrevState = CurrState;
|
|
|
|
}
|
2017-07-25 21:05:12 +08:00
|
|
|
|
|
|
|
bool onRegister(unsigned Reg, StringRef &ErrMsg) {
|
2013-04-18 05:01:45 +08:00
|
|
|
IntelExprState CurrState = State;
|
2013-04-17 02:15:40 +08:00
|
|
|
switch (State) {
|
|
|
|
default:
|
|
|
|
State = IES_ERROR;
|
|
|
|
break;
|
|
|
|
case IES_PLUS:
|
|
|
|
case IES_LPAREN:
|
2017-08-24 16:46:25 +08:00
|
|
|
case IES_LBRAC:
|
2013-04-17 02:15:40 +08:00
|
|
|
State = IES_REGISTER;
|
|
|
|
TmpReg = Reg;
|
|
|
|
IC.pushOperand(IC_REGISTER);
|
|
|
|
break;
|
2013-04-18 05:01:45 +08:00
|
|
|
case IES_MULTIPLY:
|
|
|
|
// Index Register - Scale * Register
|
|
|
|
if (PrevState == IES_INTEGER) {
|
2017-07-25 21:05:12 +08:00
|
|
|
if (IndexReg) {
|
|
|
|
ErrMsg = "BaseReg/IndexReg already set!";
|
|
|
|
return true;
|
|
|
|
}
|
2013-04-18 05:01:45 +08:00
|
|
|
State = IES_REGISTER;
|
|
|
|
IndexReg = Reg;
|
|
|
|
// Get the scale and replace the 'Scale * Register' with '0'.
|
|
|
|
Scale = IC.popOperand();
|
2017-07-25 21:05:12 +08:00
|
|
|
if (checkScale(Scale, ErrMsg))
|
|
|
|
return true;
|
2013-04-18 05:01:45 +08:00
|
|
|
IC.pushOperand(IC_IMM);
|
|
|
|
IC.popOperator();
|
|
|
|
} else {
|
|
|
|
State = IES_ERROR;
|
|
|
|
}
|
2013-04-17 02:15:40 +08:00
|
|
|
break;
|
|
|
|
}
|
2013-04-18 05:01:45 +08:00
|
|
|
PrevState = CurrState;
|
2017-07-25 21:05:12 +08:00
|
|
|
return false;
|
2013-04-17 02:15:40 +08:00
|
|
|
}
|
2017-08-24 16:46:25 +08:00
|
|
|
bool onIdentifierExpr(const MCExpr *SymRef, StringRef SymRefName,
|
2017-09-29 15:02:46 +08:00
|
|
|
const InlineAsmIdentifierInfo &IDInfo,
|
|
|
|
bool ParsingInlineAsm, StringRef &ErrMsg) {
|
|
|
|
// InlineAsm: Treat an enum value as an integer
|
|
|
|
if (ParsingInlineAsm)
|
|
|
|
if (IDInfo.isKind(InlineAsmIdentifierInfo::IK_EnumVal))
|
|
|
|
return onInteger(IDInfo.Enum.EnumVal, ErrMsg);
|
|
|
|
// Treat a symbolic constant like an integer
|
|
|
|
if (auto *CE = dyn_cast<MCConstantExpr>(SymRef))
|
|
|
|
return onInteger(CE->getValue(), ErrMsg);
|
2013-04-19 00:28:19 +08:00
|
|
|
PrevState = State;
|
2017-08-24 16:46:25 +08:00
|
|
|
bool HasSymbol = Sym != nullptr;
|
2013-04-17 02:15:40 +08:00
|
|
|
switch (State) {
|
|
|
|
default:
|
|
|
|
State = IES_ERROR;
|
|
|
|
break;
|
|
|
|
case IES_PLUS:
|
|
|
|
case IES_MINUS:
|
2014-07-05 03:13:05 +08:00
|
|
|
case IES_NOT:
|
2017-08-24 16:46:25 +08:00
|
|
|
case IES_INIT:
|
|
|
|
case IES_LBRAC:
|
2017-09-29 15:02:46 +08:00
|
|
|
MemExpr = true;
|
2013-04-17 02:15:40 +08:00
|
|
|
State = IES_INTEGER;
|
|
|
|
Sym = SymRef;
|
|
|
|
SymName = SymRefName;
|
|
|
|
IC.pushOperand(IC_IMM);
|
2017-09-29 15:02:46 +08:00
|
|
|
if (ParsingInlineAsm)
|
|
|
|
Info = IDInfo;
|
2013-04-17 02:15:40 +08:00
|
|
|
break;
|
|
|
|
}
|
2017-08-24 16:46:25 +08:00
|
|
|
if (HasSymbol)
|
|
|
|
ErrMsg = "cannot use more than one symbol in memory operand";
|
|
|
|
return HasSymbol;
|
2013-04-17 02:15:40 +08:00
|
|
|
}
|
2014-01-24 05:52:41 +08:00
|
|
|
bool onInteger(int64_t TmpInt, StringRef &ErrMsg) {
|
2013-04-18 05:01:45 +08:00
|
|
|
IntelExprState CurrState = State;
|
2013-04-17 02:15:40 +08:00
|
|
|
switch (State) {
|
|
|
|
default:
|
|
|
|
State = IES_ERROR;
|
|
|
|
break;
|
|
|
|
case IES_PLUS:
|
|
|
|
case IES_MINUS:
|
2014-07-05 03:13:05 +08:00
|
|
|
case IES_NOT:
|
2014-01-16 03:05:24 +08:00
|
|
|
case IES_OR:
|
2015-06-14 20:59:45 +08:00
|
|
|
case IES_XOR:
|
2014-01-16 03:05:24 +08:00
|
|
|
case IES_AND:
|
2014-02-06 09:21:15 +08:00
|
|
|
case IES_LSHIFT:
|
|
|
|
case IES_RSHIFT:
|
2013-04-17 02:15:40 +08:00
|
|
|
case IES_DIVIDE:
|
2017-06-28 00:58:27 +08:00
|
|
|
case IES_MOD:
|
2013-04-18 05:01:45 +08:00
|
|
|
case IES_MULTIPLY:
|
2013-04-17 02:15:40 +08:00
|
|
|
case IES_LPAREN:
|
2017-08-24 16:46:25 +08:00
|
|
|
case IES_INIT:
|
|
|
|
case IES_LBRAC:
|
2013-04-17 02:15:40 +08:00
|
|
|
State = IES_INTEGER;
|
2013-04-18 05:01:45 +08:00
|
|
|
if (PrevState == IES_REGISTER && CurrState == IES_MULTIPLY) {
|
|
|
|
// Index Register - Register * Scale
|
2017-07-25 21:05:12 +08:00
|
|
|
if (IndexReg) {
|
|
|
|
ErrMsg = "BaseReg/IndexReg already set!";
|
|
|
|
return true;
|
|
|
|
}
|
2013-04-18 05:01:45 +08:00
|
|
|
IndexReg = TmpReg;
|
|
|
|
Scale = TmpInt;
|
2017-07-25 21:05:12 +08:00
|
|
|
if (checkScale(Scale, ErrMsg))
|
2014-01-24 05:52:41 +08:00
|
|
|
return true;
|
2013-04-18 05:01:45 +08:00
|
|
|
// Get the scale and replace the 'Register * Scale' with '0'.
|
|
|
|
IC.popOperator();
|
|
|
|
} else {
|
|
|
|
IC.pushOperand(IC_IMM, TmpInt);
|
|
|
|
}
|
2013-04-17 02:15:40 +08:00
|
|
|
break;
|
|
|
|
}
|
2013-04-18 05:01:45 +08:00
|
|
|
PrevState = CurrState;
|
2014-01-24 05:52:41 +08:00
|
|
|
return false;
|
2013-04-17 02:15:40 +08:00
|
|
|
}
|
|
|
|
void onStar() {
|
2013-04-19 00:28:19 +08:00
|
|
|
PrevState = State;
|
2013-04-17 02:15:40 +08:00
|
|
|
switch (State) {
|
|
|
|
default:
|
|
|
|
State = IES_ERROR;
|
|
|
|
break;
|
|
|
|
case IES_INTEGER:
|
|
|
|
case IES_REGISTER:
|
|
|
|
case IES_RPAREN:
|
|
|
|
State = IES_MULTIPLY;
|
|
|
|
IC.pushOperator(IC_MULTIPLY);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void onDivide() {
|
2013-04-19 00:28:19 +08:00
|
|
|
PrevState = State;
|
2013-04-17 02:15:40 +08:00
|
|
|
switch (State) {
|
|
|
|
default:
|
|
|
|
State = IES_ERROR;
|
|
|
|
break;
|
|
|
|
case IES_INTEGER:
|
2013-04-18 05:01:45 +08:00
|
|
|
case IES_RPAREN:
|
2013-04-17 02:15:40 +08:00
|
|
|
State = IES_DIVIDE;
|
|
|
|
IC.pushOperator(IC_DIVIDE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2017-06-28 00:58:27 +08:00
|
|
|
void onMod() {
|
|
|
|
PrevState = State;
|
|
|
|
switch (State) {
|
|
|
|
default:
|
|
|
|
State = IES_ERROR;
|
|
|
|
break;
|
|
|
|
case IES_INTEGER:
|
|
|
|
case IES_RPAREN:
|
|
|
|
State = IES_MOD;
|
|
|
|
IC.pushOperator(IC_MOD);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2017-08-24 16:46:25 +08:00
|
|
|
bool onLBrac() {
|
|
|
|
if (BracCount)
|
|
|
|
return true;
|
2013-04-19 00:28:19 +08:00
|
|
|
PrevState = State;
|
2013-04-17 02:15:40 +08:00
|
|
|
switch (State) {
|
|
|
|
default:
|
|
|
|
State = IES_ERROR;
|
|
|
|
break;
|
|
|
|
case IES_RBRAC:
|
2017-08-24 16:46:25 +08:00
|
|
|
case IES_INTEGER:
|
|
|
|
case IES_RPAREN:
|
2013-04-17 02:15:40 +08:00
|
|
|
State = IES_PLUS;
|
|
|
|
IC.pushOperator(IC_PLUS);
|
|
|
|
break;
|
2017-08-24 16:46:25 +08:00
|
|
|
case IES_INIT:
|
|
|
|
assert(!BracCount && "BracCount should be zero on parsing's start");
|
|
|
|
State = IES_LBRAC;
|
|
|
|
break;
|
2013-04-17 02:15:40 +08:00
|
|
|
}
|
2017-08-24 16:46:25 +08:00
|
|
|
MemExpr = true;
|
|
|
|
BracCount++;
|
|
|
|
return false;
|
2013-04-17 02:15:40 +08:00
|
|
|
}
|
2017-08-24 16:46:25 +08:00
|
|
|
bool onRBrac() {
|
2013-04-18 05:01:45 +08:00
|
|
|
IntelExprState CurrState = State;
|
2013-04-17 02:15:40 +08:00
|
|
|
switch (State) {
|
|
|
|
default:
|
|
|
|
State = IES_ERROR;
|
|
|
|
break;
|
|
|
|
case IES_INTEGER:
|
|
|
|
case IES_REGISTER:
|
2013-04-18 05:01:45 +08:00
|
|
|
case IES_RPAREN:
|
2017-08-24 16:46:25 +08:00
|
|
|
if (BracCount-- != 1)
|
|
|
|
return true;
|
2013-04-17 02:15:40 +08:00
|
|
|
State = IES_RBRAC;
|
2013-04-18 05:01:45 +08:00
|
|
|
if (CurrState == IES_REGISTER && PrevState != IES_MULTIPLY) {
|
|
|
|
// If we already have a BaseReg, then assume this is the IndexReg with
|
|
|
|
// a scale of 1.
|
|
|
|
if (!BaseReg) {
|
|
|
|
BaseReg = TmpReg;
|
|
|
|
} else {
|
|
|
|
assert (!IndexReg && "BaseReg/IndexReg already set!");
|
|
|
|
IndexReg = TmpReg;
|
|
|
|
Scale = 1;
|
|
|
|
}
|
2013-04-17 02:15:40 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2013-04-18 05:01:45 +08:00
|
|
|
PrevState = CurrState;
|
2017-08-24 16:46:25 +08:00
|
|
|
return false;
|
2013-04-17 02:15:40 +08:00
|
|
|
}
|
|
|
|
void onLParen() {
|
2013-04-18 05:01:45 +08:00
|
|
|
IntelExprState CurrState = State;
|
2013-04-17 02:15:40 +08:00
|
|
|
switch (State) {
|
|
|
|
default:
|
|
|
|
State = IES_ERROR;
|
|
|
|
break;
|
|
|
|
case IES_PLUS:
|
|
|
|
case IES_MINUS:
|
2014-07-05 03:13:05 +08:00
|
|
|
case IES_NOT:
|
2014-01-16 03:05:24 +08:00
|
|
|
case IES_OR:
|
2015-06-14 20:59:45 +08:00
|
|
|
case IES_XOR:
|
2014-01-16 03:05:24 +08:00
|
|
|
case IES_AND:
|
2014-02-06 09:21:15 +08:00
|
|
|
case IES_LSHIFT:
|
|
|
|
case IES_RSHIFT:
|
2013-04-17 02:15:40 +08:00
|
|
|
case IES_MULTIPLY:
|
|
|
|
case IES_DIVIDE:
|
2017-06-28 00:58:27 +08:00
|
|
|
case IES_MOD:
|
2013-04-17 02:15:40 +08:00
|
|
|
case IES_LPAREN:
|
2017-08-24 16:46:25 +08:00
|
|
|
case IES_INIT:
|
|
|
|
case IES_LBRAC:
|
2013-04-17 02:15:40 +08:00
|
|
|
State = IES_LPAREN;
|
|
|
|
IC.pushOperator(IC_LPAREN);
|
|
|
|
break;
|
|
|
|
}
|
2013-04-18 05:01:45 +08:00
|
|
|
PrevState = CurrState;
|
2013-04-17 02:15:40 +08:00
|
|
|
}
|
|
|
|
void onRParen() {
|
2013-04-19 00:28:19 +08:00
|
|
|
PrevState = State;
|
2013-04-17 02:15:40 +08:00
|
|
|
switch (State) {
|
|
|
|
default:
|
|
|
|
State = IES_ERROR;
|
|
|
|
break;
|
|
|
|
case IES_INTEGER:
|
2013-04-18 05:01:45 +08:00
|
|
|
case IES_REGISTER:
|
2013-04-17 02:15:40 +08:00
|
|
|
case IES_RPAREN:
|
|
|
|
State = IES_RPAREN;
|
|
|
|
IC.pushOperator(IC_RPAREN);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-09-17 02:30:20 +08:00
|
|
|
bool Error(SMLoc L, const Twine &Msg, SMRange Range = None,
|
2012-10-13 07:09:25 +08:00
|
|
|
bool MatchingInlineAsm = false) {
|
2014-11-11 13:18:41 +08:00
|
|
|
MCAsmParser &Parser = getParser();
|
2016-09-17 02:30:20 +08:00
|
|
|
if (MatchingInlineAsm) {
|
|
|
|
if (!getLexer().isAtStartOfStatement())
|
|
|
|
Parser.eatToEndOfStatement();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return Parser.Error(L, Msg, Range);
|
2014-02-20 14:34:39 +08:00
|
|
|
}
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
std::nullptr_t ErrorOperand(SMLoc Loc, StringRef Msg) {
|
2012-01-18 02:00:18 +08:00
|
|
|
Error(Loc, Msg);
|
2014-04-25 13:30:21 +08:00
|
|
|
return nullptr;
|
2012-01-18 02:00:18 +08:00
|
|
|
}
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
std::unique_ptr<X86Operand> DefaultMemSIOperand(SMLoc Loc);
|
|
|
|
std::unique_ptr<X86Operand> DefaultMemDIOperand(SMLoc Loc);
|
2016-01-19 23:37:56 +08:00
|
|
|
bool IsSIReg(unsigned Reg);
|
|
|
|
unsigned GetSIDIForRegClass(unsigned RegClassID, unsigned Reg, bool IsSIReg);
|
|
|
|
void
|
|
|
|
AddDefaultSrcDestOperands(OperandVector &Operands,
|
|
|
|
std::unique_ptr<llvm::MCParsedAsmOperand> &&Src,
|
|
|
|
std::unique_ptr<llvm::MCParsedAsmOperand> &&Dst);
|
|
|
|
bool VerifyAndAdjustOperands(OperandVector &OrigOperands,
|
|
|
|
OperandVector &FinalOperands);
|
2014-06-09 00:18:35 +08:00
|
|
|
std::unique_ptr<X86Operand> ParseOperand();
|
|
|
|
std::unique_ptr<X86Operand> ParseATTOperand();
|
|
|
|
std::unique_ptr<X86Operand> ParseIntelOperand();
|
|
|
|
std::unique_ptr<X86Operand> ParseIntelOffsetOfOperator();
|
2017-08-24 16:46:25 +08:00
|
|
|
bool ParseIntelDotOperator(IntelExprStateMachine &SM, SMLoc &End);
|
|
|
|
unsigned IdentifyIntelInlineAsmOperator(StringRef Name);
|
|
|
|
unsigned ParseIntelInlineAsmOperator(unsigned OpKind);
|
2018-01-06 14:41:07 +08:00
|
|
|
std::unique_ptr<X86Operand> ParseRoundingModeOp(SMLoc Start);
|
2017-04-04 22:43:23 +08:00
|
|
|
bool ParseIntelNamedOperator(StringRef Name, IntelExprStateMachine &SM);
|
2017-08-24 16:46:25 +08:00
|
|
|
void RewriteIntelExpression(IntelExprStateMachine &SM, SMLoc Start,
|
|
|
|
SMLoc End);
|
2013-12-01 19:47:42 +08:00
|
|
|
bool ParseIntelExpression(IntelExprStateMachine &SM, SMLoc &End);
|
2017-08-24 16:46:25 +08:00
|
|
|
bool ParseIntelInlineAsmIdentifier(const MCExpr *&Val, StringRef &Identifier,
|
|
|
|
InlineAsmIdentifierInfo &Info,
|
|
|
|
bool IsUnevaluatedOperand, SMLoc &End);
|
2013-04-23 03:42:15 +08:00
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
std::unique_ptr<X86Operand> ParseMemOperand(unsigned SegReg, SMLoc StartLoc);
|
2009-09-11 04:51:44 +08:00
|
|
|
|
2017-08-24 16:46:25 +08:00
|
|
|
bool ParseIntelMemoryOperandSize(unsigned &Size);
|
2014-06-09 00:18:35 +08:00
|
|
|
std::unique_ptr<X86Operand>
|
|
|
|
CreateMemForInlineAsm(unsigned SegReg, const MCExpr *Disp, unsigned BaseReg,
|
|
|
|
unsigned IndexReg, unsigned Scale, SMLoc Start,
|
|
|
|
SMLoc End, unsigned Size, StringRef Identifier,
|
2017-09-10 20:21:24 +08:00
|
|
|
const InlineAsmIdentifierInfo &Info);
|
2013-03-20 05:11:56 +08:00
|
|
|
|
2015-12-14 01:07:23 +08:00
|
|
|
bool parseDirectiveEven(SMLoc L);
|
2009-09-11 04:51:44 +08:00
|
|
|
bool ParseDirectiveWord(unsigned Size, SMLoc L);
|
2011-07-27 08:38:12 +08:00
|
|
|
bool ParseDirectiveCode(StringRef IDVal, SMLoc L);
|
2009-09-11 04:51:44 +08:00
|
|
|
|
[codeview] Implement FPO data assembler directives
Summary:
This adds a set of new directives that describe 32-bit x86 prologues.
The directives are limited and do not expose the full complexity of
codeview FPO data. They are merely a convenience for the compiler to
generate more readable assembly so we don't need to generate tons of
labels in CodeGen. If our prologue emission changes in the future, we
can change the set of available directives to suit our needs. These are
modelled after the .seh_ directives, which use a different format that
interacts with exception handling.
The directives are:
.cv_fpo_proc _foo
.cv_fpo_pushreg ebp/ebx/etc
.cv_fpo_setframe ebp/esi/etc
.cv_fpo_stackalloc 200
.cv_fpo_endprologue
.cv_fpo_endproc
.cv_fpo_data _foo
I tried to follow the implementation of ARM EHABI CFI directives by
sinking most directives out of MCStreamer and into X86TargetStreamer.
This helps avoid polluting non-X86 code with WinCOFF specific logic.
I used cdb to confirm that this can show locals in parent CSRs in a few
cases, most importantly the one where we use ESI as a frame pointer,
i.e. the one in http://crbug.com/756153#c28
Once we have cdb integration in debuginfo-tests, we can add integration
tests there.
Reviewers: majnemer, hans
Subscribers: aemerson, mgorny, kristof.beyls, llvm-commits, hiraditya
Differential Revision: https://reviews.llvm.org/D38776
llvm-svn: 315513
2017-10-12 05:24:33 +08:00
|
|
|
/// CodeView FPO data directives.
|
|
|
|
bool parseDirectiveFPOProc(SMLoc L);
|
|
|
|
bool parseDirectiveFPOSetFrame(SMLoc L);
|
|
|
|
bool parseDirectiveFPOPushReg(SMLoc L);
|
|
|
|
bool parseDirectiveFPOStackAlloc(SMLoc L);
|
|
|
|
bool parseDirectiveFPOEndPrologue(SMLoc L);
|
|
|
|
bool parseDirectiveFPOEndProc(SMLoc L);
|
|
|
|
bool parseDirectiveFPOData(SMLoc L);
|
|
|
|
|
2017-10-27 05:03:54 +08:00
|
|
|
bool validateInstruction(MCInst &Inst, const OperandVector &Ops);
|
2014-06-09 00:18:35 +08:00
|
|
|
bool processInstruction(MCInst &Inst, const OperandVector &Ops);
|
2012-01-19 06:42:29 +08:00
|
|
|
|
2014-03-14 16:58:04 +08:00
|
|
|
/// Wrapper around MCStreamer::EmitInstruction(). Possibly adds
|
|
|
|
/// instrumentation around Inst.
|
2014-06-09 00:18:35 +08:00
|
|
|
void EmitInstruction(MCInst &Inst, OperandVector &Operands, MCStreamer &Out);
|
2014-03-14 16:58:04 +08:00
|
|
|
|
2012-10-13 08:26:04 +08:00
|
|
|
bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
2014-06-09 00:18:35 +08:00
|
|
|
OperandVector &Operands, MCStreamer &Out,
|
2014-08-18 19:49:42 +08:00
|
|
|
uint64_t &ErrorInfo,
|
2014-03-10 02:03:14 +08:00
|
|
|
bool MatchingInlineAsm) override;
|
2012-08-10 06:04:55 +08:00
|
|
|
|
2014-08-27 04:32:34 +08:00
|
|
|
void MatchFPUWaitAlias(SMLoc IDLoc, X86Operand &Op, OperandVector &Operands,
|
|
|
|
MCStreamer &Out, bool MatchingInlineAsm);
|
|
|
|
|
2015-06-30 20:32:53 +08:00
|
|
|
bool ErrorMissingFeature(SMLoc IDLoc, uint64_t ErrorInfo,
|
2014-08-27 04:32:34 +08:00
|
|
|
bool MatchingInlineAsm);
|
|
|
|
|
|
|
|
bool MatchAndEmitATTInstruction(SMLoc IDLoc, unsigned &Opcode,
|
|
|
|
OperandVector &Operands, MCStreamer &Out,
|
|
|
|
uint64_t &ErrorInfo,
|
|
|
|
bool MatchingInlineAsm);
|
|
|
|
|
|
|
|
bool MatchAndEmitIntelInstruction(SMLoc IDLoc, unsigned &Opcode,
|
|
|
|
OperandVector &Operands, MCStreamer &Out,
|
|
|
|
uint64_t &ErrorInfo,
|
|
|
|
bool MatchingInlineAsm);
|
|
|
|
|
2014-08-31 00:48:34 +08:00
|
|
|
bool OmitRegisterFromClobberLists(unsigned RegNo) override;
|
2014-07-18 04:24:55 +08:00
|
|
|
|
2014-02-20 14:34:39 +08:00
|
|
|
/// Parses AVX512 specific operand primitives: masked registers ({%k<NUM>}, {z})
|
|
|
|
/// and memory broadcasting ({1to<NUM>}) primitives, updating Operands vector if required.
|
2016-10-18 21:52:39 +08:00
|
|
|
/// return false if no parsing errors occurred, true otherwise.
|
2014-06-09 00:18:35 +08:00
|
|
|
bool HandleAVX512Operand(OperandVector &Operands,
|
|
|
|
const MCParsedAsmOperand &Op);
|
2014-02-20 14:34:39 +08:00
|
|
|
|
2016-10-18 21:52:39 +08:00
|
|
|
bool ParseZ(std::unique_ptr<X86Operand> &Z, const SMLoc &StartLoc);
|
|
|
|
|
2011-07-11 11:57:24 +08:00
|
|
|
bool is64BitMode() const {
|
2011-07-08 09:53:10 +08:00
|
|
|
// FIXME: Can tablegen auto-generate this?
|
2015-11-14 13:20:05 +08:00
|
|
|
return getSTI().getFeatureBits()[X86::Mode64Bit];
|
2011-07-08 09:53:10 +08:00
|
|
|
}
|
2014-01-06 12:55:54 +08:00
|
|
|
bool is32BitMode() const {
|
|
|
|
// FIXME: Can tablegen auto-generate this?
|
2015-11-14 13:20:05 +08:00
|
|
|
return getSTI().getFeatureBits()[X86::Mode32Bit];
|
2014-01-06 12:55:54 +08:00
|
|
|
}
|
|
|
|
bool is16BitMode() const {
|
|
|
|
// FIXME: Can tablegen auto-generate this?
|
2015-11-14 13:20:05 +08:00
|
|
|
return getSTI().getFeatureBits()[X86::Mode16Bit];
|
2014-01-06 12:55:54 +08:00
|
|
|
}
|
2015-05-26 18:47:10 +08:00
|
|
|
void SwitchMode(unsigned mode) {
|
2015-11-14 14:35:56 +08:00
|
|
|
MCSubtargetInfo &STI = copySTI();
|
2015-05-26 18:47:10 +08:00
|
|
|
FeatureBitset AllModes({X86::Mode64Bit, X86::Mode32Bit, X86::Mode16Bit});
|
|
|
|
FeatureBitset OldMode = STI.getFeatureBits() & AllModes;
|
2017-10-26 14:46:38 +08:00
|
|
|
uint64_t FB = ComputeAvailableFeatures(
|
2015-05-26 18:47:10 +08:00
|
|
|
STI.ToggleFeature(OldMode.flip(mode)));
|
2011-07-27 08:38:12 +08:00
|
|
|
setAvailableFeatures(FB);
|
2015-09-22 19:14:39 +08:00
|
|
|
|
2015-05-26 18:47:10 +08:00
|
|
|
assert(FeatureBitset({mode}) == (STI.getFeatureBits() & AllModes));
|
2011-07-27 08:38:12 +08:00
|
|
|
}
|
2011-07-08 09:53:10 +08:00
|
|
|
|
2014-08-02 04:21:24 +08:00
|
|
|
unsigned getPointerWidth() {
|
|
|
|
if (is16BitMode()) return 16;
|
|
|
|
if (is32BitMode()) return 32;
|
|
|
|
if (is64BitMode()) return 64;
|
|
|
|
llvm_unreachable("invalid mode");
|
|
|
|
}
|
|
|
|
|
2013-04-19 00:13:18 +08:00
|
|
|
bool isParsingIntelSyntax() {
|
|
|
|
return getParser().getAssemblerDialect();
|
|
|
|
}
|
|
|
|
|
2010-07-19 13:44:09 +08:00
|
|
|
/// @name Auto-generated Matcher Functions
|
|
|
|
/// {
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2010-09-07 03:11:01 +08:00
|
|
|
#define GET_ASSEMBLER_HEADER
|
|
|
|
#include "X86GenAsmMatcher.inc"
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2009-07-29 08:02:19 +08:00
|
|
|
/// }
|
2009-07-29 06:40:46 +08:00
|
|
|
|
|
|
|
public:
|
2017-03-22 03:31:55 +08:00
|
|
|
|
2015-11-14 14:35:56 +08:00
|
|
|
X86AsmParser(const MCSubtargetInfo &sti, MCAsmParser &Parser,
|
2014-11-11 13:18:41 +08:00
|
|
|
const MCInstrInfo &mii, const MCTargetOptions &Options)
|
2017-10-11 17:17:43 +08:00
|
|
|
: MCTargetAsmParser(Options, sti, mii), InstInfo(nullptr),
|
2016-09-27 03:33:36 +08:00
|
|
|
Code16GCC(false) {
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2010-07-19 13:44:09 +08:00
|
|
|
// Initialize the set of available features.
|
2015-11-14 13:20:05 +08:00
|
|
|
setAvailableFeatures(ComputeAvailableFeatures(getSTI().getFeatureBits()));
|
2014-04-23 19:16:03 +08:00
|
|
|
Instrumentation.reset(
|
|
|
|
CreateX86AsmInstrumentation(Options, Parser.getContext(), STI));
|
2010-07-19 13:44:09 +08:00
|
|
|
}
|
2014-04-23 19:16:03 +08:00
|
|
|
|
2014-03-10 02:03:14 +08:00
|
|
|
bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override;
|
2009-07-29 06:40:46 +08:00
|
|
|
|
2014-09-10 17:45:49 +08:00
|
|
|
void SetFrameRegister(unsigned RegNo) override;
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
|
|
|
|
SMLoc NameLoc, OperandVector &Operands) override;
|
2009-09-11 04:51:44 +08:00
|
|
|
|
2014-03-10 02:03:14 +08:00
|
|
|
bool ParseDirective(AsmToken DirectiveID) override;
|
2009-07-29 06:40:46 +08:00
|
|
|
};
|
2009-07-29 14:33:53 +08:00
|
|
|
} // end anonymous namespace
|
|
|
|
|
2010-01-23 08:40:33 +08:00
|
|
|
/// @name Auto-generated Match Functions
|
2010-07-24 06:15:26 +08:00
|
|
|
/// {
|
2010-01-23 08:40:33 +08:00
|
|
|
|
2010-02-09 08:34:28 +08:00
|
|
|
static unsigned MatchRegisterName(StringRef Name);
|
2010-01-23 08:40:33 +08:00
|
|
|
|
|
|
|
/// }
|
2009-07-29 14:33:53 +08:00
|
|
|
|
2017-07-25 21:05:12 +08:00
|
|
|
static bool CheckBaseRegAndIndexRegAndScale(unsigned BaseReg, unsigned IndexReg,
|
|
|
|
unsigned Scale, StringRef &ErrMsg) {
|
2014-01-24 06:34:42 +08:00
|
|
|
// If we have both a base register and an index register make sure they are
|
|
|
|
// both 64-bit or 32-bit registers.
|
|
|
|
// To support VSIB, IndexReg can be 128-bit or 256-bit registers.
|
2016-10-05 23:23:35 +08:00
|
|
|
|
|
|
|
if ((BaseReg == X86::RIP && IndexReg != 0) || (IndexReg == X86::RIP)) {
|
|
|
|
ErrMsg = "invalid base+index expression";
|
|
|
|
return true;
|
|
|
|
}
|
2014-01-24 06:34:42 +08:00
|
|
|
if (BaseReg != 0 && IndexReg != 0) {
|
|
|
|
if (X86MCRegisterClasses[X86::GR64RegClassID].contains(BaseReg) &&
|
|
|
|
(X86MCRegisterClasses[X86::GR16RegClassID].contains(IndexReg) ||
|
|
|
|
X86MCRegisterClasses[X86::GR32RegClassID].contains(IndexReg)) &&
|
|
|
|
IndexReg != X86::RIZ) {
|
|
|
|
ErrMsg = "base register is 64-bit, but index register is not";
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (X86MCRegisterClasses[X86::GR32RegClassID].contains(BaseReg) &&
|
|
|
|
(X86MCRegisterClasses[X86::GR16RegClassID].contains(IndexReg) ||
|
|
|
|
X86MCRegisterClasses[X86::GR64RegClassID].contains(IndexReg)) &&
|
|
|
|
IndexReg != X86::EIZ){
|
|
|
|
ErrMsg = "base register is 32-bit, but index register is not";
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (X86MCRegisterClasses[X86::GR16RegClassID].contains(BaseReg)) {
|
|
|
|
if (X86MCRegisterClasses[X86::GR32RegClassID].contains(IndexReg) ||
|
|
|
|
X86MCRegisterClasses[X86::GR64RegClassID].contains(IndexReg)) {
|
|
|
|
ErrMsg = "base register is 16-bit, but index register is not";
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (((BaseReg == X86::BX || BaseReg == X86::BP) &&
|
|
|
|
IndexReg != X86::SI && IndexReg != X86::DI) ||
|
|
|
|
((BaseReg == X86::SI || BaseReg == X86::DI) &&
|
|
|
|
IndexReg != X86::BX && IndexReg != X86::BP)) {
|
|
|
|
ErrMsg = "invalid 16-bit base/index register combination";
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-07-25 21:05:12 +08:00
|
|
|
return checkScale(Scale, ErrMsg);
|
2014-01-24 06:34:42 +08:00
|
|
|
}
|
|
|
|
|
2012-01-13 02:03:40 +08:00
|
|
|
bool X86AsmParser::ParseRegister(unsigned &RegNo,
|
|
|
|
SMLoc &StartLoc, SMLoc &EndLoc) {
|
2014-11-11 13:18:41 +08:00
|
|
|
MCAsmParser &Parser = getParser();
|
2010-01-16 02:27:19 +08:00
|
|
|
RegNo = 0;
|
2012-09-07 22:51:35 +08:00
|
|
|
const AsmToken &PercentTok = Parser.getTok();
|
|
|
|
StartLoc = PercentTok.getLoc();
|
|
|
|
|
|
|
|
// If we encounter a %, ignore it. This code handles registers with and
|
|
|
|
// without the prefix, unprefixed registers can occur in cfi directives.
|
|
|
|
if (!isParsingIntelSyntax() && PercentTok.is(AsmToken::Percent))
|
2012-01-18 02:00:18 +08:00
|
|
|
Parser.Lex(); // Eat percent token.
|
2009-09-04 01:15:07 +08:00
|
|
|
|
2010-01-20 05:44:56 +08:00
|
|
|
const AsmToken &Tok = Parser.getTok();
|
2013-01-08 03:00:49 +08:00
|
|
|
EndLoc = Tok.getEndLoc();
|
|
|
|
|
2012-01-21 06:32:05 +08:00
|
|
|
if (Tok.isNot(AsmToken::Identifier)) {
|
2017-07-25 04:48:15 +08:00
|
|
|
if (isParsingIntelSyntax()) return true;
|
2011-10-16 20:10:27 +08:00
|
|
|
return Error(StartLoc, "invalid register name",
|
2013-01-08 03:00:49 +08:00
|
|
|
SMRange(StartLoc, EndLoc));
|
2012-01-21 06:32:05 +08:00
|
|
|
}
|
2009-07-29 06:40:46 +08:00
|
|
|
|
2009-09-04 01:15:07 +08:00
|
|
|
RegNo = MatchRegisterName(Tok.getString());
|
2010-07-24 06:15:26 +08:00
|
|
|
|
2010-09-22 12:11:10 +08:00
|
|
|
// If the match failed, try the register name as lowercase.
|
|
|
|
if (RegNo == 0)
|
2011-11-07 04:37:06 +08:00
|
|
|
RegNo = MatchRegisterName(Tok.getString().lower());
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2015-07-30 18:10:25 +08:00
|
|
|
// The "flags" register cannot be referenced directly.
|
|
|
|
// Treat it as an identifier instead.
|
|
|
|
if (isParsingInlineAsm() && isParsingIntelSyntax() && RegNo == X86::EFLAGS)
|
|
|
|
RegNo = 0;
|
|
|
|
|
2011-07-28 07:22:03 +08:00
|
|
|
if (!is64BitMode()) {
|
2013-12-20 10:04:49 +08:00
|
|
|
// FIXME: This should be done using Requires<Not64BitMode> and
|
2011-07-28 07:22:03 +08:00
|
|
|
// Requires<In64BitMode> so "eiz" usage in 64-bit instructions can be also
|
|
|
|
// checked.
|
|
|
|
// FIXME: Check AH, CH, DH, BH cannot be used in an instruction requiring a
|
|
|
|
// REX prefix.
|
|
|
|
if (RegNo == X86::RIZ ||
|
|
|
|
X86MCRegisterClasses[X86::GR64RegClassID].contains(RegNo) ||
|
|
|
|
X86II::isX86_64NonExtLowByteReg(RegNo) ||
|
2016-08-28 01:13:37 +08:00
|
|
|
X86II::isX86_64ExtendedReg(RegNo))
|
2011-10-16 20:10:27 +08:00
|
|
|
return Error(StartLoc, "register %"
|
|
|
|
+ Tok.getString() + " is only available in 64-bit mode",
|
2013-01-08 03:00:49 +08:00
|
|
|
SMRange(StartLoc, EndLoc));
|
2011-07-28 07:22:03 +08:00
|
|
|
}
|
2010-07-24 08:06:39 +08:00
|
|
|
|
2010-09-22 12:11:10 +08:00
|
|
|
// Parse "%st" as "%st(0)" and "%st(1)", which is multiple tokens.
|
|
|
|
if (RegNo == 0 && (Tok.getString() == "st" || Tok.getString() == "ST")) {
|
2010-02-09 08:49:22 +08:00
|
|
|
RegNo = X86::ST0;
|
|
|
|
Parser.Lex(); // Eat 'st'
|
2010-07-24 06:15:26 +08:00
|
|
|
|
2010-02-09 08:49:22 +08:00
|
|
|
// Check to see if we have '(4)' after %st.
|
|
|
|
if (getLexer().isNot(AsmToken::LParen))
|
|
|
|
return false;
|
|
|
|
// Lex the paren.
|
|
|
|
getParser().Lex();
|
|
|
|
|
|
|
|
const AsmToken &IntTok = Parser.getTok();
|
|
|
|
if (IntTok.isNot(AsmToken::Integer))
|
|
|
|
return Error(IntTok.getLoc(), "expected stack index");
|
|
|
|
switch (IntTok.getIntVal()) {
|
|
|
|
case 0: RegNo = X86::ST0; break;
|
|
|
|
case 1: RegNo = X86::ST1; break;
|
|
|
|
case 2: RegNo = X86::ST2; break;
|
|
|
|
case 3: RegNo = X86::ST3; break;
|
|
|
|
case 4: RegNo = X86::ST4; break;
|
|
|
|
case 5: RegNo = X86::ST5; break;
|
|
|
|
case 6: RegNo = X86::ST6; break;
|
|
|
|
case 7: RegNo = X86::ST7; break;
|
|
|
|
default: return Error(IntTok.getLoc(), "invalid stack index");
|
|
|
|
}
|
2010-07-24 06:15:26 +08:00
|
|
|
|
2010-02-09 08:49:22 +08:00
|
|
|
if (getParser().Lex().isNot(AsmToken::RParen))
|
|
|
|
return Error(Parser.getTok().getLoc(), "expected ')'");
|
2010-07-24 06:15:26 +08:00
|
|
|
|
2013-01-08 03:00:49 +08:00
|
|
|
EndLoc = Parser.getTok().getEndLoc();
|
2010-02-09 08:49:22 +08:00
|
|
|
Parser.Lex(); // Eat ')'
|
|
|
|
return false;
|
|
|
|
}
|
2010-07-24 06:15:26 +08:00
|
|
|
|
2013-01-08 03:00:49 +08:00
|
|
|
EndLoc = Parser.getTok().getEndLoc();
|
|
|
|
|
2017-12-02 16:27:46 +08:00
|
|
|
// If this is "db[0-15]", match it as an alias
|
|
|
|
// for dr[0-15].
|
|
|
|
if (RegNo == 0 && Tok.getString().startswith("db")) {
|
|
|
|
if (Tok.getString().size() == 3) {
|
|
|
|
switch (Tok.getString()[2]) {
|
|
|
|
case '0': RegNo = X86::DR0; break;
|
|
|
|
case '1': RegNo = X86::DR1; break;
|
|
|
|
case '2': RegNo = X86::DR2; break;
|
|
|
|
case '3': RegNo = X86::DR3; break;
|
|
|
|
case '4': RegNo = X86::DR4; break;
|
|
|
|
case '5': RegNo = X86::DR5; break;
|
|
|
|
case '6': RegNo = X86::DR6; break;
|
|
|
|
case '7': RegNo = X86::DR7; break;
|
|
|
|
case '8': RegNo = X86::DR8; break;
|
|
|
|
case '9': RegNo = X86::DR9; break;
|
|
|
|
}
|
|
|
|
} else if (Tok.getString().size() == 4 && Tok.getString()[2] == '1') {
|
|
|
|
switch (Tok.getString()[3]) {
|
|
|
|
case '0': RegNo = X86::DR10; break;
|
|
|
|
case '1': RegNo = X86::DR11; break;
|
|
|
|
case '2': RegNo = X86::DR12; break;
|
|
|
|
case '3': RegNo = X86::DR13; break;
|
|
|
|
case '4': RegNo = X86::DR14; break;
|
|
|
|
case '5': RegNo = X86::DR15; break;
|
|
|
|
}
|
2010-06-24 15:29:18 +08:00
|
|
|
}
|
2010-07-24 06:15:26 +08:00
|
|
|
|
2010-06-24 15:29:18 +08:00
|
|
|
if (RegNo != 0) {
|
2013-01-08 03:00:49 +08:00
|
|
|
EndLoc = Parser.getTok().getEndLoc();
|
2010-06-24 15:29:18 +08:00
|
|
|
Parser.Lex(); // Eat it.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2010-07-24 06:15:26 +08:00
|
|
|
|
2012-01-21 06:32:05 +08:00
|
|
|
if (RegNo == 0) {
|
2012-01-31 04:02:42 +08:00
|
|
|
if (isParsingIntelSyntax()) return true;
|
2011-10-16 20:10:27 +08:00
|
|
|
return Error(StartLoc, "invalid register name",
|
2013-01-08 03:00:49 +08:00
|
|
|
SMRange(StartLoc, EndLoc));
|
2012-01-21 06:32:05 +08:00
|
|
|
}
|
2009-07-29 08:02:19 +08:00
|
|
|
|
2010-01-20 04:27:46 +08:00
|
|
|
Parser.Lex(); // Eat identifier token.
|
2009-07-29 06:40:46 +08:00
|
|
|
return false;
|
2009-07-18 04:42:00 +08:00
|
|
|
}
|
|
|
|
|
2014-09-10 17:45:49 +08:00
|
|
|
void X86AsmParser::SetFrameRegister(unsigned RegNo) {
|
2014-10-07 19:03:09 +08:00
|
|
|
Instrumentation->SetInitialFrameRegister(RegNo);
|
2014-09-10 17:45:49 +08:00
|
|
|
}
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
std::unique_ptr<X86Operand> X86AsmParser::DefaultMemSIOperand(SMLoc Loc) {
|
2016-09-27 03:33:36 +08:00
|
|
|
bool Parse32 = is32BitMode() || Code16GCC;
|
|
|
|
unsigned Basereg = is64BitMode() ? X86::RSI : (Parse32 ? X86::ESI : X86::SI);
|
2015-05-30 09:25:56 +08:00
|
|
|
const MCExpr *Disp = MCConstantExpr::create(0, getContext());
|
2015-01-02 15:02:25 +08:00
|
|
|
return X86Operand::CreateMem(getPointerWidth(), /*SegReg=*/0, Disp,
|
2016-09-27 03:33:36 +08:00
|
|
|
/*BaseReg=*/Basereg, /*IndexReg=*/0, /*Scale=*/1,
|
2015-01-02 15:02:25 +08:00
|
|
|
Loc, Loc, 0);
|
2014-01-22 23:08:08 +08:00
|
|
|
}
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
std::unique_ptr<X86Operand> X86AsmParser::DefaultMemDIOperand(SMLoc Loc) {
|
2016-09-27 03:33:36 +08:00
|
|
|
bool Parse32 = is32BitMode() || Code16GCC;
|
|
|
|
unsigned Basereg = is64BitMode() ? X86::RDI : (Parse32 ? X86::EDI : X86::DI);
|
2015-05-30 09:25:56 +08:00
|
|
|
const MCExpr *Disp = MCConstantExpr::create(0, getContext());
|
2015-01-02 15:02:25 +08:00
|
|
|
return X86Operand::CreateMem(getPointerWidth(), /*SegReg=*/0, Disp,
|
2016-09-27 03:33:36 +08:00
|
|
|
/*BaseReg=*/Basereg, /*IndexReg=*/0, /*Scale=*/1,
|
2015-01-02 15:02:25 +08:00
|
|
|
Loc, Loc, 0);
|
2014-01-22 23:08:21 +08:00
|
|
|
}
|
|
|
|
|
2016-01-19 23:37:56 +08:00
|
|
|
bool X86AsmParser::IsSIReg(unsigned Reg) {
|
|
|
|
switch (Reg) {
|
2016-02-26 13:29:39 +08:00
|
|
|
default: llvm_unreachable("Only (R|E)SI and (R|E)DI are expected!");
|
2016-01-19 23:37:56 +08:00
|
|
|
case X86::RSI:
|
|
|
|
case X86::ESI:
|
|
|
|
case X86::SI:
|
|
|
|
return true;
|
|
|
|
case X86::RDI:
|
|
|
|
case X86::EDI:
|
|
|
|
case X86::DI:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned X86AsmParser::GetSIDIForRegClass(unsigned RegClassID, unsigned Reg,
|
|
|
|
bool IsSIReg) {
|
|
|
|
switch (RegClassID) {
|
2016-02-26 13:29:39 +08:00
|
|
|
default: llvm_unreachable("Unexpected register class");
|
2016-01-19 23:37:56 +08:00
|
|
|
case X86::GR64RegClassID:
|
|
|
|
return IsSIReg ? X86::RSI : X86::RDI;
|
|
|
|
case X86::GR32RegClassID:
|
|
|
|
return IsSIReg ? X86::ESI : X86::EDI;
|
|
|
|
case X86::GR16RegClassID:
|
|
|
|
return IsSIReg ? X86::SI : X86::DI;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-23 18:23:48 +08:00
|
|
|
void X86AsmParser::AddDefaultSrcDestOperands(
|
|
|
|
OperandVector& Operands, std::unique_ptr<llvm::MCParsedAsmOperand> &&Src,
|
|
|
|
std::unique_ptr<llvm::MCParsedAsmOperand> &&Dst) {
|
|
|
|
if (isParsingIntelSyntax()) {
|
|
|
|
Operands.push_back(std::move(Dst));
|
|
|
|
Operands.push_back(std::move(Src));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Operands.push_back(std::move(Src));
|
|
|
|
Operands.push_back(std::move(Dst));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-19 23:37:56 +08:00
|
|
|
bool X86AsmParser::VerifyAndAdjustOperands(OperandVector &OrigOperands,
|
|
|
|
OperandVector &FinalOperands) {
|
|
|
|
|
|
|
|
if (OrigOperands.size() > 1) {
|
2016-02-16 15:45:07 +08:00
|
|
|
// Check if sizes match, OrigOperands also contains the instruction name
|
2016-01-19 23:37:56 +08:00
|
|
|
assert(OrigOperands.size() == FinalOperands.size() + 1 &&
|
2016-02-16 15:45:07 +08:00
|
|
|
"Operand size mismatch");
|
2016-01-19 23:37:56 +08:00
|
|
|
|
2016-01-21 19:37:06 +08:00
|
|
|
SmallVector<std::pair<SMLoc, std::string>, 2> Warnings;
|
2016-01-19 23:37:56 +08:00
|
|
|
// Verify types match
|
|
|
|
int RegClassID = -1;
|
|
|
|
for (unsigned int i = 0; i < FinalOperands.size(); ++i) {
|
|
|
|
X86Operand &OrigOp = static_cast<X86Operand &>(*OrigOperands[i + 1]);
|
|
|
|
X86Operand &FinalOp = static_cast<X86Operand &>(*FinalOperands[i]);
|
|
|
|
|
|
|
|
if (FinalOp.isReg() &&
|
|
|
|
(!OrigOp.isReg() || FinalOp.getReg() != OrigOp.getReg()))
|
|
|
|
// Return false and let a normal complaint about bogus operands happen
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (FinalOp.isMem()) {
|
|
|
|
|
|
|
|
if (!OrigOp.isMem())
|
|
|
|
// Return false and let a normal complaint about bogus operands happen
|
|
|
|
return false;
|
|
|
|
|
|
|
|
unsigned OrigReg = OrigOp.Mem.BaseReg;
|
|
|
|
unsigned FinalReg = FinalOp.Mem.BaseReg;
|
|
|
|
|
|
|
|
// If we've already encounterd a register class, make sure all register
|
|
|
|
// bases are of the same register class
|
|
|
|
if (RegClassID != -1 &&
|
|
|
|
!X86MCRegisterClasses[RegClassID].contains(OrigReg)) {
|
|
|
|
return Error(OrigOp.getStartLoc(),
|
|
|
|
"mismatching source and destination index registers");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (X86MCRegisterClasses[X86::GR64RegClassID].contains(OrigReg))
|
|
|
|
RegClassID = X86::GR64RegClassID;
|
|
|
|
else if (X86MCRegisterClasses[X86::GR32RegClassID].contains(OrigReg))
|
|
|
|
RegClassID = X86::GR32RegClassID;
|
|
|
|
else if (X86MCRegisterClasses[X86::GR16RegClassID].contains(OrigReg))
|
|
|
|
RegClassID = X86::GR16RegClassID;
|
2016-01-20 22:03:47 +08:00
|
|
|
else
|
2016-02-16 15:28:03 +08:00
|
|
|
// Unexpected register class type
|
2016-01-20 22:03:47 +08:00
|
|
|
// Return false and let a normal complaint about bogus operands happen
|
|
|
|
return false;
|
2016-01-19 23:37:56 +08:00
|
|
|
|
|
|
|
bool IsSI = IsSIReg(FinalReg);
|
|
|
|
FinalReg = GetSIDIForRegClass(RegClassID, FinalReg, IsSI);
|
|
|
|
|
|
|
|
if (FinalReg != OrigReg) {
|
|
|
|
std::string RegName = IsSI ? "ES:(R|E)SI" : "ES:(R|E)DI";
|
2016-01-21 19:37:06 +08:00
|
|
|
Warnings.push_back(std::make_pair(
|
|
|
|
OrigOp.getStartLoc(),
|
|
|
|
"memory operand is only for determining the size, " + RegName +
|
|
|
|
" will be used for the location"));
|
2016-01-19 23:37:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
FinalOp.Mem.Size = OrigOp.Mem.Size;
|
|
|
|
FinalOp.Mem.SegReg = OrigOp.Mem.SegReg;
|
|
|
|
FinalOp.Mem.BaseReg = FinalReg;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-21 19:37:06 +08:00
|
|
|
// Produce warnings only if all the operands passed the adjustment - prevent
|
|
|
|
// legal cases like "movsd (%rax), %xmm0" mistakenly produce warnings
|
2016-02-16 15:45:04 +08:00
|
|
|
for (auto &WarningMsg : Warnings) {
|
|
|
|
Warning(WarningMsg.first, WarningMsg.second);
|
2016-01-21 19:37:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Remove old operands
|
2016-01-19 23:37:56 +08:00
|
|
|
for (unsigned int i = 0; i < FinalOperands.size(); ++i)
|
|
|
|
OrigOperands.pop_back();
|
|
|
|
}
|
|
|
|
// OrigOperands.append(FinalOperands.begin(), FinalOperands.end());
|
|
|
|
for (unsigned int i = 0; i < FinalOperands.size(); ++i)
|
|
|
|
OrigOperands.push_back(std::move(FinalOperands[i]));
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
std::unique_ptr<X86Operand> X86AsmParser::ParseOperand() {
|
2012-01-31 04:02:42 +08:00
|
|
|
if (isParsingIntelSyntax())
|
2012-01-12 09:36:43 +08:00
|
|
|
return ParseIntelOperand();
|
|
|
|
return ParseATTOperand();
|
|
|
|
}
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
std::unique_ptr<X86Operand> X86AsmParser::CreateMemForInlineAsm(
|
|
|
|
unsigned SegReg, const MCExpr *Disp, unsigned BaseReg, unsigned IndexReg,
|
|
|
|
unsigned Scale, SMLoc Start, SMLoc End, unsigned Size, StringRef Identifier,
|
2017-09-10 20:21:24 +08:00
|
|
|
const InlineAsmIdentifierInfo &Info) {
|
2014-08-02 04:21:24 +08:00
|
|
|
// If we found a decl other than a VarDecl, then assume it is a FuncDecl or
|
|
|
|
// some other label reference.
|
2017-09-29 15:02:46 +08:00
|
|
|
if (Info.isKind(InlineAsmIdentifierInfo::IK_Label)) {
|
2014-08-02 04:21:24 +08:00
|
|
|
// Insert an explicit size if the user didn't have one.
|
|
|
|
if (!Size) {
|
|
|
|
Size = getPointerWidth();
|
2015-10-10 13:25:02 +08:00
|
|
|
InstInfo->AsmRewrites->emplace_back(AOK_SizeDirective, Start,
|
|
|
|
/*Len=*/0, Size);
|
2014-08-02 04:21:24 +08:00
|
|
|
}
|
|
|
|
// Create an absolute memory reference in order to match against
|
|
|
|
// instructions taking a PC relative operand.
|
2015-01-02 15:02:25 +08:00
|
|
|
return X86Operand::CreateMem(getPointerWidth(), Disp, Start, End, Size,
|
2017-09-29 15:02:46 +08:00
|
|
|
Identifier, Info.Label.Decl);
|
2014-03-04 08:33:17 +08:00
|
|
|
}
|
|
|
|
// We either have a direct symbol reference, or an offset from a symbol. The
|
|
|
|
// parser always puts the symbol on the LHS, so look there for size
|
|
|
|
// calculation purposes.
|
2017-05-05 02:19:52 +08:00
|
|
|
unsigned FrontendSize = 0;
|
2017-09-29 15:02:46 +08:00
|
|
|
void *Decl = nullptr;
|
|
|
|
bool IsGlobalLV = false;
|
|
|
|
if (Info.isKind(InlineAsmIdentifierInfo::IK_Var)) {
|
|
|
|
// Size is in terms of bits in this context.
|
|
|
|
FrontendSize = Info.Var.Type * 8;
|
|
|
|
Decl = Info.Var.Decl;
|
|
|
|
IsGlobalLV = Info.Var.IsGlobalLV;
|
|
|
|
}
|
|
|
|
// It is widely common for MS InlineAsm to use a global variable and one/two
|
|
|
|
// registers in a mmory expression, and though unaccessible via rip/eip.
|
|
|
|
if (IsGlobalLV && (BaseReg || IndexReg)) {
|
|
|
|
return X86Operand::CreateMem(getPointerWidth(), Disp, Start, End);
|
|
|
|
// Otherwise, we set the base register to a non-zero value
|
2013-04-13 02:21:18 +08:00
|
|
|
// if we don't know the actual value at this time. This is necessary to
|
2013-03-20 05:11:56 +08:00
|
|
|
// get the matching correct in some cases.
|
2017-09-29 15:02:46 +08:00
|
|
|
} else {
|
|
|
|
BaseReg = BaseReg ? BaseReg : 1;
|
|
|
|
return X86Operand::CreateMem(getPointerWidth(), SegReg, Disp, BaseReg,
|
|
|
|
IndexReg, Scale, Start, End, Size, Identifier,
|
|
|
|
Decl, FrontendSize);
|
|
|
|
}
|
2013-03-20 05:11:56 +08:00
|
|
|
}
|
|
|
|
|
2017-04-04 22:43:23 +08:00
|
|
|
// Some binary bitwise operators have a named synonymous
|
|
|
|
// Query a candidate string for being such a named operator
|
|
|
|
// and if so - invoke the appropriate handler
|
|
|
|
bool X86AsmParser::ParseIntelNamedOperator(StringRef Name, IntelExprStateMachine &SM) {
|
|
|
|
// A named operator should be either lower or upper case, but not a mix
|
|
|
|
if (Name.compare(Name.lower()) && Name.compare(Name.upper()))
|
|
|
|
return false;
|
|
|
|
if (Name.equals_lower("not"))
|
|
|
|
SM.onNot();
|
|
|
|
else if (Name.equals_lower("or"))
|
|
|
|
SM.onOr();
|
|
|
|
else if (Name.equals_lower("shl"))
|
|
|
|
SM.onLShift();
|
|
|
|
else if (Name.equals_lower("shr"))
|
|
|
|
SM.onRShift();
|
|
|
|
else if (Name.equals_lower("xor"))
|
|
|
|
SM.onXor();
|
|
|
|
else if (Name.equals_lower("and"))
|
|
|
|
SM.onAnd();
|
2017-06-28 00:58:27 +08:00
|
|
|
else if (Name.equals_lower("mod"))
|
|
|
|
SM.onMod();
|
2017-04-04 22:43:23 +08:00
|
|
|
else
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-12-01 19:47:42 +08:00
|
|
|
bool X86AsmParser::ParseIntelExpression(IntelExprStateMachine &SM, SMLoc &End) {
|
2014-11-11 13:18:41 +08:00
|
|
|
MCAsmParser &Parser = getParser();
|
2012-10-25 06:13:37 +08:00
|
|
|
const AsmToken &Tok = Parser.getTok();
|
2017-07-25 21:05:12 +08:00
|
|
|
StringRef ErrMsg;
|
2012-06-28 06:34:28 +08:00
|
|
|
|
2015-12-24 20:09:51 +08:00
|
|
|
AsmToken::TokenKind PrevTK = AsmToken::Error;
|
2013-01-15 06:31:35 +08:00
|
|
|
bool Done = false;
|
|
|
|
while (!Done) {
|
|
|
|
bool UpdateLocLex = true;
|
2017-05-26 21:23:34 +08:00
|
|
|
AsmToken::TokenKind TK = getLexer().getKind();
|
2013-01-15 06:31:35 +08:00
|
|
|
|
2014-06-19 09:25:43 +08:00
|
|
|
switch (TK) {
|
2017-08-24 16:46:25 +08:00
|
|
|
default:
|
|
|
|
if ((Done = SM.isValidEndState()))
|
2013-01-15 06:31:35 +08:00
|
|
|
break;
|
2013-12-01 19:47:42 +08:00
|
|
|
return Error(Tok.getLoc(), "unknown token in expression");
|
2017-08-24 16:46:25 +08:00
|
|
|
case AsmToken::EndOfStatement:
|
2013-04-17 08:11:46 +08:00
|
|
|
Done = true;
|
|
|
|
break;
|
2017-08-24 16:46:25 +08:00
|
|
|
case AsmToken::Real:
|
|
|
|
// DotOperator: [ebx].0
|
|
|
|
UpdateLocLex = false;
|
|
|
|
if (ParseIntelDotOperator(SM, End))
|
|
|
|
return true;
|
|
|
|
break;
|
2018-03-12 20:47:27 +08:00
|
|
|
case AsmToken::At:
|
2014-06-19 09:25:43 +08:00
|
|
|
case AsmToken::String:
|
2013-01-15 06:31:35 +08:00
|
|
|
case AsmToken::Identifier: {
|
2013-04-13 02:54:20 +08:00
|
|
|
SMLoc IdentLoc = Tok.getLoc();
|
|
|
|
StringRef Identifier = Tok.getString();
|
2017-03-22 03:31:55 +08:00
|
|
|
UpdateLocLex = false;
|
2017-09-29 15:02:46 +08:00
|
|
|
// Register
|
|
|
|
unsigned Reg;
|
2018-03-12 20:47:27 +08:00
|
|
|
if (Tok.is(AsmToken::Identifier) && !ParseRegister(Reg, IdentLoc, End)) {
|
2017-09-29 15:02:46 +08:00
|
|
|
if (SM.onRegister(Reg, ErrMsg))
|
2017-07-25 21:05:12 +08:00
|
|
|
return Error(Tok.getLoc(), ErrMsg);
|
2017-09-29 15:02:46 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Operator synonymous ("not", "or" etc.)
|
|
|
|
if ((UpdateLocLex = ParseIntelNamedOperator(Identifier, SM)))
|
|
|
|
break;
|
|
|
|
// Symbol reference, when parsing assembly content
|
|
|
|
InlineAsmIdentifierInfo Info;
|
|
|
|
const MCExpr *Val;
|
|
|
|
if (!isParsingInlineAsm()) {
|
|
|
|
if (getParser().parsePrimaryExpr(Val, End)) {
|
2017-03-22 03:31:55 +08:00
|
|
|
return Error(Tok.getLoc(), "Unexpected identifier!");
|
2017-09-29 15:02:46 +08:00
|
|
|
} else if (SM.onIdentifierExpr(Val, Identifier, Info, false, ErrMsg)) {
|
2017-08-24 16:46:25 +08:00
|
|
|
return Error(IdentLoc, ErrMsg);
|
2017-09-29 15:02:46 +08:00
|
|
|
} else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// MS InlineAsm operators (TYPE/LENGTH/SIZE)
|
|
|
|
if (unsigned OpKind = IdentifyIntelInlineAsmOperator(Identifier)) {
|
2017-08-24 16:46:25 +08:00
|
|
|
if (OpKind == IOK_OFFSET)
|
2017-03-22 03:31:55 +08:00
|
|
|
return Error(IdentLoc, "Dealing OFFSET operator as part of"
|
|
|
|
"a compound immediate expression is yet to be supported");
|
2017-09-29 15:02:46 +08:00
|
|
|
if (int64_t Val = ParseIntelInlineAsmOperator(OpKind)) {
|
|
|
|
if (SM.onInteger(Val, ErrMsg))
|
|
|
|
return Error(IdentLoc, ErrMsg);
|
|
|
|
} else
|
2017-03-22 03:31:55 +08:00
|
|
|
return true;
|
2017-09-29 15:02:46 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
// MS Dot Operator expression
|
|
|
|
if (Identifier.count('.') && PrevTK == AsmToken::RBrac) {
|
|
|
|
if (ParseIntelDotOperator(SM, End))
|
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// MS InlineAsm identifier
|
2018-03-12 20:47:27 +08:00
|
|
|
// Call parseIdentifier() to combine @ with the identifier behind it.
|
|
|
|
if (TK == AsmToken::At && Parser.parseIdentifier(Identifier))
|
|
|
|
return Error(IdentLoc, "expected identifier");
|
2017-09-29 15:02:46 +08:00
|
|
|
if (ParseIntelInlineAsmIdentifier(Val, Identifier, Info, false, End))
|
2017-08-24 16:46:25 +08:00
|
|
|
return true;
|
2017-09-29 15:02:46 +08:00
|
|
|
else if (SM.onIdentifierExpr(Val, Identifier, Info, true, ErrMsg))
|
2017-08-24 16:46:25 +08:00
|
|
|
return Error(IdentLoc, ErrMsg);
|
2017-03-22 03:31:55 +08:00
|
|
|
break;
|
2013-01-15 06:31:35 +08:00
|
|
|
}
|
2013-12-20 07:16:14 +08:00
|
|
|
case AsmToken::Integer: {
|
|
|
|
// Look for 'b' or 'f' following an Integer as a directional label
|
|
|
|
SMLoc Loc = getTok().getLoc();
|
|
|
|
int64_t IntVal = getTok().getIntVal();
|
|
|
|
End = consumeToken();
|
|
|
|
UpdateLocLex = false;
|
|
|
|
if (getLexer().getKind() == AsmToken::Identifier) {
|
|
|
|
StringRef IDVal = getTok().getString();
|
|
|
|
if (IDVal == "f" || IDVal == "b") {
|
|
|
|
MCSymbol *Sym =
|
2015-05-19 02:43:14 +08:00
|
|
|
getContext().getDirectionalLocalSymbol(IntVal, IDVal == "b");
|
2013-12-20 07:16:14 +08:00
|
|
|
MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
|
2014-12-04 13:20:33 +08:00
|
|
|
const MCExpr *Val =
|
2015-09-22 19:15:07 +08:00
|
|
|
MCSymbolRefExpr::create(Sym, Variant, getContext());
|
2013-12-20 07:16:14 +08:00
|
|
|
if (IDVal == "b" && Sym->isUndefined())
|
|
|
|
return Error(Loc, "invalid reference to undefined symbol");
|
|
|
|
StringRef Identifier = Sym->getName();
|
2017-09-29 15:02:46 +08:00
|
|
|
InlineAsmIdentifierInfo Info;
|
|
|
|
if (SM.onIdentifierExpr(Val, Identifier, Info,
|
|
|
|
isParsingInlineAsm(), ErrMsg))
|
2017-08-24 16:46:25 +08:00
|
|
|
return Error(Loc, ErrMsg);
|
2013-12-20 07:16:14 +08:00
|
|
|
End = consumeToken();
|
|
|
|
} else {
|
2014-01-24 05:52:41 +08:00
|
|
|
if (SM.onInteger(IntVal, ErrMsg))
|
|
|
|
return Error(Loc, ErrMsg);
|
2013-12-20 07:16:14 +08:00
|
|
|
}
|
|
|
|
} else {
|
2014-01-24 05:52:41 +08:00
|
|
|
if (SM.onInteger(IntVal, ErrMsg))
|
|
|
|
return Error(Loc, ErrMsg);
|
2013-12-20 07:16:14 +08:00
|
|
|
}
|
2013-01-15 06:31:35 +08:00
|
|
|
break;
|
2013-12-20 07:16:14 +08:00
|
|
|
}
|
2017-07-25 21:05:12 +08:00
|
|
|
case AsmToken::Plus:
|
|
|
|
if (SM.onPlus(ErrMsg))
|
|
|
|
return Error(getTok().getLoc(), ErrMsg);
|
|
|
|
break;
|
|
|
|
case AsmToken::Minus:
|
|
|
|
if (SM.onMinus(ErrMsg))
|
|
|
|
return Error(getTok().getLoc(), ErrMsg);
|
|
|
|
break;
|
2014-07-05 03:13:05 +08:00
|
|
|
case AsmToken::Tilde: SM.onNot(); break;
|
2013-01-15 06:31:35 +08:00
|
|
|
case AsmToken::Star: SM.onStar(); break;
|
2013-04-06 00:28:55 +08:00
|
|
|
case AsmToken::Slash: SM.onDivide(); break;
|
2017-11-01 00:47:38 +08:00
|
|
|
case AsmToken::Percent: SM.onMod(); break;
|
2014-01-16 03:05:24 +08:00
|
|
|
case AsmToken::Pipe: SM.onOr(); break;
|
2015-06-14 20:59:45 +08:00
|
|
|
case AsmToken::Caret: SM.onXor(); break;
|
2014-01-16 03:05:24 +08:00
|
|
|
case AsmToken::Amp: SM.onAnd(); break;
|
2014-02-06 09:21:15 +08:00
|
|
|
case AsmToken::LessLess:
|
|
|
|
SM.onLShift(); break;
|
|
|
|
case AsmToken::GreaterGreater:
|
|
|
|
SM.onRShift(); break;
|
2017-08-24 16:46:25 +08:00
|
|
|
case AsmToken::LBrac:
|
|
|
|
if (SM.onLBrac())
|
|
|
|
return Error(Tok.getLoc(), "unexpected bracket encountered");
|
|
|
|
break;
|
|
|
|
case AsmToken::RBrac:
|
|
|
|
if (SM.onRBrac())
|
|
|
|
return Error(Tok.getLoc(), "unexpected bracket encountered");
|
|
|
|
break;
|
2013-04-06 00:28:55 +08:00
|
|
|
case AsmToken::LParen: SM.onLParen(); break;
|
|
|
|
case AsmToken::RParen: SM.onRParen(); break;
|
2013-01-15 06:31:35 +08:00
|
|
|
}
|
2013-04-18 05:01:45 +08:00
|
|
|
if (SM.hadError())
|
2013-12-01 19:47:42 +08:00
|
|
|
return Error(Tok.getLoc(), "unknown token in expression");
|
2013-04-18 05:01:45 +08:00
|
|
|
|
2013-12-03 00:06:06 +08:00
|
|
|
if (!Done && UpdateLocLex)
|
|
|
|
End = consumeToken();
|
2015-12-24 20:09:51 +08:00
|
|
|
|
|
|
|
PrevTK = TK;
|
2012-10-30 02:01:54 +08:00
|
|
|
}
|
2013-12-01 19:47:42 +08:00
|
|
|
return false;
|
2013-04-17 02:15:40 +08:00
|
|
|
}
|
|
|
|
|
2017-08-24 16:46:25 +08:00
|
|
|
void X86AsmParser::RewriteIntelExpression(IntelExprStateMachine &SM,
|
|
|
|
SMLoc Start, SMLoc End) {
|
|
|
|
SMLoc Loc = Start;
|
|
|
|
unsigned ExprLen = End.getPointer() - Start.getPointer();
|
|
|
|
// Skip everything before a symbol displacement (if we have one)
|
|
|
|
if (SM.getSym()) {
|
|
|
|
StringRef SymName = SM.getSymName();
|
|
|
|
if (unsigned Len = SymName.data() - Start.getPointer())
|
|
|
|
InstInfo->AsmRewrites->emplace_back(AOK_Skip, Start, Len);
|
|
|
|
Loc = SMLoc::getFromPointer(SymName.data() + SymName.size());
|
|
|
|
ExprLen = End.getPointer() - (SymName.data() + SymName.size());
|
|
|
|
// If we have only a symbol than there's no need for complex rewrite,
|
|
|
|
// simply skip everything after it
|
|
|
|
if (!(SM.getBaseReg() || SM.getIndexReg() || SM.getImm())) {
|
|
|
|
if (ExprLen)
|
|
|
|
InstInfo->AsmRewrites->emplace_back(AOK_Skip, Loc, ExprLen);
|
|
|
|
return;
|
2014-01-24 06:34:42 +08:00
|
|
|
}
|
2013-01-15 06:31:35 +08:00
|
|
|
}
|
2017-08-24 16:46:25 +08:00
|
|
|
// Build an Intel Expression rewrite
|
|
|
|
StringRef BaseRegStr;
|
|
|
|
StringRef IndexRegStr;
|
|
|
|
if (SM.getBaseReg())
|
|
|
|
BaseRegStr = X86IntelInstPrinter::getRegisterName(SM.getBaseReg());
|
|
|
|
if (SM.getIndexReg())
|
|
|
|
IndexRegStr = X86IntelInstPrinter::getRegisterName(SM.getIndexReg());
|
|
|
|
// Emit it
|
|
|
|
IntelExpr Expr(BaseRegStr, IndexRegStr, SM.getScale(), SM.getImm(), SM.isMemExpr());
|
|
|
|
InstInfo->AsmRewrites->emplace_back(Loc, ExprLen, Expr);
|
2012-01-18 02:00:18 +08:00
|
|
|
}
|
|
|
|
|
2013-04-03 04:02:33 +08:00
|
|
|
// Inline assembly may use variable names with namespace alias qualifiers.
|
2017-08-24 16:46:25 +08:00
|
|
|
bool X86AsmParser::ParseIntelInlineAsmIdentifier(const MCExpr *&Val,
|
|
|
|
StringRef &Identifier,
|
|
|
|
InlineAsmIdentifierInfo &Info,
|
|
|
|
bool IsUnevaluatedOperand,
|
|
|
|
SMLoc &End) {
|
2014-11-11 13:18:41 +08:00
|
|
|
MCAsmParser &Parser = getParser();
|
2015-08-27 05:57:25 +08:00
|
|
|
assert(isParsingInlineAsm() && "Expected to be parsing inline assembly.");
|
2014-04-25 13:30:21 +08:00
|
|
|
Val = nullptr;
|
2013-04-03 04:02:33 +08:00
|
|
|
|
2013-04-23 03:42:15 +08:00
|
|
|
StringRef LineBuf(Identifier.data());
|
2017-09-29 15:02:46 +08:00
|
|
|
SemaCallback->LookupInlineAsmIdentifier(LineBuf, Info, IsUnevaluatedOperand);
|
2013-04-23 03:42:15 +08:00
|
|
|
|
2013-04-03 04:02:33 +08:00
|
|
|
const AsmToken &Tok = Parser.getTok();
|
2014-09-22 10:21:35 +08:00
|
|
|
SMLoc Loc = Tok.getLoc();
|
2013-05-03 08:15:41 +08:00
|
|
|
|
|
|
|
// Advance the token stream until the end of the current token is
|
|
|
|
// after the end of what the frontend claimed.
|
|
|
|
const char *EndPtr = Tok.getLoc().getPointer() + LineBuf.size();
|
2015-08-27 05:57:25 +08:00
|
|
|
do {
|
2013-05-03 08:15:41 +08:00
|
|
|
End = Tok.getEndLoc();
|
|
|
|
getLexer().Lex();
|
2015-08-27 05:57:25 +08:00
|
|
|
} while (End.getPointer() < EndPtr);
|
2014-09-22 10:21:35 +08:00
|
|
|
Identifier = LineBuf;
|
|
|
|
|
2015-08-27 05:57:25 +08:00
|
|
|
// The frontend should end parsing on an assembler token boundary, unless it
|
|
|
|
// failed parsing.
|
2017-09-29 15:02:46 +08:00
|
|
|
assert((End.getPointer() == EndPtr ||
|
|
|
|
Info.isKind(InlineAsmIdentifierInfo::IK_Invalid)) &&
|
|
|
|
"frontend claimed part of a token?");
|
2015-08-27 05:57:25 +08:00
|
|
|
|
2014-09-22 10:21:35 +08:00
|
|
|
// If the identifier lookup was unsuccessful, assume that we are dealing with
|
|
|
|
// a label.
|
2017-09-29 15:02:46 +08:00
|
|
|
if (Info.isKind(InlineAsmIdentifierInfo::IK_Invalid)) {
|
2014-09-23 04:40:36 +08:00
|
|
|
StringRef InternalName =
|
|
|
|
SemaCallback->LookupInlineAsmLabel(Identifier, getSourceManager(),
|
|
|
|
Loc, false);
|
|
|
|
assert(InternalName.size() && "We should have an internal name here.");
|
|
|
|
// Push a rewrite for replacing the identifier name with the internal name.
|
2015-10-10 13:25:02 +08:00
|
|
|
InstInfo->AsmRewrites->emplace_back(AOK_Label, Loc, Identifier.size(),
|
|
|
|
InternalName);
|
2017-09-29 15:02:46 +08:00
|
|
|
} else if (Info.isKind(InlineAsmIdentifierInfo::IK_EnumVal))
|
|
|
|
return false;
|
2013-04-23 03:42:15 +08:00
|
|
|
// Create the symbol reference.
|
2015-05-19 02:43:14 +08:00
|
|
|
MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier);
|
2013-04-03 04:02:33 +08:00
|
|
|
MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
|
2015-05-30 09:25:56 +08:00
|
|
|
Val = MCSymbolRefExpr::create(Sym, Variant, getParser().getContext());
|
2013-12-01 19:47:42 +08:00
|
|
|
return false;
|
2013-04-03 04:02:33 +08:00
|
|
|
}
|
|
|
|
|
2015-03-02 23:00:34 +08:00
|
|
|
//ParseRoundingModeOp - Parse AVX-512 rounding mode operand
|
|
|
|
std::unique_ptr<X86Operand>
|
2018-01-06 14:41:07 +08:00
|
|
|
X86AsmParser::ParseRoundingModeOp(SMLoc Start) {
|
2015-03-02 23:00:34 +08:00
|
|
|
MCAsmParser &Parser = getParser();
|
|
|
|
const AsmToken &Tok = Parser.getTok();
|
2015-05-07 19:24:42 +08:00
|
|
|
// Eat "{" and mark the current place.
|
|
|
|
const SMLoc consumedToken = consumeToken();
|
2015-03-02 23:00:34 +08:00
|
|
|
if (Tok.getIdentifier().startswith("r")){
|
|
|
|
int rndMode = StringSwitch<int>(Tok.getIdentifier())
|
|
|
|
.Case("rn", X86::STATIC_ROUNDING::TO_NEAREST_INT)
|
|
|
|
.Case("rd", X86::STATIC_ROUNDING::TO_NEG_INF)
|
|
|
|
.Case("ru", X86::STATIC_ROUNDING::TO_POS_INF)
|
|
|
|
.Case("rz", X86::STATIC_ROUNDING::TO_ZERO)
|
|
|
|
.Default(-1);
|
|
|
|
if (-1 == rndMode)
|
|
|
|
return ErrorOperand(Tok.getLoc(), "Invalid rounding mode.");
|
|
|
|
Parser.Lex(); // Eat "r*" of r*-sae
|
|
|
|
if (!getLexer().is(AsmToken::Minus))
|
|
|
|
return ErrorOperand(Tok.getLoc(), "Expected - at this point");
|
|
|
|
Parser.Lex(); // Eat "-"
|
|
|
|
Parser.Lex(); // Eat the sae
|
|
|
|
if (!getLexer().is(AsmToken::RCurly))
|
|
|
|
return ErrorOperand(Tok.getLoc(), "Expected } at this point");
|
2018-01-06 14:41:07 +08:00
|
|
|
SMLoc End = Tok.getEndLoc();
|
2015-03-02 23:00:34 +08:00
|
|
|
Parser.Lex(); // Eat "}"
|
|
|
|
const MCExpr *RndModeOp =
|
2015-05-30 09:25:56 +08:00
|
|
|
MCConstantExpr::create(rndMode, Parser.getContext());
|
2015-03-02 23:00:34 +08:00
|
|
|
return X86Operand::CreateImm(RndModeOp, Start, End);
|
|
|
|
}
|
2015-05-07 19:24:42 +08:00
|
|
|
if(Tok.getIdentifier().equals("sae")){
|
|
|
|
Parser.Lex(); // Eat the sae
|
|
|
|
if (!getLexer().is(AsmToken::RCurly))
|
|
|
|
return ErrorOperand(Tok.getLoc(), "Expected } at this point");
|
|
|
|
Parser.Lex(); // Eat "}"
|
|
|
|
return X86Operand::CreateToken("{sae}", consumedToken);
|
|
|
|
}
|
2015-03-02 23:00:34 +08:00
|
|
|
return ErrorOperand(Tok.getLoc(), "unknown token in expression");
|
|
|
|
}
|
2012-10-25 01:22:29 +08:00
|
|
|
|
2012-10-25 06:21:50 +08:00
|
|
|
/// Parse the '.' operator.
|
2017-08-24 16:46:25 +08:00
|
|
|
bool X86AsmParser::ParseIntelDotOperator(IntelExprStateMachine &SM, SMLoc &End) {
|
|
|
|
const AsmToken &Tok = getTok();
|
|
|
|
unsigned Offset;
|
2012-10-25 06:21:50 +08:00
|
|
|
|
2014-03-07 03:19:12 +08:00
|
|
|
// Drop the optional '.'.
|
|
|
|
StringRef DotDispStr = Tok.getString();
|
|
|
|
if (DotDispStr.startswith("."))
|
|
|
|
DotDispStr = DotDispStr.drop_front(1);
|
2012-10-25 06:21:50 +08:00
|
|
|
|
|
|
|
// .Imm gets lexed as a real.
|
|
|
|
if (Tok.is(AsmToken::Real)) {
|
|
|
|
APInt DotDisp;
|
|
|
|
DotDispStr.getAsInteger(10, DotDisp);
|
2017-08-24 16:46:25 +08:00
|
|
|
Offset = DotDisp.getZExtValue();
|
2013-04-19 23:57:00 +08:00
|
|
|
} else if (isParsingInlineAsm() && Tok.is(AsmToken::Identifier)) {
|
2012-10-26 05:51:10 +08:00
|
|
|
std::pair<StringRef, StringRef> BaseMember = DotDispStr.split('.');
|
|
|
|
if (SemaCallback->LookupInlineAsmField(BaseMember.first, BaseMember.second,
|
2017-08-24 16:46:25 +08:00
|
|
|
Offset))
|
2013-12-01 19:47:42 +08:00
|
|
|
return Error(Tok.getLoc(), "Unable to lookup field reference!");
|
2013-04-19 23:57:00 +08:00
|
|
|
} else
|
2013-12-01 19:47:42 +08:00
|
|
|
return Error(Tok.getLoc(), "Unexpected token type!");
|
2012-10-25 06:21:50 +08:00
|
|
|
|
2017-08-24 16:46:25 +08:00
|
|
|
// Eat the DotExpression and update End
|
|
|
|
End = SMLoc::getFromPointer(DotDispStr.data());
|
|
|
|
const char *DotExprEndLoc = DotDispStr.data() + DotDispStr.size();
|
|
|
|
while (Tok.getLoc().getPointer() < DotExprEndLoc)
|
|
|
|
Lex();
|
|
|
|
SM.addImm(Offset);
|
2013-12-01 19:47:42 +08:00
|
|
|
return false;
|
2012-10-25 06:21:50 +08:00
|
|
|
}
|
|
|
|
|
2012-10-25 01:22:29 +08:00
|
|
|
/// Parse the 'offset' operator. This operator is used to specify the
|
|
|
|
/// location rather then the content of a variable.
|
2014-06-09 00:18:35 +08:00
|
|
|
std::unique_ptr<X86Operand> X86AsmParser::ParseIntelOffsetOfOperator() {
|
2014-11-11 13:18:41 +08:00
|
|
|
MCAsmParser &Parser = getParser();
|
2013-04-10 04:58:48 +08:00
|
|
|
const AsmToken &Tok = Parser.getTok();
|
2013-04-10 04:44:09 +08:00
|
|
|
SMLoc OffsetOfLoc = Tok.getLoc();
|
2012-10-25 01:22:29 +08:00
|
|
|
Parser.Lex(); // Eat offset.
|
|
|
|
|
|
|
|
const MCExpr *Val;
|
2013-04-23 03:42:15 +08:00
|
|
|
InlineAsmIdentifierInfo Info;
|
2013-04-10 04:58:48 +08:00
|
|
|
SMLoc Start = Tok.getLoc(), End;
|
2013-04-12 07:37:34 +08:00
|
|
|
StringRef Identifier = Tok.getString();
|
2017-08-24 16:46:25 +08:00
|
|
|
if (ParseIntelInlineAsmIdentifier(Val, Identifier, Info,
|
|
|
|
/*Unevaluated=*/false, End))
|
2014-04-25 13:30:21 +08:00
|
|
|
return nullptr;
|
2013-04-12 07:37:34 +08:00
|
|
|
|
2017-09-29 15:02:46 +08:00
|
|
|
void *Decl = nullptr;
|
|
|
|
// FIXME: MS evaluates "offset <Constant>" to the underlying integral
|
|
|
|
if (Info.isKind(InlineAsmIdentifierInfo::IK_EnumVal))
|
|
|
|
return ErrorOperand(Start, "offset operator cannot yet handle constants");
|
|
|
|
else if (Info.isKind(InlineAsmIdentifierInfo::IK_Var))
|
|
|
|
Decl = Info.Var.Decl;
|
2012-10-27 00:09:20 +08:00
|
|
|
// Don't emit the offset operator.
|
2015-10-10 13:25:02 +08:00
|
|
|
InstInfo->AsmRewrites->emplace_back(AOK_Skip, OffsetOfLoc, 7);
|
2012-10-27 00:09:20 +08:00
|
|
|
|
2012-10-25 01:22:29 +08:00
|
|
|
// The offset operator will have an 'r' constraint, thus we need to create
|
|
|
|
// register operand to ensure proper matching. Just pick a GPR based on
|
|
|
|
// the size of a pointer.
|
2016-09-27 03:33:36 +08:00
|
|
|
bool Parse32 = is32BitMode() || Code16GCC;
|
|
|
|
unsigned RegNo = is64BitMode() ? X86::RBX : (Parse32 ? X86::EBX : X86::BX);
|
|
|
|
|
2013-01-11 06:10:27 +08:00
|
|
|
return X86Operand::CreateReg(RegNo, Start, End, /*GetAddress=*/true,
|
2017-09-29 15:02:46 +08:00
|
|
|
OffsetOfLoc, Identifier, Decl);
|
2012-01-18 02:00:18 +08:00
|
|
|
}
|
|
|
|
|
2017-03-22 03:31:55 +08:00
|
|
|
// Query a candidate string for being an Intel assembly operator
|
|
|
|
// Report back its kind, or IOK_INVALID if does not evaluated as a known one
|
2017-08-24 16:46:25 +08:00
|
|
|
unsigned X86AsmParser::IdentifyIntelInlineAsmOperator(StringRef Name) {
|
2017-03-22 03:31:55 +08:00
|
|
|
return StringSwitch<unsigned>(Name)
|
|
|
|
.Cases("TYPE","type",IOK_TYPE)
|
|
|
|
.Cases("SIZE","size",IOK_SIZE)
|
|
|
|
.Cases("LENGTH","length",IOK_LENGTH)
|
|
|
|
.Cases("OFFSET","offset",IOK_OFFSET)
|
|
|
|
.Default(IOK_INVALID);
|
|
|
|
}
|
2013-01-18 03:21:48 +08:00
|
|
|
|
|
|
|
/// Parse the 'LENGTH', 'TYPE' and 'SIZE' operators. The LENGTH operator
|
|
|
|
/// returns the number of elements in an array. It returns the value 1 for
|
|
|
|
/// non-array variables. The SIZE operator returns the size of a C or C++
|
|
|
|
/// variable. A variable's size is the product of its LENGTH and TYPE. The
|
|
|
|
/// TYPE operator returns the size of a C or C++ type or variable. If the
|
|
|
|
/// variable is an array, TYPE returns the size of a single element.
|
2017-08-24 16:46:25 +08:00
|
|
|
unsigned X86AsmParser::ParseIntelInlineAsmOperator(unsigned OpKind) {
|
2014-11-11 13:18:41 +08:00
|
|
|
MCAsmParser &Parser = getParser();
|
2013-04-10 04:58:48 +08:00
|
|
|
const AsmToken &Tok = Parser.getTok();
|
2013-04-10 04:44:09 +08:00
|
|
|
Parser.Lex(); // Eat operator.
|
2012-10-27 02:04:20 +08:00
|
|
|
|
2014-04-25 13:30:21 +08:00
|
|
|
const MCExpr *Val = nullptr;
|
2013-04-23 03:42:15 +08:00
|
|
|
InlineAsmIdentifierInfo Info;
|
2013-04-10 04:58:48 +08:00
|
|
|
SMLoc Start = Tok.getLoc(), End;
|
2013-04-12 07:57:04 +08:00
|
|
|
StringRef Identifier = Tok.getString();
|
2017-08-24 16:46:25 +08:00
|
|
|
if (ParseIntelInlineAsmIdentifier(Val, Identifier, Info,
|
|
|
|
/*Unevaluated=*/true, End))
|
2017-03-22 03:31:55 +08:00
|
|
|
return 0;
|
2012-10-27 02:04:20 +08:00
|
|
|
|
2017-09-29 15:02:46 +08:00
|
|
|
if (!Info.isKind(InlineAsmIdentifierInfo::IK_Var)) {
|
2017-03-22 03:31:55 +08:00
|
|
|
Error(Start, "unable to lookup expression");
|
|
|
|
return 0;
|
|
|
|
}
|
2017-08-24 16:46:25 +08:00
|
|
|
|
2013-04-23 01:01:46 +08:00
|
|
|
unsigned CVal = 0;
|
2013-04-23 03:42:15 +08:00
|
|
|
switch(OpKind) {
|
|
|
|
default: llvm_unreachable("Unexpected operand kind!");
|
2017-09-29 15:02:46 +08:00
|
|
|
case IOK_LENGTH: CVal = Info.Var.Length; break;
|
|
|
|
case IOK_SIZE: CVal = Info.Var.Size; break;
|
|
|
|
case IOK_TYPE: CVal = Info.Var.Type; break;
|
2013-04-23 03:42:15 +08:00
|
|
|
}
|
2017-07-26 03:22:09 +08:00
|
|
|
|
2017-03-22 03:31:55 +08:00
|
|
|
return CVal;
|
2012-10-27 02:04:20 +08:00
|
|
|
}
|
|
|
|
|
2017-08-24 16:46:25 +08:00
|
|
|
bool X86AsmParser::ParseIntelMemoryOperandSize(unsigned &Size) {
|
|
|
|
Size = StringSwitch<unsigned>(getTok().getString())
|
|
|
|
.Cases("BYTE", "byte", 8)
|
|
|
|
.Cases("WORD", "word", 16)
|
|
|
|
.Cases("DWORD", "dword", 32)
|
2017-09-28 19:04:08 +08:00
|
|
|
.Cases("FLOAT", "float", 32)
|
|
|
|
.Cases("LONG", "long", 32)
|
2017-08-24 16:46:25 +08:00
|
|
|
.Cases("FWORD", "fword", 48)
|
2017-09-28 19:04:08 +08:00
|
|
|
.Cases("DOUBLE", "double", 64)
|
2017-08-24 16:46:25 +08:00
|
|
|
.Cases("QWORD", "qword", 64)
|
|
|
|
.Cases("MMWORD","mmword", 64)
|
|
|
|
.Cases("XWORD", "xword", 80)
|
|
|
|
.Cases("TBYTE", "tbyte", 80)
|
|
|
|
.Cases("XMMWORD", "xmmword", 128)
|
|
|
|
.Cases("YMMWORD", "ymmword", 256)
|
|
|
|
.Cases("ZMMWORD", "zmmword", 512)
|
|
|
|
.Cases("OPAQUE", "opaque", -1U) // needs to be non-zero, but doesn't matter
|
|
|
|
.Default(0);
|
|
|
|
if (Size) {
|
|
|
|
const AsmToken &Tok = Lex(); // Eat operand size (e.g., byte, word).
|
|
|
|
if (!(Tok.getString().equals("PTR") || Tok.getString().equals("ptr")))
|
|
|
|
return Error(Tok.getLoc(), "Expected 'PTR' or 'ptr' token!");
|
|
|
|
Lex(); // Eat ptr.
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
std::unique_ptr<X86Operand> X86AsmParser::ParseIntelOperand() {
|
2014-11-11 13:18:41 +08:00
|
|
|
MCAsmParser &Parser = getParser();
|
2013-04-11 04:07:47 +08:00
|
|
|
const AsmToken &Tok = Parser.getTok();
|
2013-08-28 05:56:17 +08:00
|
|
|
SMLoc Start, End;
|
2013-01-18 03:21:48 +08:00
|
|
|
|
2017-03-22 03:31:55 +08:00
|
|
|
// FIXME: Offset operator
|
|
|
|
// Should be handled as part of immediate expression, as other operators
|
|
|
|
// Currently, only supported as a stand-alone operand
|
|
|
|
if (isParsingInlineAsm())
|
2017-08-24 16:46:25 +08:00
|
|
|
if (IdentifyIntelInlineAsmOperator(Tok.getString()) == IOK_OFFSET)
|
2013-04-10 04:44:09 +08:00
|
|
|
return ParseIntelOffsetOfOperator();
|
2013-01-18 03:21:48 +08:00
|
|
|
|
2017-08-24 16:46:25 +08:00
|
|
|
// Parse optional Size directive.
|
|
|
|
unsigned Size;
|
|
|
|
if (ParseIntelMemoryOperandSize(Size))
|
|
|
|
return nullptr;
|
|
|
|
bool PtrInOperand = bool(Size);
|
2016-08-02 07:00:01 +08:00
|
|
|
|
2016-08-03 01:56:03 +08:00
|
|
|
Start = Tok.getLoc();
|
2016-08-02 07:00:01 +08:00
|
|
|
|
2017-08-24 16:46:25 +08:00
|
|
|
// Rounding mode operand.
|
2018-02-03 01:02:58 +08:00
|
|
|
if (getLexer().is(AsmToken::LCurly))
|
2018-01-06 14:41:07 +08:00
|
|
|
return ParseRoundingModeOp(Start);
|
2015-03-02 23:00:34 +08:00
|
|
|
|
2017-08-24 16:46:25 +08:00
|
|
|
// Register operand.
|
2012-01-21 06:32:05 +08:00
|
|
|
unsigned RegNo = 0;
|
2017-08-24 16:46:25 +08:00
|
|
|
if (Tok.is(AsmToken::Identifier) && !ParseRegister(RegNo, Start, End)) {
|
2016-10-05 23:23:35 +08:00
|
|
|
if (RegNo == X86::RIP)
|
|
|
|
return ErrorOperand(Start, "rip can only be used as a base register");
|
2017-08-24 16:46:25 +08:00
|
|
|
// A Register followed by ':' is considered a segment override
|
|
|
|
if (Tok.isNot(AsmToken::Colon))
|
|
|
|
return !PtrInOperand ? X86Operand::CreateReg(RegNo, Start, End) :
|
|
|
|
ErrorOperand(Start, "expected memory operand after 'ptr', "
|
|
|
|
"found register operand instead");
|
|
|
|
// An alleged segment override. check if we have a valid segment register
|
|
|
|
if (!X86MCRegisterClasses[X86::SEGMENT_REGRegClassID].contains(RegNo))
|
|
|
|
return ErrorOperand(Start, "invalid segment register");
|
|
|
|
// Eat ':' and update Start location
|
|
|
|
Start = Lex().getLoc();
|
2012-01-12 09:36:43 +08:00
|
|
|
}
|
|
|
|
|
2016-08-03 01:56:03 +08:00
|
|
|
// Immediates and Memory
|
2017-08-24 16:46:25 +08:00
|
|
|
IntelExprStateMachine SM;
|
2016-08-03 01:56:03 +08:00
|
|
|
if (ParseIntelExpression(SM, End))
|
|
|
|
return nullptr;
|
|
|
|
|
2017-08-24 16:46:25 +08:00
|
|
|
if (isParsingInlineAsm())
|
|
|
|
RewriteIntelExpression(SM, Start, Tok.getLoc());
|
2016-08-03 01:56:03 +08:00
|
|
|
|
2017-08-24 16:46:25 +08:00
|
|
|
int64_t Imm = SM.getImm();
|
|
|
|
const MCExpr *Disp = SM.getSym();
|
|
|
|
const MCExpr *ImmDisp = MCConstantExpr::create(Imm, getContext());
|
|
|
|
if (Disp && Imm)
|
|
|
|
Disp = MCBinaryExpr::createAdd(Disp, ImmDisp, getContext());
|
|
|
|
if (!Disp)
|
|
|
|
Disp = ImmDisp;
|
|
|
|
|
|
|
|
// RegNo != 0 specifies a valid segment register,
|
|
|
|
// and we are parsing a segment override
|
|
|
|
if (!SM.isMemExpr() && !RegNo)
|
|
|
|
return X86Operand::CreateImm(Disp, Start, End);
|
2016-08-03 01:56:03 +08:00
|
|
|
|
2017-08-24 16:46:25 +08:00
|
|
|
StringRef ErrMsg;
|
|
|
|
unsigned BaseReg = SM.getBaseReg();
|
|
|
|
unsigned IndexReg = SM.getIndexReg();
|
|
|
|
unsigned Scale = SM.getScale();
|
2016-08-03 01:56:03 +08:00
|
|
|
|
2017-08-24 16:46:25 +08:00
|
|
|
if ((BaseReg || IndexReg) &&
|
|
|
|
CheckBaseRegAndIndexRegAndScale(BaseReg, IndexReg, Scale, ErrMsg))
|
|
|
|
return ErrorOperand(Start, ErrMsg);
|
|
|
|
if (isParsingInlineAsm())
|
|
|
|
return CreateMemForInlineAsm(RegNo, Disp, BaseReg, IndexReg,
|
|
|
|
Scale, Start, End, Size, SM.getSymName(),
|
|
|
|
SM.getIdentifierInfo());
|
|
|
|
if (!(BaseReg || IndexReg || RegNo))
|
|
|
|
return X86Operand::CreateMem(getPointerWidth(), Disp, Start, End, Size);
|
|
|
|
return X86Operand::CreateMem(getPointerWidth(), RegNo, Disp,
|
|
|
|
BaseReg, IndexReg, Scale, Start, End, Size);
|
2012-01-12 09:36:43 +08:00
|
|
|
}
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
std::unique_ptr<X86Operand> X86AsmParser::ParseATTOperand() {
|
2014-11-11 13:18:41 +08:00
|
|
|
MCAsmParser &Parser = getParser();
|
2009-07-29 06:40:46 +08:00
|
|
|
switch (getLexer().getKind()) {
|
|
|
|
default:
|
2010-04-18 02:56:34 +08:00
|
|
|
// Parse a memory operand with no segment register.
|
|
|
|
return ParseMemOperand(0, Parser.getTok().getLoc());
|
2010-01-16 02:27:19 +08:00
|
|
|
case AsmToken::Percent: {
|
2010-04-18 02:56:34 +08:00
|
|
|
// Read the register.
|
2010-01-16 02:27:19 +08:00
|
|
|
unsigned RegNo;
|
2010-01-16 02:51:29 +08:00
|
|
|
SMLoc Start, End;
|
2014-04-25 13:30:21 +08:00
|
|
|
if (ParseRegister(RegNo, Start, End)) return nullptr;
|
2010-07-24 08:06:39 +08:00
|
|
|
if (RegNo == X86::EIZ || RegNo == X86::RIZ) {
|
2011-10-16 20:10:27 +08:00
|
|
|
Error(Start, "%eiz and %riz can only be used as index registers",
|
|
|
|
SMRange(Start, End));
|
2014-04-25 13:30:21 +08:00
|
|
|
return nullptr;
|
2010-07-24 08:06:39 +08:00
|
|
|
}
|
2016-10-05 23:23:35 +08:00
|
|
|
if (RegNo == X86::RIP) {
|
|
|
|
Error(Start, "%rip can only be used as a base register",
|
|
|
|
SMRange(Start, End));
|
|
|
|
return nullptr;
|
|
|
|
}
|
2010-07-24 06:15:26 +08:00
|
|
|
|
2010-04-18 02:56:34 +08:00
|
|
|
// If this is a segment register followed by a ':', then this is the start
|
|
|
|
// of a memory reference, otherwise this is a normal register reference.
|
|
|
|
if (getLexer().isNot(AsmToken::Colon))
|
|
|
|
return X86Operand::CreateReg(RegNo, Start, End);
|
2010-07-24 06:15:26 +08:00
|
|
|
|
2014-08-01 07:03:22 +08:00
|
|
|
if (!X86MCRegisterClasses[X86::SEGMENT_REGRegClassID].contains(RegNo))
|
|
|
|
return ErrorOperand(Start, "invalid segment register");
|
|
|
|
|
2010-04-18 02:56:34 +08:00
|
|
|
getParser().Lex(); // Eat the colon.
|
|
|
|
return ParseMemOperand(RegNo, Start);
|
2010-01-16 02:27:19 +08:00
|
|
|
}
|
2009-07-29 06:40:46 +08:00
|
|
|
case AsmToken::Dollar: {
|
|
|
|
// $42 -> immediate.
|
2010-01-20 05:44:56 +08:00
|
|
|
SMLoc Start = Parser.getTok().getLoc(), End;
|
2010-01-20 04:27:46 +08:00
|
|
|
Parser.Lex();
|
2009-08-31 16:08:38 +08:00
|
|
|
const MCExpr *Val;
|
2013-02-21 06:21:35 +08:00
|
|
|
if (getParser().parseExpression(Val, End))
|
2014-04-25 13:30:21 +08:00
|
|
|
return nullptr;
|
2010-01-16 03:28:38 +08:00
|
|
|
return X86Operand::CreateImm(Val, Start, End);
|
2009-07-29 06:40:46 +08:00
|
|
|
}
|
2015-03-02 23:00:34 +08:00
|
|
|
case AsmToken::LCurly:{
|
2018-01-06 14:41:07 +08:00
|
|
|
SMLoc Start = Parser.getTok().getLoc();
|
2018-02-03 01:02:58 +08:00
|
|
|
return ParseRoundingModeOp(Start);
|
2015-03-02 23:00:34 +08:00
|
|
|
}
|
2009-07-29 06:40:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-18 21:52:39 +08:00
|
|
|
// true on failure, false otherwise
|
|
|
|
// If no {z} mark was found - Parser doesn't advance
|
|
|
|
bool X86AsmParser::ParseZ(std::unique_ptr<X86Operand> &Z,
|
|
|
|
const SMLoc &StartLoc) {
|
|
|
|
MCAsmParser &Parser = getParser();
|
|
|
|
// Assuming we are just pass the '{' mark, quering the next token
|
2016-11-20 17:31:11 +08:00
|
|
|
// Searched for {z}, but none was found. Return false, as no parsing error was
|
2016-10-18 21:52:39 +08:00
|
|
|
// encountered
|
|
|
|
if (!(getLexer().is(AsmToken::Identifier) &&
|
|
|
|
(getLexer().getTok().getIdentifier() == "z")))
|
|
|
|
return false;
|
|
|
|
Parser.Lex(); // Eat z
|
|
|
|
// Query and eat the '}' mark
|
|
|
|
if (!getLexer().is(AsmToken::RCurly))
|
|
|
|
return Error(getLexer().getLoc(), "Expected } at this point");
|
|
|
|
Parser.Lex(); // Eat '}'
|
|
|
|
// Assign Z with the {z} mark opernad
|
2016-11-24 23:17:39 +08:00
|
|
|
Z = X86Operand::CreateToken("{z}", StartLoc);
|
2016-10-18 21:52:39 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// true on failure, false otherwise
|
2014-06-09 00:18:35 +08:00
|
|
|
bool X86AsmParser::HandleAVX512Operand(OperandVector &Operands,
|
|
|
|
const MCParsedAsmOperand &Op) {
|
2014-11-11 13:18:41 +08:00
|
|
|
MCAsmParser &Parser = getParser();
|
2018-02-03 01:02:58 +08:00
|
|
|
if (getLexer().is(AsmToken::LCurly)) {
|
|
|
|
// Eat "{" and mark the current place.
|
|
|
|
const SMLoc consumedToken = consumeToken();
|
|
|
|
// Distinguish {1to<NUM>} from {%k<NUM>}.
|
|
|
|
if(getLexer().is(AsmToken::Integer)) {
|
|
|
|
// Parse memory broadcasting ({1to<NUM>}).
|
|
|
|
if (getLexer().getTok().getIntVal() != 1)
|
|
|
|
return TokError("Expected 1to<NUM> at this point");
|
|
|
|
Parser.Lex(); // Eat "1" of 1to8
|
|
|
|
if (!getLexer().is(AsmToken::Identifier) ||
|
|
|
|
!getLexer().getTok().getIdentifier().startswith("to"))
|
|
|
|
return TokError("Expected 1to<NUM> at this point");
|
|
|
|
// Recognize only reasonable suffixes.
|
|
|
|
const char *BroadcastPrimitive =
|
|
|
|
StringSwitch<const char*>(getLexer().getTok().getIdentifier())
|
|
|
|
.Case("to2", "{1to2}")
|
|
|
|
.Case("to4", "{1to4}")
|
|
|
|
.Case("to8", "{1to8}")
|
|
|
|
.Case("to16", "{1to16}")
|
|
|
|
.Default(nullptr);
|
|
|
|
if (!BroadcastPrimitive)
|
|
|
|
return TokError("Invalid memory broadcast primitive.");
|
|
|
|
Parser.Lex(); // Eat "toN" of 1toN
|
|
|
|
if (!getLexer().is(AsmToken::RCurly))
|
|
|
|
return TokError("Expected } at this point");
|
|
|
|
Parser.Lex(); // Eat "}"
|
|
|
|
Operands.push_back(X86Operand::CreateToken(BroadcastPrimitive,
|
|
|
|
consumedToken));
|
|
|
|
// No AVX512 specific primitives can pass
|
|
|
|
// after memory broadcasting, so return.
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
// Parse either {k}{z}, {z}{k}, {k} or {z}
|
|
|
|
// last one have no meaning, but GCC accepts it
|
|
|
|
// Currently, we're just pass a '{' mark
|
|
|
|
std::unique_ptr<X86Operand> Z;
|
|
|
|
if (ParseZ(Z, consumedToken))
|
|
|
|
return true;
|
|
|
|
// Reaching here means that parsing of the allegadly '{z}' mark yielded
|
|
|
|
// no errors.
|
|
|
|
// Query for the need of further parsing for a {%k<NUM>} mark
|
|
|
|
if (!Z || getLexer().is(AsmToken::LCurly)) {
|
|
|
|
SMLoc StartLoc = Z ? consumeToken() : consumedToken;
|
|
|
|
// Parse an op-mask register mark ({%k<NUM>}), which is now to be
|
|
|
|
// expected
|
|
|
|
unsigned RegNo;
|
|
|
|
SMLoc RegLoc;
|
|
|
|
if (!ParseRegister(RegNo, RegLoc, StartLoc) &&
|
|
|
|
X86MCRegisterClasses[X86::VK1RegClassID].contains(RegNo)) {
|
|
|
|
if (RegNo == X86::K0)
|
|
|
|
return Error(RegLoc, "Register k0 can't be used as write mask");
|
|
|
|
if (!getLexer().is(AsmToken::RCurly))
|
|
|
|
return Error(getLexer().getLoc(), "Expected } at this point");
|
|
|
|
Operands.push_back(X86Operand::CreateToken("{", StartLoc));
|
|
|
|
Operands.push_back(
|
|
|
|
X86Operand::CreateReg(RegNo, StartLoc, StartLoc));
|
|
|
|
Operands.push_back(X86Operand::CreateToken("}", consumeToken()));
|
|
|
|
} else
|
|
|
|
return Error(getLexer().getLoc(),
|
|
|
|
"Expected an op-mask register at this point");
|
|
|
|
// {%k<NUM>} mark is found, inquire for {z}
|
|
|
|
if (getLexer().is(AsmToken::LCurly) && !Z) {
|
|
|
|
// Have we've found a parsing error, or found no (expected) {z} mark
|
|
|
|
// - report an error
|
|
|
|
if (ParseZ(Z, consumeToken()) || !Z)
|
2016-10-18 21:52:39 +08:00
|
|
|
return Error(getLexer().getLoc(),
|
2018-02-03 01:02:58 +08:00
|
|
|
"Expected a {z} mark at this point");
|
2016-10-18 21:52:39 +08:00
|
|
|
|
2014-02-20 14:34:39 +08:00
|
|
|
}
|
2018-02-03 01:02:58 +08:00
|
|
|
// '{z}' on its own is meaningless, hence should be ignored.
|
|
|
|
// on the contrary - have it been accompanied by a K register,
|
|
|
|
// allow it.
|
|
|
|
if (Z)
|
|
|
|
Operands.push_back(std::move(Z));
|
2014-02-20 14:34:39 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-10-18 21:52:39 +08:00
|
|
|
return false;
|
2014-02-20 14:34:39 +08:00
|
|
|
}
|
|
|
|
|
2010-04-18 02:56:34 +08:00
|
|
|
/// ParseMemOperand: segment: disp(basereg, indexreg, scale). The '%ds:' prefix
|
|
|
|
/// has already been parsed if present.
|
2014-06-09 00:18:35 +08:00
|
|
|
std::unique_ptr<X86Operand> X86AsmParser::ParseMemOperand(unsigned SegReg,
|
|
|
|
SMLoc MemStart) {
|
2010-07-24 06:15:26 +08:00
|
|
|
|
2014-11-11 13:18:41 +08:00
|
|
|
MCAsmParser &Parser = getParser();
|
2009-07-29 06:40:46 +08:00
|
|
|
// We have to disambiguate a parenthesized expression "(4+5)" from the start
|
|
|
|
// of a memory operand with a missing displacement "(%ebx)" or "(,%eax)". The
|
2010-01-24 09:07:33 +08:00
|
|
|
// only way to do this without lookahead is to eat the '(' and see what is
|
|
|
|
// after it.
|
2015-05-30 09:25:56 +08:00
|
|
|
const MCExpr *Disp = MCConstantExpr::create(0, getParser().getContext());
|
2009-07-29 06:40:46 +08:00
|
|
|
if (getLexer().isNot(AsmToken::LParen)) {
|
2010-01-16 03:39:23 +08:00
|
|
|
SMLoc ExprEnd;
|
2014-04-25 13:30:21 +08:00
|
|
|
if (getParser().parseExpression(Disp, ExprEnd)) return nullptr;
|
2010-07-24 06:15:26 +08:00
|
|
|
|
2009-07-29 06:40:46 +08:00
|
|
|
// After parsing the base expression we could either have a parenthesized
|
|
|
|
// memory address or not. If not, return now. If so, eat the (.
|
|
|
|
if (getLexer().isNot(AsmToken::LParen)) {
|
2009-08-01 06:22:54 +08:00
|
|
|
// Unless we have a segment register, treat this as an immediate.
|
2010-01-16 02:44:13 +08:00
|
|
|
if (SegReg == 0)
|
2015-01-02 15:02:25 +08:00
|
|
|
return X86Operand::CreateMem(getPointerWidth(), Disp, MemStart, ExprEnd);
|
|
|
|
return X86Operand::CreateMem(getPointerWidth(), SegReg, Disp, 0, 0, 1,
|
|
|
|
MemStart, ExprEnd);
|
2009-07-29 06:40:46 +08:00
|
|
|
}
|
2010-07-24 06:15:26 +08:00
|
|
|
|
2009-07-29 06:40:46 +08:00
|
|
|
// Eat the '('.
|
2010-01-20 04:27:46 +08:00
|
|
|
Parser.Lex();
|
2009-07-29 06:40:46 +08:00
|
|
|
} else {
|
|
|
|
// Okay, we have a '('. We don't know if this is an expression or not, but
|
|
|
|
// so we have to eat the ( to see beyond it.
|
2010-01-20 05:44:56 +08:00
|
|
|
SMLoc LParenLoc = Parser.getTok().getLoc();
|
2010-01-20 04:27:46 +08:00
|
|
|
Parser.Lex(); // Eat the '('.
|
2010-07-24 06:15:26 +08:00
|
|
|
|
2009-09-04 01:15:07 +08:00
|
|
|
if (getLexer().is(AsmToken::Percent) || getLexer().is(AsmToken::Comma)) {
|
2009-07-29 06:40:46 +08:00
|
|
|
// Nothing to do here, fall into the code below with the '(' part of the
|
|
|
|
// memory operand consumed.
|
|
|
|
} else {
|
2010-01-16 03:28:38 +08:00
|
|
|
SMLoc ExprEnd;
|
2017-09-23 07:37:48 +08:00
|
|
|
getLexer().UnLex(AsmToken(AsmToken::LParen, "("));
|
2010-07-24 06:15:26 +08:00
|
|
|
|
2017-09-23 07:37:48 +08:00
|
|
|
// It must be either an parenthesized expression, or an expression that
|
|
|
|
// begins from a parenthesized expression, parse it now. Example: (1+2) or
|
|
|
|
// (1+2)+3
|
|
|
|
if (getParser().parseExpression(Disp, ExprEnd))
|
2014-04-25 13:30:21 +08:00
|
|
|
return nullptr;
|
2010-07-24 06:15:26 +08:00
|
|
|
|
2009-07-29 06:40:46 +08:00
|
|
|
// After parsing the base expression we could either have a parenthesized
|
|
|
|
// memory address or not. If not, return now. If so, eat the (.
|
|
|
|
if (getLexer().isNot(AsmToken::LParen)) {
|
2009-08-01 06:22:54 +08:00
|
|
|
// Unless we have a segment register, treat this as an immediate.
|
2010-01-16 02:44:13 +08:00
|
|
|
if (SegReg == 0)
|
2015-01-02 15:02:25 +08:00
|
|
|
return X86Operand::CreateMem(getPointerWidth(), Disp, LParenLoc,
|
|
|
|
ExprEnd);
|
|
|
|
return X86Operand::CreateMem(getPointerWidth(), SegReg, Disp, 0, 0, 1,
|
|
|
|
MemStart, ExprEnd);
|
2009-07-29 06:40:46 +08:00
|
|
|
}
|
2010-07-24 06:15:26 +08:00
|
|
|
|
2009-07-29 06:40:46 +08:00
|
|
|
// Eat the '('.
|
2010-01-20 04:27:46 +08:00
|
|
|
Parser.Lex();
|
2009-07-29 06:40:46 +08:00
|
|
|
}
|
|
|
|
}
|
2010-07-24 06:15:26 +08:00
|
|
|
|
2009-07-29 06:40:46 +08:00
|
|
|
// If we reached here, then we just ate the ( of the memory operand. Process
|
|
|
|
// the rest of the memory operand.
|
2009-08-01 04:53:16 +08:00
|
|
|
unsigned BaseReg = 0, IndexReg = 0, Scale = 1;
|
2014-01-08 20:58:28 +08:00
|
|
|
SMLoc IndexLoc, BaseLoc;
|
2010-07-24 06:15:26 +08:00
|
|
|
|
2010-01-16 02:51:29 +08:00
|
|
|
if (getLexer().is(AsmToken::Percent)) {
|
2011-10-16 20:10:27 +08:00
|
|
|
SMLoc StartLoc, EndLoc;
|
2014-01-08 20:58:28 +08:00
|
|
|
BaseLoc = Parser.getTok().getLoc();
|
2014-04-25 13:30:21 +08:00
|
|
|
if (ParseRegister(BaseReg, StartLoc, EndLoc)) return nullptr;
|
2010-07-24 08:06:39 +08:00
|
|
|
if (BaseReg == X86::EIZ || BaseReg == X86::RIZ) {
|
2011-10-16 20:10:27 +08:00
|
|
|
Error(StartLoc, "eiz and riz can only be used as index registers",
|
|
|
|
SMRange(StartLoc, EndLoc));
|
2014-04-25 13:30:21 +08:00
|
|
|
return nullptr;
|
2010-07-24 08:06:39 +08:00
|
|
|
}
|
2010-01-16 02:51:29 +08:00
|
|
|
}
|
2010-07-24 06:15:26 +08:00
|
|
|
|
2009-07-29 06:40:46 +08:00
|
|
|
if (getLexer().is(AsmToken::Comma)) {
|
2010-01-20 04:27:46 +08:00
|
|
|
Parser.Lex(); // Eat the comma.
|
2012-03-13 05:32:09 +08:00
|
|
|
IndexLoc = Parser.getTok().getLoc();
|
2009-07-29 06:40:46 +08:00
|
|
|
|
|
|
|
// Following the comma we should have either an index register, or a scale
|
|
|
|
// value. We don't support the later form, but we want to parse it
|
|
|
|
// correctly.
|
|
|
|
//
|
|
|
|
// Not that even though it would be completely consistent to support syntax
|
2010-07-24 08:06:39 +08:00
|
|
|
// like "1(%eax,,1)", the assembler doesn't. Use "eiz" or "riz" for this.
|
2009-09-04 01:15:07 +08:00
|
|
|
if (getLexer().is(AsmToken::Percent)) {
|
2010-01-16 02:51:29 +08:00
|
|
|
SMLoc L;
|
2016-10-05 23:23:35 +08:00
|
|
|
if (ParseRegister(IndexReg, L, L))
|
|
|
|
return nullptr;
|
|
|
|
if (BaseReg == X86::RIP) {
|
|
|
|
Error(IndexLoc, "%rip as base register can not have an index register");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
if (IndexReg == X86::RIP) {
|
|
|
|
Error(IndexLoc, "%rip is not allowed as an index register");
|
|
|
|
return nullptr;
|
|
|
|
}
|
2010-07-24 06:15:26 +08:00
|
|
|
|
2009-07-29 06:40:46 +08:00
|
|
|
if (getLexer().isNot(AsmToken::RParen)) {
|
|
|
|
// Parse the scale amount:
|
|
|
|
// ::= ',' [scale-expression]
|
2018-03-21 03:12:41 +08:00
|
|
|
if (parseToken(AsmToken::Comma, "expected comma in scale expression"))
|
2014-04-25 13:30:21 +08:00
|
|
|
return nullptr;
|
2009-07-29 06:40:46 +08:00
|
|
|
|
|
|
|
if (getLexer().isNot(AsmToken::RParen)) {
|
2010-01-20 05:44:56 +08:00
|
|
|
SMLoc Loc = Parser.getTok().getLoc();
|
2009-07-29 06:40:46 +08:00
|
|
|
|
|
|
|
int64_t ScaleVal;
|
2013-02-21 06:21:35 +08:00
|
|
|
if (getParser().parseAbsoluteExpression(ScaleVal)){
|
2012-03-10 06:24:10 +08:00
|
|
|
Error(Loc, "expected scale expression");
|
2014-04-25 13:30:21 +08:00
|
|
|
return nullptr;
|
2012-07-18 12:59:16 +08:00
|
|
|
}
|
2010-07-24 06:15:26 +08:00
|
|
|
|
2009-07-29 06:40:46 +08:00
|
|
|
// Validate the scale amount.
|
2015-09-22 19:15:07 +08:00
|
|
|
if (X86MCRegisterClasses[X86::GR16RegClassID].contains(BaseReg) &&
|
2014-01-08 20:58:28 +08:00
|
|
|
ScaleVal != 1) {
|
|
|
|
Error(Loc, "scale factor in 16-bit address must be 1");
|
2014-04-25 13:30:21 +08:00
|
|
|
return nullptr;
|
2015-09-22 19:15:07 +08:00
|
|
|
}
|
|
|
|
if (ScaleVal != 1 && ScaleVal != 2 && ScaleVal != 4 &&
|
|
|
|
ScaleVal != 8) {
|
2010-01-16 02:44:13 +08:00
|
|
|
Error(Loc, "scale factor in address must be 1, 2, 4 or 8");
|
2014-04-25 13:30:21 +08:00
|
|
|
return nullptr;
|
2010-01-16 02:44:13 +08:00
|
|
|
}
|
2009-07-29 06:40:46 +08:00
|
|
|
Scale = (unsigned)ScaleVal;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (getLexer().isNot(AsmToken::RParen)) {
|
2010-08-25 03:13:38 +08:00
|
|
|
// A scale amount without an index is ignored.
|
2009-07-29 06:40:46 +08:00
|
|
|
// index.
|
2010-01-20 05:44:56 +08:00
|
|
|
SMLoc Loc = Parser.getTok().getLoc();
|
2009-07-29 06:40:46 +08:00
|
|
|
|
|
|
|
int64_t Value;
|
2013-02-21 06:21:35 +08:00
|
|
|
if (getParser().parseAbsoluteExpression(Value))
|
2014-04-25 13:30:21 +08:00
|
|
|
return nullptr;
|
2010-07-24 06:15:26 +08:00
|
|
|
|
2010-08-25 03:13:38 +08:00
|
|
|
if (Value != 1)
|
|
|
|
Warning(Loc, "scale factor without index register is ignored");
|
|
|
|
Scale = 1;
|
2009-07-29 06:40:46 +08:00
|
|
|
}
|
|
|
|
}
|
2010-07-24 06:15:26 +08:00
|
|
|
|
2009-07-29 06:40:46 +08:00
|
|
|
// Ok, we've eaten the memory operand, verify we have a ')' and eat it too.
|
2013-01-08 03:00:49 +08:00
|
|
|
SMLoc MemEnd = Parser.getTok().getEndLoc();
|
2018-03-21 03:12:41 +08:00
|
|
|
if (parseToken(AsmToken::RParen, "unexpected token in memory operand"))
|
|
|
|
return nullptr;
|
2010-07-24 06:15:26 +08:00
|
|
|
|
2014-01-08 20:58:28 +08:00
|
|
|
// Check for use of invalid 16-bit registers. Only BX/BP/SI/DI are allowed,
|
|
|
|
// and then only in non-64-bit modes. Except for DX, which is a special case
|
|
|
|
// because an unofficial form of in/out instructions uses it.
|
|
|
|
if (X86MCRegisterClasses[X86::GR16RegClassID].contains(BaseReg) &&
|
|
|
|
(is64BitMode() || (BaseReg != X86::BX && BaseReg != X86::BP &&
|
|
|
|
BaseReg != X86::SI && BaseReg != X86::DI)) &&
|
|
|
|
BaseReg != X86::DX) {
|
|
|
|
Error(BaseLoc, "invalid 16-bit base register");
|
2014-04-25 13:30:21 +08:00
|
|
|
return nullptr;
|
2014-01-08 20:58:28 +08:00
|
|
|
}
|
|
|
|
if (BaseReg == 0 &&
|
|
|
|
X86MCRegisterClasses[X86::GR16RegClassID].contains(IndexReg)) {
|
|
|
|
Error(IndexLoc, "16-bit memory operand may not include only index register");
|
2014-04-25 13:30:21 +08:00
|
|
|
return nullptr;
|
2014-01-08 20:58:28 +08:00
|
|
|
}
|
2014-01-24 06:34:42 +08:00
|
|
|
|
|
|
|
StringRef ErrMsg;
|
2017-07-25 21:05:12 +08:00
|
|
|
if (CheckBaseRegAndIndexRegAndScale(BaseReg, IndexReg, Scale, ErrMsg)) {
|
2014-01-24 06:34:42 +08:00
|
|
|
Error(BaseLoc, ErrMsg);
|
2014-04-25 13:30:21 +08:00
|
|
|
return nullptr;
|
2012-03-13 05:32:09 +08:00
|
|
|
}
|
|
|
|
|
2014-08-01 07:26:35 +08:00
|
|
|
if (SegReg || BaseReg || IndexReg)
|
2015-01-02 15:02:25 +08:00
|
|
|
return X86Operand::CreateMem(getPointerWidth(), SegReg, Disp, BaseReg,
|
|
|
|
IndexReg, Scale, MemStart, MemEnd);
|
|
|
|
return X86Operand::CreateMem(getPointerWidth(), Disp, MemStart, MemEnd);
|
2009-07-21 04:01:54 +08:00
|
|
|
}
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
|
|
|
|
SMLoc NameLoc, OperandVector &Operands) {
|
2014-11-11 13:18:41 +08:00
|
|
|
MCAsmParser &Parser = getParser();
|
2012-10-26 04:41:34 +08:00
|
|
|
InstInfo = &Info;
|
2010-10-31 03:23:13 +08:00
|
|
|
StringRef PatchedName = Name;
|
2010-05-26 03:49:32 +08:00
|
|
|
|
2017-07-30 19:12:47 +08:00
|
|
|
if ((Name.equals("jmp") || Name.equals("jc") || Name.equals("jz")) &&
|
|
|
|
isParsingIntelSyntax() && isParsingInlineAsm()) {
|
2016-10-14 16:09:40 +08:00
|
|
|
StringRef NextTok = Parser.getTok().getString();
|
|
|
|
if (NextTok == "short") {
|
|
|
|
SMLoc NameEndLoc =
|
|
|
|
NameLoc.getFromPointer(NameLoc.getPointer() + Name.size());
|
|
|
|
// Eat the short keyword
|
|
|
|
Parser.Lex();
|
|
|
|
// MS ignores the short keyword, it determines the jmp type based
|
|
|
|
// on the distance of the label
|
|
|
|
InstInfo->AsmRewrites->emplace_back(AOK_Skip, NameEndLoc,
|
|
|
|
NextTok.size() + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-29 04:23:50 +08:00
|
|
|
// FIXME: Hack to recognize setneb as setne.
|
|
|
|
if (PatchedName.startswith("set") && PatchedName.endswith("b") &&
|
|
|
|
PatchedName != "setb" && PatchedName != "setnb")
|
|
|
|
PatchedName = PatchedName.substr(0, Name.size()-1);
|
2012-06-28 06:34:28 +08:00
|
|
|
|
2010-05-26 03:49:32 +08:00
|
|
|
// FIXME: Hack to recognize cmp<comparison code>{ss,sd,ps,pd}.
|
2010-06-24 05:10:57 +08:00
|
|
|
if ((PatchedName.startswith("cmp") || PatchedName.startswith("vcmp")) &&
|
2010-05-26 03:49:32 +08:00
|
|
|
(PatchedName.endswith("ss") || PatchedName.endswith("sd") ||
|
|
|
|
PatchedName.endswith("ps") || PatchedName.endswith("pd"))) {
|
2012-03-29 15:11:23 +08:00
|
|
|
bool IsVCMP = PatchedName[0] == 'v';
|
2015-02-15 15:13:48 +08:00
|
|
|
unsigned CCIdx = IsVCMP ? 4 : 3;
|
|
|
|
unsigned ComparisonCode = StringSwitch<unsigned>(
|
|
|
|
PatchedName.slice(CCIdx, PatchedName.size() - 2))
|
2012-03-29 15:11:23 +08:00
|
|
|
.Case("eq", 0x00)
|
2016-01-25 16:43:26 +08:00
|
|
|
.Case("eq_oq", 0x00)
|
2012-03-29 15:11:23 +08:00
|
|
|
.Case("lt", 0x01)
|
2016-01-25 16:43:26 +08:00
|
|
|
.Case("lt_os", 0x01)
|
2012-03-29 15:11:23 +08:00
|
|
|
.Case("le", 0x02)
|
2016-01-25 16:43:26 +08:00
|
|
|
.Case("le_os", 0x02)
|
2012-03-29 15:11:23 +08:00
|
|
|
.Case("unord", 0x03)
|
2016-01-25 16:43:26 +08:00
|
|
|
.Case("unord_q", 0x03)
|
2012-03-29 15:11:23 +08:00
|
|
|
.Case("neq", 0x04)
|
2016-01-25 16:43:26 +08:00
|
|
|
.Case("neq_uq", 0x04)
|
2012-03-29 15:11:23 +08:00
|
|
|
.Case("nlt", 0x05)
|
2016-01-25 16:43:26 +08:00
|
|
|
.Case("nlt_us", 0x05)
|
2012-03-29 15:11:23 +08:00
|
|
|
.Case("nle", 0x06)
|
2016-01-25 16:43:26 +08:00
|
|
|
.Case("nle_us", 0x06)
|
2012-03-29 15:11:23 +08:00
|
|
|
.Case("ord", 0x07)
|
2016-01-25 16:43:26 +08:00
|
|
|
.Case("ord_q", 0x07)
|
2012-03-29 15:11:23 +08:00
|
|
|
/* AVX only from here */
|
|
|
|
.Case("eq_uq", 0x08)
|
|
|
|
.Case("nge", 0x09)
|
2016-01-25 16:43:26 +08:00
|
|
|
.Case("nge_us", 0x09)
|
2010-07-08 06:24:03 +08:00
|
|
|
.Case("ngt", 0x0A)
|
2016-01-25 16:43:26 +08:00
|
|
|
.Case("ngt_us", 0x0A)
|
2010-07-08 06:24:03 +08:00
|
|
|
.Case("false", 0x0B)
|
2016-01-25 16:43:26 +08:00
|
|
|
.Case("false_oq", 0x0B)
|
2010-07-08 06:24:03 +08:00
|
|
|
.Case("neq_oq", 0x0C)
|
|
|
|
.Case("ge", 0x0D)
|
2016-01-25 16:43:26 +08:00
|
|
|
.Case("ge_os", 0x0D)
|
2010-07-08 06:24:03 +08:00
|
|
|
.Case("gt", 0x0E)
|
2016-01-25 16:43:26 +08:00
|
|
|
.Case("gt_os", 0x0E)
|
2010-07-08 06:24:03 +08:00
|
|
|
.Case("true", 0x0F)
|
2016-01-25 16:43:26 +08:00
|
|
|
.Case("true_uq", 0x0F)
|
2010-07-08 06:24:03 +08:00
|
|
|
.Case("eq_os", 0x10)
|
|
|
|
.Case("lt_oq", 0x11)
|
|
|
|
.Case("le_oq", 0x12)
|
|
|
|
.Case("unord_s", 0x13)
|
|
|
|
.Case("neq_us", 0x14)
|
|
|
|
.Case("nlt_uq", 0x15)
|
|
|
|
.Case("nle_uq", 0x16)
|
|
|
|
.Case("ord_s", 0x17)
|
|
|
|
.Case("eq_us", 0x18)
|
|
|
|
.Case("nge_uq", 0x19)
|
|
|
|
.Case("ngt_uq", 0x1A)
|
|
|
|
.Case("false_os", 0x1B)
|
|
|
|
.Case("neq_os", 0x1C)
|
|
|
|
.Case("ge_oq", 0x1D)
|
|
|
|
.Case("gt_oq", 0x1E)
|
|
|
|
.Case("true_us", 0x1F)
|
2010-05-26 03:49:32 +08:00
|
|
|
.Default(~0U);
|
2015-02-15 15:13:48 +08:00
|
|
|
if (ComparisonCode != ~0U && (IsVCMP || ComparisonCode < 8)) {
|
2015-02-15 05:54:03 +08:00
|
|
|
|
2015-02-15 15:13:48 +08:00
|
|
|
Operands.push_back(X86Operand::CreateToken(PatchedName.slice(0, CCIdx),
|
2015-02-15 05:54:03 +08:00
|
|
|
NameLoc));
|
|
|
|
|
2015-05-30 09:25:56 +08:00
|
|
|
const MCExpr *ImmOp = MCConstantExpr::create(ComparisonCode,
|
2015-02-15 05:54:03 +08:00
|
|
|
getParser().getContext());
|
|
|
|
Operands.push_back(X86Operand::CreateImm(ImmOp, NameLoc, NameLoc));
|
|
|
|
|
|
|
|
PatchedName = PatchedName.substr(PatchedName.size() - 2);
|
2010-05-26 03:49:32 +08:00
|
|
|
}
|
|
|
|
}
|
2010-07-24 02:41:12 +08:00
|
|
|
|
2015-02-15 15:13:48 +08:00
|
|
|
// FIXME: Hack to recognize vpcmp<comparison code>{ub,uw,ud,uq,b,w,d,q}.
|
|
|
|
if (PatchedName.startswith("vpcmp") &&
|
|
|
|
(PatchedName.endswith("b") || PatchedName.endswith("w") ||
|
|
|
|
PatchedName.endswith("d") || PatchedName.endswith("q"))) {
|
|
|
|
unsigned CCIdx = PatchedName.drop_back().back() == 'u' ? 2 : 1;
|
|
|
|
unsigned ComparisonCode = StringSwitch<unsigned>(
|
|
|
|
PatchedName.slice(5, PatchedName.size() - CCIdx))
|
|
|
|
.Case("eq", 0x0) // Only allowed on unsigned. Checked below.
|
|
|
|
.Case("lt", 0x1)
|
|
|
|
.Case("le", 0x2)
|
|
|
|
//.Case("false", 0x3) // Not a documented alias.
|
|
|
|
.Case("neq", 0x4)
|
|
|
|
.Case("nlt", 0x5)
|
|
|
|
.Case("nle", 0x6)
|
|
|
|
//.Case("true", 0x7) // Not a documented alias.
|
|
|
|
.Default(~0U);
|
|
|
|
if (ComparisonCode != ~0U && (ComparisonCode != 0 || CCIdx == 2)) {
|
|
|
|
Operands.push_back(X86Operand::CreateToken("vpcmp", NameLoc));
|
|
|
|
|
2015-05-30 09:25:56 +08:00
|
|
|
const MCExpr *ImmOp = MCConstantExpr::create(ComparisonCode,
|
2015-02-15 15:13:48 +08:00
|
|
|
getParser().getContext());
|
|
|
|
Operands.push_back(X86Operand::CreateImm(ImmOp, NameLoc, NameLoc));
|
|
|
|
|
|
|
|
PatchedName = PatchedName.substr(PatchedName.size() - CCIdx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-13 15:42:25 +08:00
|
|
|
// FIXME: Hack to recognize vpcom<comparison code>{ub,uw,ud,uq,b,w,d,q}.
|
|
|
|
if (PatchedName.startswith("vpcom") &&
|
|
|
|
(PatchedName.endswith("b") || PatchedName.endswith("w") ||
|
|
|
|
PatchedName.endswith("d") || PatchedName.endswith("q"))) {
|
2015-02-15 15:13:48 +08:00
|
|
|
unsigned CCIdx = PatchedName.drop_back().back() == 'u' ? 2 : 1;
|
|
|
|
unsigned ComparisonCode = StringSwitch<unsigned>(
|
|
|
|
PatchedName.slice(5, PatchedName.size() - CCIdx))
|
2015-02-13 15:42:25 +08:00
|
|
|
.Case("lt", 0x0)
|
|
|
|
.Case("le", 0x1)
|
|
|
|
.Case("gt", 0x2)
|
|
|
|
.Case("ge", 0x3)
|
|
|
|
.Case("eq", 0x4)
|
|
|
|
.Case("neq", 0x5)
|
|
|
|
.Case("false", 0x6)
|
|
|
|
.Case("true", 0x7)
|
|
|
|
.Default(~0U);
|
2015-02-15 15:13:48 +08:00
|
|
|
if (ComparisonCode != ~0U) {
|
2015-02-13 15:42:25 +08:00
|
|
|
Operands.push_back(X86Operand::CreateToken("vpcom", NameLoc));
|
|
|
|
|
2015-05-30 09:25:56 +08:00
|
|
|
const MCExpr *ImmOp = MCConstantExpr::create(ComparisonCode,
|
2015-02-13 15:42:25 +08:00
|
|
|
getParser().getContext());
|
|
|
|
Operands.push_back(X86Operand::CreateImm(ImmOp, NameLoc, NameLoc));
|
|
|
|
|
2015-02-15 15:13:48 +08:00
|
|
|
PatchedName = PatchedName.substr(PatchedName.size() - CCIdx);
|
2015-02-13 15:42:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-29 06:40:46 +08:00
|
|
|
|
2010-09-08 13:17:37 +08:00
|
|
|
// Determine whether this is an instruction prefix.
|
2017-08-21 15:50:15 +08:00
|
|
|
// FIXME:
|
2017-09-27 05:35:04 +08:00
|
|
|
// Enhance prefixes integrity robustness. for example, following forms
|
2017-08-21 15:50:15 +08:00
|
|
|
// are currently tolerated:
|
|
|
|
// repz repnz <insn> ; GAS errors for the use of two similar prefixes
|
|
|
|
// lock addq %rax, %rbx ; Destination operand must be of memory type
|
|
|
|
// xacquire <insn> ; xacquire must be accompanied by 'lock'
|
|
|
|
bool isPrefix = StringSwitch<bool>(Name)
|
2017-10-16 19:14:29 +08:00
|
|
|
.Cases("rex64", "data32", "data16", true)
|
|
|
|
.Cases("xacquire", "xrelease", true)
|
|
|
|
.Cases("acquire", "release", isParsingIntelSyntax())
|
|
|
|
.Default(false);
|
|
|
|
|
2018-03-17 21:29:46 +08:00
|
|
|
auto isLockRepeatNtPrefix = [](StringRef N) {
|
2017-10-16 19:14:29 +08:00
|
|
|
return StringSwitch<bool>(N)
|
2018-03-17 21:29:46 +08:00
|
|
|
.Cases("lock", "rep", "repe", "repz", "repne", "repnz", "notrack", true)
|
2017-10-16 19:14:29 +08:00
|
|
|
.Default(false);
|
|
|
|
};
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2016-03-08 02:11:16 +08:00
|
|
|
bool CurlyAsEndOfStatement = false;
|
2017-10-16 19:14:29 +08:00
|
|
|
|
|
|
|
unsigned Flags = X86::IP_NO_PREFIX;
|
2018-03-17 21:29:46 +08:00
|
|
|
while (isLockRepeatNtPrefix(Name.lower())) {
|
2017-10-16 19:14:29 +08:00
|
|
|
unsigned Prefix =
|
|
|
|
StringSwitch<unsigned>(Name)
|
|
|
|
.Cases("lock", "lock", X86::IP_HAS_LOCK)
|
|
|
|
.Cases("rep", "repe", "repz", X86::IP_HAS_REPEAT)
|
|
|
|
.Cases("repne", "repnz", X86::IP_HAS_REPEAT_NE)
|
2018-03-17 21:29:46 +08:00
|
|
|
.Cases("notrack", "notrack", X86::IP_HAS_NOTRACK)
|
2017-10-16 19:14:29 +08:00
|
|
|
.Default(X86::IP_NO_PREFIX); // Invalid prefix (impossible)
|
|
|
|
Flags |= Prefix;
|
2018-01-17 18:12:06 +08:00
|
|
|
if (getLexer().is(AsmToken::EndOfStatement)) {
|
|
|
|
// We don't have real instr with the given prefix
|
|
|
|
// let's use the prefix as the instr.
|
|
|
|
// TODO: there could be several prefixes one after another
|
|
|
|
Flags = X86::IP_NO_PREFIX;
|
|
|
|
break;
|
|
|
|
}
|
2017-10-16 19:14:29 +08:00
|
|
|
Name = Parser.getTok().getString();
|
|
|
|
Parser.Lex(); // eat the prefix
|
2017-12-27 02:29:52 +08:00
|
|
|
// Hack: we could have something like "rep # some comment" or
|
2017-10-16 19:14:29 +08:00
|
|
|
// "lock; cmpxchg16b $1" or "lock\0A\09incl" or "lock/incl"
|
|
|
|
while (Name.startswith(";") || Name.startswith("\n") ||
|
2017-12-27 02:29:52 +08:00
|
|
|
Name.startswith("#") || Name.startswith("\t") ||
|
|
|
|
Name.startswith("/")) {
|
2017-10-16 19:14:29 +08:00
|
|
|
Name = Parser.getTok().getString();
|
|
|
|
Parser.Lex(); // go to next prefix or instr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Flags)
|
|
|
|
PatchedName = Name;
|
|
|
|
Operands.push_back(X86Operand::CreateToken(PatchedName, NameLoc));
|
|
|
|
|
2010-09-08 13:17:37 +08:00
|
|
|
// This does the actual operand parsing. Don't parse any more if we have a
|
|
|
|
// prefix juxtaposed with an operation like "lock incl 4(%rax)", because we
|
|
|
|
// just want to parse the "lock" as the first instruction and the "incl" as
|
|
|
|
// the next one.
|
|
|
|
if (getLexer().isNot(AsmToken::EndOfStatement) && !isPrefix) {
|
2009-08-11 13:00:25 +08:00
|
|
|
// Parse '*' modifier.
|
2013-12-03 00:06:06 +08:00
|
|
|
if (getLexer().is(AsmToken::Star))
|
|
|
|
Operands.push_back(X86Operand::CreateToken("*", consumeToken()));
|
2009-08-11 13:00:25 +08:00
|
|
|
|
2014-02-20 14:34:39 +08:00
|
|
|
// Read the operands.
|
2017-01-19 00:34:25 +08:00
|
|
|
while(1) {
|
2014-06-09 00:18:35 +08:00
|
|
|
if (std::unique_ptr<X86Operand> Op = ParseOperand()) {
|
|
|
|
Operands.push_back(std::move(Op));
|
2016-10-18 21:52:39 +08:00
|
|
|
if (HandleAVX512Operand(Operands, *Operands.back()))
|
2013-09-12 16:55:00 +08:00
|
|
|
return true;
|
2014-02-20 14:34:39 +08:00
|
|
|
} else {
|
|
|
|
return true;
|
2013-09-12 16:55:00 +08:00
|
|
|
}
|
2014-02-20 14:34:39 +08:00
|
|
|
// check for comma and eat it
|
|
|
|
if (getLexer().is(AsmToken::Comma))
|
|
|
|
Parser.Lex();
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
2013-09-12 16:55:00 +08:00
|
|
|
|
2017-07-13 14:48:39 +08:00
|
|
|
// In MS inline asm curly braces mark the beginning/end of a block,
|
|
|
|
// therefore they should be interepreted as end of statement
|
2016-03-08 02:11:16 +08:00
|
|
|
CurlyAsEndOfStatement =
|
|
|
|
isParsingIntelSyntax() && isParsingInlineAsm() &&
|
|
|
|
(getLexer().is(AsmToken::LCurly) || getLexer().is(AsmToken::RCurly));
|
|
|
|
if (getLexer().isNot(AsmToken::EndOfStatement) && !CurlyAsEndOfStatement)
|
2016-09-17 02:30:20 +08:00
|
|
|
return TokError("unexpected token in argument list");
|
2014-02-20 14:34:39 +08:00
|
|
|
}
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2014-02-20 14:34:39 +08:00
|
|
|
// Consume the EndOfStatement or the prefix separator Slash
|
2014-02-20 15:00:10 +08:00
|
|
|
if (getLexer().is(AsmToken::EndOfStatement) ||
|
|
|
|
(isPrefix && getLexer().is(AsmToken::Slash)))
|
2014-02-20 14:34:39 +08:00
|
|
|
Parser.Lex();
|
2016-03-08 02:11:16 +08:00
|
|
|
else if (CurlyAsEndOfStatement)
|
|
|
|
// Add an actual EndOfStatement before the curly brace
|
|
|
|
Info.AsmRewrites->emplace_back(AOK_EndOfStatement,
|
|
|
|
getLexer().getTok().getLoc(), 0);
|
2009-07-29 06:40:46 +08:00
|
|
|
|
[x86] translating "fp" (floating point) instructions from {fadd,fdiv,fmul,fsub,fsubr,fdivr} to {faddp,fdivp,fmulp,fsubp,fsubrp,fdivrp}
LLVM Missing the following instructions: fadd\fdiv\fmul\fsub\fsubr\fdivr.
GAS and MS supporting this instruction and lowering them in to a faddp\fdivp\fmulp\fsubp\fsubrp\fdivrp instructions.
Differential Revision: http://reviews.llvm.org/D14217
llvm-svn: 252908
2015-11-13 00:58:51 +08:00
|
|
|
// This is for gas compatibility and cannot be done in td.
|
|
|
|
// Adding "p" for some floating point with no argument.
|
|
|
|
// For example: fsub --> fsubp
|
|
|
|
bool IsFp =
|
|
|
|
Name == "fsub" || Name == "fdiv" || Name == "fsubr" || Name == "fdivr";
|
|
|
|
if (IsFp && Operands.size() == 1) {
|
|
|
|
const char *Repl = StringSwitch<const char *>(Name)
|
|
|
|
.Case("fsub", "fsubp")
|
|
|
|
.Case("fdiv", "fdivp")
|
|
|
|
.Case("fsubr", "fsubrp")
|
|
|
|
.Case("fdivr", "fdivrp");
|
|
|
|
static_cast<X86Operand &>(*Operands[0]).setTokenValue(Repl);
|
|
|
|
}
|
|
|
|
|
2016-08-09 02:01:04 +08:00
|
|
|
// Moving a 32 or 16 bit value into a segment register has the same
|
|
|
|
// behavior. Modify such instructions to always take shorter form.
|
|
|
|
if ((Name == "mov" || Name == "movw" || Name == "movl") &&
|
|
|
|
(Operands.size() == 3)) {
|
|
|
|
X86Operand &Op1 = (X86Operand &)*Operands[1];
|
|
|
|
X86Operand &Op2 = (X86Operand &)*Operands[2];
|
|
|
|
SMLoc Loc = Op1.getEndLoc();
|
|
|
|
if (Op1.isReg() && Op2.isReg() &&
|
|
|
|
X86MCRegisterClasses[X86::SEGMENT_REGRegClassID].contains(
|
|
|
|
Op2.getReg()) &&
|
|
|
|
(X86MCRegisterClasses[X86::GR16RegClassID].contains(Op1.getReg()) ||
|
|
|
|
X86MCRegisterClasses[X86::GR32RegClassID].contains(Op1.getReg()))) {
|
|
|
|
// Change instruction name to match new instruction.
|
|
|
|
if (Name != "mov" && Name[3] == (is16BitMode() ? 'l' : 'w')) {
|
|
|
|
Name = is16BitMode() ? "movw" : "movl";
|
|
|
|
Operands[0] = X86Operand::CreateToken(Name, NameLoc);
|
|
|
|
}
|
|
|
|
// Select the correct equivalent 16-/32-bit source register.
|
|
|
|
unsigned Reg =
|
|
|
|
getX86SubSuperRegisterOrZero(Op1.getReg(), is16BitMode() ? 16 : 32);
|
|
|
|
Operands[1] = X86Operand::CreateReg(Reg, Loc, Loc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-30 03:54:27 +08:00
|
|
|
// This is a terrible hack to handle "out[s]?[bwl]? %al, (%dx)" ->
|
2010-11-07 03:25:43 +08:00
|
|
|
// "outb %al, %dx". Out doesn't take a memory form, but this is a widely
|
|
|
|
// documented form in various unofficial manuals, so a lot of code uses it.
|
2016-06-30 03:54:27 +08:00
|
|
|
if ((Name == "outb" || Name == "outsb" || Name == "outw" || Name == "outsw" ||
|
|
|
|
Name == "outl" || Name == "outsl" || Name == "out" || Name == "outs") &&
|
2010-11-07 03:25:43 +08:00
|
|
|
Operands.size() == 3) {
|
2014-06-09 00:18:35 +08:00
|
|
|
X86Operand &Op = (X86Operand &)*Operands.back();
|
2010-11-07 03:25:43 +08:00
|
|
|
if (Op.isMem() && Op.Mem.SegReg == 0 &&
|
|
|
|
isa<MCConstantExpr>(Op.Mem.Disp) &&
|
|
|
|
cast<MCConstantExpr>(Op.Mem.Disp)->getValue() == 0 &&
|
|
|
|
Op.Mem.BaseReg == MatchRegisterName("dx") && Op.Mem.IndexReg == 0) {
|
|
|
|
SMLoc Loc = Op.getEndLoc();
|
|
|
|
Operands.back() = X86Operand::CreateReg(Op.Mem.BaseReg, Loc, Loc);
|
|
|
|
}
|
|
|
|
}
|
2016-06-30 03:54:27 +08:00
|
|
|
// Same hack for "in[s]?[bwl]? (%dx), %al" -> "inb %dx, %al".
|
|
|
|
if ((Name == "inb" || Name == "insb" || Name == "inw" || Name == "insw" ||
|
|
|
|
Name == "inl" || Name == "insl" || Name == "in" || Name == "ins") &&
|
2011-02-23 04:40:09 +08:00
|
|
|
Operands.size() == 3) {
|
2014-06-09 00:18:35 +08:00
|
|
|
X86Operand &Op = (X86Operand &)*Operands[1];
|
2011-02-23 04:40:09 +08:00
|
|
|
if (Op.isMem() && Op.Mem.SegReg == 0 &&
|
|
|
|
isa<MCConstantExpr>(Op.Mem.Disp) &&
|
|
|
|
cast<MCConstantExpr>(Op.Mem.Disp)->getValue() == 0 &&
|
|
|
|
Op.Mem.BaseReg == MatchRegisterName("dx") && Op.Mem.IndexReg == 0) {
|
|
|
|
SMLoc Loc = Op.getEndLoc();
|
2014-06-09 00:18:35 +08:00
|
|
|
Operands[1] = X86Operand::CreateReg(Op.Mem.BaseReg, Loc, Loc);
|
2011-02-23 04:40:09 +08:00
|
|
|
}
|
|
|
|
}
|
2014-01-22 23:08:55 +08:00
|
|
|
|
2016-01-19 23:37:56 +08:00
|
|
|
SmallVector<std::unique_ptr<MCParsedAsmOperand>, 2> TmpOperands;
|
|
|
|
bool HadVerifyError = false;
|
|
|
|
|
2014-01-22 23:08:55 +08:00
|
|
|
// Append default arguments to "ins[bwld]"
|
2016-01-19 23:37:56 +08:00
|
|
|
if (Name.startswith("ins") &&
|
|
|
|
(Operands.size() == 1 || Operands.size() == 3) &&
|
|
|
|
(Name == "insb" || Name == "insw" || Name == "insl" || Name == "insd" ||
|
|
|
|
Name == "ins")) {
|
|
|
|
|
|
|
|
AddDefaultSrcDestOperands(TmpOperands,
|
2015-07-23 18:23:48 +08:00
|
|
|
X86Operand::CreateReg(X86::DX, NameLoc, NameLoc),
|
|
|
|
DefaultMemDIOperand(NameLoc));
|
2016-01-19 23:37:56 +08:00
|
|
|
HadVerifyError = VerifyAndAdjustOperands(Operands, TmpOperands);
|
2011-03-18 19:59:40 +08:00
|
|
|
}
|
|
|
|
|
2014-01-22 23:08:49 +08:00
|
|
|
// Append default arguments to "outs[bwld]"
|
2016-01-19 23:37:56 +08:00
|
|
|
if (Name.startswith("outs") &&
|
|
|
|
(Operands.size() == 1 || Operands.size() == 3) &&
|
2014-01-22 23:08:49 +08:00
|
|
|
(Name == "outsb" || Name == "outsw" || Name == "outsl" ||
|
2016-01-19 23:37:56 +08:00
|
|
|
Name == "outsd" || Name == "outs")) {
|
|
|
|
AddDefaultSrcDestOperands(TmpOperands, DefaultMemSIOperand(NameLoc),
|
2015-07-23 18:23:48 +08:00
|
|
|
X86Operand::CreateReg(X86::DX, NameLoc, NameLoc));
|
2016-01-19 23:37:56 +08:00
|
|
|
HadVerifyError = VerifyAndAdjustOperands(Operands, TmpOperands);
|
2011-03-18 19:59:40 +08:00
|
|
|
}
|
|
|
|
|
2014-01-22 23:08:08 +08:00
|
|
|
// Transform "lods[bwlq]" into "lods[bwlq] ($SIREG)" for appropriate
|
|
|
|
// values of $SIREG according to the mode. It would be nice if this
|
|
|
|
// could be achieved with InstAlias in the tables.
|
2016-01-19 23:37:56 +08:00
|
|
|
if (Name.startswith("lods") &&
|
|
|
|
(Operands.size() == 1 || Operands.size() == 2) &&
|
2011-03-18 19:59:40 +08:00
|
|
|
(Name == "lods" || Name == "lodsb" || Name == "lodsw" ||
|
2016-01-19 23:37:56 +08:00
|
|
|
Name == "lodsl" || Name == "lodsd" || Name == "lodsq")) {
|
|
|
|
TmpOperands.push_back(DefaultMemSIOperand(NameLoc));
|
|
|
|
HadVerifyError = VerifyAndAdjustOperands(Operands, TmpOperands);
|
|
|
|
}
|
2014-01-22 23:08:08 +08:00
|
|
|
|
2014-01-22 23:08:21 +08:00
|
|
|
// Transform "stos[bwlq]" into "stos[bwlq] ($DIREG)" for appropriate
|
|
|
|
// values of $DIREG according to the mode. It would be nice if this
|
|
|
|
// could be achieved with InstAlias in the tables.
|
2016-01-19 23:37:56 +08:00
|
|
|
if (Name.startswith("stos") &&
|
|
|
|
(Operands.size() == 1 || Operands.size() == 2) &&
|
2011-03-18 19:59:40 +08:00
|
|
|
(Name == "stos" || Name == "stosb" || Name == "stosw" ||
|
2016-01-19 23:37:56 +08:00
|
|
|
Name == "stosl" || Name == "stosd" || Name == "stosq")) {
|
|
|
|
TmpOperands.push_back(DefaultMemDIOperand(NameLoc));
|
|
|
|
HadVerifyError = VerifyAndAdjustOperands(Operands, TmpOperands);
|
|
|
|
}
|
2011-03-18 19:59:40 +08:00
|
|
|
|
2014-01-22 23:08:27 +08:00
|
|
|
// Transform "scas[bwlq]" into "scas[bwlq] ($DIREG)" for appropriate
|
|
|
|
// values of $DIREG according to the mode. It would be nice if this
|
|
|
|
// could be achieved with InstAlias in the tables.
|
2016-01-19 23:37:56 +08:00
|
|
|
if (Name.startswith("scas") &&
|
|
|
|
(Operands.size() == 1 || Operands.size() == 2) &&
|
2014-01-22 23:08:27 +08:00
|
|
|
(Name == "scas" || Name == "scasb" || Name == "scasw" ||
|
2016-01-19 23:37:56 +08:00
|
|
|
Name == "scasl" || Name == "scasd" || Name == "scasq")) {
|
|
|
|
TmpOperands.push_back(DefaultMemDIOperand(NameLoc));
|
|
|
|
HadVerifyError = VerifyAndAdjustOperands(Operands, TmpOperands);
|
|
|
|
}
|
2014-01-22 23:08:27 +08:00
|
|
|
|
2014-01-22 23:08:36 +08:00
|
|
|
// Add default SI and DI operands to "cmps[bwlq]".
|
|
|
|
if (Name.startswith("cmps") &&
|
2016-01-19 23:37:56 +08:00
|
|
|
(Operands.size() == 1 || Operands.size() == 3) &&
|
2014-01-22 23:08:36 +08:00
|
|
|
(Name == "cmps" || Name == "cmpsb" || Name == "cmpsw" ||
|
|
|
|
Name == "cmpsl" || Name == "cmpsd" || Name == "cmpsq")) {
|
2016-01-19 23:37:56 +08:00
|
|
|
AddDefaultSrcDestOperands(TmpOperands, DefaultMemDIOperand(NameLoc),
|
|
|
|
DefaultMemSIOperand(NameLoc));
|
|
|
|
HadVerifyError = VerifyAndAdjustOperands(Operands, TmpOperands);
|
2014-01-22 23:08:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Add default SI and DI operands to "movs[bwlq]".
|
2016-01-19 23:37:56 +08:00
|
|
|
if (((Name.startswith("movs") &&
|
|
|
|
(Name == "movs" || Name == "movsb" || Name == "movsw" ||
|
|
|
|
Name == "movsl" || Name == "movsd" || Name == "movsq")) ||
|
|
|
|
(Name.startswith("smov") &&
|
|
|
|
(Name == "smov" || Name == "smovb" || Name == "smovw" ||
|
|
|
|
Name == "smovl" || Name == "smovd" || Name == "smovq"))) &&
|
|
|
|
(Operands.size() == 1 || Operands.size() == 3)) {
|
2016-11-21 23:50:56 +08:00
|
|
|
if (Name == "movsd" && Operands.size() == 1 && !isParsingIntelSyntax())
|
2016-01-19 23:37:56 +08:00
|
|
|
Operands.back() = X86Operand::CreateToken("movsl", NameLoc);
|
|
|
|
AddDefaultSrcDestOperands(TmpOperands, DefaultMemSIOperand(NameLoc),
|
|
|
|
DefaultMemDIOperand(NameLoc));
|
|
|
|
HadVerifyError = VerifyAndAdjustOperands(Operands, TmpOperands);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if we encountered an error for one the string insturctions
|
|
|
|
if (HadVerifyError) {
|
|
|
|
return HadVerifyError;
|
2014-01-22 23:08:36 +08:00
|
|
|
}
|
|
|
|
|
2010-09-15 12:33:27 +08:00
|
|
|
// FIXME: Hack to handle recognize s{hr,ar,hl} $1, <op>. Canonicalize to
|
2010-09-12 00:32:12 +08:00
|
|
|
// "shift <op>".
|
2010-03-13 08:47:29 +08:00
|
|
|
if ((Name.startswith("shr") || Name.startswith("sar") ||
|
2010-11-07 05:23:40 +08:00
|
|
|
Name.startswith("shl") || Name.startswith("sal") ||
|
|
|
|
Name.startswith("rcl") || Name.startswith("rcr") ||
|
|
|
|
Name.startswith("rol") || Name.startswith("ror")) &&
|
2010-09-07 02:32:06 +08:00
|
|
|
Operands.size() == 3) {
|
2012-01-31 04:02:42 +08:00
|
|
|
if (isParsingIntelSyntax()) {
|
2012-01-25 05:43:36 +08:00
|
|
|
// Intel syntax
|
2014-06-09 00:18:35 +08:00
|
|
|
X86Operand &Op1 = static_cast<X86Operand &>(*Operands[2]);
|
|
|
|
if (Op1.isImm() && isa<MCConstantExpr>(Op1.getImm()) &&
|
|
|
|
cast<MCConstantExpr>(Op1.getImm())->getValue() == 1)
|
2012-07-18 12:59:16 +08:00
|
|
|
Operands.pop_back();
|
2012-01-25 05:43:36 +08:00
|
|
|
} else {
|
2014-06-09 00:18:35 +08:00
|
|
|
X86Operand &Op1 = static_cast<X86Operand &>(*Operands[1]);
|
|
|
|
if (Op1.isImm() && isa<MCConstantExpr>(Op1.getImm()) &&
|
|
|
|
cast<MCConstantExpr>(Op1.getImm())->getValue() == 1)
|
2012-07-18 12:59:16 +08:00
|
|
|
Operands.erase(Operands.begin() + 1);
|
2010-09-07 02:32:06 +08:00
|
|
|
}
|
2010-03-21 06:36:38 +08:00
|
|
|
}
|
2012-06-28 06:34:28 +08:00
|
|
|
|
2011-04-10 03:41:05 +08:00
|
|
|
// Transforms "int $3" into "int3" as a size optimization. We can't write an
|
|
|
|
// instalias with an immediate operand yet.
|
|
|
|
if (Name == "int" && Operands.size() == 2) {
|
2014-06-09 00:18:35 +08:00
|
|
|
X86Operand &Op1 = static_cast<X86Operand &>(*Operands[1]);
|
2015-07-24 03:27:07 +08:00
|
|
|
if (Op1.isImm())
|
|
|
|
if (auto *CE = dyn_cast<MCConstantExpr>(Op1.getImm()))
|
|
|
|
if (CE->getValue() == 3) {
|
|
|
|
Operands.erase(Operands.begin() + 1);
|
|
|
|
static_cast<X86Operand &>(*Operands[0]).setTokenValue("int3");
|
|
|
|
}
|
2011-04-10 03:41:05 +08:00
|
|
|
}
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2016-01-20 00:35:38 +08:00
|
|
|
// Transforms "xlat mem8" into "xlatb"
|
|
|
|
if ((Name == "xlat" || Name == "xlatb") && Operands.size() == 2) {
|
|
|
|
X86Operand &Op1 = static_cast<X86Operand &>(*Operands[1]);
|
|
|
|
if (Op1.isMem8()) {
|
|
|
|
Warning(Op1.getStartLoc(), "memory operand is only for determining the "
|
|
|
|
"size, (R|E)BX will be used for the location");
|
|
|
|
Operands.pop_back();
|
|
|
|
static_cast<X86Operand &>(*Operands[0]).setTokenValue("xlatb");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-16 19:14:29 +08:00
|
|
|
if (Flags)
|
|
|
|
Operands.push_back(X86Operand::CreatePrefix(Flags, NameLoc, NameLoc));
|
2010-01-15 06:21:20 +08:00
|
|
|
return false;
|
2009-07-21 02:55:04 +08:00
|
|
|
}
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
bool X86AsmParser::processInstruction(MCInst &Inst, const OperandVector &Ops) {
|
2016-05-23 23:52:59 +08:00
|
|
|
return false;
|
2012-01-19 06:42:29 +08:00
|
|
|
}
|
|
|
|
|
2017-10-27 05:03:54 +08:00
|
|
|
bool X86AsmParser::validateInstruction(MCInst &Inst, const OperandVector &Ops) {
|
|
|
|
const MCRegisterInfo *MRI = getContext().getRegisterInfo();
|
|
|
|
|
|
|
|
switch (Inst.getOpcode()) {
|
|
|
|
case X86::VGATHERDPDYrm:
|
|
|
|
case X86::VGATHERDPDrm:
|
|
|
|
case X86::VGATHERDPSYrm:
|
|
|
|
case X86::VGATHERDPSrm:
|
|
|
|
case X86::VGATHERQPDYrm:
|
|
|
|
case X86::VGATHERQPDrm:
|
|
|
|
case X86::VGATHERQPSYrm:
|
|
|
|
case X86::VGATHERQPSrm:
|
|
|
|
case X86::VPGATHERDDYrm:
|
|
|
|
case X86::VPGATHERDDrm:
|
|
|
|
case X86::VPGATHERDQYrm:
|
|
|
|
case X86::VPGATHERDQrm:
|
|
|
|
case X86::VPGATHERQDYrm:
|
|
|
|
case X86::VPGATHERQDrm:
|
|
|
|
case X86::VPGATHERQQYrm:
|
|
|
|
case X86::VPGATHERQQrm: {
|
|
|
|
unsigned Dest = MRI->getEncodingValue(Inst.getOperand(0).getReg());
|
|
|
|
unsigned Mask = MRI->getEncodingValue(Inst.getOperand(1).getReg());
|
|
|
|
unsigned Index =
|
|
|
|
MRI->getEncodingValue(Inst.getOperand(3 + X86::AddrIndexReg).getReg());
|
|
|
|
if (Dest == Mask || Dest == Index || Mask == Index)
|
|
|
|
return Warning(Ops[0]->getStartLoc(), "mask, index, and destination "
|
|
|
|
"registers should be distinct");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case X86::VGATHERDPDZ128rm:
|
|
|
|
case X86::VGATHERDPDZ256rm:
|
|
|
|
case X86::VGATHERDPDZrm:
|
|
|
|
case X86::VGATHERDPSZ128rm:
|
|
|
|
case X86::VGATHERDPSZ256rm:
|
|
|
|
case X86::VGATHERDPSZrm:
|
|
|
|
case X86::VGATHERQPDZ128rm:
|
|
|
|
case X86::VGATHERQPDZ256rm:
|
|
|
|
case X86::VGATHERQPDZrm:
|
|
|
|
case X86::VGATHERQPSZ128rm:
|
|
|
|
case X86::VGATHERQPSZ256rm:
|
|
|
|
case X86::VGATHERQPSZrm:
|
|
|
|
case X86::VPGATHERDDZ128rm:
|
|
|
|
case X86::VPGATHERDDZ256rm:
|
|
|
|
case X86::VPGATHERDDZrm:
|
|
|
|
case X86::VPGATHERDQZ128rm:
|
|
|
|
case X86::VPGATHERDQZ256rm:
|
|
|
|
case X86::VPGATHERDQZrm:
|
|
|
|
case X86::VPGATHERQDZ128rm:
|
|
|
|
case X86::VPGATHERQDZ256rm:
|
|
|
|
case X86::VPGATHERQDZrm:
|
|
|
|
case X86::VPGATHERQQZ128rm:
|
|
|
|
case X86::VPGATHERQQZ256rm:
|
|
|
|
case X86::VPGATHERQQZrm: {
|
|
|
|
unsigned Dest = MRI->getEncodingValue(Inst.getOperand(0).getReg());
|
|
|
|
unsigned Index =
|
|
|
|
MRI->getEncodingValue(Inst.getOperand(4 + X86::AddrIndexReg).getReg());
|
|
|
|
if (Dest == Index)
|
|
|
|
return Warning(Ops[0]->getStartLoc(), "index and destination registers "
|
|
|
|
"should be distinct");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-06-30 20:32:53 +08:00
|
|
|
static const char *getSubtargetFeatureName(uint64_t Val);
|
2014-03-14 16:58:04 +08:00
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
void X86AsmParser::EmitInstruction(MCInst &Inst, OperandVector &Operands,
|
|
|
|
MCStreamer &Out) {
|
2017-11-09 20:45:40 +08:00
|
|
|
Instrumentation->InstrumentAndEmitInstruction(
|
|
|
|
Inst, Operands, getContext(), MII, Out,
|
|
|
|
getParser().shouldPrintSchedInfo());
|
2014-03-14 16:58:04 +08:00
|
|
|
}
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
bool X86AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
|
|
|
OperandVector &Operands,
|
2014-08-18 19:49:42 +08:00
|
|
|
MCStreamer &Out, uint64_t &ErrorInfo,
|
2014-06-09 00:18:35 +08:00
|
|
|
bool MatchingInlineAsm) {
|
2014-08-27 04:32:34 +08:00
|
|
|
if (isParsingIntelSyntax())
|
|
|
|
return MatchAndEmitIntelInstruction(IDLoc, Opcode, Operands, Out, ErrorInfo,
|
2015-06-30 20:32:53 +08:00
|
|
|
MatchingInlineAsm);
|
2014-08-27 04:32:34 +08:00
|
|
|
return MatchAndEmitATTInstruction(IDLoc, Opcode, Operands, Out, ErrorInfo,
|
2015-06-30 20:32:53 +08:00
|
|
|
MatchingInlineAsm);
|
2014-08-27 04:32:34 +08:00
|
|
|
}
|
2010-09-29 09:50:45 +08:00
|
|
|
|
2014-08-27 04:32:34 +08:00
|
|
|
void X86AsmParser::MatchFPUWaitAlias(SMLoc IDLoc, X86Operand &Op,
|
|
|
|
OperandVector &Operands, MCStreamer &Out,
|
|
|
|
bool MatchingInlineAsm) {
|
2010-09-29 09:50:45 +08:00
|
|
|
// FIXME: This should be replaced with a real .td file alias mechanism.
|
2012-08-29 07:57:47 +08:00
|
|
|
// Also, MatchInstructionImpl should actually *do* the EmitInstruction
|
2010-11-07 03:57:21 +08:00
|
|
|
// call.
|
2014-07-31 08:07:33 +08:00
|
|
|
const char *Repl = StringSwitch<const char *>(Op.getToken())
|
|
|
|
.Case("finit", "fninit")
|
|
|
|
.Case("fsave", "fnsave")
|
|
|
|
.Case("fstcw", "fnstcw")
|
|
|
|
.Case("fstcww", "fnstcw")
|
|
|
|
.Case("fstenv", "fnstenv")
|
|
|
|
.Case("fstsw", "fnstsw")
|
|
|
|
.Case("fstsww", "fnstsw")
|
|
|
|
.Case("fclex", "fnclex")
|
|
|
|
.Default(nullptr);
|
|
|
|
if (Repl) {
|
2010-09-29 09:50:45 +08:00
|
|
|
MCInst Inst;
|
|
|
|
Inst.setOpcode(X86::WAIT);
|
2012-01-27 08:51:27 +08:00
|
|
|
Inst.setLoc(IDLoc);
|
2012-10-13 07:09:25 +08:00
|
|
|
if (!MatchingInlineAsm)
|
2014-03-14 16:58:04 +08:00
|
|
|
EmitInstruction(Inst, Operands, Out);
|
2010-10-01 00:39:29 +08:00
|
|
|
Operands[0] = X86Operand::CreateToken(Repl, IDLoc);
|
2010-09-29 09:50:45 +08:00
|
|
|
}
|
2014-08-27 04:32:34 +08:00
|
|
|
}
|
|
|
|
|
2015-06-30 20:32:53 +08:00
|
|
|
bool X86AsmParser::ErrorMissingFeature(SMLoc IDLoc, uint64_t ErrorInfo,
|
2014-08-27 04:32:34 +08:00
|
|
|
bool MatchingInlineAsm) {
|
2015-06-30 20:32:53 +08:00
|
|
|
assert(ErrorInfo && "Unknown missing feature!");
|
2014-08-27 04:32:34 +08:00
|
|
|
SmallString<126> Msg;
|
|
|
|
raw_svector_ostream OS(Msg);
|
|
|
|
OS << "instruction requires:";
|
2015-06-30 20:32:53 +08:00
|
|
|
uint64_t Mask = 1;
|
|
|
|
for (unsigned i = 0; i < (sizeof(ErrorInfo)*8-1); ++i) {
|
|
|
|
if (ErrorInfo & Mask)
|
|
|
|
OS << ' ' << getSubtargetFeatureName(ErrorInfo & Mask);
|
|
|
|
Mask <<= 1;
|
2014-08-27 04:32:34 +08:00
|
|
|
}
|
2016-09-17 02:30:20 +08:00
|
|
|
return Error(IDLoc, OS.str(), SMRange(), MatchingInlineAsm);
|
2014-08-27 04:32:34 +08:00
|
|
|
}
|
|
|
|
|
2017-10-16 19:14:29 +08:00
|
|
|
static unsigned getPrefixes(OperandVector &Operands) {
|
|
|
|
unsigned Result = 0;
|
|
|
|
X86Operand &Prefix = static_cast<X86Operand &>(*Operands.back());
|
|
|
|
if (Prefix.isPrefix()) {
|
|
|
|
Result = Prefix.getPrefix();
|
|
|
|
Operands.pop_back();
|
|
|
|
}
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2014-08-27 04:32:34 +08:00
|
|
|
bool X86AsmParser::MatchAndEmitATTInstruction(SMLoc IDLoc, unsigned &Opcode,
|
|
|
|
OperandVector &Operands,
|
|
|
|
MCStreamer &Out,
|
|
|
|
uint64_t &ErrorInfo,
|
|
|
|
bool MatchingInlineAsm) {
|
|
|
|
assert(!Operands.empty() && "Unexpect empty operand list!");
|
|
|
|
X86Operand &Op = static_cast<X86Operand &>(*Operands[0]);
|
|
|
|
assert(Op.isToken() && "Leading operand should always be a mnemonic!");
|
2016-09-17 02:30:20 +08:00
|
|
|
SMRange EmptyRange = None;
|
2014-08-27 04:32:34 +08:00
|
|
|
|
|
|
|
// First, handle aliases that expand to multiple instructions.
|
|
|
|
MatchFPUWaitAlias(IDLoc, Op, Operands, Out, MatchingInlineAsm);
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2010-09-07 05:54:15 +08:00
|
|
|
bool WasOriginallyInvalidOperand = false;
|
2017-10-16 19:14:29 +08:00
|
|
|
unsigned Prefixes = getPrefixes(Operands);
|
|
|
|
|
2010-09-29 09:42:58 +08:00
|
|
|
MCInst Inst;
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2017-10-16 19:14:29 +08:00
|
|
|
if (Prefixes)
|
|
|
|
Inst.setFlags(Prefixes);
|
|
|
|
|
2010-05-05 00:12:42 +08:00
|
|
|
// First, try a direct match.
|
2016-09-27 03:33:36 +08:00
|
|
|
switch (MatchInstruction(Operands, Inst, ErrorInfo, MatchingInlineAsm,
|
|
|
|
isParsingIntelSyntax())) {
|
2015-01-03 16:16:34 +08:00
|
|
|
default: llvm_unreachable("Unexpected match result!");
|
2010-09-07 04:08:02 +08:00
|
|
|
case Match_Success:
|
2017-11-09 03:38:48 +08:00
|
|
|
if (!MatchingInlineAsm && validateInstruction(Inst, Operands))
|
2017-10-27 05:03:54 +08:00
|
|
|
return true;
|
2012-01-19 06:42:29 +08:00
|
|
|
// Some instructions need post-processing to, for example, tweak which
|
|
|
|
// encoding is selected. Loop on it while changes happen so the
|
2012-06-28 06:34:28 +08:00
|
|
|
// individual transformations can chain off each other.
|
2012-10-13 07:09:25 +08:00
|
|
|
if (!MatchingInlineAsm)
|
2012-10-02 07:45:51 +08:00
|
|
|
while (processInstruction(Inst, Operands))
|
|
|
|
;
|
2012-01-19 06:42:29 +08:00
|
|
|
|
2012-01-27 08:51:27 +08:00
|
|
|
Inst.setLoc(IDLoc);
|
2012-10-13 07:09:25 +08:00
|
|
|
if (!MatchingInlineAsm)
|
2014-03-14 16:58:04 +08:00
|
|
|
EmitInstruction(Inst, Operands, Out);
|
2012-10-02 07:45:51 +08:00
|
|
|
Opcode = Inst.getOpcode();
|
2010-05-05 00:12:42 +08:00
|
|
|
return false;
|
2014-08-27 04:32:34 +08:00
|
|
|
case Match_MissingFeature:
|
2015-06-30 20:32:53 +08:00
|
|
|
return ErrorMissingFeature(IDLoc, ErrorInfo, MatchingInlineAsm);
|
2010-09-07 05:54:15 +08:00
|
|
|
case Match_InvalidOperand:
|
|
|
|
WasOriginallyInvalidOperand = true;
|
|
|
|
break;
|
|
|
|
case Match_MnemonicFail:
|
2010-09-07 04:08:02 +08:00
|
|
|
break;
|
|
|
|
}
|
2010-05-05 00:12:42 +08:00
|
|
|
|
|
|
|
// FIXME: Ideally, we would only attempt suffix matches for things which are
|
|
|
|
// valid prefixes, and we could just infer the right unambiguous
|
|
|
|
// type. However, that requires substantially more matcher support than the
|
|
|
|
// following hack.
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2010-05-05 00:12:42 +08:00
|
|
|
// Change the operand to point to a temporary token.
|
2014-06-09 00:18:35 +08:00
|
|
|
StringRef Base = Op.getToken();
|
2010-08-12 08:55:38 +08:00
|
|
|
SmallString<16> Tmp;
|
|
|
|
Tmp += Base;
|
|
|
|
Tmp += ' ';
|
2015-03-30 23:42:36 +08:00
|
|
|
Op.setTokenValue(Tmp);
|
2010-05-05 00:12:42 +08:00
|
|
|
|
2010-11-07 02:28:02 +08:00
|
|
|
// If this instruction starts with an 'f', then it is a floating point stack
|
|
|
|
// instruction. These come in up to three forms for 32-bit, 64-bit, and
|
|
|
|
// 80-bit floating point, which use the suffixes s,l,t respectively.
|
|
|
|
//
|
|
|
|
// Otherwise, we assume that this may be an integer instruction, which comes
|
|
|
|
// in 8/16/32/64-bit forms using the b,w,l,q suffixes respectively.
|
|
|
|
const char *Suffixes = Base[0] != 'f' ? "bwlq" : "slt\0";
|
2012-06-28 06:34:28 +08:00
|
|
|
|
2010-05-05 00:12:42 +08:00
|
|
|
// Check for the various suffix matches.
|
2014-08-18 19:49:42 +08:00
|
|
|
uint64_t ErrorInfoIgnore;
|
2015-06-30 20:32:53 +08:00
|
|
|
uint64_t ErrorInfoMissingFeature = 0; // Init suppresses compiler warnings.
|
2014-07-31 06:23:11 +08:00
|
|
|
unsigned Match[4];
|
|
|
|
|
|
|
|
for (unsigned I = 0, E = array_lengthof(Match); I != E; ++I) {
|
|
|
|
Tmp.back() = Suffixes[I];
|
2016-09-27 03:33:36 +08:00
|
|
|
Match[I] = MatchInstruction(Operands, Inst, ErrorInfoIgnore,
|
|
|
|
MatchingInlineAsm, isParsingIntelSyntax());
|
2014-07-31 06:23:11 +08:00
|
|
|
// If this returned as a missing feature failure, remember that.
|
|
|
|
if (Match[I] == Match_MissingFeature)
|
2015-06-30 20:32:53 +08:00
|
|
|
ErrorInfoMissingFeature = ErrorInfoIgnore;
|
2014-07-31 06:23:11 +08:00
|
|
|
}
|
2010-05-05 00:12:42 +08:00
|
|
|
|
|
|
|
// Restore the old token.
|
2014-06-09 00:18:35 +08:00
|
|
|
Op.setTokenValue(Base);
|
2010-05-05 00:12:42 +08:00
|
|
|
|
|
|
|
// If exactly one matched, then we treat that as a successful match (and the
|
|
|
|
// instruction will already have been filled in correctly, since the failing
|
|
|
|
// matches won't have modified it).
|
2010-09-07 04:08:02 +08:00
|
|
|
unsigned NumSuccessfulMatches =
|
2014-07-31 06:23:11 +08:00
|
|
|
std::count(std::begin(Match), std::end(Match), Match_Success);
|
2010-09-29 09:42:58 +08:00
|
|
|
if (NumSuccessfulMatches == 1) {
|
2012-01-27 08:51:27 +08:00
|
|
|
Inst.setLoc(IDLoc);
|
2012-10-13 07:09:25 +08:00
|
|
|
if (!MatchingInlineAsm)
|
2014-03-14 16:58:04 +08:00
|
|
|
EmitInstruction(Inst, Operands, Out);
|
2012-10-02 07:45:51 +08:00
|
|
|
Opcode = Inst.getOpcode();
|
2010-05-05 00:12:42 +08:00
|
|
|
return false;
|
2010-09-29 09:42:58 +08:00
|
|
|
}
|
2010-05-05 00:12:42 +08:00
|
|
|
|
2010-09-07 04:08:02 +08:00
|
|
|
// Otherwise, the match failed, try to produce a decent error message.
|
2010-08-12 08:55:38 +08:00
|
|
|
|
2010-08-12 08:55:42 +08:00
|
|
|
// If we had multiple suffix matches, then identify this as an ambiguous
|
|
|
|
// match.
|
2010-09-07 04:08:02 +08:00
|
|
|
if (NumSuccessfulMatches > 1) {
|
2010-08-12 08:55:42 +08:00
|
|
|
char MatchChars[4];
|
|
|
|
unsigned NumMatches = 0;
|
2014-07-31 06:23:11 +08:00
|
|
|
for (unsigned I = 0, E = array_lengthof(Match); I != E; ++I)
|
|
|
|
if (Match[I] == Match_Success)
|
|
|
|
MatchChars[NumMatches++] = Suffixes[I];
|
2010-08-12 08:55:42 +08:00
|
|
|
|
2014-06-27 06:52:05 +08:00
|
|
|
SmallString<126> Msg;
|
|
|
|
raw_svector_ostream OS(Msg);
|
2010-08-12 08:55:42 +08:00
|
|
|
OS << "ambiguous instructions require an explicit suffix (could be ";
|
|
|
|
for (unsigned i = 0; i != NumMatches; ++i) {
|
|
|
|
if (i != 0)
|
|
|
|
OS << ", ";
|
|
|
|
if (i + 1 == NumMatches)
|
|
|
|
OS << "or ";
|
|
|
|
OS << "'" << Base << MatchChars[i] << "'";
|
|
|
|
}
|
|
|
|
OS << ")";
|
2016-09-17 02:30:20 +08:00
|
|
|
Error(IDLoc, OS.str(), EmptyRange, MatchingInlineAsm);
|
2010-09-07 04:08:02 +08:00
|
|
|
return true;
|
2010-08-12 08:55:42 +08:00
|
|
|
}
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2010-09-07 05:54:15 +08:00
|
|
|
// Okay, we know that none of the variants matched successfully.
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2010-09-07 05:54:15 +08:00
|
|
|
// If all of the instructions reported an invalid mnemonic, then the original
|
|
|
|
// mnemonic was invalid.
|
2014-07-31 06:23:11 +08:00
|
|
|
if (std::count(std::begin(Match), std::end(Match), Match_MnemonicFail) == 4) {
|
2010-09-07 06:11:18 +08:00
|
|
|
if (!WasOriginallyInvalidOperand) {
|
2011-10-16 19:28:29 +08:00
|
|
|
return Error(IDLoc, "invalid instruction mnemonic '" + Base + "'",
|
2016-09-17 02:30:20 +08:00
|
|
|
Op.getLocRange(), MatchingInlineAsm);
|
2010-09-07 06:11:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Recover location info for the operand if we know which was the problem.
|
2014-08-18 19:49:42 +08:00
|
|
|
if (ErrorInfo != ~0ULL) {
|
2012-10-13 08:26:04 +08:00
|
|
|
if (ErrorInfo >= Operands.size())
|
2016-09-17 02:30:20 +08:00
|
|
|
return Error(IDLoc, "too few operands for instruction", EmptyRange,
|
|
|
|
MatchingInlineAsm);
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
X86Operand &Operand = (X86Operand &)*Operands[ErrorInfo];
|
|
|
|
if (Operand.getStartLoc().isValid()) {
|
|
|
|
SMRange OperandRange = Operand.getLocRange();
|
|
|
|
return Error(Operand.getStartLoc(), "invalid operand for instruction",
|
2012-10-13 07:09:25 +08:00
|
|
|
OperandRange, MatchingInlineAsm);
|
2011-10-16 12:47:35 +08:00
|
|
|
}
|
2010-09-07 06:11:18 +08:00
|
|
|
}
|
|
|
|
|
2016-09-17 02:30:20 +08:00
|
|
|
return Error(IDLoc, "invalid operand for instruction", EmptyRange,
|
2012-10-13 07:09:25 +08:00
|
|
|
MatchingInlineAsm);
|
2010-09-07 05:54:15 +08:00
|
|
|
}
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2010-09-07 04:08:02 +08:00
|
|
|
// If one instruction matched with a missing feature, report this as a
|
|
|
|
// missing feature.
|
2014-07-31 06:23:11 +08:00
|
|
|
if (std::count(std::begin(Match), std::end(Match),
|
|
|
|
Match_MissingFeature) == 1) {
|
2015-06-30 20:32:53 +08:00
|
|
|
ErrorInfo = ErrorInfoMissingFeature;
|
|
|
|
return ErrorMissingFeature(IDLoc, ErrorInfoMissingFeature,
|
2014-08-27 04:32:34 +08:00
|
|
|
MatchingInlineAsm);
|
2010-09-07 04:08:02 +08:00
|
|
|
}
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2010-09-07 05:54:15 +08:00
|
|
|
// If one instruction matched with an invalid operand, report this as an
|
|
|
|
// operand failure.
|
2014-07-31 06:23:11 +08:00
|
|
|
if (std::count(std::begin(Match), std::end(Match),
|
|
|
|
Match_InvalidOperand) == 1) {
|
2016-09-17 02:30:20 +08:00
|
|
|
return Error(IDLoc, "invalid operand for instruction", EmptyRange,
|
2014-08-27 04:32:34 +08:00
|
|
|
MatchingInlineAsm);
|
2010-09-07 05:54:15 +08:00
|
|
|
}
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2010-09-07 04:08:02 +08:00
|
|
|
// If all of these were an outright failure, report it in a useless way.
|
2012-08-22 03:36:59 +08:00
|
|
|
Error(IDLoc, "unknown use of instruction mnemonic without a size suffix",
|
2016-09-17 02:30:20 +08:00
|
|
|
EmptyRange, MatchingInlineAsm);
|
2010-05-05 00:12:42 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-08-27 04:32:34 +08:00
|
|
|
bool X86AsmParser::MatchAndEmitIntelInstruction(SMLoc IDLoc, unsigned &Opcode,
|
|
|
|
OperandVector &Operands,
|
|
|
|
MCStreamer &Out,
|
|
|
|
uint64_t &ErrorInfo,
|
|
|
|
bool MatchingInlineAsm) {
|
|
|
|
assert(!Operands.empty() && "Unexpect empty operand list!");
|
|
|
|
X86Operand &Op = static_cast<X86Operand &>(*Operands[0]);
|
|
|
|
assert(Op.isToken() && "Leading operand should always be a mnemonic!");
|
|
|
|
StringRef Mnemonic = Op.getToken();
|
2016-09-17 02:30:20 +08:00
|
|
|
SMRange EmptyRange = None;
|
2016-10-06 23:28:08 +08:00
|
|
|
StringRef Base = Op.getToken();
|
2017-10-16 19:14:29 +08:00
|
|
|
unsigned Prefixes = getPrefixes(Operands);
|
2014-08-27 04:32:34 +08:00
|
|
|
|
|
|
|
// First, handle aliases that expand to multiple instructions.
|
|
|
|
MatchFPUWaitAlias(IDLoc, Op, Operands, Out, MatchingInlineAsm);
|
|
|
|
|
|
|
|
MCInst Inst;
|
|
|
|
|
2017-10-16 19:14:29 +08:00
|
|
|
if (Prefixes)
|
|
|
|
Inst.setFlags(Prefixes);
|
|
|
|
|
2014-08-27 04:32:34 +08:00
|
|
|
// Find one unsized memory operand, if present.
|
|
|
|
X86Operand *UnsizedMemOp = nullptr;
|
|
|
|
for (const auto &Op : Operands) {
|
|
|
|
X86Operand *X86Op = static_cast<X86Operand *>(Op.get());
|
2017-05-05 02:19:52 +08:00
|
|
|
if (X86Op->isMemUnsized()) {
|
|
|
|
UnsizedMemOp = X86Op;
|
2016-11-22 17:30:29 +08:00
|
|
|
// Have we found an unqualified memory operand,
|
|
|
|
// break. IA allows only one memory operand.
|
|
|
|
break;
|
|
|
|
}
|
2014-08-27 04:32:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Allow some instructions to have implicitly pointer-sized operands. This is
|
|
|
|
// compatible with gas.
|
|
|
|
if (UnsizedMemOp) {
|
|
|
|
static const char *const PtrSizedInstrs[] = {"call", "jmp", "push"};
|
|
|
|
for (const char *Instr : PtrSizedInstrs) {
|
|
|
|
if (Mnemonic == Instr) {
|
2015-01-02 15:02:25 +08:00
|
|
|
UnsizedMemOp->Mem.Size = getPointerWidth();
|
2014-08-27 04:32:34 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-06 23:28:08 +08:00
|
|
|
SmallVector<unsigned, 8> Match;
|
|
|
|
uint64_t ErrorInfoMissingFeature = 0;
|
|
|
|
|
|
|
|
// If unsized push has immediate operand we should default the default pointer
|
|
|
|
// size for the size.
|
|
|
|
if (Mnemonic == "push" && Operands.size() == 2) {
|
|
|
|
auto *X86Op = static_cast<X86Operand *>(Operands[1].get());
|
|
|
|
if (X86Op->isImm()) {
|
|
|
|
// If it's not a constant fall through and let remainder take care of it.
|
|
|
|
const auto *CE = dyn_cast<MCConstantExpr>(X86Op->getImm());
|
|
|
|
unsigned Size = getPointerWidth();
|
|
|
|
if (CE &&
|
|
|
|
(isIntN(Size, CE->getValue()) || isUIntN(Size, CE->getValue()))) {
|
|
|
|
SmallString<16> Tmp;
|
|
|
|
Tmp += Base;
|
|
|
|
Tmp += (is64BitMode())
|
|
|
|
? "q"
|
|
|
|
: (is32BitMode()) ? "l" : (is16BitMode()) ? "w" : " ";
|
|
|
|
Op.setTokenValue(Tmp);
|
|
|
|
// Do match in ATT mode to allow explicit suffix usage.
|
|
|
|
Match.push_back(MatchInstruction(Operands, Inst, ErrorInfo,
|
|
|
|
MatchingInlineAsm,
|
|
|
|
false /*isParsingIntelSyntax()*/));
|
|
|
|
Op.setTokenValue(Base);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-27 04:32:34 +08:00
|
|
|
// If an unsized memory operand is present, try to match with each memory
|
|
|
|
// operand size. In Intel assembly, the size is not part of the instruction
|
|
|
|
// mnemonic.
|
|
|
|
if (UnsizedMemOp && UnsizedMemOp->isMemUnsized()) {
|
2014-12-03 10:03:26 +08:00
|
|
|
static const unsigned MopSizes[] = {8, 16, 32, 64, 80, 128, 256, 512};
|
2014-08-27 04:32:34 +08:00
|
|
|
for (unsigned Size : MopSizes) {
|
|
|
|
UnsizedMemOp->Mem.Size = Size;
|
|
|
|
uint64_t ErrorInfoIgnore;
|
2014-08-28 04:10:38 +08:00
|
|
|
unsigned LastOpcode = Inst.getOpcode();
|
2016-09-27 03:33:36 +08:00
|
|
|
unsigned M = MatchInstruction(Operands, Inst, ErrorInfoIgnore,
|
|
|
|
MatchingInlineAsm, isParsingIntelSyntax());
|
2014-08-28 04:10:38 +08:00
|
|
|
if (Match.empty() || LastOpcode != Inst.getOpcode())
|
|
|
|
Match.push_back(M);
|
|
|
|
|
2014-08-27 04:32:34 +08:00
|
|
|
// If this returned as a missing feature failure, remember that.
|
|
|
|
if (Match.back() == Match_MissingFeature)
|
2015-06-30 20:32:53 +08:00
|
|
|
ErrorInfoMissingFeature = ErrorInfoIgnore;
|
2014-08-27 04:32:34 +08:00
|
|
|
}
|
2014-08-28 04:10:38 +08:00
|
|
|
|
|
|
|
// Restore the size of the unsized memory operand if we modified it.
|
2017-05-05 02:19:52 +08:00
|
|
|
UnsizedMemOp->Mem.Size = 0;
|
2014-08-28 04:10:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// If we haven't matched anything yet, this is not a basic integer or FPU
|
2015-01-17 04:16:06 +08:00
|
|
|
// operation. There shouldn't be any ambiguity in our mnemonic table, so try
|
2014-08-28 04:10:38 +08:00
|
|
|
// matching with the unsized operand.
|
|
|
|
if (Match.empty()) {
|
2016-09-27 03:33:36 +08:00
|
|
|
Match.push_back(MatchInstruction(
|
|
|
|
Operands, Inst, ErrorInfo, MatchingInlineAsm, isParsingIntelSyntax()));
|
2014-08-27 04:32:34 +08:00
|
|
|
// If this returned as a missing feature failure, remember that.
|
|
|
|
if (Match.back() == Match_MissingFeature)
|
2015-06-30 20:32:53 +08:00
|
|
|
ErrorInfoMissingFeature = ErrorInfo;
|
2014-08-27 04:32:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Restore the size of the unsized memory operand if we modified it.
|
|
|
|
if (UnsizedMemOp)
|
|
|
|
UnsizedMemOp->Mem.Size = 0;
|
|
|
|
|
|
|
|
// If it's a bad mnemonic, all results will be the same.
|
|
|
|
if (Match.back() == Match_MnemonicFail) {
|
|
|
|
return Error(IDLoc, "invalid instruction mnemonic '" + Mnemonic + "'",
|
2016-09-17 02:30:20 +08:00
|
|
|
Op.getLocRange(), MatchingInlineAsm);
|
2014-08-27 04:32:34 +08:00
|
|
|
}
|
|
|
|
|
2017-05-05 02:19:52 +08:00
|
|
|
unsigned NumSuccessfulMatches =
|
|
|
|
std::count(std::begin(Match), std::end(Match), Match_Success);
|
|
|
|
|
|
|
|
// If matching was ambiguous and we had size information from the frontend,
|
|
|
|
// try again with that. This handles cases like "movxz eax, m8/m16".
|
|
|
|
if (UnsizedMemOp && NumSuccessfulMatches > 1 &&
|
|
|
|
UnsizedMemOp->getMemFrontendSize()) {
|
|
|
|
UnsizedMemOp->Mem.Size = UnsizedMemOp->getMemFrontendSize();
|
|
|
|
unsigned M = MatchInstruction(
|
|
|
|
Operands, Inst, ErrorInfo, MatchingInlineAsm, isParsingIntelSyntax());
|
|
|
|
if (M == Match_Success)
|
|
|
|
NumSuccessfulMatches = 1;
|
|
|
|
|
|
|
|
// Add a rewrite that encodes the size information we used from the
|
|
|
|
// frontend.
|
|
|
|
InstInfo->AsmRewrites->emplace_back(
|
|
|
|
AOK_SizeDirective, UnsizedMemOp->getStartLoc(),
|
|
|
|
/*Len=*/0, UnsizedMemOp->getMemFrontendSize());
|
|
|
|
}
|
|
|
|
|
2014-08-27 04:32:34 +08:00
|
|
|
// If exactly one matched, then we treat that as a successful match (and the
|
|
|
|
// instruction will already have been filled in correctly, since the failing
|
|
|
|
// matches won't have modified it).
|
|
|
|
if (NumSuccessfulMatches == 1) {
|
2017-11-09 03:38:48 +08:00
|
|
|
if (!MatchingInlineAsm && validateInstruction(Inst, Operands))
|
2017-10-27 05:03:54 +08:00
|
|
|
return true;
|
2014-08-27 04:32:34 +08:00
|
|
|
// Some instructions need post-processing to, for example, tweak which
|
|
|
|
// encoding is selected. Loop on it while changes happen so the individual
|
|
|
|
// transformations can chain off each other.
|
|
|
|
if (!MatchingInlineAsm)
|
|
|
|
while (processInstruction(Inst, Operands))
|
|
|
|
;
|
|
|
|
Inst.setLoc(IDLoc);
|
|
|
|
if (!MatchingInlineAsm)
|
|
|
|
EmitInstruction(Inst, Operands, Out);
|
|
|
|
Opcode = Inst.getOpcode();
|
|
|
|
return false;
|
|
|
|
} else if (NumSuccessfulMatches > 1) {
|
|
|
|
assert(UnsizedMemOp &&
|
|
|
|
"multiple matches only possible with unsized memory operands");
|
|
|
|
return Error(UnsizedMemOp->getStartLoc(),
|
|
|
|
"ambiguous operand size for instruction '" + Mnemonic + "\'",
|
2017-05-05 02:19:52 +08:00
|
|
|
UnsizedMemOp->getLocRange());
|
2014-08-27 04:32:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// If one instruction matched with a missing feature, report this as a
|
|
|
|
// missing feature.
|
|
|
|
if (std::count(std::begin(Match), std::end(Match),
|
|
|
|
Match_MissingFeature) == 1) {
|
2015-06-30 20:32:53 +08:00
|
|
|
ErrorInfo = ErrorInfoMissingFeature;
|
2014-08-27 04:32:34 +08:00
|
|
|
return ErrorMissingFeature(IDLoc, ErrorInfoMissingFeature,
|
|
|
|
MatchingInlineAsm);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If one instruction matched with an invalid operand, report this as an
|
|
|
|
// operand failure.
|
|
|
|
if (std::count(std::begin(Match), std::end(Match),
|
|
|
|
Match_InvalidOperand) == 1) {
|
2016-09-17 02:30:20 +08:00
|
|
|
return Error(IDLoc, "invalid operand for instruction", EmptyRange,
|
2014-08-27 04:32:34 +08:00
|
|
|
MatchingInlineAsm);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If all of these were an outright failure, report it in a useless way.
|
2016-09-17 02:30:20 +08:00
|
|
|
return Error(IDLoc, "unknown instruction mnemonic", EmptyRange,
|
2014-08-27 04:32:34 +08:00
|
|
|
MatchingInlineAsm);
|
|
|
|
}
|
|
|
|
|
2014-07-18 04:24:55 +08:00
|
|
|
bool X86AsmParser::OmitRegisterFromClobberLists(unsigned RegNo) {
|
|
|
|
return X86MCRegisterClasses[X86::SEGMENT_REGRegClassID].contains(RegNo);
|
|
|
|
}
|
2010-05-05 00:12:42 +08:00
|
|
|
|
2012-01-13 02:03:40 +08:00
|
|
|
bool X86AsmParser::ParseDirective(AsmToken DirectiveID) {
|
2014-11-11 13:18:41 +08:00
|
|
|
MCAsmParser &Parser = getParser();
|
2010-10-31 01:38:55 +08:00
|
|
|
StringRef IDVal = DirectiveID.getIdentifier();
|
|
|
|
if (IDVal == ".word")
|
|
|
|
return ParseDirectiveWord(2, DirectiveID.getLoc());
|
2011-07-27 08:38:12 +08:00
|
|
|
else if (IDVal.startswith(".code"))
|
|
|
|
return ParseDirectiveCode(IDVal, DirectiveID.getLoc());
|
2012-09-11 04:54:39 +08:00
|
|
|
else if (IDVal.startswith(".att_syntax")) {
|
2017-04-26 17:56:59 +08:00
|
|
|
getParser().setParsingInlineAsm(false);
|
2014-08-07 07:21:13 +08:00
|
|
|
if (getLexer().isNot(AsmToken::EndOfStatement)) {
|
|
|
|
if (Parser.getTok().getString() == "prefix")
|
|
|
|
Parser.Lex();
|
|
|
|
else if (Parser.getTok().getString() == "noprefix")
|
|
|
|
return Error(DirectiveID.getLoc(), "'.att_syntax noprefix' is not "
|
|
|
|
"supported: registers must have a "
|
|
|
|
"'%' prefix in .att_syntax");
|
|
|
|
}
|
2012-09-11 04:54:39 +08:00
|
|
|
getParser().setAssemblerDialect(0);
|
|
|
|
return false;
|
|
|
|
} else if (IDVal.startswith(".intel_syntax")) {
|
2012-02-01 02:14:05 +08:00
|
|
|
getParser().setAssemblerDialect(1);
|
2017-04-26 17:56:59 +08:00
|
|
|
getParser().setParsingInlineAsm(true);
|
2012-01-31 04:02:42 +08:00
|
|
|
if (getLexer().isNot(AsmToken::EndOfStatement)) {
|
2014-01-13 09:15:39 +08:00
|
|
|
if (Parser.getTok().getString() == "noprefix")
|
2012-07-18 12:59:16 +08:00
|
|
|
Parser.Lex();
|
2014-08-07 07:21:13 +08:00
|
|
|
else if (Parser.getTok().getString() == "prefix")
|
|
|
|
return Error(DirectiveID.getLoc(), "'.intel_syntax prefix' is not "
|
|
|
|
"supported: registers must not have "
|
|
|
|
"a '%' prefix in .intel_syntax");
|
2012-01-31 04:02:42 +08:00
|
|
|
}
|
|
|
|
return false;
|
2015-12-14 01:07:23 +08:00
|
|
|
} else if (IDVal == ".even")
|
|
|
|
return parseDirectiveEven(DirectiveID.getLoc());
|
[codeview] Implement FPO data assembler directives
Summary:
This adds a set of new directives that describe 32-bit x86 prologues.
The directives are limited and do not expose the full complexity of
codeview FPO data. They are merely a convenience for the compiler to
generate more readable assembly so we don't need to generate tons of
labels in CodeGen. If our prologue emission changes in the future, we
can change the set of available directives to suit our needs. These are
modelled after the .seh_ directives, which use a different format that
interacts with exception handling.
The directives are:
.cv_fpo_proc _foo
.cv_fpo_pushreg ebp/ebx/etc
.cv_fpo_setframe ebp/esi/etc
.cv_fpo_stackalloc 200
.cv_fpo_endprologue
.cv_fpo_endproc
.cv_fpo_data _foo
I tried to follow the implementation of ARM EHABI CFI directives by
sinking most directives out of MCStreamer and into X86TargetStreamer.
This helps avoid polluting non-X86 code with WinCOFF specific logic.
I used cdb to confirm that this can show locals in parent CSRs in a few
cases, most importantly the one where we use ESI as a frame pointer,
i.e. the one in http://crbug.com/756153#c28
Once we have cdb integration in debuginfo-tests, we can add integration
tests there.
Reviewers: majnemer, hans
Subscribers: aemerson, mgorny, kristof.beyls, llvm-commits, hiraditya
Differential Revision: https://reviews.llvm.org/D38776
llvm-svn: 315513
2017-10-12 05:24:33 +08:00
|
|
|
else if (IDVal == ".cv_fpo_proc")
|
|
|
|
return parseDirectiveFPOProc(DirectiveID.getLoc());
|
|
|
|
else if (IDVal == ".cv_fpo_setframe")
|
|
|
|
return parseDirectiveFPOSetFrame(DirectiveID.getLoc());
|
|
|
|
else if (IDVal == ".cv_fpo_pushreg")
|
|
|
|
return parseDirectiveFPOPushReg(DirectiveID.getLoc());
|
|
|
|
else if (IDVal == ".cv_fpo_stackalloc")
|
|
|
|
return parseDirectiveFPOStackAlloc(DirectiveID.getLoc());
|
|
|
|
else if (IDVal == ".cv_fpo_endprologue")
|
|
|
|
return parseDirectiveFPOEndPrologue(DirectiveID.getLoc());
|
|
|
|
else if (IDVal == ".cv_fpo_endproc")
|
|
|
|
return parseDirectiveFPOEndProc(DirectiveID.getLoc());
|
|
|
|
|
2010-10-31 01:38:55 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-12-14 01:07:23 +08:00
|
|
|
/// parseDirectiveEven
|
|
|
|
/// ::= .even
|
|
|
|
bool X86AsmParser::parseDirectiveEven(SMLoc L) {
|
2018-03-21 03:12:41 +08:00
|
|
|
if (parseToken(AsmToken::EndOfStatement, "unexpected token in directive"))
|
|
|
|
return false;
|
|
|
|
|
2016-10-14 13:47:37 +08:00
|
|
|
const MCSection *Section = getStreamer().getCurrentSectionOnly();
|
2015-12-14 01:07:23 +08:00
|
|
|
if (!Section) {
|
|
|
|
getStreamer().InitSections(false);
|
2016-10-14 13:47:37 +08:00
|
|
|
Section = getStreamer().getCurrentSectionOnly();
|
2015-12-14 01:07:23 +08:00
|
|
|
}
|
|
|
|
if (Section->UseCodeAlign())
|
|
|
|
getStreamer().EmitCodeAlignment(2, 0);
|
|
|
|
else
|
|
|
|
getStreamer().EmitValueToAlignment(2, 0, 1, 0);
|
|
|
|
return false;
|
|
|
|
}
|
2010-10-31 01:38:55 +08:00
|
|
|
/// ParseDirectiveWord
|
|
|
|
/// ::= .word [ expression (, expression)* ]
|
2012-01-13 02:03:40 +08:00
|
|
|
bool X86AsmParser::ParseDirectiveWord(unsigned Size, SMLoc L) {
|
2018-03-21 03:12:41 +08:00
|
|
|
auto parseOp = [&]() -> bool {
|
|
|
|
const MCExpr *Value;
|
|
|
|
SMLoc ExprLoc = getLexer().getLoc();
|
|
|
|
if (getParser().parseExpression(Value))
|
|
|
|
return true;
|
|
|
|
if (const auto *MCE = dyn_cast<MCConstantExpr>(Value)) {
|
|
|
|
assert(Size <= 8 && "Invalid size");
|
|
|
|
uint64_t IntValue = MCE->getValue();
|
|
|
|
if (!isUIntN(8 * Size, IntValue) && !isIntN(8 * Size, IntValue))
|
|
|
|
return Error(ExprLoc, "literal value out of range for directive");
|
|
|
|
getStreamer().EmitIntValue(IntValue, Size);
|
|
|
|
} else
|
|
|
|
getStreamer().EmitValue(Value, Size, ExprLoc);
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
parseMany(parseOp);
|
2010-10-31 01:38:55 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-07-27 08:38:12 +08:00
|
|
|
/// ParseDirectiveCode
|
2014-01-06 12:55:54 +08:00
|
|
|
/// ::= .code16 | .code32 | .code64
|
2012-01-13 02:03:40 +08:00
|
|
|
bool X86AsmParser::ParseDirectiveCode(StringRef IDVal, SMLoc L) {
|
2014-11-11 13:18:41 +08:00
|
|
|
MCAsmParser &Parser = getParser();
|
2016-09-27 03:33:36 +08:00
|
|
|
Code16GCC = false;
|
2014-01-06 12:55:54 +08:00
|
|
|
if (IDVal == ".code16") {
|
|
|
|
Parser.Lex();
|
|
|
|
if (!is16BitMode()) {
|
|
|
|
SwitchMode(X86::Mode16Bit);
|
|
|
|
getParser().getStreamer().EmitAssemblerFlag(MCAF_Code16);
|
|
|
|
}
|
2016-09-27 03:33:36 +08:00
|
|
|
} else if (IDVal == ".code16gcc") {
|
|
|
|
// .code16gcc parses as if in 32-bit mode, but emits code in 16-bit mode.
|
|
|
|
Parser.Lex();
|
|
|
|
Code16GCC = true;
|
|
|
|
if (!is16BitMode()) {
|
|
|
|
SwitchMode(X86::Mode16Bit);
|
|
|
|
getParser().getStreamer().EmitAssemblerFlag(MCAF_Code16);
|
|
|
|
}
|
2014-01-13 09:15:39 +08:00
|
|
|
} else if (IDVal == ".code32") {
|
2011-07-27 08:38:12 +08:00
|
|
|
Parser.Lex();
|
2014-01-06 12:55:54 +08:00
|
|
|
if (!is32BitMode()) {
|
|
|
|
SwitchMode(X86::Mode32Bit);
|
2011-07-27 08:38:12 +08:00
|
|
|
getParser().getStreamer().EmitAssemblerFlag(MCAF_Code32);
|
|
|
|
}
|
|
|
|
} else if (IDVal == ".code64") {
|
|
|
|
Parser.Lex();
|
|
|
|
if (!is64BitMode()) {
|
2014-01-06 12:55:54 +08:00
|
|
|
SwitchMode(X86::Mode64Bit);
|
2011-07-27 08:38:12 +08:00
|
|
|
getParser().getStreamer().EmitAssemblerFlag(MCAF_Code64);
|
|
|
|
}
|
|
|
|
} else {
|
2014-01-13 09:15:39 +08:00
|
|
|
Error(L, "unknown directive " + IDVal);
|
|
|
|
return false;
|
2011-07-27 08:38:12 +08:00
|
|
|
}
|
2010-10-31 01:38:55 +08:00
|
|
|
|
2011-07-27 08:38:12 +08:00
|
|
|
return false;
|
|
|
|
}
|
2010-10-31 01:38:55 +08:00
|
|
|
|
[codeview] Implement FPO data assembler directives
Summary:
This adds a set of new directives that describe 32-bit x86 prologues.
The directives are limited and do not expose the full complexity of
codeview FPO data. They are merely a convenience for the compiler to
generate more readable assembly so we don't need to generate tons of
labels in CodeGen. If our prologue emission changes in the future, we
can change the set of available directives to suit our needs. These are
modelled after the .seh_ directives, which use a different format that
interacts with exception handling.
The directives are:
.cv_fpo_proc _foo
.cv_fpo_pushreg ebp/ebx/etc
.cv_fpo_setframe ebp/esi/etc
.cv_fpo_stackalloc 200
.cv_fpo_endprologue
.cv_fpo_endproc
.cv_fpo_data _foo
I tried to follow the implementation of ARM EHABI CFI directives by
sinking most directives out of MCStreamer and into X86TargetStreamer.
This helps avoid polluting non-X86 code with WinCOFF specific logic.
I used cdb to confirm that this can show locals in parent CSRs in a few
cases, most importantly the one where we use ESI as a frame pointer,
i.e. the one in http://crbug.com/756153#c28
Once we have cdb integration in debuginfo-tests, we can add integration
tests there.
Reviewers: majnemer, hans
Subscribers: aemerson, mgorny, kristof.beyls, llvm-commits, hiraditya
Differential Revision: https://reviews.llvm.org/D38776
llvm-svn: 315513
2017-10-12 05:24:33 +08:00
|
|
|
// .cv_fpo_proc foo
|
|
|
|
bool X86AsmParser::parseDirectiveFPOProc(SMLoc L) {
|
|
|
|
MCAsmParser &Parser = getParser();
|
|
|
|
StringRef ProcName;
|
|
|
|
int64_t ParamsSize;
|
|
|
|
if (Parser.parseIdentifier(ProcName))
|
|
|
|
return Parser.TokError("expected symbol name");
|
|
|
|
if (Parser.parseIntToken(ParamsSize, "expected parameter byte count"))
|
|
|
|
return true;
|
|
|
|
if (!isUIntN(32, ParamsSize))
|
|
|
|
return Parser.TokError("parameters size out of range");
|
|
|
|
if (Parser.parseEOL("unexpected tokens"))
|
|
|
|
return addErrorSuffix(" in '.cv_fpo_proc' directive");
|
|
|
|
MCSymbol *ProcSym = getContext().getOrCreateSymbol(ProcName);
|
|
|
|
return getTargetStreamer().emitFPOProc(ProcSym, ParamsSize, L);
|
|
|
|
}
|
|
|
|
|
|
|
|
// .cv_fpo_setframe ebp
|
|
|
|
bool X86AsmParser::parseDirectiveFPOSetFrame(SMLoc L) {
|
|
|
|
MCAsmParser &Parser = getParser();
|
|
|
|
unsigned Reg;
|
|
|
|
SMLoc DummyLoc;
|
|
|
|
if (ParseRegister(Reg, DummyLoc, DummyLoc) ||
|
|
|
|
Parser.parseEOL("unexpected tokens"))
|
|
|
|
return addErrorSuffix(" in '.cv_fpo_setframe' directive");
|
|
|
|
return getTargetStreamer().emitFPOSetFrame(Reg, L);
|
|
|
|
}
|
|
|
|
|
|
|
|
// .cv_fpo_pushreg ebx
|
|
|
|
bool X86AsmParser::parseDirectiveFPOPushReg(SMLoc L) {
|
|
|
|
MCAsmParser &Parser = getParser();
|
|
|
|
unsigned Reg;
|
|
|
|
SMLoc DummyLoc;
|
|
|
|
if (ParseRegister(Reg, DummyLoc, DummyLoc) ||
|
|
|
|
Parser.parseEOL("unexpected tokens"))
|
|
|
|
return addErrorSuffix(" in '.cv_fpo_pushreg' directive");
|
|
|
|
return getTargetStreamer().emitFPOPushReg(Reg, L);
|
|
|
|
}
|
|
|
|
|
|
|
|
// .cv_fpo_stackalloc 20
|
|
|
|
bool X86AsmParser::parseDirectiveFPOStackAlloc(SMLoc L) {
|
|
|
|
MCAsmParser &Parser = getParser();
|
|
|
|
int64_t Offset;
|
|
|
|
if (Parser.parseIntToken(Offset, "expected offset") ||
|
|
|
|
Parser.parseEOL("unexpected tokens"))
|
|
|
|
return addErrorSuffix(" in '.cv_fpo_stackalloc' directive");
|
|
|
|
return getTargetStreamer().emitFPOStackAlloc(Offset, L);
|
|
|
|
}
|
|
|
|
|
|
|
|
// .cv_fpo_endprologue
|
|
|
|
bool X86AsmParser::parseDirectiveFPOEndPrologue(SMLoc L) {
|
|
|
|
MCAsmParser &Parser = getParser();
|
|
|
|
if (Parser.parseEOL("unexpected tokens"))
|
|
|
|
return addErrorSuffix(" in '.cv_fpo_endprologue' directive");
|
|
|
|
return getTargetStreamer().emitFPOEndPrologue(L);
|
|
|
|
}
|
|
|
|
|
|
|
|
// .cv_fpo_endproc
|
|
|
|
bool X86AsmParser::parseDirectiveFPOEndProc(SMLoc L) {
|
|
|
|
MCAsmParser &Parser = getParser();
|
|
|
|
if (Parser.parseEOL("unexpected tokens"))
|
|
|
|
return addErrorSuffix(" in '.cv_fpo_endproc' directive");
|
|
|
|
return getTargetStreamer().emitFPOEndProc(L);
|
|
|
|
}
|
|
|
|
|
2009-07-18 04:42:00 +08:00
|
|
|
// Force static initialization.
|
|
|
|
extern "C" void LLVMInitializeX86AsmParser() {
|
2016-10-10 07:00:34 +08:00
|
|
|
RegisterMCAsmParser<X86AsmParser> X(getTheX86_32Target());
|
|
|
|
RegisterMCAsmParser<X86AsmParser> Y(getTheX86_64Target());
|
2009-07-18 04:42:00 +08:00
|
|
|
}
|
2009-07-29 08:02:19 +08:00
|
|
|
|
2010-09-07 03:11:01 +08:00
|
|
|
#define GET_REGISTER_MATCHER
|
|
|
|
#define GET_MATCHER_IMPLEMENTATION
|
2012-11-15 02:04:47 +08:00
|
|
|
#define GET_SUBTARGET_FEATURE_NAME
|
2009-07-29 08:02:19 +08:00
|
|
|
#include "X86GenAsmMatcher.inc"
|