diff --git a/llvm/include/llvm/MC/MCInstPrinter.h b/llvm/include/llvm/MC/MCInstPrinter.h --- a/llvm/include/llvm/MC/MCInstPrinter.h +++ b/llvm/include/llvm/MC/MCInstPrinter.h @@ -131,6 +131,9 @@ enum CondKind : uint8_t { K_Feature, // Match only if a feature is enabled. K_NegFeature, // Match only if a feature is disabled. + K_OrFeature, // Match only if one of a set of features is enabled. + K_OrNegFeature, // Match only if one of a set of features is disabled. + K_EndOrFeatures, // Note end of list of K_Or(Neg)?Features. K_Ignore, // Match any operand. K_Reg, // Match a specific register. K_TiedReg, // Match another already matched register. diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td --- a/llvm/include/llvm/Target/Target.td +++ b/llvm/include/llvm/Target/Target.td @@ -657,9 +657,11 @@ /// as alternative condition string used for assembler matcher. /// e.g. "ModeThumb" is translated to "(Bits & ModeThumb) != 0". /// "!ModeThumb" is translated to "(Bits & ModeThumb) == 0". - /// It can also list multiple features separated by ",". + /// It can also list multiple features separated by "," or "|". /// e.g. "ModeThumb,FeatureThumb2" is translated to /// "(Bits & ModeThumb) != 0 && (Bits & FeatureThumb2) != 0". + /// e.g. "ModeTumb|FeatureThumb2" is translated to + /// "(Bits & ModeThumb) != 0 || (Bits & FeatureThumb2) != 0". string AssemblerCondString = ""; /// PredicateName - User-level name to use for the predicate. Mainly for use diff --git a/llvm/lib/MC/MCInstPrinter.cpp b/llvm/lib/MC/MCInstPrinter.cpp --- a/llvm/lib/MC/MCInstPrinter.cpp +++ b/llvm/lib/MC/MCInstPrinter.cpp @@ -62,12 +62,29 @@ static bool matchAliasCondition(const MCInst &MI, const MCSubtargetInfo *STI, const MCRegisterInfo &MRI, unsigned &OpIdx, const AliasMatchingData &M, - const AliasPatternCond &C) { + const AliasPatternCond &C, + bool &OrPredicateResult) { // Feature tests are special, they don't consume operands. if (C.Kind == AliasPatternCond::K_Feature) return STI->getFeatureBits().test(C.Value); if (C.Kind == AliasPatternCond::K_NegFeature) return !STI->getFeatureBits().test(C.Value); + // For feature tests where just one feature is required in a list, set the + // predicate result bit to whether the expression will return true, and only + // return the real result at the end of list marker. + if (C.Kind == AliasPatternCond::K_OrFeature) { + OrPredicateResult |= STI->getFeatureBits().test(C.Value); + return true; + } + if (C.Kind == AliasPatternCond::K_OrNegFeature) { + OrPredicateResult |= !(STI->getFeatureBits().test(C.Value)); + return true; + } + if (C.Kind == AliasPatternCond::K_EndOrFeatures) { + bool Res = OrPredicateResult; + OrPredicateResult = false; + return Res; + } // Get and consume an operand. const MCOperand &Opnd = MI.getOperand(OpIdx); @@ -95,6 +112,9 @@ return true; case AliasPatternCond::K_Feature: case AliasPatternCond::K_NegFeature: + case AliasPatternCond::K_OrFeature: + case AliasPatternCond::K_OrNegFeature: + case AliasPatternCond::K_EndOrFeatures: llvm_unreachable("handled earlier"); } llvm_unreachable("invalid kind"); @@ -125,8 +145,10 @@ ArrayRef Conds = M.PatternConds.slice(P.AliasCondStart, P.NumConds); unsigned OpIdx = 0; + bool OrPredicateResult = false; if (llvm::all_of(Conds, [&](const AliasPatternCond &C) { - return matchAliasCondition(*MI, STI, MRI, OpIdx, M, C); + return matchAliasCondition(*MI, STI, MRI, OpIdx, M, C, + OrPredicateResult); })) { // If all conditions matched, use this asm string. AsmStrOffset = P.AsmStrOffset; diff --git a/llvm/lib/Target/RISCV/RISCV.td b/llvm/lib/Target/RISCV/RISCV.td --- a/llvm/lib/Target/RISCV/RISCV.td +++ b/llvm/lib/Target/RISCV/RISCV.td @@ -105,7 +105,8 @@ // For instructions that belong to both the basic and the permutation subextensions. // They should be added if any of the two subextension has been specified. def HasStdExtZbbOrZbp - : Predicate<"Subtarget->hasStdExtZbb() || Subtarget->hasStdExtZbp()">; + : Predicate<"Subtarget->hasStdExtZbb() || Subtarget->hasStdExtZbp()">, + AssemblerPredicate<"FeatureExtZbb|FeatureExtZbp">; def FeatureStdExtB : SubtargetFeature<"b", "HasStdExtB", "true", diff --git a/llvm/utils/TableGen/AsmWriterEmitter.cpp b/llvm/utils/TableGen/AsmWriterEmitter.cpp --- a/llvm/utils/TableGen/AsmWriterEmitter.cpp +++ b/llvm/utils/TableGen/AsmWriterEmitter.cpp @@ -943,9 +943,14 @@ Record *R = *I; StringRef AsmCondString = R->getValueAsString("AssemblerCondString"); - // AsmCondString has syntax [!]F(,[!]F)* + // AsmCondString has syntax [!]F([,|][!]F)* + if (AsmCondString.find(',') != StringRef::npos && + AsmCondString.find('|') != StringRef::npos) + PrintFatalError(R->getLoc(), + "Cannot combine operators in AsmPredicate!"); + bool IsOr = AsmCondString.find('|') != StringRef::npos; SmallVector Ops; - SplitString(AsmCondString, Ops, ","); + SplitString(AsmCondString, Ops, ",|"); assert(!Ops.empty() && "AssemblerCondString cannot be empty"); for (StringRef Op : Ops) { @@ -953,9 +958,14 @@ bool IsNeg = Op[0] == '!'; StringRef Feature = Op.drop_front(IsNeg ? 1 : 0); IAP.addCond( - std::string(formatv("AliasPatternCond::K_{0}Feature, {1}::{2}", - IsNeg ? "Neg" : "", Namespace, Feature))); + std::string(formatv("AliasPatternCond::K_{0}{1}Feature, {2}::{3}", + IsOr ? "Or" : "", IsNeg ? "Neg" : "", + Namespace, Feature))); } + // If an AsmPredicate with ors is used, note end of list should these + // be combined. + if (IsOr) + IAP.addCond("AliasPatternCond::K_EndOrFeatures, 0"); } IAPrinterMap[Aliases.first].push_back(std::move(IAP)); diff --git a/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp b/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp --- a/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp +++ b/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp @@ -1209,13 +1209,26 @@ if (!IsFirstEmission) o << " && "; - std::pair pairs = P.split(','); + if (P.find(',') != StringRef::npos && P.find('|') != StringRef::npos) + PrintFatalError(Pred->getLoc(), + "Cannot combine operators in AsmPredicate!"); + bool SplitOr = P.find('|') != StringRef::npos; + + if (SplitOr) + o << "("; + std::pair pairs = + P.split(SplitOr ? '|' : ','); while (!pairs.second.empty()) { emitSinglePredicateMatch(o, pairs.first, Emitter->PredicateNamespace); - o << " && "; - pairs = pairs.second.split(','); + if (SplitOr) + o << " || "; + else + o << " && "; + pairs = pairs.second.split(SplitOr ? '|' : ','); } emitSinglePredicateMatch(o, pairs.first, Emitter->PredicateNamespace); + if (SplitOr) + o << ")"; IsFirstEmission = false; } return !Predicates->empty(); diff --git a/llvm/utils/TableGen/SubtargetFeatureInfo.cpp b/llvm/utils/TableGen/SubtargetFeatureInfo.cpp --- a/llvm/utils/TableGen/SubtargetFeatureInfo.cpp +++ b/llvm/utils/TableGen/SubtargetFeatureInfo.cpp @@ -122,11 +122,21 @@ std::string CondStorage = std::string(SFI.TheDef->getValueAsString("AssemblerCondString")); StringRef Conds = CondStorage; - std::pair Comma = Conds.split(','); + if (Conds.find(',') != StringRef::npos && + Conds.find('|') != StringRef::npos) + PrintFatalError(SFI.TheDef->getLoc(), + "Cannot combine operators in AsmPredicate!"); + bool SplitOr = Conds.find('|') != StringRef::npos; + std::pair Comma = + Conds.split(SplitOr ? '|' : ','); bool First = true; do { - if (!First) - OS << " && "; + if (!First) { + if (SplitOr) + OS << " || "; + else + OS << " && "; + } bool Neg = false; StringRef Cond = Comma.first; @@ -144,7 +154,7 @@ break; First = false; - Comma = Comma.second.split(','); + Comma = Comma.second.split(SplitOr ? '|' : ','); } while (true); OS << ")\n";