1 //===- XtensaAsmParser.cpp - Parse Xtensa assembly to MCInst instructions -===//
3 // The LLVM Compiler Infrastructure
5 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
6 // See https://llvm.org/LICENSE.txt for license information.
7 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
9 //===----------------------------------------------------------------------===//
11 #include "MCTargetDesc/XtensaMCTargetDesc.h"
12 #include "TargetInfo/XtensaTargetInfo.h"
13 #include "llvm/ADT/STLExtras.h"
14 #include "llvm/ADT/StringSwitch.h"
15 #include "llvm/MC/MCContext.h"
16 #include "llvm/MC/MCExpr.h"
17 #include "llvm/MC/MCInst.h"
18 #include "llvm/MC/MCInstrInfo.h"
19 #include "llvm/MC/MCParser/MCAsmLexer.h"
20 #include "llvm/MC/MCParser/MCParsedAsmOperand.h"
21 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
22 #include "llvm/MC/MCRegisterInfo.h"
23 #include "llvm/MC/MCStreamer.h"
24 #include "llvm/MC/MCSubtargetInfo.h"
25 #include "llvm/MC/TargetRegistry.h"
26 #include "llvm/Support/Casting.h"
30 #define DEBUG_TYPE "xtensa-asm-parser"
34 class XtensaAsmParser
: public MCTargetAsmParser
{
36 SMLoc
getLoc() const { return getParser().getTok().getLoc(); }
38 bool parseRegister(MCRegister
&Reg
, SMLoc
&StartLoc
, SMLoc
&EndLoc
) override
;
39 bool ParseInstruction(ParseInstructionInfo
&Info
, StringRef Name
,
40 SMLoc NameLoc
, OperandVector
&Operands
) override
;
41 bool MatchAndEmitInstruction(SMLoc IDLoc
, unsigned &Opcode
,
42 OperandVector
&Operands
, MCStreamer
&Out
,
44 bool MatchingInlineAsm
) override
;
45 unsigned validateTargetOperandClass(MCParsedAsmOperand
&Op
,
46 unsigned Kind
) override
;
48 // Auto-generated instruction matching functions
49 #define GET_ASSEMBLER_HEADER
50 #include "XtensaGenAsmMatcher.inc"
52 ParseStatus
parseImmediate(OperandVector
&Operands
);
53 ParseStatus
parseRegister(OperandVector
&Operands
, bool AllowParens
= false,
55 ParseStatus
parseOperandWithModifier(OperandVector
&Operands
);
56 bool parseOperand(OperandVector
&Operands
, StringRef Mnemonic
,
58 bool ParseInstructionWithSR(ParseInstructionInfo
&Info
, StringRef Name
,
59 SMLoc NameLoc
, OperandVector
&Operands
);
60 ParseStatus
tryParseRegister(MCRegister
&Reg
, SMLoc
&StartLoc
,
61 SMLoc
&EndLoc
) override
{
62 return ParseStatus::NoMatch
;
64 ParseStatus
parsePCRelTarget(OperandVector
&Operands
);
67 enum XtensaMatchResultTy
{
68 Match_Dummy
= FIRST_TARGET_MATCH_RESULT_TY
,
69 #define GET_OPERAND_DIAGNOSTIC_TYPES
70 #include "XtensaGenAsmMatcher.inc"
71 #undef GET_OPERAND_DIAGNOSTIC_TYPES
74 XtensaAsmParser(const MCSubtargetInfo
&STI
, MCAsmParser
&Parser
,
75 const MCInstrInfo
&MII
, const MCTargetOptions
&Options
)
76 : MCTargetAsmParser(Options
, STI
, MII
) {
77 setAvailableFeatures(ComputeAvailableFeatures(STI
.getFeatureBits()));
81 // Return true if Expr is in the range [MinValue, MaxValue].
82 static bool inRange(const MCExpr
*Expr
, int64_t MinValue
, int64_t MaxValue
) {
83 if (auto *CE
= dyn_cast
<MCConstantExpr
>(Expr
)) {
84 int64_t Value
= CE
->getValue();
85 return Value
>= MinValue
&& Value
<= MaxValue
;
90 struct XtensaOperand
: public MCParsedAsmOperand
{
106 SMLoc StartLoc
, EndLoc
;
113 XtensaOperand(KindTy K
) : MCParsedAsmOperand(), Kind(K
) {}
116 XtensaOperand(const XtensaOperand
&o
) : MCParsedAsmOperand() {
118 StartLoc
= o
.StartLoc
;
133 bool isToken() const override
{ return Kind
== Token
; }
134 bool isReg() const override
{ return Kind
== Register
; }
135 bool isImm() const override
{ return Kind
== Immediate
; }
136 bool isMem() const override
{ return false; }
138 bool isImm(int64_t MinValue
, int64_t MaxValue
) const {
139 return Kind
== Immediate
&& inRange(getImm(), MinValue
, MaxValue
);
142 bool isImm8() const { return isImm(-128, 127); }
144 bool isImm8_sh8() const {
145 return isImm(-32768, 32512) &&
146 ((cast
<MCConstantExpr
>(getImm())->getValue() & 0xFF) == 0);
149 bool isImm12() const { return isImm(-2048, 2047); }
151 bool isImm12m() const { return isImm(-2048, 2047); }
153 bool isOffset4m32() const {
154 return isImm(0, 60) &&
155 ((cast
<MCConstantExpr
>(getImm())->getValue() & 0x3) == 0);
158 bool isOffset8m8() const { return isImm(0, 255); }
160 bool isOffset8m16() const {
161 return isImm(0, 510) &&
162 ((cast
<MCConstantExpr
>(getImm())->getValue() & 0x1) == 0);
165 bool isOffset8m32() const {
166 return isImm(0, 1020) &&
167 ((cast
<MCConstantExpr
>(getImm())->getValue() & 0x3) == 0);
170 bool isUimm4() const { return isImm(0, 15); }
172 bool isUimm5() const { return isImm(0, 31); }
174 bool isImm8n_7() const { return isImm(-8, 7); }
176 bool isShimm1_31() const { return isImm(1, 31); }
178 bool isImm16_31() const { return isImm(16, 31); }
180 bool isImm1_16() const { return isImm(1, 16); }
182 bool isB4const() const {
183 if (Kind
!= Immediate
)
185 if (auto *CE
= dyn_cast
<MCConstantExpr
>(getImm())) {
186 int64_t Value
= CE
->getValue();
212 bool isB4constu() const {
213 if (Kind
!= Immediate
)
215 if (auto *CE
= dyn_cast
<MCConstantExpr
>(getImm())) {
216 int64_t Value
= CE
->getValue();
242 /// getStartLoc - Gets location of the first token of this operand
243 SMLoc
getStartLoc() const override
{ return StartLoc
; }
244 /// getEndLoc - Gets location of the last token of this operand
245 SMLoc
getEndLoc() const override
{ return EndLoc
; }
247 unsigned getReg() const override
{
248 assert(Kind
== Register
&& "Invalid type access!");
252 const MCExpr
*getImm() const {
253 assert(Kind
== Immediate
&& "Invalid type access!");
257 StringRef
getToken() const {
258 assert(Kind
== Token
&& "Invalid type access!");
262 void print(raw_ostream
&OS
) const override
{
269 OS
<< getReg() << ">";
272 OS
<< "'" << getToken() << "'";
277 static std::unique_ptr
<XtensaOperand
> createToken(StringRef Str
, SMLoc S
) {
278 auto Op
= std::make_unique
<XtensaOperand
>(Token
);
285 static std::unique_ptr
<XtensaOperand
> createReg(unsigned RegNo
, SMLoc S
,
287 auto Op
= std::make_unique
<XtensaOperand
>(Register
);
288 Op
->Reg
.RegNum
= RegNo
;
294 static std::unique_ptr
<XtensaOperand
> createImm(const MCExpr
*Val
, SMLoc S
,
296 auto Op
= std::make_unique
<XtensaOperand
>(Immediate
);
303 void addExpr(MCInst
&Inst
, const MCExpr
*Expr
) const {
304 assert(Expr
&& "Expr shouldn't be null!");
306 bool IsConstant
= false;
308 if (auto *CE
= dyn_cast
<MCConstantExpr
>(Expr
)) {
310 Imm
= CE
->getValue();
314 Inst
.addOperand(MCOperand::createImm(Imm
));
316 Inst
.addOperand(MCOperand::createExpr(Expr
));
319 // Used by the TableGen Code
320 void addRegOperands(MCInst
&Inst
, unsigned N
) const {
321 assert(N
== 1 && "Invalid number of operands!");
322 Inst
.addOperand(MCOperand::createReg(getReg()));
325 void addImmOperands(MCInst
&Inst
, unsigned N
) const {
326 assert(N
== 1 && "Invalid number of operands!");
327 addExpr(Inst
, getImm());
331 #define GET_REGISTER_MATCHER
332 #define GET_MATCHER_IMPLEMENTATION
333 #include "XtensaGenAsmMatcher.inc"
335 unsigned XtensaAsmParser::validateTargetOperandClass(MCParsedAsmOperand
&AsmOp
,
337 return Match_InvalidOperand
;
340 static SMLoc
RefineErrorLoc(const SMLoc Loc
, const OperandVector
&Operands
,
341 uint64_t ErrorInfo
) {
342 if (ErrorInfo
!= ~0ULL && ErrorInfo
< Operands
.size()) {
343 SMLoc ErrorLoc
= Operands
[ErrorInfo
]->getStartLoc();
344 if (ErrorLoc
== SMLoc())
351 bool XtensaAsmParser::MatchAndEmitInstruction(SMLoc IDLoc
, unsigned &Opcode
,
352 OperandVector
&Operands
,
355 bool MatchingInlineAsm
) {
358 MatchInstructionImpl(Operands
, Inst
, ErrorInfo
, MatchingInlineAsm
);
365 Out
.emitInstruction(Inst
, getSTI());
367 case Match_MissingFeature
:
368 return Error(IDLoc
, "instruction use requires an option to be enabled");
369 case Match_MnemonicFail
:
370 return Error(IDLoc
, "unrecognized instruction mnemonic");
371 case Match_InvalidOperand
: {
372 SMLoc ErrorLoc
= IDLoc
;
373 if (ErrorInfo
!= ~0U) {
374 if (ErrorInfo
>= Operands
.size())
375 return Error(ErrorLoc
, "too few operands for instruction");
377 ErrorLoc
= ((XtensaOperand
&)*Operands
[ErrorInfo
]).getStartLoc();
378 if (ErrorLoc
== SMLoc())
381 return Error(ErrorLoc
, "invalid operand for instruction");
383 case Match_InvalidImm8
:
384 return Error(RefineErrorLoc(IDLoc
, Operands
, ErrorInfo
),
385 "expected immediate in range [-128, 127]");
386 case Match_InvalidImm8_sh8
:
387 return Error(RefineErrorLoc(IDLoc
, Operands
, ErrorInfo
),
388 "expected immediate in range [-32768, 32512], first 8 bits "
390 case Match_InvalidB4const
:
391 return Error(RefineErrorLoc(IDLoc
, Operands
, ErrorInfo
),
392 "expected b4const immediate");
393 case Match_InvalidB4constu
:
394 return Error(RefineErrorLoc(IDLoc
, Operands
, ErrorInfo
),
395 "expected b4constu immediate");
396 case Match_InvalidImm12
:
397 return Error(RefineErrorLoc(IDLoc
, Operands
, ErrorInfo
),
398 "expected immediate in range [-2048, 2047]");
399 case Match_InvalidImm12m
:
400 return Error(RefineErrorLoc(IDLoc
, Operands
, ErrorInfo
),
401 "expected immediate in range [-2048, 2047]");
402 case Match_InvalidImm1_16
:
403 return Error(RefineErrorLoc(IDLoc
, Operands
, ErrorInfo
),
404 "expected immediate in range [1, 16]");
405 case Match_InvalidShimm1_31
:
406 return Error(RefineErrorLoc(IDLoc
, Operands
, ErrorInfo
),
407 "expected immediate in range [1, 31]");
408 case Match_InvalidUimm4
:
409 return Error(RefineErrorLoc(IDLoc
, Operands
, ErrorInfo
),
410 "expected immediate in range [0, 15]");
411 case Match_InvalidUimm5
:
412 return Error(RefineErrorLoc(IDLoc
, Operands
, ErrorInfo
),
413 "expected immediate in range [0, 31]");
414 case Match_InvalidOffset8m8
:
415 return Error(RefineErrorLoc(IDLoc
, Operands
, ErrorInfo
),
416 "expected immediate in range [0, 255]");
417 case Match_InvalidOffset8m16
:
418 return Error(RefineErrorLoc(IDLoc
, Operands
, ErrorInfo
),
419 "expected immediate in range [0, 510], first bit "
421 case Match_InvalidOffset8m32
:
422 return Error(RefineErrorLoc(IDLoc
, Operands
, ErrorInfo
),
423 "expected immediate in range [0, 1020], first 2 bits "
425 case Match_InvalidOffset4m32
:
426 return Error(RefineErrorLoc(IDLoc
, Operands
, ErrorInfo
),
427 "expected immediate in range [0, 60], first 2 bits "
431 report_fatal_error("Unknown match type detected!");
434 ParseStatus
XtensaAsmParser::parsePCRelTarget(OperandVector
&Operands
) {
435 MCAsmParser
&Parser
= getParser();
436 LLVM_DEBUG(dbgs() << "parsePCRelTarget\n");
438 SMLoc S
= getLexer().getLoc();
440 // Expressions are acceptable
441 const MCExpr
*Expr
= nullptr;
442 if (Parser
.parseExpression(Expr
)) {
443 // We have no way of knowing if a symbol was consumed so we must ParseFail
444 return ParseStatus::Failure
;
447 // Currently not support constants
448 if (Expr
->getKind() == MCExpr::ExprKind::Constant
)
449 return Error(getLoc(), "unknown operand");
451 Operands
.push_back(XtensaOperand::createImm(Expr
, S
, getLexer().getLoc()));
452 return ParseStatus::Success
;
455 bool XtensaAsmParser::parseRegister(MCRegister
&Reg
, SMLoc
&StartLoc
,
457 const AsmToken
&Tok
= getParser().getTok();
458 StartLoc
= Tok
.getLoc();
459 EndLoc
= Tok
.getEndLoc();
460 Reg
= Xtensa::NoRegister
;
461 StringRef Name
= getLexer().getTok().getIdentifier();
463 if (!MatchRegisterName(Name
) && !MatchRegisterAltName(Name
)) {
464 getParser().Lex(); // Eat identifier token.
468 return Error(StartLoc
, "invalid register name");
471 ParseStatus
XtensaAsmParser::parseRegister(OperandVector
&Operands
,
472 bool AllowParens
, bool SR
) {
473 SMLoc FirstS
= getLoc();
474 bool HadParens
= false;
478 // If this a parenthesised register name is allowed, parse it atomically
479 if (AllowParens
&& getLexer().is(AsmToken::LParen
)) {
480 size_t ReadCount
= getLexer().peekTokens(Buf
);
481 if (ReadCount
== 2 && Buf
[1].getKind() == AsmToken::RParen
) {
482 if ((Buf
[0].getKind() == AsmToken::Integer
) && (!SR
))
483 return ParseStatus::NoMatch
;
485 getParser().Lex(); // Eat '('
491 switch (getLexer().getKind()) {
493 return ParseStatus::NoMatch
;
494 case AsmToken::Integer
:
496 return ParseStatus::NoMatch
;
497 RegName
= StringRef(std::to_string(getLexer().getTok().getIntVal()));
498 RegNo
= MatchRegisterName(RegName
);
500 RegNo
= MatchRegisterAltName(RegName
);
502 case AsmToken::Identifier
:
503 RegName
= getLexer().getTok().getIdentifier();
504 RegNo
= MatchRegisterName(RegName
);
506 RegNo
= MatchRegisterAltName(RegName
);
512 getLexer().UnLex(Buf
[0]);
513 return ParseStatus::NoMatch
;
516 Operands
.push_back(XtensaOperand::createToken("(", FirstS
));
518 SMLoc E
= getParser().getTok().getEndLoc();
520 Operands
.push_back(XtensaOperand::createReg(RegNo
, S
, E
));
523 getParser().Lex(); // Eat ')'
524 Operands
.push_back(XtensaOperand::createToken(")", getLoc()));
527 return ParseStatus::Success
;
530 ParseStatus
XtensaAsmParser::parseImmediate(OperandVector
&Operands
) {
535 switch (getLexer().getKind()) {
537 return ParseStatus::NoMatch
;
538 case AsmToken::LParen
:
539 case AsmToken::Minus
:
541 case AsmToken::Tilde
:
542 case AsmToken::Integer
:
543 case AsmToken::String
:
544 if (getParser().parseExpression(Res
))
545 return ParseStatus::Failure
;
547 case AsmToken::Identifier
: {
548 StringRef Identifier
;
549 if (getParser().parseIdentifier(Identifier
))
550 return ParseStatus::Failure
;
552 MCSymbol
*Sym
= getContext().getOrCreateSymbol(Identifier
);
553 Res
= MCSymbolRefExpr::create(Sym
, MCSymbolRefExpr::VK_None
, getContext());
556 case AsmToken::Percent
:
557 return parseOperandWithModifier(Operands
);
560 E
= SMLoc::getFromPointer(S
.getPointer() - 1);
561 Operands
.push_back(XtensaOperand::createImm(Res
, S
, E
));
562 return ParseStatus::Success
;
565 ParseStatus
XtensaAsmParser::parseOperandWithModifier(OperandVector
&Operands
) {
566 return ParseStatus::Failure
;
569 /// Looks at a token type and creates the relevant operand
570 /// from this information, adding to Operands.
571 /// If operand was parsed, returns false, else true.
572 bool XtensaAsmParser::parseOperand(OperandVector
&Operands
, StringRef Mnemonic
,
574 // Check if the current operand has a custom associated parser, if so, try to
575 // custom parse the operand, or fallback to the general approach.
576 ParseStatus Res
= MatchOperandParserImpl(Operands
, Mnemonic
);
580 // If there wasn't a custom match, try the generic matcher below. Otherwise,
581 // there was a match, but an error occurred, in which case, just return that
582 // the operand parsing failed.
586 // Attempt to parse token as register
587 if (parseRegister(Operands
, true, SR
).isSuccess())
590 // Attempt to parse token as an immediate
591 if (parseImmediate(Operands
).isSuccess())
594 // Finally we have exhausted all options and must declare defeat.
595 return Error(getLoc(), "unknown operand");
598 bool XtensaAsmParser::ParseInstructionWithSR(ParseInstructionInfo
&Info
,
599 StringRef Name
, SMLoc NameLoc
,
600 OperandVector
&Operands
) {
601 if ((Name
.startswith("wsr.") || Name
.startswith("rsr.") ||
602 Name
.startswith("xsr.")) &&
604 // Parse case when instruction name is concatenated with SR register
605 // name, like "wsr.sar a1"
607 // First operand is token for instruction
608 Operands
.push_back(XtensaOperand::createToken(Name
.take_front(3), NameLoc
));
610 StringRef RegName
= Name
.drop_front(4);
611 unsigned RegNo
= MatchRegisterName(RegName
);
614 RegNo
= MatchRegisterAltName(RegName
);
617 return Error(NameLoc
, "invalid register name");
620 if (parseOperand(Operands
, Name
))
624 SMLoc E
= SMLoc::getFromPointer(S
.getPointer() - 1);
625 Operands
.push_back(XtensaOperand::createReg(RegNo
, S
, E
));
627 // First operand is token for instruction
628 Operands
.push_back(XtensaOperand::createToken(Name
, NameLoc
));
630 // Parse first operand
631 if (parseOperand(Operands
, Name
))
634 if (!parseOptionalToken(AsmToken::Comma
)) {
635 SMLoc Loc
= getLexer().getLoc();
636 getParser().eatToEndOfStatement();
637 return Error(Loc
, "unexpected token");
640 // Parse second operand
641 if (parseOperand(Operands
, Name
, true))
645 if (getLexer().isNot(AsmToken::EndOfStatement
)) {
646 SMLoc Loc
= getLexer().getLoc();
647 getParser().eatToEndOfStatement();
648 return Error(Loc
, "unexpected token");
651 getParser().Lex(); // Consume the EndOfStatement.
655 bool XtensaAsmParser::ParseInstruction(ParseInstructionInfo
&Info
,
656 StringRef Name
, SMLoc NameLoc
,
657 OperandVector
&Operands
) {
658 if (Name
.startswith("wsr") || Name
.startswith("rsr") ||
659 Name
.startswith("xsr")) {
660 return ParseInstructionWithSR(Info
, Name
, NameLoc
, Operands
);
663 // First operand is token for instruction
664 Operands
.push_back(XtensaOperand::createToken(Name
, NameLoc
));
666 // If there are no more operands, then finish
667 if (getLexer().is(AsmToken::EndOfStatement
))
670 // Parse first operand
671 if (parseOperand(Operands
, Name
))
674 // Parse until end of statement, consuming commas between operands
675 while (parseOptionalToken(AsmToken::Comma
))
676 if (parseOperand(Operands
, Name
))
679 if (getLexer().isNot(AsmToken::EndOfStatement
)) {
680 SMLoc Loc
= getLexer().getLoc();
681 getParser().eatToEndOfStatement();
682 return Error(Loc
, "unexpected token");
685 getParser().Lex(); // Consume the EndOfStatement.
689 // Force static initialization.
690 extern "C" LLVM_EXTERNAL_VISIBILITY
void LLVMInitializeXtensaAsmParser() {
691 RegisterMCAsmParser
<XtensaAsmParser
> X(getTheXtensaTarget());