Skip to content

[SPARC][IAS] Reject unknown/unavailable mnemonics early in ParseInstruction #96021

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 65 additions & 10 deletions llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ class SparcAsmParser : public MCTargetAsmParser {
// Helper function to see if current token can start an expression.
bool isPossibleExpression(const AsmToken &Token);

// Check if mnemonic is valid.
MatchResultTy mnemonicIsValid(StringRef Mnemonic, unsigned VariantID);

// returns true if Tok is matched to a register and returns register in RegNo.
MCRegister matchRegisterName(const AsmToken &Tok, unsigned &RegKind);

Expand Down Expand Up @@ -601,6 +604,45 @@ class SparcOperand : public MCParsedAsmOperand {

} // end anonymous namespace

#define GET_MATCHER_IMPLEMENTATION
#define GET_REGISTER_MATCHER
#define GET_MNEMONIC_SPELL_CHECKER
#include "SparcGenAsmMatcher.inc"

// Use a custom function instead of the one from SparcGenAsmMatcher
// so we can differentiate between unavailable and unknown instructions.
SparcAsmParser::MatchResultTy
SparcAsmParser::mnemonicIsValid(StringRef Mnemonic, unsigned VariantID) {
// Process all MnemonicAliases to remap the mnemonic.
applyMnemonicAliases(Mnemonic, getAvailableFeatures(), VariantID);

// Find the appropriate table for this asm variant.
const MatchEntry *Start, *End;
switch (VariantID) {
default:
llvm_unreachable("invalid variant!");
case 0:
Start = std::begin(MatchTable0);
End = std::end(MatchTable0);
break;
}

// Search the table.
auto MnemonicRange = std::equal_range(Start, End, Mnemonic, LessOpcode());

if (MnemonicRange.first == MnemonicRange.second)
return Match_MnemonicFail;

for (const MatchEntry *it = MnemonicRange.first, *ie = MnemonicRange.second;
it != ie; ++it) {
const FeatureBitset &RequiredFeatures =
FeatureBitsets[it->RequiredFeaturesIdx];
if ((getAvailableFeatures() & RequiredFeatures) == RequiredFeatures)
return Match_Success;
}
return Match_MissingFeature;
}

bool SparcAsmParser::expandSET(MCInst &Inst, SMLoc IDLoc,
SmallVectorImpl<MCInst> &Instructions) {
MCOperand MCRegOp = Inst.getOperand(0);
Expand Down Expand Up @@ -829,13 +871,32 @@ ParseStatus SparcAsmParser::tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,
return ParseStatus::NoMatch;
}

static void applyMnemonicAliases(StringRef &Mnemonic,
const FeatureBitset &Features,
unsigned VariantID);

bool SparcAsmParser::ParseInstruction(ParseInstructionInfo &Info,
StringRef Name, SMLoc NameLoc,
OperandVector &Operands) {
// Validate and reject unavailable mnemonics early before
// running any operand parsing.
// This is needed because some operands (mainly memory ones)
// differ between V8 and V9 ISA and so any operand parsing errors
// will cause IAS to bail out before it reaches MatchAndEmitInstruction
// (where the instruction as a whole, including the mnemonic, is validated
// once again just before emission).
// As a nice side effect this also allows us to reject unknown
// instructions and suggest replacements.
MatchResultTy MS = mnemonicIsValid(Name, 0);
switch (MS) {
case Match_Success:
break;
case Match_MissingFeature:
return Error(NameLoc,
"instruction requires a CPU feature not currently enabled");
case Match_MnemonicFail:
return Error(NameLoc,
"invalid instruction mnemonic" +
SparcMnemonicSpellCheck(Name, getAvailableFeatures(), 0));
default:
llvm_unreachable("invalid return status!");
}

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

#define GET_REGISTER_MATCHER
#include "SparcGenAsmMatcher.inc"

MCRegister SparcAsmParser::matchRegisterName(const AsmToken &Tok,
unsigned &RegKind) {
RegKind = SparcOperand::rk_None;
Expand Down Expand Up @@ -1628,9 +1686,6 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSparcAsmParser() {
RegisterMCAsmParser<SparcAsmParser> C(getTheSparcelTarget());
}

#define GET_MATCHER_IMPLEMENTATION
#include "SparcGenAsmMatcher.inc"

unsigned SparcAsmParser::validateTargetOperandClass(MCParsedAsmOperand &GOp,
unsigned Kind) {
SparcOperand &Op = (SparcOperand &)GOp;
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/MC/Sparc/sparc-asm-errors.s
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
! CHECK: argument must be between
set 4294967296, %o1

! V8: unexpected token
! V8: instruction requires a CPU feature not currently enabled
! V9: unknown membar tag
membar #BadTag

Expand Down
6 changes: 3 additions & 3 deletions llvm/test/MC/Sparc/sparc-cas-instructions.s
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ casx [%i0], %l6, %o2
! LEON: error: instruction requires a CPU feature not currently enabled
casxl [%i0], %l6, %o2

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

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

! V8: error: malformed ASI tag, must be a constant integer expression
! V8: error: instruction requires a CPU feature not currently enabled
! V9: casa [%i0] %asi, %l6, %o2 ! encoding: [0xd5,0xe6,0x20,0x16]
! LEON: error: malformed ASI tag, must be a constant integer expression
casa [%i0] %asi, %l6, %o2
Expand Down
56 changes: 28 additions & 28 deletions llvm/test/MC/Sparc/sparcv9-instructions.s
Original file line number Diff line number Diff line change
Expand Up @@ -537,142 +537,142 @@
! V9: stxa %g0, [%g2+%i5] #ASI_SNF ! encoding: [0xc0,0xf0,0x90,0x7d]
stxa %g0, [%g2 + %i5] #ASI_SNF

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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