forked from OSchip/llvm-project
[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
This commit is contained in:
parent
1a05affa80
commit
9e4931834b
|
@ -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<StringInit>(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);
|
||||
|
|
|
@ -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());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ class CodeGenTarget {
|
|||
mutable std::unique_ptr<CodeGenSchedModels> SchedModels;
|
||||
|
||||
mutable std::vector<const CodeGenInstruction*> 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<const CodeGenInstruction *> getInstructionsByEnumValue() const {
|
||||
if (InstrsByEnum.empty())
|
||||
ComputeInstrsByEnum();
|
||||
|
|
Loading…
Reference in New Issue