From 9e4931834bf62fc8c375a10b093e3c6c4d4e80b7 Mon Sep 17 00:00:00 2001 From: Roman Tereshin Date: Wed, 23 May 2018 22:10:21 +0000 Subject: [PATCH] [GlobalISel][Tablegen] Assign small opcodes to pseudos Sort pseudo instructions first while emitting enum's for target instructions info. That puts them close to each other and to generic G_* opcodes for GlobalISel. This makes it easier to build small jump tables over opcodes that could be directly embedded into MatchTable's Tablegen'erated for GlobalISel's InstructionSelect. Reviewed By: bogner Differential Revision: https://reviews.llvm.org/D47240 llvm-svn: 333135 --- llvm/utils/TableGen/CodeGenSchedule.cpp | 22 ++++++++++++++-------- llvm/utils/TableGen/CodeGenTarget.cpp | 19 ++++++++++++------- llvm/utils/TableGen/CodeGenTarget.h | 12 ++++++++++++ 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/llvm/utils/TableGen/CodeGenSchedule.cpp b/llvm/utils/TableGen/CodeGenSchedule.cpp index ea22ce6ce9fa..9331fadf4099 100644 --- a/llvm/utils/TableGen/CodeGenSchedule.cpp +++ b/llvm/utils/TableGen/CodeGenSchedule.cpp @@ -82,8 +82,10 @@ struct InstRegexOp : public SetTheory::Operator { Target.getInstructionsByEnumValue(); unsigned NumGeneric = Target.getNumFixedInstructions(); + unsigned NumPseudos = Target.getNumPseudoInstructions(); auto Generics = Instructions.slice(0, NumGeneric); - auto NonGenerics = Instructions.slice(NumGeneric); + auto Pseudos = Instructions.slice(NumGeneric, NumPseudos); + auto NonPseudos = Instructions.slice(NumGeneric + NumPseudos); for (Init *Arg : make_range(Expr->arg_begin(), Expr->arg_end())) { StringInit *SI = dyn_cast(Arg); @@ -125,8 +127,9 @@ struct InstRegexOp : public SetTheory::Operator { } } - // Target instructions are sorted. Find the range that starts with our - // prefix. + // Target instructions are split into two ranges: pseudo instructions + // first, than non-pseudos. Each range is in lexicographical order + // sorted by name. Find the sub-ranges that start with our prefix. struct Comp { bool operator()(const CodeGenInstruction *LHS, StringRef RHS) { return LHS->TheDef->getName() < RHS; @@ -136,11 +139,13 @@ struct InstRegexOp : public SetTheory::Operator { !RHS->TheDef->getName().startswith(LHS); } }; - auto Range = std::equal_range(NonGenerics.begin(), NonGenerics.end(), - Prefix, Comp()); + auto Range1 = + std::equal_range(Pseudos.begin(), Pseudos.end(), Prefix, Comp()); + auto Range2 = std::equal_range(NonPseudos.begin(), NonPseudos.end(), + Prefix, Comp()); - // For this range we know that it starts with the prefix. Check if there's - // a regex that needs to be checked. + // For these ranges we know that instruction names start with the prefix. + // Check if there's a regex that needs to be checked. const auto HandleNonGeneric = [&](const CodeGenInstruction *Inst) { StringRef InstName = Inst->TheDef->getName(); if (!Regexpr || Regexpr->match(InstName.substr(Prefix.size()))) { @@ -148,7 +153,8 @@ struct InstRegexOp : public SetTheory::Operator { NumMatches++; } }; - std::for_each(Range.first, Range.second, HandleNonGeneric); + std::for_each(Range1.first, Range1.second, HandleNonGeneric); + std::for_each(Range2.first, Range2.second, HandleNonGeneric); if (0 == NumMatches) PrintFatalError(Loc, "instregex has no matches: " + Original); diff --git a/llvm/utils/TableGen/CodeGenTarget.cpp b/llvm/utils/TableGen/CodeGenTarget.cpp index ebde61801593..cb73ca83c9bb 100644 --- a/llvm/utils/TableGen/CodeGenTarget.cpp +++ b/llvm/utils/TableGen/CodeGenTarget.cpp @@ -374,19 +374,24 @@ void CodeGenTarget::ComputeInstrsByEnum() const { for (const auto &I : Insts) { const CodeGenInstruction *CGI = I.second.get(); - if (CGI->Namespace != "TargetOpcode") + if (CGI->Namespace != "TargetOpcode") { InstrsByEnum.push_back(CGI); + if (CGI->TheDef->getValueAsBit("isPseudo")) + ++NumPseudoInstructions; + } } assert(InstrsByEnum.size() == Insts.size() && "Missing predefined instr"); // All of the instructions are now in random order based on the map iteration. - // Sort them by name. - llvm::sort(InstrsByEnum.begin() + EndOfPredefines, InstrsByEnum.end(), - [](const CodeGenInstruction *Rec1, - const CodeGenInstruction *Rec2) { - return Rec1->TheDef->getName() < Rec2->TheDef->getName(); - }); + llvm::sort( + InstrsByEnum.begin() + EndOfPredefines, InstrsByEnum.end(), + [](const CodeGenInstruction *Rec1, const CodeGenInstruction *Rec2) { + const auto &D1 = *Rec1->TheDef; + const auto &D2 = *Rec2->TheDef; + return std::make_tuple(!D1.getValueAsBit("isPseudo"), D1.getName()) < + std::make_tuple(!D2.getValueAsBit("isPseudo"), D2.getName()); + }); } diff --git a/llvm/utils/TableGen/CodeGenTarget.h b/llvm/utils/TableGen/CodeGenTarget.h index ef6f8227f993..d2833d5b6a92 100644 --- a/llvm/utils/TableGen/CodeGenTarget.h +++ b/llvm/utils/TableGen/CodeGenTarget.h @@ -62,6 +62,7 @@ class CodeGenTarget { mutable std::unique_ptr SchedModels; mutable std::vector InstrsByEnum; + mutable unsigned NumPseudoInstructions = 0; public: CodeGenTarget(RecordKeeper &Records); ~CodeGenTarget(); @@ -148,8 +149,19 @@ public: /// Returns the number of predefined instructions. static unsigned getNumFixedInstructions(); + /// Returns the number of pseudo instructions. + unsigned getNumPseudoInstructions() const { + if (InstrsByEnum.empty()) + ComputeInstrsByEnum(); + return NumPseudoInstructions; + } + /// Return all of the instructions defined by the target, ordered by their /// enum value. + /// The following order of instructions is also guaranteed: + /// - fixed / generic instructions as declared in TargetOpcodes.def, in order; + /// - pseudo instructions in lexicographical order sorted by name; + /// - other instructions in lexicographical order sorted by name. ArrayRef getInstructionsByEnumValue() const { if (InstrsByEnum.empty()) ComputeInstrsByEnum();