diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td index 0577c58f8da2d..e27ecb21ecbc3 100644 --- a/llvm/include/llvm/Target/Target.td +++ b/llvm/include/llvm/Target/Target.td @@ -1564,6 +1564,20 @@ class AsmParser { // method shall be called for all operands as opposed to only those // that have their own specified custom parsers. bit CallCustomParserForAllOperands = false; + + // PreferSmallerInstructions - Should the assembly matcher prefer the smaller + // instructions. + // + // This is useful for the ARM instructions set where smaller encodings must + // be preferentially selected. + // + // The preference order is: + // Instrution size (if this option is enabled, smallest first) + // Number of Operands (least first), + // Operand Classes (lexicographically by operand), + // (Optional) Instruction id (see AsmMatcherEmitter.cpp for details), + // Number of required features (least first) + bit PreferSmallerInstructions = false; } def DefaultAsmParser : AsmParser; diff --git a/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/llvm/utils/TableGen/AsmMatcherEmitter.cpp index febd96086df27..1f1efbabe7b35 100644 --- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp +++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp @@ -375,6 +375,10 @@ class AsmVariantInfo { int AsmVariantNo; }; +bool getPreferSmallerInstructions(CodeGenTarget const &Target) { + return Target.getAsmParser()->getValueAsBit("PreferSmallerInstructions"); +} + /// MatchableInfo - Helper class for storing the necessary information for an /// instruction or alias which is capable of being matched. struct MatchableInfo { @@ -502,6 +506,9 @@ struct MatchableInfo { /// matchable came from. Record *const TheDef; + // ResInstSize - The size of the resulting instruction for this matchable. + unsigned ResInstSize; + /// DefRec - This is the definition that it came from. PointerUnion DefRec; @@ -543,10 +550,12 @@ struct MatchableInfo { MatchableInfo(const CodeGenInstruction &CGI) : AsmVariantID(0), AsmString(CGI.AsmString), TheDef(CGI.TheDef), - DefRec(&CGI), UseInstAsmMatchConverter(true) {} + ResInstSize(TheDef->getValueAsInt("Size")), DefRec(&CGI), + UseInstAsmMatchConverter(true) {} MatchableInfo(std::unique_ptr Alias) : AsmVariantID(0), AsmString(Alias->AsmString), TheDef(Alias->TheDef), + ResInstSize(Alias->ResultInst->TheDef->getValueAsInt("Size")), DefRec(Alias.release()), UseInstAsmMatchConverter(TheDef->getValueAsBit( "UseInstAsmMatchConverter")) {} @@ -555,9 +564,9 @@ struct MatchableInfo { // where it was copied while being in an owning state. MatchableInfo(const MatchableInfo &RHS) : AsmVariantID(RHS.AsmVariantID), AsmString(RHS.AsmString), - TheDef(RHS.TheDef), DefRec(RHS.DefRec), ResOperands(RHS.ResOperands), - Mnemonic(RHS.Mnemonic), AsmOperands(RHS.AsmOperands), - RequiredFeatures(RHS.RequiredFeatures), + TheDef(RHS.TheDef), ResInstSize(RHS.ResInstSize), DefRec(RHS.DefRec), + ResOperands(RHS.ResOperands), Mnemonic(RHS.Mnemonic), + AsmOperands(RHS.AsmOperands), RequiredFeatures(RHS.RequiredFeatures), ConversionFnKind(RHS.ConversionFnKind), HasDeprecation(RHS.HasDeprecation), UseInstAsmMatchConverter(RHS.UseInstAsmMatchConverter) { @@ -608,12 +617,18 @@ struct MatchableInfo { void buildInstructionResultOperands(); void buildAliasResultOperands(bool AliasConstraintsAreChecked); - /// operator< - Compare two matchables. - bool operator<(const MatchableInfo &RHS) const { + /// shouldBeMatchedBefore - Compare two matchables for ordering. + bool shouldBeMatchedBefore(const MatchableInfo &RHS, + bool PreferSmallerInstructions) const { // The primary comparator is the instruction mnemonic. if (int Cmp = Mnemonic.compare_insensitive(RHS.Mnemonic)) return Cmp == -1; + // (Optionally) Order by the resultant instuctions size. + // eg. for ARM thumb instructions smaller encodings should be preferred. + if (PreferSmallerInstructions && ResInstSize != RHS.ResInstSize) + return ResInstSize < RHS.ResInstSize; + if (AsmOperands.size() != RHS.AsmOperands.size()) return AsmOperands.size() < RHS.AsmOperands.size(); @@ -652,7 +667,8 @@ struct MatchableInfo { /// couldMatchAmbiguouslyWith - Check whether this matchable could /// ambiguously match the same set of operands as \p RHS (without being a /// strictly superior match). - bool couldMatchAmbiguouslyWith(const MatchableInfo &RHS) const { + bool couldMatchAmbiguouslyWith(const MatchableInfo &RHS, + bool PreferSmallerInstructions) const { // The primary comparator is the instruction mnemonic. if (Mnemonic != RHS.Mnemonic) return false; @@ -661,6 +677,10 @@ struct MatchableInfo { if (AsmVariantID != RHS.AsmVariantID) return false; + // The size of instruction is unambiguous. + if (PreferSmallerInstructions && ResInstSize != RHS.ResInstSize) + return false; + // The number of operands is unambiguous. if (AsmOperands.size() != RHS.AsmOperands.size()) return false; @@ -3221,20 +3241,23 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { AsmMatcherInfo Info(AsmParser, Target, Records); Info.buildInfo(); + bool PreferSmallerInstructions = getPreferSmallerInstructions(Target); // Sort the instruction table using the partial order on classes. We use // stable_sort to ensure that ambiguous instructions are still // deterministically ordered. llvm::stable_sort( Info.Matchables, - [](const std::unique_ptr &a, - const std::unique_ptr &b) { return *a < *b; }); + [PreferSmallerInstructions](const std::unique_ptr &A, + const std::unique_ptr &B) { + return A->shouldBeMatchedBefore(*B, PreferSmallerInstructions); + }); #ifdef EXPENSIVE_CHECKS // Verify that the table is sorted and operator < works transitively. for (auto I = Info.Matchables.begin(), E = Info.Matchables.end(); I != E; ++I) { for (auto J = I; J != E; ++J) { - assert(!(**J < **I)); + assert(!(*J)->shouldBeMatchedBefore(**I, PreferSmallerInstructions)); } } #endif @@ -3253,7 +3276,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { const MatchableInfo &A = **I; const MatchableInfo &B = **J; - if (A.couldMatchAmbiguouslyWith(B)) { + if (A.couldMatchAmbiguouslyWith(B, PreferSmallerInstructions)) { errs() << "warning: ambiguous matchables:\n"; A.dump(); errs() << "\nis incomparable with:\n";