[globalisel][tablegen] Add infrastructure to potentially allow BuildMIAction to choose a mutatable instruction. NFC

Prepare for multiple instruction emission by allowing BuildMIAction to
search for a suitable matcher that will support mutation.

This patch deliberately neglects to add matchers aside from the root to
preserve NFC. That said, it should be noted that until we support mutations
other than just the opcode the chances of finding a non-root instruction
for which canMutate() is true, is essentially zero. Furthermore in the
presence of multi-instruction emission the chances of finding any
instruction for which canMutate() is true is also zero. Nevertheless, we
can't continue to require that all BuildMIAction's consider the root of the match
to be recyclable due to the risk of recycling it twice in the same rule.

llvm-svn: 317022
This commit is contained in:
Daniel Sanders 2017-10-31 18:50:24 +00:00
parent a5793820fd
commit a7b7526416
1 changed files with 73 additions and 43 deletions

View File

@ -527,12 +527,19 @@ class RuleMatcher {
/// have succeeded.
std::vector<std::unique_ptr<MatchAction>> Actions;
typedef std::map<const InstructionMatcher *, unsigned>
DefinedInsnVariablesMap;
using DefinedInsnVariablesMap =
std::map<const InstructionMatcher *, unsigned>;
/// A map of instruction matchers to the local variables created by
/// emitCaptureOpcodes().
DefinedInsnVariablesMap InsnVariableIDs;
using MutatableInsnSet = SmallPtrSet<const InstructionMatcher *, 4>;
// The set of instruction matchers that have not yet been claimed for mutation
// by a BuildMI.
MutatableInsnSet MutatableInsns;
/// A map of named operands defined by the matchers that may be referenced by
/// the renderers.
StringMap<OperandMatcher *> DefinedOperands;
@ -553,8 +560,9 @@ class RuleMatcher {
public:
RuleMatcher(ArrayRef<SMLoc> SrcLoc)
: Matchers(), Actions(), InsnVariableIDs(), DefinedOperands(),
NextInsnVarID(0), SrcLoc(SrcLoc), ComplexSubOperands() {}
: Matchers(), Actions(), InsnVariableIDs(), MutatableInsns(),
DefinedOperands(), NextInsnVarID(0), SrcLoc(SrcLoc),
ComplexSubOperands() {}
RuleMatcher(RuleMatcher &&Other) = default;
RuleMatcher &operator=(RuleMatcher &&Other) = default;
@ -582,6 +590,22 @@ public:
return make_range(defined_insn_vars_begin(), defined_insn_vars_end());
}
MutatableInsnSet::const_iterator mutatable_insns_begin() const {
return MutatableInsns.begin();
}
MutatableInsnSet::const_iterator mutatable_insns_end() const {
return MutatableInsns.end();
}
iterator_range<typename MutatableInsnSet::const_iterator>
mutatable_insns() const {
return make_range(mutatable_insns_begin(), mutatable_insns_end());
}
void reserveInsnMatcherForMutation(const InstructionMatcher *InsnMatcher) {
bool R = MutatableInsns.erase(InsnMatcher);
assert(R && "Reserving a mutatable insn that isn't available");
(void)R;
}
void defineOperand(StringRef SymbolicName, OperandMatcher &OM);
void defineComplexSubOperand(StringRef SymbolicName, Record *ComplexPattern,
@ -1723,12 +1747,8 @@ public:
virtual ~MatchAction() {}
/// Emit the MatchTable opcodes to implement the action.
///
/// \param RecycleInsnID If given, it's an instruction to recycle. The
/// requirements on the instruction vary from action to
/// action.
virtual void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule,
unsigned RecycleInsnID) const = 0;
virtual void emitActionOpcodes(MatchTable &Table,
RuleMatcher &Rule) const = 0;
};
/// Generates a comment describing the matched rule being acted upon.
@ -1739,8 +1759,7 @@ private:
public:
DebugCommentAction(StringRef S) : S(S) {}
void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule,
unsigned RecycleInsnID) const override {
void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
Table << MatchTable::Comment(S) << MatchTable::LineBreak;
}
};
@ -1755,17 +1774,17 @@ private:
std::vector<std::unique_ptr<OperandRenderer>> OperandRenderers;
/// True if the instruction can be built solely by mutating the opcode.
bool canMutate(RuleMatcher &Rule) const {
if (!Matched)
bool canMutate(RuleMatcher &Rule, const InstructionMatcher *Insn) const {
if (!Insn)
return false;
if (OperandRenderers.size() != Matched->getNumOperands())
if (OperandRenderers.size() != Insn->getNumOperands())
return false;
for (const auto &Renderer : enumerate(OperandRenderers)) {
if (const auto *Copy = dyn_cast<CopyRenderer>(&*Renderer.value())) {
const OperandMatcher &OM = Rule.getOperandMatcher(Copy->getSymbolicName());
if (Matched != &OM.getInstructionMatcher() ||
if (Insn != &OM.getInstructionMatcher() ||
OM.getOperandIndex() != Renderer.index())
return false;
} else
@ -1776,9 +1795,19 @@ private:
}
public:
BuildMIAction(unsigned InsnID, const CodeGenInstruction *I,
const InstructionMatcher *Matched)
: InsnID(InsnID), I(I), Matched(Matched) {}
BuildMIAction(unsigned InsnID, const CodeGenInstruction *I)
: InsnID(InsnID), I(I), Matched(nullptr) {}
void chooseInsnToMutate(RuleMatcher &Rule) {
for (const auto *MutateCandidate : Rule.mutatable_insns()) {
if (canMutate(Rule, MutateCandidate)) {
// Take the first one we're offered that we're able to mutate.
Rule.reserveInsnMatcherForMutation(MutateCandidate);
Matched = MutateCandidate;
return;
}
}
}
template <class Kind, class... Args>
Kind &addRenderer(Args&&... args) {
@ -1787,9 +1816,12 @@ public:
return *static_cast<Kind *>(OperandRenderers.back().get());
}
void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule,
unsigned RecycleInsnID) const override {
if (canMutate(Rule)) {
void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
if (Matched) {
assert(canMutate(Rule, Matched) &&
"Arranged to mutate an insn that isn't mutatable");
unsigned RecycleInsnID = Rule.getInsnVarID(*Matched);
Table << MatchTable::Opcode("GIR_MutateOpcode")
<< MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
<< MatchTable::Comment("RecycleInsnID")
@ -1853,8 +1885,8 @@ public:
}
Table << MatchTable::Opcode("GIR_EraseFromParent")
<< MatchTable::Comment("InsnID")
<< MatchTable::IntValue(RecycleInsnID) << MatchTable::LineBreak;
<< MatchTable::Comment("InsnID") << MatchTable::IntValue(0)
<< MatchTable::LineBreak;
}
};
@ -1866,8 +1898,7 @@ class ConstrainOperandsToDefinitionAction : public MatchAction {
public:
ConstrainOperandsToDefinitionAction(unsigned InsnID) : InsnID(InsnID) {}
void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule,
unsigned RecycleInsnID) const override {
void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
Table << MatchTable::Opcode("GIR_ConstrainSelectedInstOperands")
<< MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
<< MatchTable::LineBreak;
@ -1886,8 +1917,7 @@ public:
const CodeGenRegisterClass &RC)
: InsnID(InsnID), OpIdx(OpIdx), RC(RC) {}
void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule,
unsigned RecycleInsnID) const override {
void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
Table << MatchTable::Opcode("GIR_ConstrainOperandRC")
<< MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
<< MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx)
@ -1898,6 +1928,7 @@ public:
InstructionMatcher &RuleMatcher::addInstructionMatcher(StringRef SymbolicName) {
Matchers.emplace_back(new InstructionMatcher(*this, SymbolicName));
MutatableInsns.insert(Matchers.back().get());
return *Matchers.back();
}
@ -2069,7 +2100,7 @@ void RuleMatcher::emit(MatchTable &Table) {
}
for (const auto &MA : Actions)
MA->emitActionOpcodes(Table, *this, 0);
MA->emitActionOpcodes(Table, *this);
Table << MatchTable::Opcode("GIR_Done", -1) << MatchTable::LineBreak
<< MatchTable::Label(LabelID);
}
@ -2189,12 +2220,11 @@ private:
bool OperandIsAPointer, unsigned OpIdx,
unsigned &TempOpIdx) const;
Expected<BuildMIAction &>
createAndImportInstructionRenderer(RuleMatcher &M, const TreePatternNode *Dst,
const InstructionMatcher &InsnMatcher);
createAndImportInstructionRenderer(RuleMatcher &M,
const TreePatternNode *Dst);
Error importExplicitUseRenderer(RuleMatcher &Rule,
BuildMIAction &DstMIBuilder,
TreePatternNode *DstChild,
const InstructionMatcher &InsnMatcher) const;
TreePatternNode *DstChild) const;
Error importDefaultOperandRenderers(BuildMIAction &DstMIBuilder,
DagInit *DefaultOps) const;
Error
@ -2525,8 +2555,8 @@ Error GlobalISelEmitter::importChildMatcher(RuleMatcher &Rule,
}
Error GlobalISelEmitter::importExplicitUseRenderer(
RuleMatcher &Rule, BuildMIAction &DstMIBuilder, TreePatternNode *DstChild,
const InstructionMatcher &InsnMatcher) const {
RuleMatcher &Rule, BuildMIAction &DstMIBuilder,
TreePatternNode *DstChild) const {
if (DstChild->getTransformFn() != nullptr) {
return failedImport("Dst pattern child has transform fn " +
DstChild->getTransformFn()->getName());
@ -2626,8 +2656,7 @@ Error GlobalISelEmitter::importExplicitUseRenderer(
}
Expected<BuildMIAction &> GlobalISelEmitter::createAndImportInstructionRenderer(
RuleMatcher &M, const TreePatternNode *Dst,
const InstructionMatcher &InsnMatcher) {
RuleMatcher &M, const TreePatternNode *Dst) {
Record *DstOp = Dst->getOperator();
if (!DstOp->isSubClassOf("Instruction")) {
if (DstOp->isSubClassOf("ValueType"))
@ -2652,7 +2681,7 @@ Expected<BuildMIAction &> GlobalISelEmitter::createAndImportInstructionRenderer(
IsExtractSubReg = true;
}
auto &DstMIBuilder = M.addAction<BuildMIAction>(0, DstI, &InsnMatcher);
auto &DstMIBuilder = M.addAction<BuildMIAction>(0, DstI);
// Render the explicit defs.
for (unsigned I = 0; I < DstI->Operands.NumDefs; ++I) {
@ -2707,8 +2736,8 @@ Expected<BuildMIAction &> GlobalISelEmitter::createAndImportInstructionRenderer(
continue;
}
if (auto Error = importExplicitUseRenderer(
M, DstMIBuilder, Dst->getChild(Child), InsnMatcher))
if (auto Error =
importExplicitUseRenderer(M, DstMIBuilder, Dst->getChild(Child)))
return std::move(Error);
++Child;
}
@ -2805,7 +2834,7 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
M.defineOperand(OM0.getSymbolicName(), OM0);
OM0.addPredicate<RegisterBankOperandMatcher>(RC);
auto &DstMIBuilder = M.addAction<BuildMIAction>(0, &DstI, &InsnMatcher);
auto &DstMIBuilder = M.addAction<BuildMIAction>(0, &DstI);
DstMIBuilder.addRenderer<CopyRenderer>(0, DstIOperand.Name);
DstMIBuilder.addRenderer<CopyRenderer>(0, Dst->getName());
M.addAction<ConstrainOperandToRegClassAction>(0, 0, RC);
@ -2869,8 +2898,7 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
++OpIdx;
}
auto DstMIBuilderOrError =
createAndImportInstructionRenderer(M, Dst, InsnMatcher);
auto DstMIBuilderOrError = createAndImportInstructionRenderer(M, Dst);
if (auto Error = DstMIBuilderOrError.takeError())
return std::move(Error);
BuildMIAction &DstMIBuilder = DstMIBuilderOrError.get();
@ -2880,6 +2908,8 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
if (auto Error = importImplicitDefRenderers(DstMIBuilder, P.getDstRegs()))
return std::move(Error);
DstMIBuilder.chooseInsnToMutate(M);
// Constrain the registers to classes. This is normally derived from the
// emitted instruction but a few instructions require special handling.
if (DstI.TheDef->getName() == "COPY_TO_REGCLASS") {