[GlobalISel] Improving InstructionSelect's performance by reducing MatchTable, mostly NFC, perf patch 1

This patch starts 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.

The performance improvements are achieved solely by reducing the
number of matching GIM_* opcodes executed by the MatchTable's
interpreter during the selection by approx. a factor of 30, which also
brings contribution of this particular part of the selection process
to the overall runtime of InstructionSelect pass down from approx.
60-70% to 5-7%, thus making further improvements in this particular
direction not very profitable.

The improvements described above are expected for any target that
doesn't have many complex patterns. The targets that do should
strictly benefit from the changes, but by how much exactly is hard to
estimate beforehand. It's also likely that such target WILL benefit
from further improvements to MatchTable, most likely the ones that
bring it closer to a perfect decision tree.

This commit specifically is rather large mostly NFC commit that does
necessary preparation work and refactoring, there will be a following
series of small patches introducing a specific optimization each
shortly after.

This commit specifically is expected to cause a small compile time
regression (around 2.5% of InstructionSelect pass time), which should
be fixed by the next commit of 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: 332907
This commit is contained in:
Roman Tereshin 2018-05-21 22:04:39 +00:00
parent 0322e3cbf5
commit f0dc9fa934
4 changed files with 1257 additions and 1055 deletions

View File

@ -20,6 +20,7 @@
#include "llvm/ADT/Optional.h" #include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallVector.h"
#include "llvm/Support/CodeGenCoverage.h" #include "llvm/Support/CodeGenCoverage.h"
#include "llvm/Support/LowLevelTypeImpl.h"
#include <bitset> #include <bitset>
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
@ -31,7 +32,6 @@ namespace llvm {
class APInt; class APInt;
class APFloat; class APFloat;
class LLT;
class MachineInstr; class MachineInstr;
class MachineInstrBuilder; class MachineInstrBuilder;
class MachineFunction; class MachineFunction;
@ -146,12 +146,14 @@ enum {
/// - OpIdx - Operand index /// - OpIdx - Operand index
/// - Expected register bank (specified as a register class) /// - Expected register bank (specified as a register class)
GIM_CheckRegBankForClass, GIM_CheckRegBankForClass,
/// Check the operand matches a complex predicate /// Check the operand matches a complex predicate
/// - InsnID - Instruction ID /// - InsnID - Instruction ID
/// - OpIdx - Operand index /// - OpIdx - Operand index
/// - RendererID - The renderer to hold the result /// - RendererID - The renderer to hold the result
/// - Complex predicate ID /// - Complex predicate ID
GIM_CheckComplexPattern, GIM_CheckComplexPattern,
/// Check the operand is a specific integer /// Check the operand is a specific integer
/// - InsnID - Instruction ID /// - InsnID - Instruction ID
/// - OpIdx - Operand index /// - OpIdx - Operand index
@ -168,6 +170,7 @@ enum {
/// - OpIdx - Operand index /// - OpIdx - Operand index
/// - Expected Intrinsic ID /// - Expected Intrinsic ID
GIM_CheckIntrinsicID, GIM_CheckIntrinsicID,
/// Check the specified operand is an MBB /// Check the specified operand is an MBB
/// - InsnID - Instruction ID /// - InsnID - Instruction ID
/// - OpIdx - Operand index /// - OpIdx - Operand index
@ -196,6 +199,7 @@ enum {
/// - OldInsnID - Instruction ID to mutate /// - OldInsnID - Instruction ID to mutate
/// - NewOpcode - The new opcode to use /// - NewOpcode - The new opcode to use
GIR_MutateOpcode, GIR_MutateOpcode,
/// Build a new instruction /// Build a new instruction
/// - InsnID - Instruction ID to define /// - InsnID - Instruction ID to define
/// - Opcode - The new opcode to use /// - Opcode - The new opcode to use
@ -206,6 +210,7 @@ enum {
/// - OldInsnID - Instruction ID to copy from /// - OldInsnID - Instruction ID to copy from
/// - OpIdx - The operand to copy /// - OpIdx - The operand to copy
GIR_Copy, GIR_Copy,
/// Copy an operand to the specified instruction or add a zero register if the /// Copy an operand to the specified instruction or add a zero register if the
/// operand is a zero immediate. /// operand is a zero immediate.
/// - NewInsnID - Instruction ID to modify /// - NewInsnID - Instruction ID to modify
@ -219,6 +224,7 @@ enum {
/// - OpIdx - The operand to copy /// - OpIdx - The operand to copy
/// - SubRegIdx - The subregister to copy /// - SubRegIdx - The subregister to copy
GIR_CopySubReg, GIR_CopySubReg,
/// Add an implicit register def to the specified instruction /// Add an implicit register def to the specified instruction
/// - InsnID - Instruction ID to modify /// - InsnID - Instruction ID to modify
/// - RegNum - The register to add /// - RegNum - The register to add
@ -231,11 +237,13 @@ enum {
/// - InsnID - Instruction ID to modify /// - InsnID - Instruction ID to modify
/// - RegNum - The register to add /// - RegNum - The register to add
GIR_AddRegister, GIR_AddRegister,
/// Add a temporary register to the specified instruction /// Add a temporary register to the specified instruction
/// - InsnID - Instruction ID to modify /// - InsnID - Instruction ID to modify
/// - TempRegID - The temporary register ID to add /// - TempRegID - The temporary register ID to add
/// - TempRegFlags - The register flags to set /// - TempRegFlags - The register flags to set
GIR_AddTempRegister, GIR_AddTempRegister,
/// Add an immediate to the specified instruction /// Add an immediate to the specified instruction
/// - InsnID - Instruction ID to modify /// - InsnID - Instruction ID to modify
/// - Imm - The immediate to add /// - Imm - The immediate to add
@ -244,6 +252,7 @@ enum {
/// - InsnID - Instruction ID to modify /// - InsnID - Instruction ID to modify
/// - RendererID - The renderer to call /// - RendererID - The renderer to call
GIR_ComplexRenderer, GIR_ComplexRenderer,
/// Render sub-operands of complex operands to the specified instruction /// Render sub-operands of complex operands to the specified instruction
/// - InsnID - Instruction ID to modify /// - InsnID - Instruction ID to modify
/// - RendererID - The renderer to call /// - RendererID - The renderer to call
@ -272,19 +281,23 @@ enum {
/// - OpIdx - Operand index /// - OpIdx - Operand index
/// - RCEnum - Register class enumeration value /// - RCEnum - Register class enumeration value
GIR_ConstrainOperandRC, GIR_ConstrainOperandRC,
/// Constrain an instructions operands according to the instruction /// Constrain an instructions operands according to the instruction
/// description. /// description.
/// - InsnID - Instruction ID to modify /// - InsnID - Instruction ID to modify
GIR_ConstrainSelectedInstOperands, GIR_ConstrainSelectedInstOperands,
/// Merge all memory operands into instruction. /// Merge all memory operands into instruction.
/// - InsnID - Instruction ID to modify /// - InsnID - Instruction ID to modify
/// - MergeInsnID... - One or more Instruction ID to merge into the result. /// - MergeInsnID... - One or more Instruction ID to merge into the result.
/// - GIU_MergeMemOperands_EndOfList - Terminates the list of instructions to /// - GIU_MergeMemOperands_EndOfList - Terminates the list of instructions to
/// merge. /// merge.
GIR_MergeMemOperands, GIR_MergeMemOperands,
/// Erase from parent. /// Erase from parent.
/// - InsnID - Instruction ID to erase /// - InsnID - Instruction ID to erase
GIR_EraseFromParent, GIR_EraseFromParent,
/// Create a new temporary register that's not constrained. /// Create a new temporary register that's not constrained.
/// - TempRegID - The temporary register ID to initialize. /// - TempRegID - The temporary register ID to initialize.
/// - Expected type /// - Expected type
@ -297,6 +310,7 @@ enum {
/// - RuleID - The ID of the rule that was covered. /// - RuleID - The ID of the rule that was covered.
GIR_Coverage, GIR_Coverage,
/// Keeping track of the number of the GI opcodes. Must be the last entry.
GIU_NumOpcodes, GIU_NumOpcodes,
}; };
@ -341,6 +355,15 @@ public:
template <class PredicateBitset, class ComplexMatcherMemFn, template <class PredicateBitset, class ComplexMatcherMemFn,
class CustomRendererFn> class CustomRendererFn>
struct ISelInfoTy { struct ISelInfoTy {
ISelInfoTy(const LLT *TypeObjects, size_t NumTypeObjects,
const PredicateBitset *FeatureBitsets,
const ComplexMatcherMemFn *ComplexPredicates,
const CustomRendererFn *CustomRenderers)
: TypeObjects(TypeObjects),
FeatureBitsets(FeatureBitsets),
ComplexPredicates(ComplexPredicates),
CustomRenderers(CustomRenderers) {
}
const LLT *TypeObjects; const LLT *TypeObjects;
const PredicateBitset *FeatureBitsets; const PredicateBitset *FeatureBitsets;
const ComplexMatcherMemFn *ComplexPredicates; const ComplexMatcherMemFn *ComplexPredicates;

View File

@ -53,8 +53,9 @@ bool InstructionSelector::executeMatchTable(
MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
const RegisterBankInfo &RBI, const PredicateBitset &AvailableFeatures, const RegisterBankInfo &RBI, const PredicateBitset &AvailableFeatures,
CodeGenCoverage &CoverageInfo) const { CodeGenCoverage &CoverageInfo) const {
uint64_t CurrentIdx = 0; uint64_t CurrentIdx = 0;
SmallVector<uint64_t, 8> OnFailResumeAt; SmallVector<uint64_t, 4> OnFailResumeAt;
enum RejectAction { RejectAndGiveUp, RejectAndResume }; enum RejectAction { RejectAndGiveUp, RejectAndResume };
auto handleReject = [&]() -> RejectAction { auto handleReject = [&]() -> RejectAction {
@ -62,8 +63,7 @@ bool InstructionSelector::executeMatchTable(
dbgs() << CurrentIdx << ": Rejected\n"); dbgs() << CurrentIdx << ": Rejected\n");
if (OnFailResumeAt.empty()) if (OnFailResumeAt.empty())
return RejectAndGiveUp; return RejectAndGiveUp;
CurrentIdx = OnFailResumeAt.back(); CurrentIdx = OnFailResumeAt.pop_back_val();
OnFailResumeAt.pop_back();
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(), DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
dbgs() << CurrentIdx << ": Resume at " << CurrentIdx << " (" dbgs() << CurrentIdx << ": Resume at " << CurrentIdx << " ("
<< OnFailResumeAt.size() << " try-blocks remain)\n"); << OnFailResumeAt.size() << " try-blocks remain)\n");
@ -139,12 +139,13 @@ bool InstructionSelector::executeMatchTable(
int64_t InsnID = MatchTable[CurrentIdx++]; int64_t InsnID = MatchTable[CurrentIdx++];
int64_t Expected = MatchTable[CurrentIdx++]; int64_t Expected = MatchTable[CurrentIdx++];
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
unsigned Opcode = State.MIs[InsnID]->getOpcode(); unsigned Opcode = State.MIs[InsnID]->getOpcode();
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(), DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
dbgs() << CurrentIdx << ": GIM_CheckOpcode(MIs[" << InsnID dbgs() << CurrentIdx << ": GIM_CheckOpcode(MIs[" << InsnID
<< "], ExpectedOpcode=" << Expected << "], ExpectedOpcode=" << Expected
<< ") // Got=" << Opcode << "\n"); << ") // Got=" << Opcode << "\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
if (Opcode != Expected) { if (Opcode != Expected) {
if (handleReject() == RejectAndGiveUp) if (handleReject() == RejectAndGiveUp)
return false; return false;
@ -197,7 +198,8 @@ bool InstructionSelector::executeMatchTable(
<< CurrentIdx << ": GIM_CheckAPIntImmPredicate(MIs[" << CurrentIdx << ": GIM_CheckAPIntImmPredicate(MIs["
<< InsnID << "], Predicate=" << Predicate << ")\n"); << InsnID << "], Predicate=" << Predicate << ")\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined"); assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
assert(State.MIs[InsnID]->getOpcode() && "Expected G_CONSTANT"); assert(State.MIs[InsnID]->getOpcode() == TargetOpcode::G_CONSTANT &&
"Expected G_CONSTANT");
assert(Predicate > GIPFP_APInt_Invalid && "Expected a valid predicate"); assert(Predicate > GIPFP_APInt_Invalid && "Expected a valid predicate");
APInt Value; APInt Value;
if (State.MIs[InsnID]->getOperand(1).isCImm()) if (State.MIs[InsnID]->getOperand(1).isCImm())
@ -236,7 +238,6 @@ bool InstructionSelector::executeMatchTable(
dbgs() << CurrentIdx << ": GIM_CheckAtomicOrdering(MIs[" dbgs() << CurrentIdx << ": GIM_CheckAtomicOrdering(MIs["
<< InsnID << "], " << (uint64_t)Ordering << ")\n"); << InsnID << "], " << (uint64_t)Ordering << ")\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined"); assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
if (!State.MIs[InsnID]->hasOneMemOperand()) if (!State.MIs[InsnID]->hasOneMemOperand())
if (handleReject() == RejectAndGiveUp) if (handleReject() == RejectAndGiveUp)
return false; return false;
@ -255,7 +256,6 @@ bool InstructionSelector::executeMatchTable(
<< ": GIM_CheckAtomicOrderingOrStrongerThan(MIs[" << ": GIM_CheckAtomicOrderingOrStrongerThan(MIs["
<< InsnID << "], " << (uint64_t)Ordering << ")\n"); << InsnID << "], " << (uint64_t)Ordering << ")\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined"); assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
if (!State.MIs[InsnID]->hasOneMemOperand()) if (!State.MIs[InsnID]->hasOneMemOperand())
if (handleReject() == RejectAndGiveUp) if (handleReject() == RejectAndGiveUp)
return false; return false;
@ -274,7 +274,6 @@ bool InstructionSelector::executeMatchTable(
<< ": GIM_CheckAtomicOrderingWeakerThan(MIs[" << ": GIM_CheckAtomicOrderingWeakerThan(MIs["
<< InsnID << "], " << (uint64_t)Ordering << ")\n"); << InsnID << "], " << (uint64_t)Ordering << ")\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined"); assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
if (!State.MIs[InsnID]->hasOneMemOperand()) if (!State.MIs[InsnID]->hasOneMemOperand())
if (handleReject() == RejectAndGiveUp) if (handleReject() == RejectAndGiveUp)
return false; return false;
@ -375,7 +374,6 @@ bool InstructionSelector::executeMatchTable(
<< "]->getOperand(" << OpIdx << "]->getOperand(" << OpIdx
<< "), TypeID=" << TypeID << ")\n"); << "), TypeID=" << TypeID << ")\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined"); assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
MachineOperand &MO = State.MIs[InsnID]->getOperand(OpIdx); MachineOperand &MO = State.MIs[InsnID]->getOperand(OpIdx);
if (!MO.isReg() || if (!MO.isReg() ||
MRI.getType(MO.getReg()) != ISelInfo.TypeObjects[TypeID]) { MRI.getType(MO.getReg()) != ISelInfo.TypeObjects[TypeID]) {
@ -394,7 +392,6 @@ bool InstructionSelector::executeMatchTable(
<< InsnID << "]->getOperand(" << OpIdx << InsnID << "]->getOperand(" << OpIdx
<< "), SizeInBits=" << SizeInBits << ")\n"); << "), SizeInBits=" << SizeInBits << ")\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined"); assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
// iPTR must be looked up in the target. // iPTR must be looked up in the target.
if (SizeInBits == 0) { if (SizeInBits == 0) {
MachineFunction *MF = State.MIs[InsnID]->getParent()->getParent(); MachineFunction *MF = State.MIs[InsnID]->getParent()->getParent();
@ -466,7 +463,6 @@ bool InstructionSelector::executeMatchTable(
<< InsnID << "]->getOperand(" << OpIdx << InsnID << "]->getOperand(" << OpIdx
<< "), Value=" << Value << ")\n"); << "), Value=" << Value << ")\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined"); assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
MachineOperand &MO = State.MIs[InsnID]->getOperand(OpIdx); MachineOperand &MO = State.MIs[InsnID]->getOperand(OpIdx);
if (MO.isReg()) { if (MO.isReg()) {
// isOperandImmEqual() will sign-extend to 64-bits, so should we. // isOperandImmEqual() will sign-extend to 64-bits, so should we.
@ -562,7 +558,7 @@ bool InstructionSelector::executeMatchTable(
} }
case GIM_Reject: case GIM_Reject:
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(), DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
dbgs() << CurrentIdx << ": GIM_Reject"); dbgs() << CurrentIdx << ": GIM_Reject\n");
if (handleReject() == RejectAndGiveUp) if (handleReject() == RejectAndGiveUp)
return false; return false;
break; break;
@ -854,7 +850,7 @@ bool InstructionSelector::executeMatchTable(
case GIR_Done: case GIR_Done:
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(), DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
dbgs() << CurrentIdx << ": GIR_Done"); dbgs() << CurrentIdx << ": GIR_Done\n");
return true; return true;
default: default:

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff