Skip to content

Commit 154549e

Browse files
arichardsonsbaranga-arm
authored andcommitted
[AsmMatcher] Add support for conflicting features
This helps avoiding diagnostics for instructions that could never be selected and is required for RISC-V CHERI support. An example here are the CHERI mode-dependent instructions where we have loads/stores that are identical other than the register class for the base register and have predicates that can never both be set. To avoid nonsensical error messages, we should only use the candidate instructions with the currently available feature bits. For RVY (CHERI), loads and stores are mode-dependent, using either a YLEN register or a XLEN register as the base. Prior to the standardization process CHERI assembly used c-prefixed register names for capabilities, so we had the following syntax for RISC-V compatible mode and CHERI pure-capability mode: lw x4, 0(c3) # capability mode: use new `CLW` tablegen instruction lw x4, 0(x3) # integer mode: use existing `LW` tablegen instruction During the standardization this was changed to keep the same register name in both modes, so now we have `lw x4, 0(x3)` in both modes but we have to select between two instructions: one using the normal GPR register class and one using the YGPR register class. We now have a choice between two instructions `LW` and `LW_Y` that have predicates that can never both be true, so we should avoid reporting missing predicates or wrong operands for the "unreachable" instruction. This change was taken from Morello LLVM with a few minor comment clarifications and changes to naming of variables. Co-authored-by: Silviu Baranga <[email protected]>
1 parent 8261528 commit 154549e

File tree

3 files changed

+62
-3
lines changed

3 files changed

+62
-3
lines changed

llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,14 @@ class LLVM_ABI MCTargetAsmParser : public MCAsmParserExtension {
353353

354354
/// AvailableFeatures - The current set of available features.
355355
FeatureBitset AvailableFeatures;
356+
/// A set of features that conflict with each other. This helps improve
357+
/// diagnostics by ignoring instruction variants that are mutually exclusive.
358+
/// An example here are the CHERI mode-dependent instructions where we have
359+
/// loads/stores that are identical other than the register class for the base
360+
/// register and have predicates that can never both be set. To avoid
361+
/// nonsensical error messages, we should only use the candidate instructions
362+
/// with the currently available feature bits.
363+
FeatureBitset ConflictingFeatures;
356364

357365
/// ParsingMSInlineAsm - Are we parsing ms-style inline assembly?
358366
bool ParsingMSInlineAsm = false;
@@ -384,6 +392,15 @@ class LLVM_ABI MCTargetAsmParser : public MCAsmParserExtension {
384392
AvailableFeatures = Value;
385393
}
386394

395+
const FeatureBitset &getConflictingFeatures() const {
396+
return ConflictingFeatures;
397+
}
398+
void setConflictingFeatures(const FeatureBitset &Value) {
399+
assert((Value.none() || Value.count() == 2) &&
400+
"Only zero or two conflicting features supported");
401+
ConflictingFeatures = Value;
402+
}
403+
387404
bool isParsingMSInlineAsm () { return ParsingMSInlineAsm; }
388405
void setParsingMSInlineAsm (bool Value) { ParsingMSInlineAsm = Value; }
389406

llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,15 @@ class RISCVAsmParser : public MCTargetAsmParser {
345345
Parser.addAliasForDirective(".word", ".4byte");
346346
Parser.addAliasForDirective(".dword", ".8byte");
347347
setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
348+
// Don't record errors based on the CapMode feature. XOR the two
349+
// bit patterns to get something that has just CapMode and NotCapMode.
350+
// Skipping mnemonics that are not available in the current assembler mode
351+
// significantly improves diagnostics and allows reusing the same register
352+
// names for capmode vs non-capmode.
353+
FeatureBitset CapModeSet =
354+
ComputeAvailableFeatures({RISCV::FeatureCapMode});
355+
FeatureBitset NoCapModeSet = ComputeAvailableFeatures({});
356+
// setConflictingFeatures(CapModeSet ^ NoCapModeSet);
348357

349358
auto ABIName = StringRef(Options.ABIName);
350359
if (ABIName.ends_with("f") && !getSTI().hasFeature(RISCV::FeatureStdExtF)) {

llvm/utils/TableGen/AsmMatcherEmitter.cpp

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3610,6 +3610,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
36103610
OS << " // Get the current feature set.\n";
36113611
OS << " const FeatureBitset &AvailableFeatures = "
36123612
"getAvailableFeatures();\n\n";
3613+
OS << " // Get the set of features to not report as missing features\n";
3614+
OS << " const FeatureBitset &ConflictingFeatures = "
3615+
"getConflictingFeatures();\n\n";
36133616

36143617
OS << " // Get the instruction mnemonic, which is the first token.\n";
36153618
if (HasMnemonicFirst) {
@@ -3676,7 +3679,10 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
36763679
OS << " // Return a more specific error code if no mnemonics match.\n";
36773680
OS << " if (MnemonicRange.first == MnemonicRange.second)\n";
36783681
OS << " return Match_MnemonicFail;\n\n";
3679-
3682+
if (!ReportMultipleNearMisses)
3683+
OS << " auto FirstValidMnemonic = MnemonicRange.first;\n";
3684+
OS << " bool FoundValidMnemonic = false;\n";
3685+
OS << " bool HasNonConflictingMnemonic = false;\n";
36803686
OS << " for (const MatchEntry *it = MnemonicRange.first, "
36813687
<< "*ie = MnemonicRange.second;\n";
36823688
OS << " it != ie; ++it) {\n";
@@ -3688,7 +3694,23 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
36883694
"opcode \"\n";
36893695
OS << " << MII.getName(it->Opcode) "
36903696
"<< \"\\n\");\n";
3691-
3697+
// If we have a mismatch because we're missing one of the features that are
3698+
// conflicting for diagnostics purposes, skip this mnemonic.
3699+
OS << " if (!HasRequiredFeatures &&\n";
3700+
OS << " (RequiredFeatures & ConflictingFeatures & "
3701+
"~AvailableFeatures).any()) {\n";
3702+
OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \" Skipping "
3703+
"mnemonic \"\n";
3704+
OS << " << MII.getName(it->Opcode) << \" due to "
3705+
"conflicting features\\n\");\n";
3706+
OS << " continue;\n";
3707+
OS << " }\n";
3708+
OS << " HasNonConflictingMnemonic = true;\n";
3709+
OS << " if (!FoundValidMnemonic) {\n";
3710+
if (!ReportMultipleNearMisses)
3711+
OS << " FirstValidMnemonic = it;\n";
3712+
OS << " FoundValidMnemonic = true;\n";
3713+
OS << " }\n";
36923714
if (ReportMultipleNearMisses) {
36933715
OS << " // Some state to record ways in which this instruction did not "
36943716
"match.\n";
@@ -3854,7 +3876,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
38543876
OS << " // If we already had a match that only failed due to a\n";
38553877
OS << " // target predicate, that diagnostic is preferred.\n";
38563878
OS << " if (!HadMatchOtherThanPredicate &&\n";
3857-
OS << " (it == MnemonicRange.first || ErrorInfo <= ActualIdx)) "
3879+
OS << " (it == FirstValidMnemonic || ErrorInfo <= ActualIdx)) "
38583880
"{\n";
38593881
OS << " if (HasRequiredFeatures && (ErrorInfo != ActualIdx || Diag "
38603882
"!= Match_InvalidOperand))\n";
@@ -3892,6 +3914,11 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
38923914
OS << " if (NewMissingFeatures[I])\n";
38933915
OS << " dbgs() << ' ' << I;\n";
38943916
OS << " dbgs() << \"\\n\");\n";
3917+
OS << " if ((NewMissingFeatures & ConflictingFeatures).any()) {\n";
3918+
if (!ReportMultipleNearMisses)
3919+
OS << " HadMatchOtherThanFeatures = false;\n";
3920+
OS << " continue;\n";
3921+
OS << " }\n";
38953922
if (ReportMultipleNearMisses) {
38963923
OS << " FeaturesNearMiss = "
38973924
"NearMissInfo::getMissedFeature(NewMissingFeatures);\n";
@@ -4102,6 +4129,12 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
41024129
OS << " return Match_Success;\n";
41034130
OS << " }\n\n";
41044131

4132+
OS << " if (!HasNonConflictingMnemonic) {\n";
4133+
OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Could not find "
4134+
"non-conflicting mnemonic\\n\");\n";
4135+
OS << " return Match_MnemonicFail;\n";
4136+
OS << " }\n";
4137+
41054138
if (ReportMultipleNearMisses) {
41064139
OS << " // No instruction variants matched exactly.\n";
41074140
OS << " return Match_NearMisses;\n";

0 commit comments

Comments
 (0)