[PATCH] D88214: [TableGen] Added a function to identify unsupported opcodes

Dmitry Preobrazhensky via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 24 04:05:39 PDT 2020


dp created this revision.
dp added reviewers: craig.topper, bkramer, sdesmalen, rampitec, olista01, arsenm, niravd, fhahn.
Herald added subscribers: llvm-commits, tpr.
Herald added a project: LLVM.
dp requested review of this revision.
Herald added a subscriber: wdng.

**Summary.**

This change implements generation of a function which may be used by a backend to check if a given instruction is supported for a specific subtarget.

For an example of how this function may be used see D88211 <https://reviews.llvm.org/D88211>.

**Rationale.**

AsmMatcher selects an appropriate instruction based on parsed operands and available features. However feature mismatch is used only as the last resort to improve error messages. As a result assembler may misleadingly report an invalid operand when the real issue is that the specified instruction is not supported for the current subtarget.

It should be noted that there is a difference between invalid and unsupported instructions. Invalid instructions are not supported by any subtarget; when such instruction is encountered, AsmMatcher returns Match_MnemonicFail. In contrast, if an instruction is unsupported, it cannot be used with the current subtarget but it is supported for some other subtarget(s). AsmMatcher cannot reliably identify unsupported instructions -
 Match_MissingFeature may be returned for other reasons.

A possibility to identify unsupported instructions would be especially useful for backends which have many subtargets. AMDGPU is an example. An application developed for one GPU may later be ported to another GPU. During porting it would be helpful to get a meaningful error message when assembler encounters an instruction which is valid but not supported by the current subtarget.

**Appendix.**

Below is the code of a function which is generated to check if an opcode is supported:

  #ifdef GET_MNEMONIC_CHECKER
  #undef GET_MNEMONIC_CHECKER
  
  static bool AMDGPUCheckMnemonic(StringRef Mnemonic,
                                  const FeatureBitset &AvailableFeatures,
                                  unsigned VariantID) {
    // Process all MnemonicAliases to remap the mnemonic.
    applyMnemonicAliases(Mnemonic, AvailableFeatures, 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 false;
  
    for (const MatchEntry *it = MnemonicRange.first, *ie = MnemonicRange.second;
         it != ie; ++it) {
      const FeatureBitset &RequiredFeatures =
        FeatureBitsets[it->RequiredFeaturesIdx];
      if ((AvailableFeatures & RequiredFeatures) == RequiredFeatures)
        return true;
    }
    return false;
  }
  
  #endif // GET_MNEMONIC_CHECKER


https://reviews.llvm.org/D88214

Files:
  llvm/utils/TableGen/AsmMatcherEmitter.cpp


Index: llvm/utils/TableGen/AsmMatcherEmitter.cpp
===================================================================
--- llvm/utils/TableGen/AsmMatcherEmitter.cpp
+++ llvm/utils/TableGen/AsmMatcherEmitter.cpp
@@ -3094,6 +3094,67 @@
   OS << "\n";
 }
 
+static void emitMnemonicChecker(raw_ostream &OS,
+                                CodeGenTarget &Target,
+                                unsigned VariantCount,
+                                bool HasMnemonicFirst,
+                                bool HasMnemonicAliases) {
+  OS << "static bool " << Target.getName()
+     << "CheckMnemonic(StringRef Mnemonic,\n";
+  OS << "                                "
+     << "const FeatureBitset &AvailableFeatures,\n";
+  OS << "                                "
+     << "unsigned VariantID) {\n";
+
+  if (!VariantCount) {
+    OS <<  "  return false;\n";
+  } else {
+    if (HasMnemonicAliases) {
+      OS << "  // Process all MnemonicAliases to remap the mnemonic.\n";
+      OS << "  applyMnemonicAliases(Mnemonic, AvailableFeatures, VariantID);";
+      OS << "\n\n";
+    }
+    OS << "  // Find the appropriate table for this asm variant.\n";
+    OS << "  const MatchEntry *Start, *End;\n";
+    OS << "  switch (VariantID) {\n";
+    OS << "  default: llvm_unreachable(\"invalid variant!\");\n";
+    for (unsigned VC = 0; VC != VariantCount; ++VC) {
+      Record *AsmVariant = Target.getAsmParserVariant(VC);
+      int AsmVariantNo = AsmVariant->getValueAsInt("Variant");
+      OS << "  case " << AsmVariantNo << ": Start = std::begin(MatchTable" << VC
+         << "); End = std::end(MatchTable" << VC << "); break;\n";
+    }
+    OS << "  }\n\n";
+
+    OS << "  // Search the table.\n";
+    if (HasMnemonicFirst) {
+      OS << "  auto MnemonicRange = "
+            "std::equal_range(Start, End, Mnemonic, LessOpcode());\n\n";
+    } else {
+      OS << "  auto MnemonicRange = std::make_pair(Start, End);\n";
+      OS << "  unsigned SIndex = Mnemonic.empty() ? 0 : 1;\n";
+      OS << "  if (!Mnemonic.empty())\n";
+      OS << "    MnemonicRange = "
+         << "std::equal_range(Start, End, Mnemonic.lower(), LessOpcode());\n\n";
+    }
+
+    OS << "  if (MnemonicRange.first == MnemonicRange.second)\n";
+    OS << "    return false;\n\n";
+
+    OS << "  for (const MatchEntry *it = MnemonicRange.first, "
+       << "*ie = MnemonicRange.second;\n";
+    OS << "       it != ie; ++it) {\n";
+    OS << "    const FeatureBitset &RequiredFeatures =\n";
+    OS << "      FeatureBitsets[it->RequiredFeaturesIdx];\n";
+    OS << "    if ((AvailableFeatures & RequiredFeatures) == ";
+    OS << "RequiredFeatures)\n";
+    OS << "      return true;\n";
+    OS << "  }\n";
+    OS << "  return false;\n";
+  }
+  OS << "}\n";
+  OS << "\n";
+}
 
 // Emit a function mapping match classes to strings, for debugging.
 static void emitMatchClassKindNames(std::forward_list<ClassInfo> &Infos,
@@ -3909,6 +3970,14 @@
   emitMnemonicSpellChecker(OS, Target, VariantCount);
 
   OS << "#endif // GET_MNEMONIC_SPELL_CHECKER\n\n";
+
+  OS << "\n#ifdef GET_MNEMONIC_CHECKER\n";
+  OS << "#undef GET_MNEMONIC_CHECKER\n\n";
+
+  emitMnemonicChecker(OS, Target, VariantCount,
+                      HasMnemonicFirst, HasMnemonicAliases);
+
+  OS << "#endif // GET_MNEMONIC_CHECKER\n\n";
 }
 
 namespace llvm {


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D88214.294005.patch
Type: text/x-patch
Size: 3323 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20200924/d181faea/attachment.bin>


More information about the llvm-commits mailing list