334 lines
8.2 KiB
C++

#include "MCTargetDesc/FootInstPrinter.h"
#include "MCTargetDesc/FootMCTargetDesc.h"
#include "TargetInfo/FootTargetInfo.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/Casting.h"
using namespace llvm;
namespace {
class FootAsmParser : public MCTargetAsmParser {
private:
SMLoc getLoc() const { return getParser().getTok().getLoc(); }
bool parseInstruction(ParseInstructionInfo &Info, StringRef Name,
SMLoc NameLoc, OperandVector &Operands) override;
bool parseRegister(MCRegister &Reg, SMLoc &StartLoc,
SMLoc &EndLoc) override;
ParseStatus tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,
SMLoc &EndLoc) override;
bool matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
OperandVector &Operands, MCStreamer &Out,
uint64_t &ErrorInfo,
bool MatchingInlineAsm) override;
#define GET_ASSEMBLER_HEADER
#include "FootGenAsmMatcher.inc"
ParseStatus parseImmediate(OperandVector &Operands);
ParseStatus parseRegister(OperandVector &Operands);
public:
FootAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
const MCInstrInfo &MII, const MCTargetOptions &Options)
: MCTargetAsmParser(Options, STI, MII) {
MCAsmParserExtension::Initialize(Parser);
setAvailableFeatures(ComputeAvailableFeatures(getSTI().getFeatureBits()));
}
};
class FootOperand : public MCParsedAsmOperand {
private:
SMLoc StartLoc, EndLoc;
enum KindTy {
k_Immediate,
k_Register,
k_Token
} Kind;
struct TokOp {
const char *Data;
unsigned Length;
};
struct RegOp {
unsigned RegNum;
int ElementWidth;
};
struct ImmOp {
const MCExpr *Val;
};
union {
struct TokOp Tok;
struct RegOp Reg;
struct ImmOp Imm;
};
public:
FootOperand(KindTy K) : Kind(K) {}
FootOperand(const FootOperand &o) : MCParsedAsmOperand() {
StartLoc = o.StartLoc;
EndLoc = o.EndLoc;
Kind = o.Kind;
switch (Kind) {
case k_Token:
Tok = o.Tok;
break;
case k_Immediate:
Imm = o.Imm;
break;
case k_Register:
Reg = o.Reg;
break;
}
}
void print(raw_ostream &OS, const MCAsmInfo &MAI) const override;
static std::unique_ptr<FootOperand> createToken(StringRef Str, SMLoc S) {
auto Op = std::make_unique<FootOperand>(k_Token);
Op->StartLoc = S;
Op->EndLoc = S;
Op->Tok.Data = Str.data();
Op->Tok.Length = Str.size();
return Op;
}
static std::unique_ptr<FootOperand> createReg(unsigned RegNo, SMLoc S,
SMLoc E) {
auto Op = std::make_unique<FootOperand>(k_Register);
Op->Reg.RegNum = RegNo;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
}
static std::unique_ptr<FootOperand> createImm(const MCExpr *Val, SMLoc S,
SMLoc E) {
auto Op = std::make_unique<FootOperand>(k_Immediate);
Op->Imm.Val = Val;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
}
void addExpr(MCInst &Inst, const MCExpr *Expr) const {
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());
}
StringRef getToken() const {
assert(Kind == k_Token && "Invalid access!");
return StringRef(Tok.Data, Tok.Length);
}
SMLoc getStartLoc() const override { return StartLoc; }
SMLoc getEndLoc() const override { return EndLoc; }
bool isToken() const override { return Kind == k_Token; }
bool isImm() const override { return Kind == k_Immediate; }
bool isMem() const override { return false; }
bool isReg() const override { return Kind == k_Register; }
MCRegister getReg() const override {
assert(Kind == k_Register && "Invalid access!");
return Reg.RegNum;
}
const MCExpr *getImm() const {
assert(Kind == k_Immediate && "Invalid access!");
return Imm.Val;
}
};
} // namespace
#define GET_REGISTER_MATCHER
#include "FootGenAsmMatcher.inc"
void FootOperand::print(raw_ostream &OS, const MCAsmInfo &MAI) const {
switch (Kind) {
case k_Immediate:
MAI.printExpr(OS, *getImm());
break;
case k_Token:
OS << "'" << getToken() << "'";
break;
case k_Register:
OS << "<register " << getReg() << ">";
break;
}
}
ParseStatus FootAsmParser::parseImmediate(OperandVector &Operands) {
switch (getLexer().getKind()) {
default:
return ParseStatus::NoMatch;
case llvm::AsmToken::LParen:
case llvm::AsmToken::Minus:
case llvm::AsmToken::Plus:
case llvm::AsmToken::Integer:
case llvm::AsmToken::String:
case llvm::AsmToken::Identifier:
break;
}
const MCExpr *IdVal;
SMLoc S = getLoc();
if (getParser().parseExpression(IdVal)) {
return ParseStatus::Failure;
}
SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);
Operands.push_back(FootOperand::createImm(IdVal, S, E));
return ParseStatus::Success;
}
ParseStatus FootAsmParser::parseRegister(OperandVector &Operands) {
SMLoc S = getLoc();
SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);
switch (getLexer().getKind()) {
default:
return ParseStatus::NoMatch;
case llvm::AsmToken::Identifier:
StringRef Name = getLexer().getTok().getIdentifier();
unsigned RegNo = MatchRegisterName(Name);
if (RegNo == 0) {
return ParseStatus::NoMatch;
}
getLexer().Lex();
Operands.push_back(FootOperand::createReg(RegNo, S, E));
}
return ParseStatus::Success;
}
bool FootAsmParser::parseInstruction(ParseInstructionInfo &Info,
StringRef Name, SMLoc NameLoc,
OperandVector &Operands) {
Operands.push_back(FootOperand::createToken(Name, NameLoc));
while (!getLexer().is(AsmToken::EndOfStatement)) {
// try to parse register first
if (parseRegister(Operands).isSuccess()) {
continue;
}
// skip commas
if (getLexer().is(AsmToken::Comma)) {
getLexer().Lex();
continue;
}
if (parseImmediate(Operands).isSuccess()) {
continue;
}
SMLoc Loc = getLexer().getLoc();
return Error(Loc, "unexpected token");
}
// no errors
getParser().Lex();
return false;
}
bool FootAsmParser::parseRegister(MCRegister &Reg, SMLoc &StartLoc,
SMLoc &EndLoc) {
if (!tryParseRegister(Reg, StartLoc, EndLoc).isSuccess()) {
return Error(StartLoc, "invalid register name");
}
return false;
}
ParseStatus FootAsmParser::tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,
SMLoc &EndLoc) {
const AsmToken &Tok = getParser().getTok();
StartLoc = Tok.getLoc();
EndLoc = Tok.getEndLoc();
Reg = Foot::NoRegister;
StringRef Name = getLexer().getTok().getIdentifier();
if (!MatchRegisterName(Name)) {
// skip unknown identifier
getParser().Lex();
return ParseStatus::Success;
}
return ParseStatus::NoMatch;
}
bool FootAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
OperandVector &Operands,
MCStreamer &Out,
uint64_t &ErrorInfo,
bool MatchingInlineAsm) {
MCInst Inst;
SMLoc ErrorLoc;
FeatureBitset MissingFeatures;
switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, MissingFeatures, MatchingInlineAsm)) {
default:
break;
case Match_Success:
Inst.setLoc(IDLoc);
Out.emitInstruction(Inst, getSTI());
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_InvalidOperand:
ErrorLoc = IDLoc;
if (ErrorInfo != ~0u) {
if (ErrorInfo >= Operands.size()) {
return Error(ErrorLoc, "too few operands for instruction");
}
ErrorLoc = ((FootOperand&)*Operands[ErrorInfo]).getStartLoc();
if (ErrorLoc == SMLoc()) {
ErrorLoc = IDLoc;
}
}
return Error(ErrorLoc, "invalid operand for instruction");
}
llvm_unreachable("unknown match type detected");
}
extern "C" LLVM_C_ABI void LLVMInitializeFootAsmParser() {
RegisterMCAsmParser<FootAsmParser> Z(getTheFootTarget());
}
#define GET_MATCHER_IMPLEMENTATION
#include "FootGenAsmMatcher.inc"