[llvm-branch-commits] [llvm] [SPARC][IAS] Reject unknown/unavailable mnemonics early in ParseInstruction (PR #96021)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Jul 10 09:57:15 PDT 2024


https://github.com/koachan updated https://github.com/llvm/llvm-project/pull/96021

>From dbd8f1f421b397a4907af3811937a7815900876a Mon Sep 17 00:00:00 2001
From: Koakuma <koachan at protonmail.com>
Date: Wed, 10 Jul 2024 23:57:01 +0700
Subject: [PATCH] Don't use ParseForAllFeatures, validate all mnemonics up
 front instead

Created using spr 1.3.5
---
 .../Target/Sparc/AsmParser/SparcAsmParser.cpp | 78 ++++++++++++++++---
 llvm/test/MC/Sparc/sparc-asm-errors.s         |  4 +-
 llvm/test/MC/Sparc/sparc-cas-instructions.s   |  6 +-
 llvm/test/MC/Sparc/sparcv9-instructions.s     | 26 +++----
 4 files changed, 84 insertions(+), 30 deletions(-)

diff --git a/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp b/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
index e6728d0aae4e9..37f8a72bd4421 100644
--- a/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
+++ b/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
@@ -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);
 
@@ -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);
@@ -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,
+                 "unknown instruction" +
+                     SparcMnemonicSpellCheck(Name, getAvailableFeatures(), 0));
+  default:
+    llvm_unreachable("invalid return status!");
+  }
 
   // First operand in MCInst is instruction mnemonic.
   Operands.push_back(SparcOperand::CreateToken(Name, NameLoc));
@@ -1188,8 +1249,7 @@ ParseStatus SparcAsmParser::parseCallTarget(OperandVector &Operands) {
 ParseStatus SparcAsmParser::parseOperand(OperandVector &Operands,
                                          StringRef Mnemonic) {
 
-  ParseStatus Res =
-      MatchOperandParserImpl(Operands, Mnemonic, /*ParseForAllFeatures=*/true);
+  ParseStatus Res = MatchOperandParserImpl(Operands, Mnemonic);
 
   // If there wasn't a custom match, try the generic matcher below. Otherwise,
   // there was a match, but an error occurred, in which case, just return that
@@ -1379,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;
@@ -1629,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;
diff --git a/llvm/test/MC/Sparc/sparc-asm-errors.s b/llvm/test/MC/Sparc/sparc-asm-errors.s
index 2b3a2eb2bfae6..655fd15e3962f 100644
--- a/llvm/test/MC/Sparc/sparc-asm-errors.s
+++ b/llvm/test/MC/Sparc/sparc-asm-errors.s
@@ -7,11 +7,11 @@
         ! 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
 
-        ! V8: unexpected token
+        ! V8: instruction requires a CPU feature not currently enabled
         ! V9: invalid membar mask number
         membar -127
 
diff --git a/llvm/test/MC/Sparc/sparc-cas-instructions.s b/llvm/test/MC/Sparc/sparc-cas-instructions.s
index 30ce3fd0b2d22..fde3a8dd26056 100644
--- a/llvm/test/MC/Sparc/sparc-cas-instructions.s
+++ b/llvm/test/MC/Sparc/sparc-cas-instructions.s
@@ -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
@@ -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
diff --git a/llvm/test/MC/Sparc/sparcv9-instructions.s b/llvm/test/MC/Sparc/sparcv9-instructions.s
index 68ae2ac5c98a4..9c63f8697e7e3 100644
--- a/llvm/test/MC/Sparc/sparcv9-instructions.s
+++ b/llvm/test/MC/Sparc/sparcv9-instructions.s
@@ -1,32 +1,32 @@
 ! RUN: not llvm-mc %s -triple=sparc   -show-encoding 2>&1 | FileCheck %s --check-prefix=V8
 ! RUN: llvm-mc %s -triple=sparcv9 -show-encoding | FileCheck %s --check-prefix=V9
 
-        ! V8:      error: invalid instruction mnemonic
+        ! V8:      error: unknown instruction
         ! V8-NEXT: addc %g2, %g1, %g3
         ! V9:      addx %g2, %g1, %g3              ! encoding: [0x86,0x40,0x80,0x01]
         addc %g2, %g1, %g3
 
-        ! V8:      error: invalid instruction mnemonic
+        ! V8:      error: unknown instruction
         ! V8-NEXT: addc %g2, 1, %g3
         ! V9:      addx %g2, 1, %g3              ! encoding: [0x86,0x40,0xa0,0x01]
         addc %g2, 1, %g3
 
-        ! V8:      error: invalid instruction mnemonic
+        ! V8:      error: unknown instruction
         ! V8-NEXT: addc 1, %g2, %g3
         ! V9:      addx %g2, 1, %g3              ! encoding: [0x86,0x40,0xa0,0x01]
         addc 1, %g2, %g3
 
-        ! V8:      error: invalid instruction mnemonic
+        ! V8:      error: unknown instruction
         ! V8-NEXT: addccc %g1, %g2, %g3
         ! V9:      addxcc %g1, %g2, %g3            ! encoding: [0x86,0xc0,0x40,0x02]
         addccc %g1, %g2, %g3
 
-        ! V8:      error: invalid instruction mnemonic
+        ! V8:      error: unknown instruction
         ! V8-NEXT: subc %g2, %g1, %g3
         ! V9:      subx %g2, %g1, %g3          ! encoding: [0x86,0x60,0x80,0x01]
         subc %g2, %g1, %g3
 
-        ! V8:      error: invalid instruction mnemonic
+        ! V8:      error: unknown instruction
         ! V8-NEXT: subccc %g1, %g2, %g3
         ! V9:      subxcc %g1, %g2, %g3         ! encoding: [0x86,0xe0,0x40,0x02]
         subccc %g1, %g2, %g3
@@ -46,23 +46,23 @@
         ! V9: sra %g1, %g0, %g1               ! encoding: [0x83,0x38,0x40,0x00]
         signx %g1
 
-        ! V8:      error: invalid instruction mnemonic
+        ! V8:      error: unknown instruction
         ! V8-NEXT: lduw [%i0 + %l6], %o2
         ! V9: ld [%i0+%l6], %o2    ! encoding: [0xd4,0x06,0x00,0x16]
         lduw [%i0 + %l6], %o2
-        ! V8:      error: invalid instruction mnemonic
+        ! V8:      error: unknown instruction
         ! V8-NEXT: lduw [%i0 + 32], %o2
         ! V9: ld [%i0+32], %o2     ! encoding: [0xd4,0x06,0x20,0x20]
         lduw [%i0 + 32], %o2
-        ! V8:      error: invalid instruction mnemonic
+        ! V8:      error: unknown instruction
         ! V8-NEXT: lduw [%g1], %o2
         ! V9: ld [%g1], %o2        ! encoding: [0xd4,0x00,0x40,0x00]
         lduw [%g1], %o2
-        ! V8:      error: invalid instruction mnemonic
+        ! V8:      error: unknown instruction
         ! V8-NEXT: lduwa [%i0 + %l6] 131, %o2
         ! V9: lda [%i0+%l6] #ASI_SNF, %o2 ! encoding: [0xd4,0x86,0x10,0x76]
         lduwa [%i0 + %l6] 131, %o2
-        ! V8:      error: invalid instruction mnemonic
+        ! V8:      error: unknown instruction
         ! V8-NEXT: lduwa [%i0 + %l6] (130+1), %o2
         ! V9: lda [%i0+%l6] #ASI_SNF, %o2 ! encoding: [0xd4,0x86,0x10,0x76]
         lduwa [%i0 + %l6] (130+1), %o2
@@ -647,12 +647,12 @@
         ! 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



More information about the llvm-branch-commits mailing list