forked from OSchip/llvm-project
[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:
parent
4ca5af0721
commit
19da667599
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue