//===-- MBlazeAsmParser.cpp - Parse MBlaze asm to MCInst instructions -----===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "MCTargetDesc/MBlazeBaseInfo.h"
#include "llvm/MC/MCParser/MCAsmLexer.h"
#include "llvm/MC/MCParser/MCAsmParser.h"
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCTargetAsmParser.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
using namespace llvm;
namespace {
struct MBlazeOperand;
class MBlazeAsmParser : public MCTargetAsmParser {
MCAsmParser &Parser;
MCAsmParser &getParser() const { return Parser; }
MCAsmLexer &getLexer() const { return Parser.getLexer(); }
void Warning(SMLoc L, const Twine &Msg) { Parser.Warning(L, Msg); }
bool Error(SMLoc L, const Twine &Msg) { return Parser.Error(L, Msg); }
MBlazeOperand *ParseMemory(SmallVectorImpl<MCParsedAsmOperand*> &Operands);
MBlazeOperand *ParseRegister(unsigned &RegNo);
MBlazeOperand *ParseImmediate();
MBlazeOperand *ParseFsl();
MBlazeOperand* ParseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands);
virtual bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc);
bool ParseDirectiveWord(unsigned Size, SMLoc L);
bool MatchAndEmitInstruction(SMLoc IDLoc,
SmallVectorImpl<MCParsedAsmOperand*> &Operands,
MCStreamer &Out);
/// @name Auto-generated Match Functions
/// {
#define GET_ASSEMBLER_HEADER
#include "MBlazeGenAsmMatcher.inc"
/// }
public:
MBlazeAsmParser(MCSubtargetInfo &_STI, MCAsmParser &_Parser)
: MCTargetAsmParser(), Parser(_Parser) {}
virtual bool ParseInstruction(StringRef Name, SMLoc NameLoc,
SmallVectorImpl<MCParsedAsmOperand*> &Operands);
virtual bool ParseDirective(AsmToken DirectiveID);
};
/// MBlazeOperand - Instances of this class represent a parsed MBlaze machine
/// instruction.
struct MBlazeOperand : public MCParsedAsmOperand {
enum KindTy {
Token,
Immediate,
Register,
Memory,
Fsl
} Kind;
SMLoc StartLoc, EndLoc;
union {
struct {
const char *Data;
unsigned Length;
} Tok;
struct {
unsigned RegNum;
} Reg;
struct {
const MCExpr *Val;
} Imm;
struct {
unsigned Base;
unsigned OffReg;
const MCExpr *Off;
} Mem;
struct {
const MCExpr *Val;
} FslImm;
};
MBlazeOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {}
public:
MBlazeOperand(const MBlazeOperand &o) : MCParsedAsmOperand() {
Kind = o.Kind;
StartLoc = o.StartLoc;
EndLoc = o.EndLoc;
switch (Kind) {
case Register:
Reg = o.Reg;
break;
case Immediate:
Imm = o.Imm;
break;
case Token:
Tok = o.Tok;
break;
case Memory:
Mem = o.Mem;
break;
case Fsl:
FslImm = o.FslImm;
break;
}
}
/// getStartLoc - Get the location of the first token of this operand.
SMLoc getStartLoc() const { return StartLoc; }
/// getEndLoc - Get the location of the last token of this operand.
SMLoc getEndLoc() const { return EndLoc; }
unsigned getReg() const {
assert(Kind == Register && "Invalid access!");
return Reg.RegNum;
}
const MCExpr *getImm() const {
assert(Kind == Immediate && "Invalid access!");
return Imm.Val;
}
const MCExpr *getFslImm() const {
assert(Kind == Fsl && "Invalid access!");
return FslImm.Val;
}
unsigned getMemBase() const {
assert(Kind == Memory && "Invalid access!");
return Mem.Base;
}
const MCExpr* getMemOff() const {
assert(Kind == Memory && "Invalid access!");
return Mem.Off;
}
unsigned getMemOffReg() const {
assert(Kind == Memory && "Invalid access!");
return Mem.OffReg;
}
bool isToken() const { return Kind == Token; }
bool isImm() const { return Kind == Immediate; }
bool isMem() const { return Kind == Memory; }
bool isFsl() const { return Kind == Fsl; }
bool isReg() const { return Kind == Register; }
void addExpr(MCInst &Inst, const MCExpr *Expr) const {
// Add as immediates when possible. Null MCExpr = 0.
if (Expr == 0)
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 addRegOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateReg(getReg()));
}
void addImmOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
addExpr(Inst, getImm());
}
void addFslOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
addExpr(Inst, getFslImm());
}
void addMemOperands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateReg(getMemBase()));
unsigned RegOff = getMemOffReg();
if (RegOff)
Inst.addOperand(MCOperand::CreateReg(RegOff));
else
addExpr(Inst, getMemOff());
}
StringRef getToken() const {
assert(Kind == Token && "Invalid access!");
return StringRef(Tok.Data, Tok.Length);
}
virtual void print(raw_ostream &OS) const;
static MBlazeOperand *CreateToken(StringRef Str, SMLoc S) {
MBlazeOperand *Op = new MBlazeOperand(Token);
Op->Tok.Data = Str.data();
Op->Tok.Length = Str.size();
Op->StartLoc = S;
Op->EndLoc = S;
return Op;
}
static MBlazeOperand *CreateReg(unsigned RegNum, SMLoc S, SMLoc E) {
MBlazeOperand *Op = new MBlazeOperand(Register);
Op->Reg.RegNum = RegNum;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
}
static MBlazeOperand *CreateImm(const MCExpr *Val, SMLoc S, SMLoc E) {
MBlazeOperand *Op = new MBlazeOperand(Immediate);
Op->Imm.Val = Val;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
}
static MBlazeOperand *CreateFslImm(const MCExpr *Val, SMLoc S, SMLoc E) {
MBlazeOperand *Op = new MBlazeOperand(Fsl);
Op->Imm.Val = Val;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
}
static MBlazeOperand *CreateMem(unsigned Base, const MCExpr *Off, SMLoc S,
SMLoc E) {
MBlazeOperand *Op = new MBlazeOperand(Memory);
Op->Mem.Base = Base;
Op->Mem.Off = Off;
Op->Mem.OffReg = 0;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
}
static MBlazeOperand *CreateMem(unsigned Base, unsigned Off, SMLoc S,
SMLoc E) {
MBlazeOperand *Op = new MBlazeOperand(Memory);
Op->Mem.Base = Base;
Op->Mem.OffReg = Off;
Op->Mem.Off = 0;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
}
};
} // end anonymous namespace.
void MBlazeOperand::print(raw_ostream &OS) const {
switch (Kind) {
case Immediate:
getImm()->print(OS);
break;
case Register:
OS << "<register R";
OS << getMBlazeRegisterNumbering(getReg()) << ">";
break;
case Token:
OS << "'" << getToken() << "'";
break;
case Memory: {
OS << "<memory R";
OS << getMBlazeRegisterNumbering(getMemBase());
OS << ", ";
unsigned RegOff = getMemOffReg();
if (RegOff)
OS << "R" << getMBlazeRegisterNumbering(RegOff);
else
OS << getMemOff();
OS << ">";
}
break;
case Fsl:
getFslImm()->print(OS);
break;
}
}
/// @name Auto-generated Match Functions
/// {
static unsigned MatchRegisterName(StringRef Name);
/// }
//
bool MBlazeAsmParser::
MatchAndEmitInstruction(SMLoc IDLoc,
SmallVectorImpl<MCParsedAsmOperand*> &Operands,
MCStreamer &Out) {
MCInst Inst;
SMLoc ErrorLoc;
unsigned ErrorInfo;
switch (MatchInstructionImpl(Operands, Inst, ErrorInfo)) {
default: break;
case Match_Success:
Out.EmitInstruction(Inst);
return false;
case Match_MissingFeature:
return Error(IDLoc, "instruction use requires an option to be enabled");
case Match_MnemonicFail:
return Error(IDLoc, "unrecognized instruction mnemonic");
case Match_ConversionFail:
return Error(IDLoc, "unable to convert operands to instruction");
case Match_InvalidOperand:
ErrorLoc = IDLoc;
if (ErrorInfo != ~0U) {
if (ErrorInfo >= Operands.size())
return Error(IDLoc, "too few operands for instruction");
ErrorLoc = ((MBlazeOperand*)Operands[ErrorInfo])->getStartLoc();
if (ErrorLoc == SMLoc()) ErrorLoc = IDLoc;
}
return Error(ErrorLoc, "invalid operand for instruction");
}
llvm_unreachable("Implement any new match types added!");
return true;
}
MBlazeOperand *MBlazeAsmParser::
ParseMemory(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
if (Operands.size() != 4)
return 0;
MBlazeOperand &Base = *(MBlazeOperand*)Operands[2];
MBlazeOperand &Offset = *(MBlazeOperand*)Operands[3];
SMLoc S = Base.getStartLoc();
SMLoc O = Offset.getStartLoc();
SMLoc E = Offset.getEndLoc();
if (!Base.isReg()) {
Error(S, "base address must be a register");
return 0;
}
if (!Offset.isReg() && !Offset.isImm()) {
Error(O, "offset must be a register or immediate");
return 0;
}
MBlazeOperand *Op;
if (Offset.isReg())
Op = MBlazeOperand::CreateMem(Base.getReg(), Offset.getReg(), S, E);
else
Op = MBlazeOperand::CreateMem(Base.getReg(), Offset.getImm(), S, E);
delete Operands.pop_back_val();
delete Operands.pop_back_val();
Operands.push_back(Op);
return Op;
}
bool MBlazeAsmParser::ParseRegister(unsigned &RegNo,
SMLoc &StartLoc, SMLoc &EndLoc) {
return (ParseRegister(RegNo) == 0);
}
MBlazeOperand *MBlazeAsmParser::ParseRegister(unsigned &RegNo) {
SMLoc S = Parser.getTok().getLoc();
SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
switch (getLexer().getKind()) {
default: return 0;
case AsmToken::Identifier:
RegNo = MatchRegisterName(getLexer().getTok().getIdentifier());
if (RegNo == 0)
return 0;
getLexer().Lex();
return MBlazeOperand::CreateReg(RegNo, S, E);
}
}
static unsigned MatchFslRegister(StringRef String) {
if (!String.startswith("rfsl"))
return -1;
unsigned regNum;
if (String.substr(4).getAsInteger(10,regNum))
return -1;
return regNum;
}
MBlazeOperand *MBlazeAsmParser::ParseFsl() {
SMLoc S = Parser.getTok().getLoc();
SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
switch (getLexer().getKind()) {
default: return 0;
case AsmToken::Identifier:
unsigned reg = MatchFslRegister(getLexer().getTok().getIdentifier());
if (reg >= 16)
return 0;
getLexer().Lex();
const MCExpr *EVal = MCConstantExpr::Create(reg,getContext());
return MBlazeOperand::CreateFslImm(EVal,S,E);
}
}
MBlazeOperand *MBlazeAsmParser::ParseImmediate() {
SMLoc S = Parser.getTok().getLoc();
SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
const MCExpr *EVal;
switch (getLexer().getKind()) {
default: return 0;
case AsmToken::LParen:
case AsmToken::Plus:
case AsmToken::Minus:
case AsmToken::Integer:
case AsmToken::Identifier:
if (getParser().ParseExpression(EVal))
return 0;
return MBlazeOperand::CreateImm(EVal, S, E);
}
}
MBlazeOperand *MBlazeAsmParser::
ParseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
MBlazeOperand *Op;
// Attempt to parse the next token as a register name
unsigned RegNo;
Op = ParseRegister(RegNo);
// Attempt to parse the next token as an FSL immediate
if (!Op)
Op = ParseFsl();
// Attempt to parse the next token as an immediate
if (!Op)
Op = ParseImmediate();
// If the token could not be parsed then fail
if (!Op) {
Error(Parser.getTok().getLoc(), "unknown operand");
return 0;
}
// Push the parsed operand into the list of operands
Operands.push_back(Op);
return Op;
}
/// Parse an mblaze instruction mnemonic followed by its operands.
bool MBlazeAsmParser::
ParseInstruction(StringRef Name, SMLoc NameLoc,
SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
// The first operands is the token for the instruction name
size_t dotLoc = Name.find('.');
Operands.push_back(MBlazeOperand::CreateToken(Name.substr(0,dotLoc),NameLoc));
if (dotLoc < Name.size())
Operands.push_back(MBlazeOperand::CreateToken(Name.substr(dotLoc),NameLoc));
// If there are no more operands then finish
if (getLexer().is(AsmToken::EndOfStatement))
return false;
// Parse the first operand
if (!ParseOperand(Operands))
return true;
while (getLexer().isNot(AsmToken::EndOfStatement) &&
getLexer().is(AsmToken::Comma)) {
// Consume the comma token
getLexer().Lex();
// Parse the next operand
if (!ParseOperand(Operands))
return true;
}
// If the instruction requires a memory operand then we need to
// replace the last two operands (base+offset) with a single
// memory operand.
if (Name.startswith("lw") || Name.startswith("sw") ||
Name.startswith("lh") || Name.startswith("sh") ||
Name.startswith("lb") || Name.startswith("sb"))
return (ParseMemory(Operands) == NULL);
return false;
}
/// ParseDirective parses the MBlaze specific directives
bool MBlazeAsmParser::ParseDirective(AsmToken DirectiveID) {
StringRef IDVal = DirectiveID.getIdentifier();
if (IDVal == ".word")
return ParseDirectiveWord(2, DirectiveID.getLoc());
return true;
}
/// ParseDirectiveWord
/// ::= .word [ expression (, expression)* ]
bool MBlazeAsmParser::ParseDirectiveWord(unsigned Size, SMLoc L) {
if (getLexer().isNot(AsmToken::EndOfStatement)) {
for (;;) {
const MCExpr *Value;
if (getParser().ParseExpression(Value))
return true;
getParser().getStreamer().EmitValue(Value, Size, 0 /*addrspace*/);
if (getLexer().is(AsmToken::EndOfStatement))
break;
// FIXME: Improve diagnostic.
if (getLexer().isNot(AsmToken::Comma))
return Error(L, "unexpected token in directive");
Parser.Lex();
}
}
Parser.Lex();
return false;
}
extern "C" void LLVMInitializeMBlazeAsmLexer();
/// Force static initialization.
extern "C" void LLVMInitializeMBlazeAsmParser() {
RegisterMCAsmParser<MBlazeAsmParser> X(TheMBlazeTarget);
LLVMInitializeMBlazeAsmLexer();
}
#define GET_REGISTER_MATCHER
#define GET_MATCHER_IMPLEMENTATION
#include "MBlazeGenAsmMatcher.inc"