#include "LanaiAluCode.h"
#include "LanaiCondCode.h"
#include "LanaiInstrInfo.h"
#include "MCTargetDesc/LanaiMCExpr.h"
#include "TargetInfo/LanaiTargetInfo.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCParser/MCAsmLexer.h"
#include "llvm/MC/MCParser/MCAsmParser.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/TargetRegistry.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/SMLoc.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <memory>
using namespace llvm;
static unsigned MatchRegisterName(StringRef Name);
namespace {
struct LanaiOperand;
class LanaiAsmParser : public MCTargetAsmParser {
std::unique_ptr<LanaiOperand> parseRegister(bool RestoreOnFailure = false);
std::unique_ptr<LanaiOperand> parseImmediate();
std::unique_ptr<LanaiOperand> parseIdentifier();
unsigned parseAluOperator(bool PreOp, bool PostOp);
StringRef splitMnemonic(StringRef Name, SMLoc NameLoc,
OperandVector *Operands);
bool parsePrePost(StringRef Type, int *OffsetValue);
bool ParseDirective(AsmToken DirectiveID) override;
bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
SMLoc NameLoc, OperandVector &Operands) override;
bool ParseRegister(unsigned &RegNum, SMLoc &StartLoc, SMLoc &EndLoc) override;
OperandMatchResultTy tryParseRegister(unsigned &RegNo, 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 "LanaiGenAsmMatcher.inc"
OperandMatchResultTy parseOperand(OperandVector *Operands,
StringRef Mnemonic);
OperandMatchResultTy parseMemoryOperand(OperandVector &Operands);
public:
LanaiAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
const MCInstrInfo &MII, const MCTargetOptions &Options)
: MCTargetAsmParser(Options, STI, MII), Parser(Parser),
Lexer(Parser.getLexer()), SubtargetInfo(STI) {
setAvailableFeatures(
ComputeAvailableFeatures(SubtargetInfo.getFeatureBits()));
}
private:
MCAsmParser &Parser;
MCAsmLexer &Lexer;
const MCSubtargetInfo &SubtargetInfo;
};
struct LanaiOperand : public MCParsedAsmOperand {
enum KindTy {
TOKEN,
REGISTER,
IMMEDIATE,
MEMORY_IMM,
MEMORY_REG_IMM,
MEMORY_REG_REG,
} Kind;
SMLoc StartLoc, EndLoc;
struct Token {
const char *Data;
unsigned Length;
};
struct RegOp {
unsigned RegNum;
};
struct ImmOp {
const MCExpr *Value;
};
struct MemOp {
unsigned BaseReg;
unsigned OffsetReg;
unsigned AluOp;
const MCExpr *Offset;
};
union {
struct Token Tok;
struct RegOp Reg;
struct ImmOp Imm;
struct MemOp Mem;
};
explicit LanaiOperand(KindTy Kind) : Kind(Kind) {}
public:
SMLoc getStartLoc() const override { return StartLoc; }
SMLoc getEndLoc() const override { return EndLoc; }
unsigned getReg() const override {
assert(isReg() && "Invalid type access!");
return Reg.RegNum;
}
const MCExpr *getImm() const {
assert(isImm() && "Invalid type access!");
return Imm.Value;
}
StringRef getToken() const {
assert(isToken() && "Invalid type access!");
return StringRef(Tok.Data, Tok.Length);
}
unsigned getMemBaseReg() const {
assert(isMem() && "Invalid type access!");
return Mem.BaseReg;
}
unsigned getMemOffsetReg() const {
assert(isMem() && "Invalid type access!");
return Mem.OffsetReg;
}
const MCExpr *getMemOffset() const {
assert(isMem() && "Invalid type access!");
return Mem.Offset;
}
unsigned getMemOp() const {
assert(isMem() && "Invalid type access!");
return Mem.AluOp;
}
bool isReg() const override { return Kind == REGISTER; }
bool isImm() const override { return Kind == IMMEDIATE; }
bool isMem() const override {
return isMemImm() || isMemRegImm() || isMemRegReg();
}
bool isMemImm() const { return Kind == MEMORY_IMM; }
bool isMemRegImm() const { return Kind == MEMORY_REG_IMM; }
bool isMemRegReg() const { return Kind == MEMORY_REG_REG; }
bool isMemSpls() const { return isMemRegImm() || isMemRegReg(); }
bool isToken() const override { return Kind == TOKEN; }
bool isBrImm() {
if (!isImm())
return false;
const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Imm.Value);
if (!MCE)
return true;
int64_t Value = MCE->getValue();
return isShiftedUInt<23, 2>(static_cast<int32_t>(Value));
}
bool isBrTarget() { return isBrImm() || isToken(); }
bool isCallTarget() { return isImm() || isToken(); }
bool isHiImm16() {
if (!isImm())
return false;
if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value)) {
int64_t Value = ConstExpr->getValue();
return Value != 0 && isShiftedUInt<16, 16>(Value);
}
if (const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(Imm.Value))
return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_HI;
if (const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(Imm.Value))
if (const LanaiMCExpr *SymbolRefExpr =
dyn_cast<LanaiMCExpr>(BinaryExpr->getLHS()))
return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_HI;
return false;
}
bool isHiImm16And() {
if (!isImm())
return false;
const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value);
if (ConstExpr) {
int64_t Value = ConstExpr->getValue();
return (Value != 0) && ((Value & ~0xffff0000) == 0xffff);
}
return false;
}
bool isLoImm16() {
if (!isImm())
return false;
if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value)) {
int64_t Value = ConstExpr->getValue();
return isUInt<16>(static_cast<int32_t>(Value));
}
if (const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(Imm.Value))
return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_LO;
if (const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(Imm.Value))
if (const LanaiMCExpr *SymbolRefExpr =
dyn_cast<LanaiMCExpr>(BinaryExpr->getLHS()))
return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_LO;
return false;
}
bool isLoImm16Signed() {
if (!isImm())
return false;
if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value)) {
int64_t Value = ConstExpr->getValue();
return isInt<16>(static_cast<int32_t>(Value));
}
if (const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(Imm.Value))
return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_LO;
if (const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(Imm.Value))
if (const LanaiMCExpr *SymbolRefExpr =
dyn_cast<LanaiMCExpr>(BinaryExpr->getLHS()))
return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_LO;
return false;
}
bool isLoImm16And() {
if (!isImm())
return false;
const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value);
if (ConstExpr) {
int64_t Value = ConstExpr->getValue();
return ((Value & ~0xffff) == 0xffff0000);
}
return false;
}
bool isImmShift() {
if (!isImm())
return false;
const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value);
if (!ConstExpr)
return false;
int64_t Value = ConstExpr->getValue();
return (Value >= -31) && (Value <= 31);
}
bool isLoImm21() {
if (!isImm())
return false;
if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value)) {
int64_t Value = ConstExpr->getValue();
return isUInt<21>(Value);
}
if (const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(Imm.Value))
return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None;
if (const MCSymbolRefExpr *SymbolRefExpr =
dyn_cast<MCSymbolRefExpr>(Imm.Value)) {
return SymbolRefExpr->getKind() == MCSymbolRefExpr::VK_None;
}
if (const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(Imm.Value)) {
if (const LanaiMCExpr *SymbolRefExpr =
dyn_cast<LanaiMCExpr>(BinaryExpr->getLHS()))
return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None;
if (const MCSymbolRefExpr *SymbolRefExpr =
dyn_cast<MCSymbolRefExpr>(BinaryExpr->getLHS()))
return SymbolRefExpr->getKind() == MCSymbolRefExpr::VK_None;
}
return false;
}
bool isImm10() {
if (!isImm())
return false;
const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value);
if (!ConstExpr)
return false;
int64_t Value = ConstExpr->getValue();
return isInt<10>(Value);
}
bool isCondCode() {
if (!isImm())
return false;
const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value);
if (!ConstExpr)
return false;
uint64_t Value = ConstExpr->getValue();
return Value < LPCC::UNKNOWN;
}
void addExpr(MCInst &Inst, const MCExpr *Expr) const {
if (Expr == nullptr)
Inst.addOperand(MCOperand::createImm(0));
else if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Expr))
Inst.addOperand(
MCOperand::createImm(static_cast<int32_t>(ConstExpr->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 addBrTargetOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
addExpr(Inst, getImm());
}
void addCallTargetOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
addExpr(Inst, getImm());
}
void addCondCodeOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
addExpr(Inst, getImm());
}
void addMemImmOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
const MCExpr *Expr = getMemOffset();
addExpr(Inst, Expr);
}
void addMemRegImmOperands(MCInst &Inst, unsigned N) const {
assert(N == 3 && "Invalid number of operands!");
Inst.addOperand(MCOperand::createReg(getMemBaseReg()));
const MCExpr *Expr = getMemOffset();
addExpr(Inst, Expr);
Inst.addOperand(MCOperand::createImm(getMemOp()));
}
void addMemRegRegOperands(MCInst &Inst, unsigned N) const {
assert(N == 3 && "Invalid number of operands!");
Inst.addOperand(MCOperand::createReg(getMemBaseReg()));
assert(getMemOffsetReg() != 0 && "Invalid offset");
Inst.addOperand(MCOperand::createReg(getMemOffsetReg()));
Inst.addOperand(MCOperand::createImm(getMemOp()));
}
void addMemSplsOperands(MCInst &Inst, unsigned N) const {
if (isMemRegImm())
addMemRegImmOperands(Inst, N);
if (isMemRegReg())
addMemRegRegOperands(Inst, N);
}
void addImmShiftOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
addExpr(Inst, getImm());
}
void addImm10Operands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
addExpr(Inst, getImm());
}
void addLoImm16Operands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(getImm()))
Inst.addOperand(
MCOperand::createImm(static_cast<int32_t>(ConstExpr->getValue())));
else if (isa<LanaiMCExpr>(getImm())) {
#ifndef NDEBUG
const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(getImm());
assert(SymbolRefExpr &&
SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_LO);
#endif
Inst.addOperand(MCOperand::createExpr(getImm()));
} else if (isa<MCBinaryExpr>(getImm())) {
#ifndef NDEBUG
const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(getImm());
assert(BinaryExpr && isa<LanaiMCExpr>(BinaryExpr->getLHS()) &&
cast<LanaiMCExpr>(BinaryExpr->getLHS())->getKind() ==
LanaiMCExpr::VK_Lanai_ABS_LO);
#endif
Inst.addOperand(MCOperand::createExpr(getImm()));
} else
assert(false && "Operand type not supported.");
}
void addLoImm16AndOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(getImm()))
Inst.addOperand(MCOperand::createImm(ConstExpr->getValue() & 0xffff));
else
assert(false && "Operand type not supported.");
}
void addHiImm16Operands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(getImm()))
Inst.addOperand(MCOperand::createImm(ConstExpr->getValue() >> 16));
else if (isa<LanaiMCExpr>(getImm())) {
#ifndef NDEBUG
const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(getImm());
assert(SymbolRefExpr &&
SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_HI);
#endif
Inst.addOperand(MCOperand::createExpr(getImm()));
} else if (isa<MCBinaryExpr>(getImm())) {
#ifndef NDEBUG
const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(getImm());
assert(BinaryExpr && isa<LanaiMCExpr>(BinaryExpr->getLHS()) &&
cast<LanaiMCExpr>(BinaryExpr->getLHS())->getKind() ==
LanaiMCExpr::VK_Lanai_ABS_HI);
#endif
Inst.addOperand(MCOperand::createExpr(getImm()));
} else
assert(false && "Operand type not supported.");
}
void addHiImm16AndOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(getImm()))
Inst.addOperand(MCOperand::createImm(ConstExpr->getValue() >> 16));
else
assert(false && "Operand type not supported.");
}
void addLoImm21Operands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(getImm()))
Inst.addOperand(MCOperand::createImm(ConstExpr->getValue() & 0x1fffff));
else if (isa<LanaiMCExpr>(getImm())) {
#ifndef NDEBUG
const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(getImm());
assert(SymbolRefExpr &&
SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None);
#endif
Inst.addOperand(MCOperand::createExpr(getImm()));
} else if (isa<MCSymbolRefExpr>(getImm())) {
#ifndef NDEBUG
const MCSymbolRefExpr *SymbolRefExpr =
dyn_cast<MCSymbolRefExpr>(getImm());
assert(SymbolRefExpr &&
SymbolRefExpr->getKind() == MCSymbolRefExpr::VK_None);
#endif
Inst.addOperand(MCOperand::createExpr(getImm()));
} else if (isa<MCBinaryExpr>(getImm())) {
#ifndef NDEBUG
const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(getImm());
assert(BinaryExpr && isa<LanaiMCExpr>(BinaryExpr->getLHS()) &&
cast<LanaiMCExpr>(BinaryExpr->getLHS())->getKind() ==
LanaiMCExpr::VK_Lanai_None);
#endif
Inst.addOperand(MCOperand::createExpr(getImm()));
} else
assert(false && "Operand type not supported.");
}
void print(raw_ostream &OS) const override {
switch (Kind) {
case IMMEDIATE:
OS << "Imm: " << getImm() << "\n";
break;
case TOKEN:
OS << "Token: " << getToken() << "\n";
break;
case REGISTER:
OS << "Reg: %r" << getReg() << "\n";
break;
case MEMORY_IMM:
OS << "MemImm: " << *getMemOffset() << "\n";
break;
case MEMORY_REG_IMM:
OS << "MemRegImm: " << getMemBaseReg() << "+" << *getMemOffset() << "\n";
break;
case MEMORY_REG_REG:
assert(getMemOffset() == nullptr);
OS << "MemRegReg: " << getMemBaseReg() << "+"
<< "%r" << getMemOffsetReg() << "\n";
break;
}
}
static std::unique_ptr<LanaiOperand> CreateToken(StringRef Str, SMLoc Start) {
auto Op = std::make_unique<LanaiOperand>(TOKEN);
Op->Tok.Data = Str.data();
Op->Tok.Length = Str.size();
Op->StartLoc = Start;
Op->EndLoc = Start;
return Op;
}
static std::unique_ptr<LanaiOperand> createReg(unsigned RegNum, SMLoc Start,
SMLoc End) {
auto Op = std::make_unique<LanaiOperand>(REGISTER);
Op->Reg.RegNum = RegNum;
Op->StartLoc = Start;
Op->EndLoc = End;
return Op;
}
static std::unique_ptr<LanaiOperand> createImm(const MCExpr *Value,
SMLoc Start, SMLoc End) {
auto Op = std::make_unique<LanaiOperand>(IMMEDIATE);
Op->Imm.Value = Value;
Op->StartLoc = Start;
Op->EndLoc = End;
return Op;
}
static std::unique_ptr<LanaiOperand>
MorphToMemImm(std::unique_ptr<LanaiOperand> Op) {
const MCExpr *Imm = Op->getImm();
Op->Kind = MEMORY_IMM;
Op->Mem.BaseReg = 0;
Op->Mem.AluOp = LPAC::ADD;
Op->Mem.OffsetReg = 0;
Op->Mem.Offset = Imm;
return Op;
}
static std::unique_ptr<LanaiOperand>
MorphToMemRegReg(unsigned BaseReg, std::unique_ptr<LanaiOperand> Op,
unsigned AluOp) {
unsigned OffsetReg = Op->getReg();
Op->Kind = MEMORY_REG_REG;
Op->Mem.BaseReg = BaseReg;
Op->Mem.AluOp = AluOp;
Op->Mem.OffsetReg = OffsetReg;
Op->Mem.Offset = nullptr;
return Op;
}
static std::unique_ptr<LanaiOperand>
MorphToMemRegImm(unsigned BaseReg, std::unique_ptr<LanaiOperand> Op,
unsigned AluOp) {
const MCExpr *Imm = Op->getImm();
Op->Kind = MEMORY_REG_IMM;
Op->Mem.BaseReg = BaseReg;
Op->Mem.AluOp = AluOp;
Op->Mem.OffsetReg = 0;
Op->Mem.Offset = Imm;
return Op;
}
};
}
bool LanaiAsmParser::ParseDirective(AsmToken ) { return true; }
bool LanaiAsmParser::MatchAndEmitInstruction(SMLoc IdLoc, unsigned &Opcode,
OperandVector &Operands,
MCStreamer &Out,
uint64_t &ErrorInfo,
bool MatchingInlineAsm) {
MCInst Inst;
SMLoc ErrorLoc;
switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm)) {
case Match_Success:
Out.emitInstruction(Inst, SubtargetInfo);
Opcode = Inst.getOpcode();
return false;
case Match_MissingFeature:
return Error(IdLoc, "Instruction use requires 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(IdLoc, "Too few operands for instruction");
ErrorLoc = ((LanaiOperand &)*Operands[ErrorInfo]).getStartLoc();
if (ErrorLoc == SMLoc())
ErrorLoc = IdLoc;
}
return Error(ErrorLoc, "Invalid operand for instruction");
}
default:
break;
}
llvm_unreachable("Unknown match type detected!");
}
std::unique_ptr<LanaiOperand>
LanaiAsmParser::parseRegister(bool RestoreOnFailure) {
SMLoc Start = Parser.getTok().getLoc();
SMLoc End = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
Optional<AsmToken> PercentTok;
unsigned RegNum;
if (Lexer.getKind() == AsmToken::Percent) {
PercentTok = Parser.getTok();
Parser.Lex();
}
if (Lexer.getKind() == AsmToken::Identifier) {
RegNum = MatchRegisterName(Lexer.getTok().getIdentifier());
if (RegNum == 0) {
if (PercentTok && RestoreOnFailure)
Lexer.UnLex(PercentTok.value());
return nullptr;
}
Parser.Lex(); return LanaiOperand::createReg(RegNum, Start, End);
}
if (PercentTok && RestoreOnFailure)
Lexer.UnLex(PercentTok.value());
return nullptr;
}
bool LanaiAsmParser::ParseRegister(unsigned &RegNum, SMLoc &StartLoc,
SMLoc &EndLoc) {
const AsmToken &Tok = getParser().getTok();
StartLoc = Tok.getLoc();
EndLoc = Tok.getEndLoc();
std::unique_ptr<LanaiOperand> Op = parseRegister(false);
if (Op != nullptr)
RegNum = Op->getReg();
return (Op == nullptr);
}
OperandMatchResultTy LanaiAsmParser::tryParseRegister(unsigned &RegNum,
SMLoc &StartLoc,
SMLoc &EndLoc) {
const AsmToken &Tok = getParser().getTok();
StartLoc = Tok.getLoc();
EndLoc = Tok.getEndLoc();
std::unique_ptr<LanaiOperand> Op = parseRegister(true);
if (Op == nullptr)
return MatchOperand_NoMatch;
RegNum = Op->getReg();
return MatchOperand_Success;
}
std::unique_ptr<LanaiOperand> LanaiAsmParser::parseIdentifier() {
SMLoc Start = Parser.getTok().getLoc();
SMLoc End = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
const MCExpr *Res, *RHS = nullptr;
LanaiMCExpr::VariantKind Kind = LanaiMCExpr::VK_Lanai_None;
if (Lexer.getKind() != AsmToken::Identifier)
return nullptr;
StringRef Identifier;
if (Parser.parseIdentifier(Identifier))
return nullptr;
if (Identifier.equals_insensitive("hi"))
Kind = LanaiMCExpr::VK_Lanai_ABS_HI;
else if (Identifier.equals_insensitive("lo"))
Kind = LanaiMCExpr::VK_Lanai_ABS_LO;
if (Kind != LanaiMCExpr::VK_Lanai_None) {
if (Lexer.getKind() != AsmToken::LParen) {
Error(Lexer.getLoc(), "Expected '('");
return nullptr;
}
Lexer.Lex();
if (Parser.parseIdentifier(Identifier))
return nullptr;
}
if (Lexer.getKind() == AsmToken::Plus && Parser.parseExpression(RHS))
return nullptr;
if (Kind != LanaiMCExpr::VK_Lanai_None) {
if (Lexer.getKind() != AsmToken::RParen) {
Error(Lexer.getLoc(), "Expected ')'");
return nullptr;
}
Lexer.Lex(); }
End = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier);
const MCExpr *Expr = MCSymbolRefExpr::create(Sym, getContext());
Res = LanaiMCExpr::create(Kind, Expr, getContext());
if (RHS)
Res = MCBinaryExpr::createAdd(Res, RHS, getContext());
return LanaiOperand::createImm(Res, Start, End);
}
std::unique_ptr<LanaiOperand> LanaiAsmParser::parseImmediate() {
SMLoc Start = Parser.getTok().getLoc();
SMLoc End = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
const MCExpr *ExprVal;
switch (Lexer.getKind()) {
case AsmToken::Identifier:
return parseIdentifier();
case AsmToken::Plus:
case AsmToken::Minus:
case AsmToken::Integer:
case AsmToken::Dot:
if (!Parser.parseExpression(ExprVal))
return LanaiOperand::createImm(ExprVal, Start, End);
LLVM_FALLTHROUGH;
default:
return nullptr;
}
}
static unsigned AluWithPrePost(unsigned AluCode, bool PreOp, bool PostOp) {
if (PreOp)
return LPAC::makePreOp(AluCode);
if (PostOp)
return LPAC::makePostOp(AluCode);
return AluCode;
}
unsigned LanaiAsmParser::parseAluOperator(bool PreOp, bool PostOp) {
StringRef IdString;
Parser.parseIdentifier(IdString);
unsigned AluCode = LPAC::stringToLanaiAluCode(IdString);
if (AluCode == LPAC::UNKNOWN) {
Error(Parser.getTok().getLoc(), "Can't parse ALU operator");
return 0;
}
return AluCode;
}
static int SizeForSuffix(StringRef T) {
return StringSwitch<int>(T).EndsWith(".h", 2).EndsWith(".b", 1).Default(4);
}
bool LanaiAsmParser::parsePrePost(StringRef Type, int *OffsetValue) {
bool PreOrPost = false;
if (Lexer.getKind() == Lexer.peekTok(true).getKind()) {
PreOrPost = true;
if (Lexer.is(AsmToken::Minus))
*OffsetValue = -SizeForSuffix(Type);
else if (Lexer.is(AsmToken::Plus))
*OffsetValue = SizeForSuffix(Type);
else
return false;
Parser.Lex();
Parser.Lex();
} else if (Lexer.is(AsmToken::Star)) {
Parser.Lex(); PreOrPost = true;
}
return PreOrPost;
}
bool shouldBeSls(const LanaiOperand &Op) {
if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Op.getImm())) {
int64_t Value = ConstExpr->getValue();
return (Value % 4 == 0) && (Value >= 0) && (Value <= 0x1fffff);
}
if (const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(Op.getImm()))
return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None;
if (const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(Op.getImm())) {
const LanaiMCExpr *LHSSymbolRefExpr =
dyn_cast<LanaiMCExpr>(BinaryExpr->getLHS());
return (LHSSymbolRefExpr &&
LHSSymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None);
}
return false;
}
OperandMatchResultTy
LanaiAsmParser::parseMemoryOperand(OperandVector &Operands) {
StringRef Type;
if (Operands[0]->isToken())
Type = static_cast<LanaiOperand *>(Operands[0].get())->getToken();
int OffsetValue = 0;
unsigned BaseReg = 0;
unsigned AluOp = LPAC::ADD;
bool PostOp = false, PreOp = false;
std::unique_ptr<LanaiOperand> Op = parseRegister();
if (!Op)
Op = parseImmediate();
if (Lexer.isNot(AsmToken::LBrac)) {
if (!Op)
return MatchOperand_NoMatch;
Operands.push_back(std::move(Op));
return MatchOperand_Success;
}
Parser.Lex(); std::unique_ptr<LanaiOperand> Offset = nullptr;
if (Op)
Offset.swap(Op);
PreOp = parsePrePost(Type, &OffsetValue);
Op = parseRegister();
if (!Op) {
if (!Offset) {
if ((Op = parseImmediate()) && Lexer.is(AsmToken::RBrac)) {
Parser.Lex();
if (shouldBeSls(*Op)) {
Operands.push_back(LanaiOperand::MorphToMemImm(std::move(Op)));
} else {
if (!Op->isLoImm16Signed()) {
Error(Parser.getTok().getLoc(),
"Memory address is not word "
"aligned and larger than class RM can handle");
return MatchOperand_ParseFail;
}
Operands.push_back(LanaiOperand::MorphToMemRegImm(
Lanai::R0, std::move(Op), LPAC::ADD));
}
return MatchOperand_Success;
}
}
Error(Parser.getTok().getLoc(),
"Unknown operand, expected register or immediate");
return MatchOperand_ParseFail;
}
BaseReg = Op->getReg();
if (!PreOp)
PostOp = parsePrePost(Type, &OffsetValue);
if (Lexer.is(AsmToken::RBrac)) {
Parser.Lex(); if (!Offset) {
SMLoc Start = Parser.getTok().getLoc();
SMLoc End =
SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
const MCConstantExpr *OffsetConstExpr =
MCConstantExpr::create(OffsetValue, getContext());
Offset = LanaiOperand::createImm(OffsetConstExpr, Start, End);
}
} else {
if (Offset || OffsetValue != 0) {
Error(Parser.getTok().getLoc(), "Expected ']'");
return MatchOperand_ParseFail;
}
AluOp = parseAluOperator(PreOp, PostOp);
Offset = parseRegister();
if (!BaseReg || Lexer.isNot(AsmToken::RBrac)) {
Error(Parser.getTok().getLoc(), "Expected ']'");
return MatchOperand_ParseFail;
}
Parser.Lex(); }
AluOp = AluWithPrePost(AluOp, PreOp, PostOp);
if (Offset->isImm() && !Offset->isLoImm16Signed()) {
Error(Parser.getTok().getLoc(),
"Memory address is not word "
"aligned and larger than class RM can handle");
return MatchOperand_ParseFail;
}
Operands.push_back(
Offset->isImm()
? LanaiOperand::MorphToMemRegImm(BaseReg, std::move(Offset), AluOp)
: LanaiOperand::MorphToMemRegReg(BaseReg, std::move(Offset), AluOp));
return MatchOperand_Success;
}
OperandMatchResultTy
LanaiAsmParser::parseOperand(OperandVector *Operands, StringRef Mnemonic) {
OperandMatchResultTy Result = MatchOperandParserImpl(*Operands, Mnemonic);
if (Result == MatchOperand_Success)
return Result;
if (Result == MatchOperand_ParseFail) {
Parser.eatToEndOfStatement();
return Result;
}
std::unique_ptr<LanaiOperand> Op = parseRegister();
if (!Op)
Op = parseImmediate();
if (!Op) {
Error(Parser.getTok().getLoc(), "Unknown operand");
Parser.eatToEndOfStatement();
return MatchOperand_ParseFail;
}
Operands->push_back(std::move(Op));
return MatchOperand_Success;
}
StringRef LanaiAsmParser::splitMnemonic(StringRef Name, SMLoc NameLoc,
OperandVector *Operands) {
size_t Next = Name.find('.');
StringRef Mnemonic = Name;
bool IsBRR = false;
if (Name.endswith(".r")) {
Mnemonic = Name.substr(0, Name.size() - 2);
IsBRR = true;
}
if (Mnemonic[0] == 'b' ||
(Mnemonic[0] == 's' && !Mnemonic.startswith("sel") &&
!Mnemonic.startswith("st"))) {
LPCC::CondCode CondCode =
LPCC::suffixToLanaiCondCode(Mnemonic.substr(1, Next));
if (CondCode != LPCC::UNKNOWN) {
Mnemonic = Mnemonic.slice(0, 1);
Operands->push_back(LanaiOperand::CreateToken(Mnemonic, NameLoc));
Operands->push_back(LanaiOperand::createImm(
MCConstantExpr::create(CondCode, getContext()), NameLoc, NameLoc));
if (IsBRR) {
Operands->push_back(LanaiOperand::CreateToken(".r", NameLoc));
}
return Mnemonic;
}
}
if (Mnemonic.startswith("sel") ||
(!Mnemonic.endswith(".f") && !Mnemonic.startswith("st"))) {
LPCC::CondCode CondCode = LPCC::suffixToLanaiCondCode(Mnemonic);
if (CondCode != LPCC::UNKNOWN) {
size_t Next = Mnemonic.rfind('.', Name.size());
if (Mnemonic.startswith("sel")) {
Mnemonic = Mnemonic.substr(0, Next + 1);
} else {
Mnemonic = Mnemonic.substr(0, Next);
}
Operands->push_back(LanaiOperand::CreateToken(Mnemonic, NameLoc));
Operands->push_back(LanaiOperand::createImm(
MCConstantExpr::create(CondCode, getContext()), NameLoc, NameLoc));
return Mnemonic;
}
}
Operands->push_back(LanaiOperand::CreateToken(Mnemonic, NameLoc));
if (IsBRR) {
Operands->push_back(LanaiOperand::CreateToken(".r", NameLoc));
}
return Mnemonic;
}
static bool IsMemoryAssignmentError(const OperandVector &Operands) {
bool Modifies = false;
int Offset = 0;
if (Operands.size() < 5)
return false;
else if (Operands[0]->isToken() && Operands[1]->isReg() &&
Operands[2]->isImm() && Operands[3]->isImm() && Operands[4]->isReg())
Offset = 0;
else if (Operands[0]->isToken() && Operands[1]->isToken() &&
Operands[2]->isReg() && Operands[3]->isImm() &&
Operands[4]->isImm() && Operands[5]->isReg())
Offset = 1;
else
return false;
int PossibleAluOpIdx = Offset + 3;
int PossibleBaseIdx = Offset + 1;
int PossibleDestIdx = Offset + 4;
if (LanaiOperand *PossibleAluOp =
static_cast<LanaiOperand *>(Operands[PossibleAluOpIdx].get()))
if (PossibleAluOp->isImm())
if (const MCConstantExpr *ConstExpr =
dyn_cast<MCConstantExpr>(PossibleAluOp->getImm()))
Modifies = LPAC::modifiesOp(ConstExpr->getValue());
return Modifies && Operands[PossibleBaseIdx]->isReg() &&
Operands[PossibleDestIdx]->isReg() &&
Operands[PossibleBaseIdx]->getReg() ==
Operands[PossibleDestIdx]->getReg();
}
static bool IsRegister(const MCParsedAsmOperand &op) {
return static_cast<const LanaiOperand &>(op).isReg();
}
static bool MaybePredicatedInst(const OperandVector &Operands) {
if (Operands.size() < 4 || !IsRegister(*Operands[1]) ||
!IsRegister(*Operands[2]))
return false;
return StringSwitch<bool>(
static_cast<const LanaiOperand &>(*Operands[0]).getToken())
.StartsWith("addc", true)
.StartsWith("add", true)
.StartsWith("and", true)
.StartsWith("sh", true)
.StartsWith("subb", true)
.StartsWith("sub", true)
.StartsWith("or", true)
.StartsWith("xor", true)
.Default(false);
}
bool LanaiAsmParser::ParseInstruction(ParseInstructionInfo & ,
StringRef Name, SMLoc NameLoc,
OperandVector &Operands) {
StringRef Mnemonic = splitMnemonic(Name, NameLoc, &Operands);
if (Lexer.is(AsmToken::EndOfStatement))
return false;
if (parseOperand(&Operands, Mnemonic) != MatchOperand_Success)
return true;
if (Lexer.is(AsmToken::EndOfStatement) && Name == "st" &&
Operands.size() == 2) {
Operands.erase(Operands.begin(), Operands.begin() + 1);
Operands.insert(Operands.begin(), LanaiOperand::CreateToken("s", NameLoc));
Operands.insert(Operands.begin() + 1,
LanaiOperand::createImm(
MCConstantExpr::create(LPCC::ICC_T, getContext()),
NameLoc, NameLoc));
}
if (Lexer.is(AsmToken::EndOfStatement) && Name.startswith("bt") &&
Operands.size() == 3) {
Operands.erase(Operands.begin(), Operands.begin() + 2);
Operands.insert(Operands.begin(), LanaiOperand::CreateToken("bt", NameLoc));
}
while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.is(AsmToken::Comma)) {
Lex();
if (parseOperand(&Operands, Mnemonic) != MatchOperand_Success)
return true;
}
if (IsMemoryAssignmentError(Operands)) {
Error(Parser.getTok().getLoc(),
"the destination register can't equal the base register in an "
"instruction that modifies the base register.");
return true;
}
if (MaybePredicatedInst(Operands)) {
Operands.insert(Operands.begin() + 1,
LanaiOperand::createImm(
MCConstantExpr::create(LPCC::ICC_T, getContext()),
NameLoc, NameLoc));
}
return false;
}
#define GET_REGISTER_MATCHER
#define GET_MATCHER_IMPLEMENTATION
#include "LanaiGenAsmMatcher.inc"
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLanaiAsmParser() {
RegisterMCAsmParser<LanaiAsmParser> x(getTheLanaiTarget());
}