1234 lines · cpp
1//===-- LanaiAsmParser.cpp - Parse Lanai assembly to MCInst instructions --===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "LanaiAluCode.h"10#include "LanaiCondCode.h"11#include "LanaiInstrInfo.h"12#include "MCTargetDesc/LanaiMCAsmInfo.h"13#include "TargetInfo/LanaiTargetInfo.h"14#include "llvm/ADT/StringRef.h"15#include "llvm/ADT/StringSwitch.h"16#include "llvm/MC/MCContext.h"17#include "llvm/MC/MCExpr.h"18#include "llvm/MC/MCInst.h"19#include "llvm/MC/MCParser/AsmLexer.h"20#include "llvm/MC/MCParser/MCAsmParser.h"21#include "llvm/MC/MCParser/MCParsedAsmOperand.h"22#include "llvm/MC/MCParser/MCTargetAsmParser.h"23#include "llvm/MC/MCStreamer.h"24#include "llvm/MC/MCSubtargetInfo.h"25#include "llvm/MC/MCSymbol.h"26#include "llvm/MC/TargetRegistry.h"27#include "llvm/Support/Casting.h"28#include "llvm/Support/Compiler.h"29#include "llvm/Support/ErrorHandling.h"30#include "llvm/Support/MathExtras.h"31#include "llvm/Support/SMLoc.h"32#include "llvm/Support/raw_ostream.h"33#include <cassert>34#include <cstddef>35#include <cstdint>36#include <memory>37#include <optional>38 39using namespace llvm;40 41// Auto-generated by TableGen42static MCRegister MatchRegisterName(StringRef Name);43 44namespace {45 46struct LanaiOperand;47 48class LanaiAsmParser : public MCTargetAsmParser {49 // Parse operands50 std::unique_ptr<LanaiOperand> parseRegister(bool RestoreOnFailure = false);51 52 std::unique_ptr<LanaiOperand> parseImmediate();53 54 std::unique_ptr<LanaiOperand> parseIdentifier();55 56 unsigned parseAluOperator(bool PreOp, bool PostOp);57 58 // Split the mnemonic stripping conditional code and quantifiers59 StringRef splitMnemonic(StringRef Name, SMLoc NameLoc,60 OperandVector *Operands);61 62 bool parsePrePost(StringRef Type, int *OffsetValue);63 64 bool parseInstruction(ParseInstructionInfo &Info, StringRef Name,65 SMLoc NameLoc, OperandVector &Operands) override;66 67 bool parseRegister(MCRegister &Reg, SMLoc &StartLoc, SMLoc &EndLoc) override;68 ParseStatus tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,69 SMLoc &EndLoc) override;70 71 bool matchAndEmitInstruction(SMLoc IdLoc, unsigned &Opcode,72 OperandVector &Operands, MCStreamer &Out,73 uint64_t &ErrorInfo,74 bool MatchingInlineAsm) override;75 76// Auto-generated instruction matching functions77#define GET_ASSEMBLER_HEADER78#include "LanaiGenAsmMatcher.inc"79 80 ParseStatus parseOperand(OperandVector *Operands, StringRef Mnemonic);81 82 ParseStatus parseMemoryOperand(OperandVector &Operands);83 84public:85 LanaiAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,86 const MCInstrInfo &MII, const MCTargetOptions &Options)87 : MCTargetAsmParser(Options, STI, MII), Parser(Parser),88 Lexer(Parser.getLexer()), SubtargetInfo(STI) {89 setAvailableFeatures(90 ComputeAvailableFeatures(SubtargetInfo.getFeatureBits()));91 }92 93private:94 MCAsmParser &Parser;95 AsmLexer &Lexer;96 97 const MCSubtargetInfo &SubtargetInfo;98};99 100// LanaiOperand - Instances of this class represented a parsed machine101// instruction102struct LanaiOperand : public MCParsedAsmOperand {103 enum KindTy {104 TOKEN,105 REGISTER,106 IMMEDIATE,107 MEMORY_IMM,108 MEMORY_REG_IMM,109 MEMORY_REG_REG,110 } Kind;111 112 SMLoc StartLoc, EndLoc;113 114 struct Token {115 const char *Data;116 unsigned Length;117 };118 119 struct RegOp {120 MCRegister RegNum;121 };122 123 struct ImmOp {124 const MCExpr *Value;125 };126 127 struct MemOp {128 MCRegister BaseReg;129 MCRegister OffsetReg;130 unsigned AluOp;131 const MCExpr *Offset;132 };133 134 union {135 struct Token Tok;136 struct RegOp Reg;137 struct ImmOp Imm;138 struct MemOp Mem;139 };140 141 explicit LanaiOperand(KindTy Kind) : Kind(Kind) {}142 143public:144 // The functions below are used by the autogenerated ASM matcher and hence to145 // be of the form expected.146 147 // getStartLoc - Gets location of the first token of this operand148 SMLoc getStartLoc() const override { return StartLoc; }149 150 // getEndLoc - Gets location of the last token of this operand151 SMLoc getEndLoc() const override { return EndLoc; }152 153 MCRegister getReg() const override {154 assert(isReg() && "Invalid type access!");155 return Reg.RegNum;156 }157 158 const MCExpr *getImm() const {159 assert(isImm() && "Invalid type access!");160 return Imm.Value;161 }162 163 StringRef getToken() const {164 assert(isToken() && "Invalid type access!");165 return StringRef(Tok.Data, Tok.Length);166 }167 168 MCRegister getMemBaseReg() const {169 assert(isMem() && "Invalid type access!");170 return Mem.BaseReg;171 }172 173 MCRegister getMemOffsetReg() const {174 assert(isMem() && "Invalid type access!");175 return Mem.OffsetReg;176 }177 178 const MCExpr *getMemOffset() const {179 assert(isMem() && "Invalid type access!");180 return Mem.Offset;181 }182 183 unsigned getMemOp() const {184 assert(isMem() && "Invalid type access!");185 return Mem.AluOp;186 }187 188 // Functions for testing operand type189 bool isReg() const override { return Kind == REGISTER; }190 191 bool isImm() const override { return Kind == IMMEDIATE; }192 193 bool isMem() const override {194 return isMemImm() || isMemRegImm() || isMemRegReg();195 }196 197 bool isMemImm() const { return Kind == MEMORY_IMM; }198 199 bool isMemRegImm() const { return Kind == MEMORY_REG_IMM; }200 201 bool isMemRegReg() const { return Kind == MEMORY_REG_REG; }202 203 bool isMemSpls() const { return isMemRegImm() || isMemRegReg(); }204 205 bool isToken() const override { return Kind == TOKEN; }206 207 bool isBrImm() {208 if (!isImm())209 return false;210 211 // Constant case212 const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Imm.Value);213 if (!MCE)214 return true;215 int64_t Value = MCE->getValue();216 // Check if value fits in 25 bits with 2 least significant bits 0.217 return isShiftedUInt<23, 2>(static_cast<int32_t>(Value));218 }219 220 bool isBrTarget() { return isBrImm() || isToken(); }221 222 bool isCallTarget() { return isImm() || isToken(); }223 224 bool isHiImm16() {225 if (!isImm())226 return false;227 228 // Constant case229 if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value)) {230 int64_t Value = ConstExpr->getValue();231 return Value != 0 && isShiftedUInt<16, 16>(Value);232 }233 234 // Symbolic reference expression235 if (const auto *SymbolRefExpr = dyn_cast<MCSpecifierExpr>(Imm.Value))236 return SymbolRefExpr->getSpecifier() == Lanai::S_ABS_HI;237 238 // Binary expression239 if (const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(Imm.Value))240 if (const auto *SymbolRefExpr =241 dyn_cast<MCSpecifierExpr>(BinaryExpr->getLHS()))242 return SymbolRefExpr->getSpecifier() == Lanai::S_ABS_HI;243 244 return false;245 }246 247 bool isHiImm16And() {248 if (!isImm())249 return false;250 251 const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value);252 if (ConstExpr) {253 int64_t Value = ConstExpr->getValue();254 // Check if in the form 0xXYZWffff255 return (Value != 0) && ((Value & ~0xffff0000) == 0xffff);256 }257 return false;258 }259 260 bool isLoImm16() {261 if (!isImm())262 return false;263 264 // Constant case265 if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value)) {266 int64_t Value = ConstExpr->getValue();267 // Check if value fits in 16 bits268 return isUInt<16>(static_cast<int32_t>(Value));269 }270 271 // Symbolic reference expression272 if (const auto *SymbolRefExpr = dyn_cast<MCSpecifierExpr>(Imm.Value))273 return SymbolRefExpr->getSpecifier() == Lanai::S_ABS_LO;274 275 // Binary expression276 if (const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(Imm.Value))277 if (const auto *SymbolRefExpr =278 dyn_cast<MCSpecifierExpr>(BinaryExpr->getLHS()))279 return SymbolRefExpr->getSpecifier() == Lanai::S_ABS_LO;280 281 return false;282 }283 284 bool isLoImm16Signed() {285 if (!isImm())286 return false;287 288 // Constant case289 if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value)) {290 int64_t Value = ConstExpr->getValue();291 // Check if value fits in 16 bits or value of the form 0xffffxyzw292 return isInt<16>(static_cast<int32_t>(Value));293 }294 295 // Symbolic reference expression296 if (const auto *SymbolRefExpr = dyn_cast<MCSpecifierExpr>(Imm.Value))297 return SymbolRefExpr->getSpecifier() == Lanai::S_ABS_LO;298 299 // Binary expression300 if (const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(Imm.Value))301 if (const auto *SymbolRefExpr =302 dyn_cast<MCSpecifierExpr>(BinaryExpr->getLHS()))303 return SymbolRefExpr->getSpecifier() == Lanai::S_ABS_LO;304 305 return false;306 }307 308 bool isLoImm16And() {309 if (!isImm())310 return false;311 312 const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value);313 if (ConstExpr) {314 int64_t Value = ConstExpr->getValue();315 // Check if in the form 0xffffXYZW316 return ((Value & ~0xffff) == 0xffff0000);317 }318 return false;319 }320 321 bool isImmShift() {322 if (!isImm())323 return false;324 325 const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value);326 if (!ConstExpr)327 return false;328 int64_t Value = ConstExpr->getValue();329 return (Value >= -31) && (Value <= 31);330 }331 332 bool isLoImm21() {333 if (!isImm())334 return false;335 336 // Constant case337 if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value)) {338 int64_t Value = ConstExpr->getValue();339 return isUInt<21>(Value);340 }341 342 // Symbolic reference expression343 if (const auto *SymbolRefExpr = dyn_cast<MCSpecifierExpr>(Imm.Value))344 return SymbolRefExpr->getSpecifier() == Lanai::S_None;345 if (const MCSymbolRefExpr *SymbolRefExpr =346 dyn_cast<MCSymbolRefExpr>(Imm.Value)) {347 return SymbolRefExpr->getSpecifier() == 0;348 }349 350 // Binary expression351 if (const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(Imm.Value)) {352 if (const auto *SymbolRefExpr =353 dyn_cast<MCSpecifierExpr>(BinaryExpr->getLHS()))354 return SymbolRefExpr->getSpecifier() == Lanai::S_None;355 if (const MCSymbolRefExpr *SymbolRefExpr =356 dyn_cast<MCSymbolRefExpr>(BinaryExpr->getLHS()))357 return SymbolRefExpr->getSpecifier() == 0;358 }359 360 return false;361 }362 363 bool isImm10() {364 if (!isImm())365 return false;366 367 const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value);368 if (!ConstExpr)369 return false;370 int64_t Value = ConstExpr->getValue();371 return isInt<10>(Value);372 }373 374 bool isCondCode() {375 if (!isImm())376 return false;377 378 const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value);379 if (!ConstExpr)380 return false;381 uint64_t Value = ConstExpr->getValue();382 // The condition codes are between 0 (ICC_T) and 15 (ICC_LE). If the383 // unsigned value of the immediate is less than LPCC::UNKNOWN (16) then384 // value corresponds to a valid condition code.385 return Value < LPCC::UNKNOWN;386 }387 388 void addExpr(MCInst &Inst, const MCExpr *Expr) const {389 // Add as immediates where possible. Null MCExpr = 0390 if (Expr == nullptr)391 Inst.addOperand(MCOperand::createImm(0));392 else if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Expr))393 Inst.addOperand(394 MCOperand::createImm(static_cast<int32_t>(ConstExpr->getValue())));395 else396 Inst.addOperand(MCOperand::createExpr(Expr));397 }398 399 void addRegOperands(MCInst &Inst, unsigned N) const {400 assert(N == 1 && "Invalid number of operands!");401 Inst.addOperand(MCOperand::createReg(getReg()));402 }403 404 void addImmOperands(MCInst &Inst, unsigned N) const {405 assert(N == 1 && "Invalid number of operands!");406 addExpr(Inst, getImm());407 }408 409 void addBrTargetOperands(MCInst &Inst, unsigned N) const {410 assert(N == 1 && "Invalid number of operands!");411 addExpr(Inst, getImm());412 }413 414 void addCallTargetOperands(MCInst &Inst, unsigned N) const {415 assert(N == 1 && "Invalid number of operands!");416 addExpr(Inst, getImm());417 }418 419 void addCondCodeOperands(MCInst &Inst, unsigned N) const {420 assert(N == 1 && "Invalid number of operands!");421 addExpr(Inst, getImm());422 }423 424 void addMemImmOperands(MCInst &Inst, unsigned N) const {425 assert(N == 1 && "Invalid number of operands!");426 const MCExpr *Expr = getMemOffset();427 addExpr(Inst, Expr);428 }429 430 void addMemRegImmOperands(MCInst &Inst, unsigned N) const {431 assert(N == 3 && "Invalid number of operands!");432 Inst.addOperand(MCOperand::createReg(getMemBaseReg()));433 const MCExpr *Expr = getMemOffset();434 addExpr(Inst, Expr);435 Inst.addOperand(MCOperand::createImm(getMemOp()));436 }437 438 void addMemRegRegOperands(MCInst &Inst, unsigned N) const {439 assert(N == 3 && "Invalid number of operands!");440 Inst.addOperand(MCOperand::createReg(getMemBaseReg()));441 assert(getMemOffsetReg() && "Invalid offset");442 Inst.addOperand(MCOperand::createReg(getMemOffsetReg()));443 Inst.addOperand(MCOperand::createImm(getMemOp()));444 }445 446 void addMemSplsOperands(MCInst &Inst, unsigned N) const {447 if (isMemRegImm())448 addMemRegImmOperands(Inst, N);449 if (isMemRegReg())450 addMemRegRegOperands(Inst, N);451 }452 453 void addImmShiftOperands(MCInst &Inst, unsigned N) const {454 assert(N == 1 && "Invalid number of operands!");455 addExpr(Inst, getImm());456 }457 458 void addImm10Operands(MCInst &Inst, unsigned N) const {459 assert(N == 1 && "Invalid number of operands!");460 addExpr(Inst, getImm());461 }462 463 void addLoImm16Operands(MCInst &Inst, unsigned N) const {464 assert(N == 1 && "Invalid number of operands!");465 if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(getImm()))466 Inst.addOperand(467 MCOperand::createImm(static_cast<int32_t>(ConstExpr->getValue())));468 else if (isa<MCSpecifierExpr>(getImm())) {469#ifndef NDEBUG470 const auto *SymbolRefExpr = dyn_cast<MCSpecifierExpr>(getImm());471 assert(SymbolRefExpr && SymbolRefExpr->getSpecifier() == Lanai::S_ABS_LO);472#endif473 Inst.addOperand(MCOperand::createExpr(getImm()));474 } else if (isa<MCBinaryExpr>(getImm())) {475#ifndef NDEBUG476 const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(getImm());477 assert(BinaryExpr && isa<MCSpecifierExpr>(BinaryExpr->getLHS()) &&478 cast<MCSpecifierExpr>(BinaryExpr->getLHS())->getSpecifier() ==479 Lanai::S_ABS_LO);480#endif481 Inst.addOperand(MCOperand::createExpr(getImm()));482 } else483 assert(false && "Operand type not supported.");484 }485 486 void addLoImm16AndOperands(MCInst &Inst, unsigned N) const {487 assert(N == 1 && "Invalid number of operands!");488 if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(getImm()))489 Inst.addOperand(MCOperand::createImm(ConstExpr->getValue() & 0xffff));490 else491 assert(false && "Operand type not supported.");492 }493 494 void addHiImm16Operands(MCInst &Inst, unsigned N) const {495 assert(N == 1 && "Invalid number of operands!");496 if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(getImm()))497 Inst.addOperand(MCOperand::createImm(ConstExpr->getValue() >> 16));498 else if (isa<MCSpecifierExpr>(getImm())) {499#ifndef NDEBUG500 const auto *SymbolRefExpr = dyn_cast<MCSpecifierExpr>(getImm());501 assert(SymbolRefExpr && SymbolRefExpr->getSpecifier() == Lanai::S_ABS_HI);502#endif503 Inst.addOperand(MCOperand::createExpr(getImm()));504 } else if (isa<MCBinaryExpr>(getImm())) {505#ifndef NDEBUG506 const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(getImm());507 assert(BinaryExpr && isa<MCSpecifierExpr>(BinaryExpr->getLHS()) &&508 cast<MCSpecifierExpr>(BinaryExpr->getLHS())->getSpecifier() ==509 Lanai::S_ABS_HI);510#endif511 Inst.addOperand(MCOperand::createExpr(getImm()));512 } else513 assert(false && "Operand type not supported.");514 }515 516 void addHiImm16AndOperands(MCInst &Inst, unsigned N) const {517 assert(N == 1 && "Invalid number of operands!");518 if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(getImm()))519 Inst.addOperand(MCOperand::createImm(ConstExpr->getValue() >> 16));520 else521 assert(false && "Operand type not supported.");522 }523 524 void addLoImm21Operands(MCInst &Inst, unsigned N) const {525 assert(N == 1 && "Invalid number of operands!");526 if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(getImm()))527 Inst.addOperand(MCOperand::createImm(ConstExpr->getValue() & 0x1fffff));528 else if (isa<MCSpecifierExpr>(getImm())) {529#ifndef NDEBUG530 const auto *SymbolRefExpr = dyn_cast<MCSpecifierExpr>(getImm());531 assert(SymbolRefExpr && SymbolRefExpr->getSpecifier() == Lanai::S_None);532#endif533 Inst.addOperand(MCOperand::createExpr(getImm()));534 } else if (isa<MCSymbolRefExpr>(getImm())) {535#ifndef NDEBUG536 const MCSymbolRefExpr *SymbolRefExpr =537 dyn_cast<MCSymbolRefExpr>(getImm());538 assert(SymbolRefExpr && SymbolRefExpr->getSpecifier() == 0);539#endif540 Inst.addOperand(MCOperand::createExpr(getImm()));541 } else if (isa<MCBinaryExpr>(getImm())) {542#ifndef NDEBUG543 const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(getImm());544 assert(BinaryExpr && isa<MCSpecifierExpr>(BinaryExpr->getLHS()) &&545 cast<MCSpecifierExpr>(BinaryExpr->getLHS())->getSpecifier() ==546 Lanai::S_None);547#endif548 Inst.addOperand(MCOperand::createExpr(getImm()));549 } else550 assert(false && "Operand type not supported.");551 }552 553 void print(raw_ostream &OS, const MCAsmInfo &MAI) const override {554 switch (Kind) {555 case IMMEDIATE:556 OS << "Imm: " << getImm() << "\n";557 break;558 case TOKEN:559 OS << "Token: " << getToken() << "\n";560 break;561 case REGISTER:562 OS << "Reg: %r" << getReg().id() << "\n";563 break;564 case MEMORY_IMM:565 OS << "MemImm: ";566 MAI.printExpr(OS, *getMemOffset());567 OS << '\n';568 break;569 case MEMORY_REG_IMM:570 OS << "MemRegImm: " << getMemBaseReg().id() << "+";571 MAI.printExpr(OS, *getMemOffset());572 OS << '\n';573 break;574 case MEMORY_REG_REG:575 assert(getMemOffset() == nullptr);576 OS << "MemRegReg: " << getMemBaseReg().id() << "+"577 << "%r" << getMemOffsetReg().id() << "\n";578 break;579 }580 }581 582 static std::unique_ptr<LanaiOperand> CreateToken(StringRef Str, SMLoc Start) {583 auto Op = std::make_unique<LanaiOperand>(TOKEN);584 Op->Tok.Data = Str.data();585 Op->Tok.Length = Str.size();586 Op->StartLoc = Start;587 Op->EndLoc = Start;588 return Op;589 }590 591 static std::unique_ptr<LanaiOperand> createReg(MCRegister Reg, SMLoc Start,592 SMLoc End) {593 auto Op = std::make_unique<LanaiOperand>(REGISTER);594 Op->Reg.RegNum = Reg;595 Op->StartLoc = Start;596 Op->EndLoc = End;597 return Op;598 }599 600 static std::unique_ptr<LanaiOperand> createImm(const MCExpr *Value,601 SMLoc Start, SMLoc End) {602 auto Op = std::make_unique<LanaiOperand>(IMMEDIATE);603 Op->Imm.Value = Value;604 Op->StartLoc = Start;605 Op->EndLoc = End;606 return Op;607 }608 609 static std::unique_ptr<LanaiOperand>610 MorphToMemImm(std::unique_ptr<LanaiOperand> Op) {611 const MCExpr *Imm = Op->getImm();612 Op->Kind = MEMORY_IMM;613 Op->Mem.BaseReg = MCRegister();614 Op->Mem.AluOp = LPAC::ADD;615 Op->Mem.OffsetReg = 0;616 Op->Mem.Offset = Imm;617 return Op;618 }619 620 static std::unique_ptr<LanaiOperand>621 MorphToMemRegReg(MCRegister BaseReg, std::unique_ptr<LanaiOperand> Op,622 unsigned AluOp) {623 MCRegister OffsetReg = Op->getReg();624 Op->Kind = MEMORY_REG_REG;625 Op->Mem.BaseReg = BaseReg;626 Op->Mem.AluOp = AluOp;627 Op->Mem.OffsetReg = OffsetReg;628 Op->Mem.Offset = nullptr;629 return Op;630 }631 632 static std::unique_ptr<LanaiOperand>633 MorphToMemRegImm(MCRegister BaseReg, std::unique_ptr<LanaiOperand> Op,634 unsigned AluOp) {635 const MCExpr *Imm = Op->getImm();636 Op->Kind = MEMORY_REG_IMM;637 Op->Mem.BaseReg = BaseReg;638 Op->Mem.AluOp = AluOp;639 Op->Mem.OffsetReg = 0;640 Op->Mem.Offset = Imm;641 return Op;642 }643};644 645} // end anonymous namespace646 647bool LanaiAsmParser::matchAndEmitInstruction(SMLoc IdLoc, unsigned &Opcode,648 OperandVector &Operands,649 MCStreamer &Out,650 uint64_t &ErrorInfo,651 bool MatchingInlineAsm) {652 MCInst Inst;653 SMLoc ErrorLoc;654 655 switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm)) {656 case Match_Success:657 Out.emitInstruction(Inst, SubtargetInfo);658 Opcode = Inst.getOpcode();659 return false;660 case Match_MissingFeature:661 return Error(IdLoc, "Instruction use requires option to be enabled");662 case Match_MnemonicFail:663 return Error(IdLoc, "Unrecognized instruction mnemonic");664 case Match_InvalidOperand: {665 ErrorLoc = IdLoc;666 if (ErrorInfo != ~0U) {667 if (ErrorInfo >= Operands.size())668 return Error(IdLoc, "Too few operands for instruction");669 670 ErrorLoc = ((LanaiOperand &)*Operands[ErrorInfo]).getStartLoc();671 if (ErrorLoc == SMLoc())672 ErrorLoc = IdLoc;673 }674 return Error(ErrorLoc, "Invalid operand for instruction");675 }676 default:677 break;678 }679 680 llvm_unreachable("Unknown match type detected!");681}682 683// Both '%rN' and 'rN' are parsed as valid registers. This was done to remain684// backwards compatible with GCC and the different ways inline assembly is685// handled.686// TODO: see if there isn't a better way to do this.687std::unique_ptr<LanaiOperand>688LanaiAsmParser::parseRegister(bool RestoreOnFailure) {689 SMLoc Start = Parser.getTok().getLoc();690 SMLoc End = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);691 std::optional<AsmToken> PercentTok;692 693 MCRegister Reg;694 // Eat the '%'.695 if (Lexer.getKind() == AsmToken::Percent) {696 PercentTok = Parser.getTok();697 Parser.Lex();698 }699 if (Lexer.getKind() == AsmToken::Identifier) {700 Reg = MatchRegisterName(Lexer.getTok().getIdentifier());701 if (!Reg) {702 if (PercentTok && RestoreOnFailure)703 Lexer.UnLex(*PercentTok);704 return nullptr;705 }706 Parser.Lex(); // Eat identifier token707 return LanaiOperand::createReg(Reg, Start, End);708 }709 if (PercentTok && RestoreOnFailure)710 Lexer.UnLex(*PercentTok);711 return nullptr;712}713 714bool LanaiAsmParser::parseRegister(MCRegister &RegNum, SMLoc &StartLoc,715 SMLoc &EndLoc) {716 const AsmToken &Tok = getParser().getTok();717 StartLoc = Tok.getLoc();718 EndLoc = Tok.getEndLoc();719 std::unique_ptr<LanaiOperand> Op = parseRegister(/*RestoreOnFailure=*/false);720 if (Op != nullptr)721 RegNum = Op->getReg();722 return (Op == nullptr);723}724 725ParseStatus LanaiAsmParser::tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,726 SMLoc &EndLoc) {727 const AsmToken &Tok = getParser().getTok();728 StartLoc = Tok.getLoc();729 EndLoc = Tok.getEndLoc();730 std::unique_ptr<LanaiOperand> Op = parseRegister(/*RestoreOnFailure=*/true);731 if (Op == nullptr)732 return ParseStatus::NoMatch;733 Reg = Op->getReg();734 return ParseStatus::Success;735}736 737std::unique_ptr<LanaiOperand> LanaiAsmParser::parseIdentifier() {738 SMLoc Start = Parser.getTok().getLoc();739 SMLoc End = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);740 const MCExpr *Res, *RHS = nullptr;741 auto Kind = Lanai::S_None;742 743 if (Lexer.getKind() != AsmToken::Identifier)744 return nullptr;745 746 StringRef Identifier;747 if (Parser.parseIdentifier(Identifier))748 return nullptr;749 750 // Check if identifier has a modifier751 if (Identifier.equals_insensitive("hi"))752 Kind = Lanai::S_ABS_HI;753 else if (Identifier.equals_insensitive("lo"))754 Kind = Lanai::S_ABS_LO;755 756 // If the identifier corresponds to a variant then extract the real757 // identifier.758 if (Kind != Lanai::S_None) {759 if (Lexer.getKind() != AsmToken::LParen) {760 Error(Lexer.getLoc(), "Expected '('");761 return nullptr;762 }763 Lexer.Lex(); // lex '('764 765 // Parse identifier766 if (Parser.parseIdentifier(Identifier))767 return nullptr;768 }769 770 // If addition parse the RHS.771 if (Lexer.getKind() == AsmToken::Plus && Parser.parseExpression(RHS))772 return nullptr;773 774 // For variants parse the final ')'775 if (Kind != Lanai::S_None) {776 if (Lexer.getKind() != AsmToken::RParen) {777 Error(Lexer.getLoc(), "Expected ')'");778 return nullptr;779 }780 Lexer.Lex(); // lex ')'781 }782 783 End = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);784 MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier);785 Res = MCSpecifierExpr::create(Sym, Kind, getContext());786 787 // Nest if this was an addition788 if (RHS)789 Res = MCBinaryExpr::createAdd(Res, RHS, getContext());790 791 return LanaiOperand::createImm(Res, Start, End);792}793 794std::unique_ptr<LanaiOperand> LanaiAsmParser::parseImmediate() {795 SMLoc Start = Parser.getTok().getLoc();796 SMLoc End = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);797 798 const MCExpr *ExprVal;799 switch (Lexer.getKind()) {800 case AsmToken::Identifier:801 return parseIdentifier();802 case AsmToken::Plus:803 case AsmToken::Minus:804 case AsmToken::Integer:805 case AsmToken::Dot:806 if (!Parser.parseExpression(ExprVal))807 return LanaiOperand::createImm(ExprVal, Start, End);808 [[fallthrough]];809 default:810 return nullptr;811 }812}813 814static unsigned AluWithPrePost(unsigned AluCode, bool PreOp, bool PostOp) {815 if (PreOp)816 return LPAC::makePreOp(AluCode);817 if (PostOp)818 return LPAC::makePostOp(AluCode);819 return AluCode;820}821 822unsigned LanaiAsmParser::parseAluOperator(bool PreOp, bool PostOp) {823 StringRef IdString;824 Parser.parseIdentifier(IdString);825 unsigned AluCode = LPAC::stringToLanaiAluCode(IdString);826 if (AluCode == LPAC::UNKNOWN) {827 Error(Parser.getTok().getLoc(), "Can't parse ALU operator");828 return 0;829 }830 return AluCode;831}832 833static int SizeForSuffix(StringRef T) {834 return StringSwitch<int>(T).EndsWith(".h", 2).EndsWith(".b", 1).Default(4);835}836 837bool LanaiAsmParser::parsePrePost(StringRef Type, int *OffsetValue) {838 bool PreOrPost = false;839 if (Lexer.getKind() == Lexer.peekTok(true).getKind()) {840 PreOrPost = true;841 if (Lexer.is(AsmToken::Minus))842 *OffsetValue = -SizeForSuffix(Type);843 else if (Lexer.is(AsmToken::Plus))844 *OffsetValue = SizeForSuffix(Type);845 else846 return false;847 848 // Eat the '-' '-' or '+' '+'849 Parser.Lex();850 Parser.Lex();851 } else if (Lexer.is(AsmToken::Star)) {852 Parser.Lex(); // Eat the '*'853 PreOrPost = true;854 }855 856 return PreOrPost;857}858 859bool shouldBeSls(const LanaiOperand &Op) {860 // The instruction should be encoded as an SLS if the constant is word861 // aligned and will fit in 21 bits862 if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Op.getImm())) {863 int64_t Value = ConstExpr->getValue();864 return (Value % 4 == 0) && (Value >= 0) && (Value <= 0x1fffff);865 }866 // The instruction should be encoded as an SLS if the operand is a symbolic867 // reference with no variant.868 if (const auto *SymbolRefExpr = dyn_cast<MCSpecifierExpr>(Op.getImm()))869 return SymbolRefExpr->getSpecifier() == Lanai::S_None;870 // The instruction should be encoded as an SLS if the operand is a binary871 // expression with the left-hand side being a symbolic reference with no872 // variant.873 if (const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(Op.getImm())) {874 const auto *LHSSymbolRefExpr =875 dyn_cast<MCSpecifierExpr>(BinaryExpr->getLHS());876 return (LHSSymbolRefExpr &&877 LHSSymbolRefExpr->getSpecifier() == Lanai::S_None);878 }879 return false;880}881 882// Matches memory operand. Returns true if error encountered.883ParseStatus LanaiAsmParser::parseMemoryOperand(OperandVector &Operands) {884 // Try to match a memory operand.885 // The memory operands are of the form:886 // (1) Register|Immediate|'' '[' '*'? Register '*'? ']' or887 // ^888 // (2) '[' '*'? Register '*'? AluOperator Register ']'889 // ^890 // (3) '[' '--'|'++' Register '--'|'++' ']'891 //892 // (4) '[' Immediate ']' (for SLS)893 894 // Store the type for use in parsing pre/post increment/decrement operators895 StringRef Type;896 if (Operands[0]->isToken())897 Type = static_cast<LanaiOperand *>(Operands[0].get())->getToken();898 899 // Use 0 if no offset given900 int OffsetValue = 0;901 MCRegister BaseReg;902 unsigned AluOp = LPAC::ADD;903 bool PostOp = false, PreOp = false;904 905 // Try to parse the offset906 std::unique_ptr<LanaiOperand> Op = parseRegister();907 if (!Op)908 Op = parseImmediate();909 910 // Only continue if next token is '['911 if (Lexer.isNot(AsmToken::LBrac)) {912 if (!Op)913 return ParseStatus::NoMatch;914 915 // The start of this custom parsing overlaps with register/immediate so916 // consider this as a successful match of an operand of that type as the917 // token stream can't be rewound to allow them to match separately.918 Operands.push_back(std::move(Op));919 return ParseStatus::Success;920 }921 922 Parser.Lex(); // Eat the '['.923 std::unique_ptr<LanaiOperand> Offset = nullptr;924 if (Op)925 Offset.swap(Op);926 927 // Determine if a pre operation928 PreOp = parsePrePost(Type, &OffsetValue);929 930 Op = parseRegister();931 if (!Op) {932 if (!Offset) {933 if ((Op = parseImmediate()) && Lexer.is(AsmToken::RBrac)) {934 Parser.Lex(); // Eat the ']'935 936 // Memory address operations aligned to word boundary are encoded as937 // SLS, the rest as RM.938 if (shouldBeSls(*Op)) {939 Operands.push_back(LanaiOperand::MorphToMemImm(std::move(Op)));940 } else {941 if (!Op->isLoImm16Signed())942 return Error(Parser.getTok().getLoc(),943 "Memory address is not word aligned and larger than "944 "class RM can handle");945 Operands.push_back(LanaiOperand::MorphToMemRegImm(946 Lanai::R0, std::move(Op), LPAC::ADD));947 }948 return ParseStatus::Success;949 }950 }951 952 return Error(Parser.getTok().getLoc(),953 "Unknown operand, expected register or immediate");954 }955 BaseReg = Op->getReg();956 957 // Determine if a post operation958 if (!PreOp)959 PostOp = parsePrePost(Type, &OffsetValue);960 961 // If ] match form (1) else match form (2)962 if (Lexer.is(AsmToken::RBrac)) {963 Parser.Lex(); // Eat the ']'.964 if (!Offset) {965 SMLoc Start = Parser.getTok().getLoc();966 SMLoc End =967 SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);968 const MCConstantExpr *OffsetConstExpr =969 MCConstantExpr::create(OffsetValue, getContext());970 Offset = LanaiOperand::createImm(OffsetConstExpr, Start, End);971 }972 } else {973 if (Offset || OffsetValue != 0)974 return Error(Parser.getTok().getLoc(), "Expected ']'");975 976 // Parse operator977 AluOp = parseAluOperator(PreOp, PostOp);978 979 // Second form requires offset register980 Offset = parseRegister();981 if (!BaseReg || Lexer.isNot(AsmToken::RBrac))982 return Error(Parser.getTok().getLoc(), "Expected ']'");983 Parser.Lex(); // Eat the ']'.984 }985 986 // First form has addition as operator. Add pre- or post-op indicator as987 // needed.988 AluOp = AluWithPrePost(AluOp, PreOp, PostOp);989 990 // Ensure immediate offset is not too large991 if (Offset->isImm() && !Offset->isLoImm16Signed())992 return Error(Parser.getTok().getLoc(),993 "Memory address is not word aligned and larger than class RM "994 "can handle");995 996 Operands.push_back(997 Offset->isImm()998 ? LanaiOperand::MorphToMemRegImm(BaseReg, std::move(Offset), AluOp)999 : LanaiOperand::MorphToMemRegReg(BaseReg, std::move(Offset), AluOp));1000 1001 return ParseStatus::Success;1002}1003 1004// Looks at a token type and creates the relevant operand from this1005// information, adding to operands.1006// If operand was parsed, returns false, else true.1007ParseStatus LanaiAsmParser::parseOperand(OperandVector *Operands,1008 StringRef Mnemonic) {1009 // Check if the current operand has a custom associated parser, if so, try to1010 // custom parse the operand, or fallback to the general approach.1011 ParseStatus Result = MatchOperandParserImpl(*Operands, Mnemonic);1012 1013 if (Result.isSuccess())1014 return Result;1015 if (Result.isFailure()) {1016 Parser.eatToEndOfStatement();1017 return Result;1018 }1019 1020 // Attempt to parse token as register1021 std::unique_ptr<LanaiOperand> Op = parseRegister();1022 1023 // Attempt to parse token as immediate1024 if (!Op)1025 Op = parseImmediate();1026 1027 // If the token could not be parsed then fail1028 if (!Op) {1029 Error(Parser.getTok().getLoc(), "Unknown operand");1030 Parser.eatToEndOfStatement();1031 return ParseStatus::Failure;1032 }1033 1034 // Push back parsed operand into list of operands1035 Operands->push_back(std::move(Op));1036 1037 return ParseStatus::Success;1038}1039 1040// Split the mnemonic into ASM operand, conditional code and instruction1041// qualifier (half-word, byte).1042StringRef LanaiAsmParser::splitMnemonic(StringRef Name, SMLoc NameLoc,1043 OperandVector *Operands) {1044 size_t Next = Name.find('.');1045 1046 StringRef Mnemonic = Name;1047 1048 bool IsBRR = Mnemonic.consume_back(".r");1049 1050 // Match b?? and s?? (BR, BRR, and SCC instruction classes).1051 if (Mnemonic[0] == 'b' ||1052 (Mnemonic[0] == 's' && !Mnemonic.starts_with("sel") &&1053 !Mnemonic.starts_with("st"))) {1054 // Parse instructions with a conditional code. For example, 'bne' is1055 // converted into two operands 'b' and 'ne'.1056 LPCC::CondCode CondCode =1057 LPCC::suffixToLanaiCondCode(Mnemonic.substr(1, Next));1058 if (CondCode != LPCC::UNKNOWN) {1059 Mnemonic = Mnemonic.slice(0, 1);1060 Operands->push_back(LanaiOperand::CreateToken(Mnemonic, NameLoc));1061 Operands->push_back(LanaiOperand::createImm(1062 MCConstantExpr::create(CondCode, getContext()), NameLoc, NameLoc));1063 if (IsBRR) {1064 Operands->push_back(LanaiOperand::CreateToken(".r", NameLoc));1065 }1066 return Mnemonic;1067 }1068 }1069 1070 // Parse other instructions with condition codes (RR instructions).1071 // We ignore .f here and assume they are flag-setting operations, not1072 // conditional codes (except for select instructions where flag-setting1073 // variants are not yet implemented).1074 if (Mnemonic.starts_with("sel") ||1075 (!Mnemonic.ends_with(".f") && !Mnemonic.starts_with("st"))) {1076 LPCC::CondCode CondCode = LPCC::suffixToLanaiCondCode(Mnemonic);1077 if (CondCode != LPCC::UNKNOWN) {1078 size_t Next = Mnemonic.rfind('.', Name.size());1079 // 'sel' doesn't use a predicate operand whose printer adds the period,1080 // but instead has the period as part of the identifier (i.e., 'sel.' is1081 // expected by the generated matcher). If the mnemonic starts with 'sel'1082 // then include the period as part of the mnemonic, else don't include it1083 // as part of the mnemonic.1084 if (Mnemonic.starts_with("sel")) {1085 Mnemonic = Mnemonic.substr(0, Next + 1);1086 } else {1087 Mnemonic = Mnemonic.substr(0, Next);1088 }1089 Operands->push_back(LanaiOperand::CreateToken(Mnemonic, NameLoc));1090 Operands->push_back(LanaiOperand::createImm(1091 MCConstantExpr::create(CondCode, getContext()), NameLoc, NameLoc));1092 return Mnemonic;1093 }1094 }1095 1096 Operands->push_back(LanaiOperand::CreateToken(Mnemonic, NameLoc));1097 if (IsBRR) {1098 Operands->push_back(LanaiOperand::CreateToken(".r", NameLoc));1099 }1100 1101 return Mnemonic;1102}1103 1104static bool IsMemoryAssignmentError(const OperandVector &Operands) {1105 // Detects if a memory operation has an erroneous base register modification.1106 // Memory operations are detected by matching the types of operands.1107 //1108 // TODO: This test is focussed on one specific instance (ld/st).1109 // Extend it to handle more cases or be more robust.1110 bool Modifies = false;1111 1112 int Offset = 0;1113 1114 if (Operands.size() < 5)1115 return false;1116 else if (Operands[0]->isToken() && Operands[1]->isReg() &&1117 Operands[2]->isImm() && Operands[3]->isImm() && Operands[4]->isReg())1118 Offset = 0;1119 else if (Operands[0]->isToken() && Operands[1]->isToken() &&1120 Operands[2]->isReg() && Operands[3]->isImm() &&1121 Operands[4]->isImm() && Operands[5]->isReg())1122 Offset = 1;1123 else1124 return false;1125 1126 int PossibleAluOpIdx = Offset + 3;1127 int PossibleBaseIdx = Offset + 1;1128 int PossibleDestIdx = Offset + 4;1129 if (LanaiOperand *PossibleAluOp =1130 static_cast<LanaiOperand *>(Operands[PossibleAluOpIdx].get()))1131 if (PossibleAluOp->isImm())1132 if (const MCConstantExpr *ConstExpr =1133 dyn_cast<MCConstantExpr>(PossibleAluOp->getImm()))1134 Modifies = LPAC::modifiesOp(ConstExpr->getValue());1135 return Modifies && Operands[PossibleBaseIdx]->isReg() &&1136 Operands[PossibleDestIdx]->isReg() &&1137 Operands[PossibleBaseIdx]->getReg() ==1138 Operands[PossibleDestIdx]->getReg();1139}1140 1141static bool IsRegister(const MCParsedAsmOperand &op) {1142 return static_cast<const LanaiOperand &>(op).isReg();1143}1144 1145static bool MaybePredicatedInst(const OperandVector &Operands) {1146 if (Operands.size() < 4 || !IsRegister(*Operands[1]) ||1147 !IsRegister(*Operands[2]))1148 return false;1149 return StringSwitch<bool>(1150 static_cast<const LanaiOperand &>(*Operands[0]).getToken())1151 .StartsWith("addc", true)1152 .StartsWith("add", true)1153 .StartsWith("and", true)1154 .StartsWith("sh", true)1155 .StartsWith("subb", true)1156 .StartsWith("sub", true)1157 .StartsWith("or", true)1158 .StartsWith("xor", true)1159 .Default(false);1160}1161 1162bool LanaiAsmParser::parseInstruction(ParseInstructionInfo & /*Info*/,1163 StringRef Name, SMLoc NameLoc,1164 OperandVector &Operands) {1165 // First operand is token for instruction1166 StringRef Mnemonic = splitMnemonic(Name, NameLoc, &Operands);1167 1168 // If there are no more operands, then finish1169 if (Lexer.is(AsmToken::EndOfStatement))1170 return false;1171 1172 // Parse first operand1173 if (!parseOperand(&Operands, Mnemonic).isSuccess())1174 return true;1175 1176 // If it is a st instruction with one 1 operand then it is a "store true".1177 // Transform <"st"> to <"s">, <LPCC:ICC_T>1178 if (Lexer.is(AsmToken::EndOfStatement) && Name == "st" &&1179 Operands.size() == 2) {1180 Operands.erase(Operands.begin(), Operands.begin() + 1);1181 Operands.insert(Operands.begin(), LanaiOperand::CreateToken("s", NameLoc));1182 Operands.insert(Operands.begin() + 1,1183 LanaiOperand::createImm(1184 MCConstantExpr::create(LPCC::ICC_T, getContext()),1185 NameLoc, NameLoc));1186 }1187 1188 // If the instruction is a bt instruction with 1 operand (in assembly) then it1189 // is an unconditional branch instruction and the first two elements of1190 // operands need to be merged.1191 if (Lexer.is(AsmToken::EndOfStatement) && Name.starts_with("bt") &&1192 Operands.size() == 3) {1193 Operands.erase(Operands.begin(), Operands.begin() + 2);1194 Operands.insert(Operands.begin(), LanaiOperand::CreateToken("bt", NameLoc));1195 }1196 1197 // Parse until end of statement, consuming commas between operands1198 while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.is(AsmToken::Comma)) {1199 // Consume comma token1200 Lex();1201 1202 // Parse next operand1203 if (!parseOperand(&Operands, Mnemonic).isSuccess())1204 return true;1205 }1206 1207 if (IsMemoryAssignmentError(Operands)) {1208 Error(Parser.getTok().getLoc(),1209 "the destination register can't equal the base register in an "1210 "instruction that modifies the base register.");1211 return true;1212 }1213 1214 // Insert always true operand for instruction that may be predicated but1215 // are not. Currently the autogenerated parser always expects a predicate.1216 if (MaybePredicatedInst(Operands)) {1217 Operands.insert(Operands.begin() + 1,1218 LanaiOperand::createImm(1219 MCConstantExpr::create(LPCC::ICC_T, getContext()),1220 NameLoc, NameLoc));1221 }1222 1223 return false;1224}1225 1226#define GET_REGISTER_MATCHER1227#define GET_MATCHER_IMPLEMENTATION1228#include "LanaiGenAsmMatcher.inc"1229 1230extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void1231LLVMInitializeLanaiAsmParser() {1232 RegisterMCAsmParser<LanaiAsmParser> x(getTheLanaiTarget());1233}1234