597 lines
18 KiB
C++
597 lines
18 KiB
C++
|
//===- MSP430AsmParser.cpp - Parse MSP430 assembly to MCInst instructions -===//
|
||
|
//
|
||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||
|
//
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
|
||
|
#include "MSP430.h"
|
||
|
#include "MSP430RegisterInfo.h"
|
||
|
#include "MCTargetDesc/MSP430MCTargetDesc.h"
|
||
|
#include "TargetInfo/MSP430TargetInfo.h"
|
||
|
|
||
|
#include "llvm/ADT/APInt.h"
|
||
|
#include "llvm/MC/MCContext.h"
|
||
|
#include "llvm/MC/MCExpr.h"
|
||
|
#include "llvm/MC/MCInst.h"
|
||
|
#include "llvm/MC/MCInstBuilder.h"
|
||
|
#include "llvm/MC/MCParser/MCAsmLexer.h"
|
||
|
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
|
||
|
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
|
||
|
#include "llvm/MC/MCStreamer.h"
|
||
|
#include "llvm/MC/MCSubtargetInfo.h"
|
||
|
#include "llvm/MC/MCSymbol.h"
|
||
|
#include "llvm/MC/MCValue.h"
|
||
|
#include "llvm/Support/Debug.h"
|
||
|
#include "llvm/Support/MathExtras.h"
|
||
|
#include "llvm/Support/TargetRegistry.h"
|
||
|
|
||
|
#define DEBUG_TYPE "msp430-asm-parser"
|
||
|
|
||
|
using namespace llvm;
|
||
|
|
||
|
namespace {
|
||
|
|
||
|
/// Parses MSP430 assembly from a stream.
|
||
|
class MSP430AsmParser : public MCTargetAsmParser {
|
||
|
const MCSubtargetInfo &STI;
|
||
|
MCAsmParser &Parser;
|
||
|
const MCRegisterInfo *MRI;
|
||
|
|
||
|
bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||
|
OperandVector &Operands, MCStreamer &Out,
|
||
|
uint64_t &ErrorInfo,
|
||
|
bool MatchingInlineAsm) override;
|
||
|
|
||
|
bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override;
|
||
|
OperandMatchResultTy tryParseRegister(unsigned &RegNo, SMLoc &StartLoc,
|
||
|
SMLoc &EndLoc) override;
|
||
|
|
||
|
bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
|
||
|
SMLoc NameLoc, OperandVector &Operands) override;
|
||
|
|
||
|
bool ParseDirective(AsmToken DirectiveID) override;
|
||
|
bool ParseDirectiveRefSym(AsmToken DirectiveID);
|
||
|
|
||
|
unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,
|
||
|
unsigned Kind) override;
|
||
|
|
||
|
bool parseJccInstruction(ParseInstructionInfo &Info, StringRef Name,
|
||
|
SMLoc NameLoc, OperandVector &Operands);
|
||
|
|
||
|
bool ParseOperand(OperandVector &Operands);
|
||
|
|
||
|
bool ParseLiteralValues(unsigned Size, SMLoc L);
|
||
|
|
||
|
MCAsmParser &getParser() const { return Parser; }
|
||
|
MCAsmLexer &getLexer() const { return Parser.getLexer(); }
|
||
|
|
||
|
/// @name Auto-generated Matcher Functions
|
||
|
/// {
|
||
|
|
||
|
#define GET_ASSEMBLER_HEADER
|
||
|
#include "MSP430GenAsmMatcher.inc"
|
||
|
|
||
|
/// }
|
||
|
|
||
|
public:
|
||
|
MSP430AsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
|
||
|
const MCInstrInfo &MII, const MCTargetOptions &Options)
|
||
|
: MCTargetAsmParser(Options, STI, MII), STI(STI), Parser(Parser) {
|
||
|
MCAsmParserExtension::Initialize(Parser);
|
||
|
MRI = getContext().getRegisterInfo();
|
||
|
|
||
|
setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/// A parsed MSP430 assembly operand.
|
||
|
class MSP430Operand : public MCParsedAsmOperand {
|
||
|
typedef MCParsedAsmOperand Base;
|
||
|
|
||
|
enum KindTy {
|
||
|
k_Imm,
|
||
|
k_Reg,
|
||
|
k_Tok,
|
||
|
k_Mem,
|
||
|
k_IndReg,
|
||
|
k_PostIndReg
|
||
|
} Kind;
|
||
|
|
||
|
struct Memory {
|
||
|
unsigned Reg;
|
||
|
const MCExpr *Offset;
|
||
|
};
|
||
|
union {
|
||
|
const MCExpr *Imm;
|
||
|
unsigned Reg;
|
||
|
StringRef Tok;
|
||
|
Memory Mem;
|
||
|
};
|
||
|
|
||
|
SMLoc Start, End;
|
||
|
|
||
|
public:
|
||
|
MSP430Operand(StringRef Tok, SMLoc const &S)
|
||
|
: Base(), Kind(k_Tok), Tok(Tok), Start(S), End(S) {}
|
||
|
MSP430Operand(KindTy Kind, unsigned Reg, SMLoc const &S, SMLoc const &E)
|
||
|
: Base(), Kind(Kind), Reg(Reg), Start(S), End(E) {}
|
||
|
MSP430Operand(MCExpr const *Imm, SMLoc const &S, SMLoc const &E)
|
||
|
: Base(), Kind(k_Imm), Imm(Imm), Start(S), End(E) {}
|
||
|
MSP430Operand(unsigned Reg, MCExpr const *Expr, SMLoc const &S, SMLoc const &E)
|
||
|
: Base(), Kind(k_Mem), Mem({Reg, Expr}), Start(S), End(E) {}
|
||
|
|
||
|
void addRegOperands(MCInst &Inst, unsigned N) const {
|
||
|
assert((Kind == k_Reg || Kind == k_IndReg || Kind == k_PostIndReg) &&
|
||
|
"Unexpected operand kind");
|
||
|
assert(N == 1 && "Invalid number of operands!");
|
||
|
|
||
|
Inst.addOperand(MCOperand::createReg(Reg));
|
||
|
}
|
||
|
|
||
|
void addExprOperand(MCInst &Inst, const MCExpr *Expr) const {
|
||
|
// Add as immediate when possible
|
||
|
if (!Expr)
|
||
|
Inst.addOperand(MCOperand::createImm(0));
|
||
|
else if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr))
|
||
|
Inst.addOperand(MCOperand::createImm(CE->getValue()));
|
||
|
else
|
||
|
Inst.addOperand(MCOperand::createExpr(Expr));
|
||
|
}
|
||
|
|
||
|
void addImmOperands(MCInst &Inst, unsigned N) const {
|
||
|
assert(Kind == k_Imm && "Unexpected operand kind");
|
||
|
assert(N == 1 && "Invalid number of operands!");
|
||
|
|
||
|
addExprOperand(Inst, Imm);
|
||
|
}
|
||
|
|
||
|
void addMemOperands(MCInst &Inst, unsigned N) const {
|
||
|
assert(Kind == k_Mem && "Unexpected operand kind");
|
||
|
assert(N == 2 && "Invalid number of operands");
|
||
|
|
||
|
Inst.addOperand(MCOperand::createReg(Mem.Reg));
|
||
|
addExprOperand(Inst, Mem.Offset);
|
||
|
}
|
||
|
|
||
|
bool isReg() const override { return Kind == k_Reg; }
|
||
|
bool isImm() const override { return Kind == k_Imm; }
|
||
|
bool isToken() const override { return Kind == k_Tok; }
|
||
|
bool isMem() const override { return Kind == k_Mem; }
|
||
|
bool isIndReg() const { return Kind == k_IndReg; }
|
||
|
bool isPostIndReg() const { return Kind == k_PostIndReg; }
|
||
|
|
||
|
bool isCGImm() const {
|
||
|
if (Kind != k_Imm)
|
||
|
return false;
|
||
|
|
||
|
int64_t Val;
|
||
|
if (!Imm->evaluateAsAbsolute(Val))
|
||
|
return false;
|
||
|
|
||
|
if (Val == 0 || Val == 1 || Val == 2 || Val == 4 || Val == 8 || Val == -1)
|
||
|
return true;
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
StringRef getToken() const {
|
||
|
assert(Kind == k_Tok && "Invalid access!");
|
||
|
return Tok;
|
||
|
}
|
||
|
|
||
|
unsigned getReg() const override {
|
||
|
assert(Kind == k_Reg && "Invalid access!");
|
||
|
return Reg;
|
||
|
}
|
||
|
|
||
|
void setReg(unsigned RegNo) {
|
||
|
assert(Kind == k_Reg && "Invalid access!");
|
||
|
Reg = RegNo;
|
||
|
}
|
||
|
|
||
|
static std::unique_ptr<MSP430Operand> CreateToken(StringRef Str, SMLoc S) {
|
||
|
return std::make_unique<MSP430Operand>(Str, S);
|
||
|
}
|
||
|
|
||
|
static std::unique_ptr<MSP430Operand> CreateReg(unsigned RegNum, SMLoc S,
|
||
|
SMLoc E) {
|
||
|
return std::make_unique<MSP430Operand>(k_Reg, RegNum, S, E);
|
||
|
}
|
||
|
|
||
|
static std::unique_ptr<MSP430Operand> CreateImm(const MCExpr *Val, SMLoc S,
|
||
|
SMLoc E) {
|
||
|
return std::make_unique<MSP430Operand>(Val, S, E);
|
||
|
}
|
||
|
|
||
|
static std::unique_ptr<MSP430Operand> CreateMem(unsigned RegNum,
|
||
|
const MCExpr *Val,
|
||
|
SMLoc S, SMLoc E) {
|
||
|
return std::make_unique<MSP430Operand>(RegNum, Val, S, E);
|
||
|
}
|
||
|
|
||
|
static std::unique_ptr<MSP430Operand> CreateIndReg(unsigned RegNum, SMLoc S,
|
||
|
SMLoc E) {
|
||
|
return std::make_unique<MSP430Operand>(k_IndReg, RegNum, S, E);
|
||
|
}
|
||
|
|
||
|
static std::unique_ptr<MSP430Operand> CreatePostIndReg(unsigned RegNum, SMLoc S,
|
||
|
SMLoc E) {
|
||
|
return std::make_unique<MSP430Operand>(k_PostIndReg, RegNum, S, E);
|
||
|
}
|
||
|
|
||
|
SMLoc getStartLoc() const override { return Start; }
|
||
|
SMLoc getEndLoc() const override { return End; }
|
||
|
|
||
|
void print(raw_ostream &O) const override {
|
||
|
switch (Kind) {
|
||
|
case k_Tok:
|
||
|
O << "Token " << Tok;
|
||
|
break;
|
||
|
case k_Reg:
|
||
|
O << "Register " << Reg;
|
||
|
break;
|
||
|
case k_Imm:
|
||
|
O << "Immediate " << *Imm;
|
||
|
break;
|
||
|
case k_Mem:
|
||
|
O << "Memory ";
|
||
|
O << *Mem.Offset << "(" << Reg << ")";
|
||
|
break;
|
||
|
case k_IndReg:
|
||
|
O << "RegInd " << Reg;
|
||
|
break;
|
||
|
case k_PostIndReg:
|
||
|
O << "PostInc " << Reg;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
} // end anonymous namespace
|
||
|
|
||
|
bool MSP430AsmParser::MatchAndEmitInstruction(SMLoc Loc, unsigned &Opcode,
|
||
|
OperandVector &Operands,
|
||
|
MCStreamer &Out,
|
||
|
uint64_t &ErrorInfo,
|
||
|
bool MatchingInlineAsm) {
|
||
|
MCInst Inst;
|
||
|
unsigned MatchResult =
|
||
|
MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);
|
||
|
|
||
|
switch (MatchResult) {
|
||
|
case Match_Success:
|
||
|
Inst.setLoc(Loc);
|
||
|
Out.emitInstruction(Inst, STI);
|
||
|
return false;
|
||
|
case Match_MnemonicFail:
|
||
|
return Error(Loc, "invalid instruction mnemonic");
|
||
|
case Match_InvalidOperand: {
|
||
|
SMLoc ErrorLoc = Loc;
|
||
|
if (ErrorInfo != ~0U) {
|
||
|
if (ErrorInfo >= Operands.size())
|
||
|
return Error(ErrorLoc, "too few operands for instruction");
|
||
|
|
||
|
ErrorLoc = ((MSP430Operand &)*Operands[ErrorInfo]).getStartLoc();
|
||
|
if (ErrorLoc == SMLoc())
|
||
|
ErrorLoc = Loc;
|
||
|
}
|
||
|
return Error(ErrorLoc, "invalid operand for instruction");
|
||
|
}
|
||
|
default:
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Auto-generated by TableGen
|
||
|
static unsigned MatchRegisterName(StringRef Name);
|
||
|
static unsigned MatchRegisterAltName(StringRef Name);
|
||
|
|
||
|
bool MSP430AsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc,
|
||
|
SMLoc &EndLoc) {
|
||
|
switch (tryParseRegister(RegNo, StartLoc, EndLoc)) {
|
||
|
case MatchOperand_ParseFail:
|
||
|
return Error(StartLoc, "invalid register name");
|
||
|
case MatchOperand_Success:
|
||
|
return false;
|
||
|
case MatchOperand_NoMatch:
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
llvm_unreachable("unknown match result type");
|
||
|
}
|
||
|
|
||
|
OperandMatchResultTy MSP430AsmParser::tryParseRegister(unsigned &RegNo,
|
||
|
SMLoc &StartLoc,
|
||
|
SMLoc &EndLoc) {
|
||
|
if (getLexer().getKind() == AsmToken::Identifier) {
|
||
|
auto Name = getLexer().getTok().getIdentifier().lower();
|
||
|
RegNo = MatchRegisterName(Name);
|
||
|
if (RegNo == MSP430::NoRegister) {
|
||
|
RegNo = MatchRegisterAltName(Name);
|
||
|
if (RegNo == MSP430::NoRegister)
|
||
|
return MatchOperand_NoMatch;
|
||
|
}
|
||
|
|
||
|
AsmToken const &T = getParser().getTok();
|
||
|
StartLoc = T.getLoc();
|
||
|
EndLoc = T.getEndLoc();
|
||
|
getLexer().Lex(); // eat register token
|
||
|
|
||
|
return MatchOperand_Success;
|
||
|
}
|
||
|
|
||
|
return MatchOperand_ParseFail;
|
||
|
}
|
||
|
|
||
|
bool MSP430AsmParser::parseJccInstruction(ParseInstructionInfo &Info,
|
||
|
StringRef Name, SMLoc NameLoc,
|
||
|
OperandVector &Operands) {
|
||
|
if (!Name.startswith_lower("j"))
|
||
|
return true;
|
||
|
|
||
|
auto CC = Name.drop_front().lower();
|
||
|
unsigned CondCode;
|
||
|
if (CC == "ne" || CC == "nz")
|
||
|
CondCode = MSP430CC::COND_NE;
|
||
|
else if (CC == "eq" || CC == "z")
|
||
|
CondCode = MSP430CC::COND_E;
|
||
|
else if (CC == "lo" || CC == "nc")
|
||
|
CondCode = MSP430CC::COND_LO;
|
||
|
else if (CC == "hs" || CC == "c")
|
||
|
CondCode = MSP430CC::COND_HS;
|
||
|
else if (CC == "n")
|
||
|
CondCode = MSP430CC::COND_N;
|
||
|
else if (CC == "ge")
|
||
|
CondCode = MSP430CC::COND_GE;
|
||
|
else if (CC == "l")
|
||
|
CondCode = MSP430CC::COND_L;
|
||
|
else if (CC == "mp")
|
||
|
CondCode = MSP430CC::COND_NONE;
|
||
|
else
|
||
|
return Error(NameLoc, "unknown instruction");
|
||
|
|
||
|
if (CondCode == (unsigned)MSP430CC::COND_NONE)
|
||
|
Operands.push_back(MSP430Operand::CreateToken("jmp", NameLoc));
|
||
|
else {
|
||
|
Operands.push_back(MSP430Operand::CreateToken("j", NameLoc));
|
||
|
const MCExpr *CCode = MCConstantExpr::create(CondCode, getContext());
|
||
|
Operands.push_back(MSP430Operand::CreateImm(CCode, SMLoc(), SMLoc()));
|
||
|
}
|
||
|
|
||
|
// Skip optional '$' sign.
|
||
|
if (getLexer().getKind() == AsmToken::Dollar)
|
||
|
getLexer().Lex(); // Eat '$'
|
||
|
|
||
|
const MCExpr *Val;
|
||
|
SMLoc ExprLoc = getLexer().getLoc();
|
||
|
if (getParser().parseExpression(Val))
|
||
|
return Error(ExprLoc, "expected expression operand");
|
||
|
|
||
|
int64_t Res;
|
||
|
if (Val->evaluateAsAbsolute(Res))
|
||
|
if (Res < -512 || Res > 511)
|
||
|
return Error(ExprLoc, "invalid jump offset");
|
||
|
|
||
|
Operands.push_back(MSP430Operand::CreateImm(Val, ExprLoc,
|
||
|
getLexer().getLoc()));
|
||
|
|
||
|
if (getLexer().isNot(AsmToken::EndOfStatement)) {
|
||
|
SMLoc Loc = getLexer().getLoc();
|
||
|
getParser().eatToEndOfStatement();
|
||
|
return Error(Loc, "unexpected token");
|
||
|
}
|
||
|
|
||
|
getParser().Lex(); // Consume the EndOfStatement.
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool MSP430AsmParser::ParseInstruction(ParseInstructionInfo &Info,
|
||
|
StringRef Name, SMLoc NameLoc,
|
||
|
OperandVector &Operands) {
|
||
|
// Drop .w suffix
|
||
|
if (Name.endswith_lower(".w"))
|
||
|
Name = Name.drop_back(2);
|
||
|
|
||
|
if (!parseJccInstruction(Info, Name, NameLoc, Operands))
|
||
|
return false;
|
||
|
|
||
|
// First operand is instruction mnemonic
|
||
|
Operands.push_back(MSP430Operand::CreateToken(Name, NameLoc));
|
||
|
|
||
|
// If there are no more operands, then finish
|
||
|
if (getLexer().is(AsmToken::EndOfStatement))
|
||
|
return false;
|
||
|
|
||
|
// Parse first operand
|
||
|
if (ParseOperand(Operands))
|
||
|
return true;
|
||
|
|
||
|
// Parse second operand if any
|
||
|
if (getLexer().is(AsmToken::Comma)) {
|
||
|
getLexer().Lex(); // Eat ','
|
||
|
if (ParseOperand(Operands))
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if (getLexer().isNot(AsmToken::EndOfStatement)) {
|
||
|
SMLoc Loc = getLexer().getLoc();
|
||
|
getParser().eatToEndOfStatement();
|
||
|
return Error(Loc, "unexpected token");
|
||
|
}
|
||
|
|
||
|
getParser().Lex(); // Consume the EndOfStatement.
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool MSP430AsmParser::ParseDirectiveRefSym(AsmToken DirectiveID) {
|
||
|
StringRef Name;
|
||
|
if (getParser().parseIdentifier(Name))
|
||
|
return TokError("expected identifier in directive");
|
||
|
|
||
|
MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
|
||
|
getStreamer().emitSymbolAttribute(Sym, MCSA_Global);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool MSP430AsmParser::ParseDirective(AsmToken DirectiveID) {
|
||
|
StringRef IDVal = DirectiveID.getIdentifier();
|
||
|
if (IDVal.lower() == ".long") {
|
||
|
ParseLiteralValues(4, DirectiveID.getLoc());
|
||
|
} else if (IDVal.lower() == ".word" || IDVal.lower() == ".short") {
|
||
|
ParseLiteralValues(2, DirectiveID.getLoc());
|
||
|
} else if (IDVal.lower() == ".byte") {
|
||
|
ParseLiteralValues(1, DirectiveID.getLoc());
|
||
|
} else if (IDVal.lower() == ".refsym") {
|
||
|
return ParseDirectiveRefSym(DirectiveID);
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool MSP430AsmParser::ParseOperand(OperandVector &Operands) {
|
||
|
switch (getLexer().getKind()) {
|
||
|
default: return true;
|
||
|
case AsmToken::Identifier: {
|
||
|
// try rN
|
||
|
unsigned RegNo;
|
||
|
SMLoc StartLoc, EndLoc;
|
||
|
if (!ParseRegister(RegNo, StartLoc, EndLoc)) {
|
||
|
Operands.push_back(MSP430Operand::CreateReg(RegNo, StartLoc, EndLoc));
|
||
|
return false;
|
||
|
}
|
||
|
LLVM_FALLTHROUGH;
|
||
|
}
|
||
|
case AsmToken::Integer:
|
||
|
case AsmToken::Plus:
|
||
|
case AsmToken::Minus: {
|
||
|
SMLoc StartLoc = getParser().getTok().getLoc();
|
||
|
const MCExpr *Val;
|
||
|
// Try constexpr[(rN)]
|
||
|
if (!getParser().parseExpression(Val)) {
|
||
|
unsigned RegNo = MSP430::PC;
|
||
|
SMLoc EndLoc = getParser().getTok().getLoc();
|
||
|
// Try (rN)
|
||
|
if (getLexer().getKind() == AsmToken::LParen) {
|
||
|
getLexer().Lex(); // Eat '('
|
||
|
SMLoc RegStartLoc;
|
||
|
if (ParseRegister(RegNo, RegStartLoc, EndLoc))
|
||
|
return true;
|
||
|
if (getLexer().getKind() != AsmToken::RParen)
|
||
|
return true;
|
||
|
EndLoc = getParser().getTok().getEndLoc();
|
||
|
getLexer().Lex(); // Eat ')'
|
||
|
}
|
||
|
Operands.push_back(MSP430Operand::CreateMem(RegNo, Val, StartLoc,
|
||
|
EndLoc));
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
case AsmToken::Amp: {
|
||
|
// Try &constexpr
|
||
|
SMLoc StartLoc = getParser().getTok().getLoc();
|
||
|
getLexer().Lex(); // Eat '&'
|
||
|
const MCExpr *Val;
|
||
|
if (!getParser().parseExpression(Val)) {
|
||
|
SMLoc EndLoc = getParser().getTok().getLoc();
|
||
|
Operands.push_back(MSP430Operand::CreateMem(MSP430::SR, Val, StartLoc,
|
||
|
EndLoc));
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
case AsmToken::At: {
|
||
|
// Try @rN[+]
|
||
|
SMLoc StartLoc = getParser().getTok().getLoc();
|
||
|
getLexer().Lex(); // Eat '@'
|
||
|
unsigned RegNo;
|
||
|
SMLoc RegStartLoc, EndLoc;
|
||
|
if (ParseRegister(RegNo, RegStartLoc, EndLoc))
|
||
|
return true;
|
||
|
if (getLexer().getKind() == AsmToken::Plus) {
|
||
|
Operands.push_back(MSP430Operand::CreatePostIndReg(RegNo, StartLoc, EndLoc));
|
||
|
getLexer().Lex(); // Eat '+'
|
||
|
return false;
|
||
|
}
|
||
|
if (Operands.size() > 1) // Emulate @rd in destination position as 0(rd)
|
||
|
Operands.push_back(MSP430Operand::CreateMem(RegNo,
|
||
|
MCConstantExpr::create(0, getContext()), StartLoc, EndLoc));
|
||
|
else
|
||
|
Operands.push_back(MSP430Operand::CreateIndReg(RegNo, StartLoc, EndLoc));
|
||
|
return false;
|
||
|
}
|
||
|
case AsmToken::Hash:
|
||
|
// Try #constexpr
|
||
|
SMLoc StartLoc = getParser().getTok().getLoc();
|
||
|
getLexer().Lex(); // Eat '#'
|
||
|
const MCExpr *Val;
|
||
|
if (!getParser().parseExpression(Val)) {
|
||
|
SMLoc EndLoc = getParser().getTok().getLoc();
|
||
|
Operands.push_back(MSP430Operand::CreateImm(Val, StartLoc, EndLoc));
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool MSP430AsmParser::ParseLiteralValues(unsigned Size, SMLoc L) {
|
||
|
auto parseOne = [&]() -> bool {
|
||
|
const MCExpr *Value;
|
||
|
if (getParser().parseExpression(Value))
|
||
|
return true;
|
||
|
getParser().getStreamer().emitValue(Value, Size, L);
|
||
|
return false;
|
||
|
};
|
||
|
return (parseMany(parseOne));
|
||
|
}
|
||
|
|
||
|
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeMSP430AsmParser() {
|
||
|
RegisterMCAsmParser<MSP430AsmParser> X(getTheMSP430Target());
|
||
|
}
|
||
|
|
||
|
#define GET_REGISTER_MATCHER
|
||
|
#define GET_MATCHER_IMPLEMENTATION
|
||
|
#include "MSP430GenAsmMatcher.inc"
|
||
|
|
||
|
static unsigned convertGR16ToGR8(unsigned Reg) {
|
||
|
switch (Reg) {
|
||
|
default:
|
||
|
llvm_unreachable("Unknown GR16 register");
|
||
|
case MSP430::PC: return MSP430::PCB;
|
||
|
case MSP430::SP: return MSP430::SPB;
|
||
|
case MSP430::SR: return MSP430::SRB;
|
||
|
case MSP430::CG: return MSP430::CGB;
|
||
|
case MSP430::R4: return MSP430::R4B;
|
||
|
case MSP430::R5: return MSP430::R5B;
|
||
|
case MSP430::R6: return MSP430::R6B;
|
||
|
case MSP430::R7: return MSP430::R7B;
|
||
|
case MSP430::R8: return MSP430::R8B;
|
||
|
case MSP430::R9: return MSP430::R9B;
|
||
|
case MSP430::R10: return MSP430::R10B;
|
||
|
case MSP430::R11: return MSP430::R11B;
|
||
|
case MSP430::R12: return MSP430::R12B;
|
||
|
case MSP430::R13: return MSP430::R13B;
|
||
|
case MSP430::R14: return MSP430::R14B;
|
||
|
case MSP430::R15: return MSP430::R15B;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
unsigned MSP430AsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
|
||
|
unsigned Kind) {
|
||
|
MSP430Operand &Op = static_cast<MSP430Operand &>(AsmOp);
|
||
|
|
||
|
if (!Op.isReg())
|
||
|
return Match_InvalidOperand;
|
||
|
|
||
|
unsigned Reg = Op.getReg();
|
||
|
bool isGR16 =
|
||
|
MSP430MCRegisterClasses[MSP430::GR16RegClassID].contains(Reg);
|
||
|
|
||
|
if (isGR16 && (Kind == MCK_GR8)) {
|
||
|
Op.setReg(convertGR16ToGR8(Reg));
|
||
|
return Match_Success;
|
||
|
}
|
||
|
|
||
|
return Match_InvalidOperand;
|
||
|
}
|