[GlobalISel][InstructionSelect] Removing redundant num operands and nested def operands checks, perf patch 2

This patch continues a series of patches that decrease time spent by
GlobalISel in its InstructionSelect pass by roughly 60% for -O0 builds
for large inputs as measured on sqlite3-amalgamation
(http://sqlite.org/download.html) targeting AArch64.

This commit specifically removes number of operands checks that are
redundant if the instruction's opcode already guarantees that number
of operands (or more), and also avoids any kind of checks on a def
operand of a nested instruction as everything about it was already
checked at its use.

The expected performance implication is about 3% off InstructionSelect
comparing to the baseline (before the series of patches)

This patch also contains a bit of NFC changes required for further
patches in the series.

Every commit planned shares the same Phabricator Review.

Reviewers: qcolombet, dsanders, bogner, aemerson, javed.absar

Reviewed By: qcolombet

Subscribers: rovka, llvm-commits, kristof.beyls

Differential Revision: https://reviews.llvm.org/D44700

llvm-svn: 332945
This commit is contained in:
Roman Tereshin 2018-05-22 04:31:50 +00:00
parent 4ca5af0721
commit 19da667599
2 changed files with 66 additions and 10 deletions

View File

@ -243,7 +243,7 @@ def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; }
// R19O-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SELECT,
//
// R19C-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
// R19C-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/4,
// R19N-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/4,
// R19N-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SELECT,
// R19N-NEXT: // MIs[0] dst
// R19C-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
@ -257,10 +257,10 @@ def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; }
// R19C-NEXT: // MIs[0] Operand 3
// R19C-NEXT: GIM_CheckType, /*MI*/0, /*Op*/3, /*Type*/GILLT_s32,
// R19C-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/3, // MIs[1]
// R19C-NEXT: GIM_CheckNumOperands, /*MI*/1, /*Expected*/4,
// R19N-NEXT: GIM_CheckNumOperands, /*MI*/1, /*Expected*/4,
// R19C-NEXT: GIM_CheckOpcode, /*MI*/1, TargetOpcode::G_SELECT,
// R19C-NEXT: // MIs[1] Operand 0
// R19C-NEXT: GIM_CheckType, /*MI*/1, /*Op*/0, /*Type*/GILLT_s32,
// R19N-NEXT: // MIs[1] Operand 0
// R19N-NEXT: GIM_CheckType, /*MI*/1, /*Op*/0, /*Type*/GILLT_s32,
// R19N-NEXT: // MIs[1] src3
// R19C-NEXT: GIM_CheckType, /*MI*/1, /*Op*/1, /*Type*/GILLT_s32,
// R19N-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
@ -323,7 +323,7 @@ def : Pat<(select GPR32:$src1, (complex_rr GPR32:$src2a, GPR32:$src2b),
// R21C-NEXT: // Label [[PREV_NUM]]: @[[PREV]]
// R21C-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // Rule ID 21 //
//
// R21C-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/4,
// R21N-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/4,
// R21N-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SELECT,
// R21N-NEXT: // MIs[0] dst
// R21C-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,

View File

@ -854,6 +854,7 @@ public:
LLTCodeGen getFirstConditionAsRootType();
bool hasFirstCondition() const override;
unsigned getNumOperands() const;
StringRef getOpcode() const;
// FIXME: Remove this as soon as possible
InstructionMatcher &insnmatchers_front() const { return *Matchers.front(); }
@ -1545,6 +1546,7 @@ public:
return I->TheDef->getName() == "G_CONSTANT";
}
StringRef getOpcode() const { return I->TheDef->getName(); }
unsigned getNumOperands() const { return I->Operands.size(); }
StringRef getOperandType(unsigned OpIdx) const {
@ -1555,6 +1557,32 @@ public:
DenseMap<const CodeGenInstruction *, unsigned>
InstructionOpcodeMatcher::OpcodeValues;
class InstructionNumOperandsMatcher final : public InstructionPredicateMatcher {
unsigned NumOperands = 0;
public:
InstructionNumOperandsMatcher(unsigned InsnVarID, unsigned NumOperands)
: InstructionPredicateMatcher(IPM_NumOperands, InsnVarID),
NumOperands(NumOperands) {}
static bool classof(const PredicateMatcher *P) {
return P->getKind() == IPM_NumOperands;
}
bool isIdentical(const PredicateMatcher &B) const override {
return InstructionPredicateMatcher::isIdentical(B) &&
NumOperands == cast<InstructionNumOperandsMatcher>(&B)->NumOperands;
}
void emitPredicateOpcodes(MatchTable &Table,
RuleMatcher &Rule) const override {
Table << MatchTable::Opcode("GIM_CheckNumOperands")
<< MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
<< MatchTable::Comment("Expected")
<< MatchTable::IntValue(NumOperands) << MatchTable::LineBreak;
}
};
/// Generates code to check that this instruction is a constant whose value
/// meets an immediate predicate.
///
@ -1750,6 +1778,7 @@ protected:
/// The operands to match. All rendered operands must be present even if the
/// condition is always true.
OperandVec Operands;
bool NumOperandsCheck = true;
std::string SymbolicName;
unsigned InsnVarID;
@ -1811,15 +1840,14 @@ public:
void pop_front() { Operands.erase(Operands.begin()); }
void optimize() {}
void optimize();
/// Emit MatchTable opcodes that test whether the instruction named in
/// InsnVarName matches all the predicates and all the operands.
void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule) {
Table << MatchTable::Opcode("GIM_CheckNumOperands")
<< MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
<< MatchTable::Comment("Expected")
<< MatchTable::IntValue(getNumOperands()) << MatchTable::LineBreak;
if (NumOperandsCheck)
InstructionNumOperandsMatcher(InsnVarID, getNumOperands())
.emitPredicateOpcodes(Table, Rule);
emitPredicateListOpcodes(Table, Rule);
@ -1882,8 +1910,14 @@ public:
bool isConstantInstruction() {
return getOpcodeMatcher().isConstantInstruction();
}
StringRef getOpcode() { return getOpcodeMatcher().getOpcode(); }
};
StringRef RuleMatcher::getOpcode() const {
return Matchers.front()->getOpcode();
}
unsigned RuleMatcher::getNumOperands() const {
return Matchers.front()->getNumOperands();
}
@ -1954,6 +1988,28 @@ public:
}
};
void InstructionMatcher::optimize() {
SmallVector<std::unique_ptr<PredicateMatcher>, 8> Stash;
const auto &OpcMatcher = getOpcodeMatcher();
Stash.push_back(predicates_pop_front());
if (Stash.back().get() == &OpcMatcher) {
if (NumOperandsCheck && OpcMatcher.getNumOperands() < getNumOperands())
Stash.emplace_back(
new InstructionNumOperandsMatcher(InsnVarID, getNumOperands()));
NumOperandsCheck = false;
}
if (InsnVarID > 0) {
assert(!Operands.empty() && "Nested instruction is expected to def a vreg");
for (auto &OP : Operands[0]->predicates())
OP.reset();
Operands[0]->eraseNullPredicates();
}
while (!Stash.empty())
prependPredicate(Stash.pop_back_val());
}
//===- Actions ------------------------------------------------------------===//
class OperandRenderer {
public: