Skip to content

Commit 23dbf16

Browse files
koachanaaryanshukla
authored andcommitted
[SPARC][IAS] Reject unknown/unavailable mnemonics early in ParseInstruction
Validate and reject any unknown or unavailable instruction mnemonics early in ParseInstruction, before any operand parsing is performed. Some operands (mainly memory ones) can be parsed slightly differently in V8 and V9 assembly language, so by rejecting unknown or unavailable instructions early we can prevent the error message from being shadowed by the one raised during operand parsing. As a side effect this also allows us to tell unknown and unavailable mnemonics apart, and issue a suggestion in appropriate cases. This is based on the approach taken by the MIPS backend. Reviewers: brad0, rorth, s-barannikov, jrtc27 Reviewed By: s-barannikov Pull Request: llvm#96021
1 parent 232d0b1 commit 23dbf16

File tree

4 files changed

+97
-42
lines changed

4 files changed

+97
-42
lines changed

llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ class SparcAsmParser : public MCTargetAsmParser {
116116
// Helper function to see if current token can start an expression.
117117
bool isPossibleExpression(const AsmToken &Token);
118118

119+
// Check if mnemonic is valid.
120+
MatchResultTy mnemonicIsValid(StringRef Mnemonic, unsigned VariantID);
121+
119122
// returns true if Tok is matched to a register and returns register in RegNo.
120123
MCRegister matchRegisterName(const AsmToken &Tok, unsigned &RegKind);
121124

@@ -601,6 +604,45 @@ class SparcOperand : public MCParsedAsmOperand {
601604

602605
} // end anonymous namespace
603606

607+
#define GET_MATCHER_IMPLEMENTATION
608+
#define GET_REGISTER_MATCHER
609+
#define GET_MNEMONIC_SPELL_CHECKER
610+
#include "SparcGenAsmMatcher.inc"
611+
612+
// Use a custom function instead of the one from SparcGenAsmMatcher
613+
// so we can differentiate between unavailable and unknown instructions.
614+
SparcAsmParser::MatchResultTy
615+
SparcAsmParser::mnemonicIsValid(StringRef Mnemonic, unsigned VariantID) {
616+
// Process all MnemonicAliases to remap the mnemonic.
617+
applyMnemonicAliases(Mnemonic, getAvailableFeatures(), VariantID);
618+
619+
// Find the appropriate table for this asm variant.
620+
const MatchEntry *Start, *End;
621+
switch (VariantID) {
622+
default:
623+
llvm_unreachable("invalid variant!");
624+
case 0:
625+
Start = std::begin(MatchTable0);
626+
End = std::end(MatchTable0);
627+
break;
628+
}
629+
630+
// Search the table.
631+
auto MnemonicRange = std::equal_range(Start, End, Mnemonic, LessOpcode());
632+
633+
if (MnemonicRange.first == MnemonicRange.second)
634+
return Match_MnemonicFail;
635+
636+
for (const MatchEntry *it = MnemonicRange.first, *ie = MnemonicRange.second;
637+
it != ie; ++it) {
638+
const FeatureBitset &RequiredFeatures =
639+
FeatureBitsets[it->RequiredFeaturesIdx];
640+
if ((getAvailableFeatures() & RequiredFeatures) == RequiredFeatures)
641+
return Match_Success;
642+
}
643+
return Match_MissingFeature;
644+
}
645+
604646
bool SparcAsmParser::expandSET(MCInst &Inst, SMLoc IDLoc,
605647
SmallVectorImpl<MCInst> &Instructions) {
606648
MCOperand MCRegOp = Inst.getOperand(0);
@@ -829,13 +871,32 @@ ParseStatus SparcAsmParser::tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,
829871
return ParseStatus::NoMatch;
830872
}
831873

832-
static void applyMnemonicAliases(StringRef &Mnemonic,
833-
const FeatureBitset &Features,
834-
unsigned VariantID);
835-
836874
bool SparcAsmParser::ParseInstruction(ParseInstructionInfo &Info,
837875
StringRef Name, SMLoc NameLoc,
838876
OperandVector &Operands) {
877+
// Validate and reject unavailable mnemonics early before
878+
// running any operand parsing.
879+
// This is needed because some operands (mainly memory ones)
880+
// differ between V8 and V9 ISA and so any operand parsing errors
881+
// will cause IAS to bail out before it reaches MatchAndEmitInstruction
882+
// (where the instruction as a whole, including the mnemonic, is validated
883+
// once again just before emission).
884+
// As a nice side effect this also allows us to reject unknown
885+
// instructions and suggest replacements.
886+
MatchResultTy MS = mnemonicIsValid(Name, 0);
887+
switch (MS) {
888+
case Match_Success:
889+
break;
890+
case Match_MissingFeature:
891+
return Error(NameLoc,
892+
"instruction requires a CPU feature not currently enabled");
893+
case Match_MnemonicFail:
894+
return Error(NameLoc,
895+
"invalid instruction mnemonic" +
896+
SparcMnemonicSpellCheck(Name, getAvailableFeatures(), 0));
897+
default:
898+
llvm_unreachable("invalid return status!");
899+
}
839900

840901
// First operand in MCInst is instruction mnemonic.
841902
Operands.push_back(SparcOperand::CreateToken(Name, NameLoc));
@@ -1378,9 +1439,6 @@ ParseStatus SparcAsmParser::parseExpression(int64_t &Val) {
13781439
return getParser().parseAbsoluteExpression(Val);
13791440
}
13801441

1381-
#define GET_REGISTER_MATCHER
1382-
#include "SparcGenAsmMatcher.inc"
1383-
13841442
MCRegister SparcAsmParser::matchRegisterName(const AsmToken &Tok,
13851443
unsigned &RegKind) {
13861444
RegKind = SparcOperand::rk_None;
@@ -1628,9 +1686,6 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSparcAsmParser() {
16281686
RegisterMCAsmParser<SparcAsmParser> C(getTheSparcelTarget());
16291687
}
16301688

1631-
#define GET_MATCHER_IMPLEMENTATION
1632-
#include "SparcGenAsmMatcher.inc"
1633-
16341689
unsigned SparcAsmParser::validateTargetOperandClass(MCParsedAsmOperand &GOp,
16351690
unsigned Kind) {
16361691
SparcOperand &Op = (SparcOperand &)GOp;

llvm/test/MC/Sparc/sparc-asm-errors.s

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
! CHECK: argument must be between
88
set 4294967296, %o1
99

10-
! V8: unexpected token
10+
! V8: instruction requires a CPU feature not currently enabled
1111
! V9: unknown membar tag
1212
membar #BadTag
1313

llvm/test/MC/Sparc/sparc-cas-instructions.s

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ casx [%i0], %l6, %o2
2222
! LEON: error: instruction requires a CPU feature not currently enabled
2323
casxl [%i0], %l6, %o2
2424

25-
! V8: error: malformed ASI tag, must be a constant integer expression
25+
! V8: error: instruction requires a CPU feature not currently enabled
2626
! V9: casxa [%i0] %asi, %l6, %o2 ! encoding: [0xd5,0xf6,0x20,0x16]
27-
! LEON: error: malformed ASI tag, must be a constant integer expression
27+
! LEON: error: instruction requires a CPU feature not currently enabled
2828
casxa [%i0] %asi, %l6, %o2
2929

3030
! V8: error: instruction requires a CPU feature not currently enabled
@@ -37,7 +37,7 @@ casxa [%i0] 0x80, %l6, %o2
3737
! LEON: error: instruction requires a CPU feature not currently enabled
3838
casxa [%i0] (0x40+0x40), %l6, %o2
3939

40-
! V8: error: malformed ASI tag, must be a constant integer expression
40+
! V8: error: instruction requires a CPU feature not currently enabled
4141
! V9: casa [%i0] %asi, %l6, %o2 ! encoding: [0xd5,0xe6,0x20,0x16]
4242
! LEON: error: malformed ASI tag, must be a constant integer expression
4343
casa [%i0] %asi, %l6, %o2

llvm/test/MC/Sparc/sparcv9-instructions.s

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -537,142 +537,142 @@
537537
! V9: stxa %g0, [%g2+%i5] #ASI_SNF ! encoding: [0xc0,0xf0,0x90,0x7d]
538538
stxa %g0, [%g2 + %i5] #ASI_SNF
539539

540-
! V8: error: invalid operand for instruction
540+
! V8: error: instruction requires a CPU feature not currently enabled
541541
! V8-NEXT: prefetch [ %i1 + 0xf80 ], 1
542542
! V9: prefetch [%i1+3968], #one_read ! encoding: [0xc3,0x6e,0x6f,0x80]
543543
prefetch [ %i1 + 0xf80 ], 1
544544

545-
! V8: error: unexpected token
545+
! V8: error: instruction requires a CPU feature not currently enabled
546546
! V8-NEXT: prefetch [ %i1 + 0xf80 ], #n_reads
547547
! V9: prefetch [%i1+3968], #n_reads ! encoding: [0xc1,0x6e,0x6f,0x80]
548548
prefetch [ %i1 + 0xf80 ], #n_reads
549549

550-
! V8: error: unexpected token
550+
! V8: error: instruction requires a CPU feature not currently enabled
551551
! V8-NEXT: prefetch [ %i1 + 0xf80 ], #one_read
552552
! V9: prefetch [%i1+3968], #one_read ! encoding: [0xc3,0x6e,0x6f,0x80]
553553
prefetch [ %i1 + 0xf80 ], #one_read
554554

555-
! V8: error: unexpected token
555+
! V8: error: instruction requires a CPU feature not currently enabled
556556
! V8-NEXT: prefetch [ %i1 + 0xf80 ], #n_writes
557557
! V9: prefetch [%i1+3968], #n_writes ! encoding: [0xc5,0x6e,0x6f,0x80]
558558
prefetch [ %i1 + 0xf80 ], #n_writes
559559

560-
! V8: error: unexpected token
560+
! V8: error: instruction requires a CPU feature not currently enabled
561561
! V8-NEXT: prefetch [ %i1 + 0xf80 ], #one_write
562562
! V9: prefetch [%i1+3968], #one_write ! encoding: [0xc7,0x6e,0x6f,0x80]
563563
prefetch [ %i1 + 0xf80 ], #one_write
564564

565-
! V8: error: unexpected token
565+
! V8: error: instruction requires a CPU feature not currently enabled
566566
! V8-NEXT: prefetch [ %i1 + 0xf80 ], #page
567567
! V9: prefetch [%i1+3968], #page ! encoding: [0xc9,0x6e,0x6f,0x80]
568568
prefetch [ %i1 + 0xf80 ], #page
569569

570-
! V8: error: unexpected token
570+
! V8: error: instruction requires a CPU feature not currently enabled
571571
! V8-NEXT: prefetch [ %i1 + 0xf80 ], #unified
572572
! V9: prefetch [%i1+3968], #unified ! encoding: [0xe3,0x6e,0x6f,0x80]
573573
prefetch [ %i1 + 0xf80 ], #unified
574574

575-
! V8: error: unexpected token
575+
! V8: error: instruction requires a CPU feature not currently enabled
576576
! V8-NEXT: prefetch [ %i1 + 0xf80 ], #n_reads_strong
577577
! V9: prefetch [%i1+3968], #n_reads_strong ! encoding: [0xe9,0x6e,0x6f,0x80]
578578
prefetch [ %i1 + 0xf80 ], #n_reads_strong
579579

580-
! V8: error: unexpected token
580+
! V8: error: instruction requires a CPU feature not currently enabled
581581
! V8-NEXT: prefetch [ %i1 + 0xf80 ], #one_read_strong
582582
! V9: prefetch [%i1+3968], #one_read_strong ! encoding: [0xeb,0x6e,0x6f,0x80]
583583
prefetch [ %i1 + 0xf80 ], #one_read_strong
584584

585-
! V8: error: unexpected token
585+
! V8: error: instruction requires a CPU feature not currently enabled
586586
! V8-NEXT: prefetch [ %i1 + 0xf80 ], #n_writes_strong
587587
! V9: prefetch [%i1+3968], #n_writes_strong ! encoding: [0xed,0x6e,0x6f,0x80]
588588
prefetch [ %i1 + 0xf80 ], #n_writes_strong
589589

590-
! V8: error: unexpected token
590+
! V8: error: instruction requires a CPU feature not currently enabled
591591
! V8-NEXT: prefetch [ %i1 + 0xf80 ], #one_write_strong
592592
! V9: prefetch [%i1+3968], #one_write_strong ! encoding: [0xef,0x6e,0x6f,0x80]
593593
prefetch [ %i1 + 0xf80 ], #one_write_strong
594594

595-
! V8: error: invalid operand for instruction
595+
! V8: error: instruction requires a CPU feature not currently enabled
596596
! V8-NEXT: prefetch [ %i1 + %i2 ], 1
597597
! V9: prefetch [%i1+%i2], #one_read ! encoding: [0xc3,0x6e,0x40,0x1a]
598598
prefetch [ %i1 + %i2 ], 1
599599

600-
! V8: error: unexpected token
600+
! V8: error: instruction requires a CPU feature not currently enabled
601601
! V8-NEXT: prefetch [ %i1 + %i2 ], #n_reads
602602
! V9: prefetch [%i1+%i2], #n_reads ! encoding: [0xc1,0x6e,0x40,0x1a]
603603
prefetch [ %i1 + %i2 ], #n_reads
604604

605-
! V8: error: unexpected token
605+
! V8: error: instruction requires a CPU feature not currently enabled
606606
! V8-NEXT: prefetch [ %i1 + %i2 ], #one_read
607607
! V9: prefetch [%i1+%i2], #one_read ! encoding: [0xc3,0x6e,0x40,0x1a]
608608
prefetch [ %i1 + %i2 ], #one_read
609609

610-
! V8: error: unexpected token
610+
! V8: error: instruction requires a CPU feature not currently enabled
611611
! V8-NEXT: prefetch [ %i1 + %i2 ], #n_writes
612612
! V9: prefetch [%i1+%i2], #n_writes ! encoding: [0xc5,0x6e,0x40,0x1a]
613613
prefetch [ %i1 + %i2 ], #n_writes
614614

615-
! V8: error: unexpected token
615+
! V8: error: instruction requires a CPU feature not currently enabled
616616
! V8-NEXT: prefetch [ %i1 + %i2 ], #one_write
617617
! V9: prefetch [%i1+%i2], #one_write ! encoding: [0xc7,0x6e,0x40,0x1a]
618618
prefetch [ %i1 + %i2 ], #one_write
619619

620-
! V8: error: unexpected token
620+
! V8: error: instruction requires a CPU feature not currently enabled
621621
! V8-NEXT: prefetch [ %i1 + %i2 ], #page
622622
! V9: prefetch [%i1+%i2], #page ! encoding: [0xc9,0x6e,0x40,0x1a]
623623
prefetch [ %i1 + %i2 ], #page
624624

625-
! V8: error: unexpected token
625+
! V8: error: instruction requires a CPU feature not currently enabled
626626
! V8-NEXT: prefetch [ %i1 + %i2 ], #unified
627627
! V9: prefetch [%i1+%i2], #unified ! encoding: [0xe3,0x6e,0x40,0x1a]
628628
prefetch [ %i1 + %i2 ], #unified
629629

630-
! V8: error: unexpected token
630+
! V8: error: instruction requires a CPU feature not currently enabled
631631
! V8-NEXT: prefetch [ %i1 + %i2 ], #n_reads_strong
632632
! V9: prefetch [%i1+%i2], #n_reads_strong ! encoding: [0xe9,0x6e,0x40,0x1a]
633633
prefetch [ %i1 + %i2 ], #n_reads_strong
634634

635-
! V8: error: unexpected token
635+
! V8: error: instruction requires a CPU feature not currently enabled
636636
! V8-NEXT: prefetch [ %i1 + %i2 ], #one_read_strong
637637
! V9: prefetch [%i1+%i2], #one_read_strong ! encoding: [0xeb,0x6e,0x40,0x1a]
638638
prefetch [ %i1 + %i2 ], #one_read_strong
639639

640-
! V8: error: unexpected token
640+
! V8: error: instruction requires a CPU feature not currently enabled
641641
! V8-NEXT: prefetch [ %i1 + %i2 ], #n_writes_strong
642642
! V9: prefetch [%i1+%i2], #n_writes_strong ! encoding: [0xed,0x6e,0x40,0x1a]
643643
prefetch [ %i1 + %i2 ], #n_writes_strong
644644

645-
! V8: error: unexpected token
645+
! V8: error: instruction requires a CPU feature not currently enabled
646646
! V8-NEXT: prefetch [ %i1 + %i2 ], #one_write_strong
647647
! V9: prefetch [%i1+%i2], #one_write_strong ! encoding: [0xef,0x6e,0x40,0x1a]
648648
prefetch [ %i1 + %i2 ], #one_write_strong
649649

650-
! V8: error: malformed ASI tag, must be a constant integer expression
650+
! V8: error: instruction requires a CPU feature not currently enabled
651651
! V8-NEXT: prefetcha [ %i1 + 0xf80 ] %asi, 1
652652
! V9: prefetcha [%i1+3968] %asi, #one_read ! encoding: [0xc3,0xee,0x6f,0x80]
653653
prefetcha [ %i1 + 0xf80 ] %asi, 1
654654

655-
! V8: error: malformed ASI tag, must be a constant integer expression
655+
! V8: error: instruction requires a CPU feature not currently enabled
656656
! V8-NEXT: prefetcha [ %i1 + 0xf80 ] %asi, #one_read
657657
! V9: prefetcha [%i1+3968] %asi, #one_read ! encoding: [0xc3,0xee,0x6f,0x80]
658658
prefetcha [ %i1 + 0xf80 ] %asi, #one_read
659659

660-
! V8: error: invalid operand for instruction
660+
! V8: error: instruction requires a CPU feature not currently enabled
661661
! V8-NEXT: prefetcha [ %i1 + %i2 ] #ASI_SNF, 1
662662
! V9: prefetcha [%i1+%i2] #ASI_SNF, #one_read ! encoding: [0xc3,0xee,0x50,0x7a]
663663
prefetcha [ %i1 + %i2 ] #ASI_SNF, 1
664664

665-
! V8: error: unexpected token
665+
! V8: error: instruction requires a CPU feature not currently enabled
666666
! V8-NEXT: prefetcha [ %i1 + %i2 ] #ASI_SNF, #one_read
667667
! V9: prefetcha [%i1+%i2] #ASI_SNF, #one_read ! encoding: [0xc3,0xee,0x50,0x7a]
668668
prefetcha [ %i1 + %i2 ] #ASI_SNF, #one_read
669669

670-
! V8: error: invalid operand for instruction
670+
! V8: error: instruction requires a CPU feature not currently enabled
671671
! V8-NEXT: prefetcha [ %i1 + %i2 ] 131, 1
672672
! V9: prefetcha [%i1+%i2] #ASI_SNF, #one_read ! encoding: [0xc3,0xee,0x50,0x7a]
673673
prefetcha [ %i1 + %i2 ] 131, 1
674674

675-
! V8: error: unexpected token
675+
! V8: error: instruction requires a CPU feature not currently enabled
676676
! V8-NEXT: prefetcha [ %i1 + %i2 ] 131, #one_read
677677
! V9: prefetcha [%i1+%i2] #ASI_SNF, #one_read ! encoding: [0xc3,0xee,0x50,0x7a]
678678
prefetcha [ %i1 + %i2 ] 131, #one_read

0 commit comments

Comments
 (0)