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.
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
Should this be called by MatchInstructionImpl so that this feature comes for free for all AsmParsers?