Index: include/llvm/CodeGen/GlobalISel/InstructionSelector.h =================================================================== --- include/llvm/CodeGen/GlobalISel/InstructionSelector.h +++ include/llvm/CodeGen/GlobalISel/InstructionSelector.h @@ -195,6 +195,8 @@ GIR_ConstrainSelectedInstOperands, /// Merge all memory operands into instruction. /// - InsnID - Instruction ID to modify + /// - MergeInsnID... - One or more Instruction ID to merge into the result. + /// - -1 - Terminates the list of instructions to merge. GIR_MergeMemOperands, /// Erase from parent. /// - InsnID - Instruction ID to erase Index: include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h =================================================================== --- include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h +++ include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h @@ -370,11 +370,16 @@ case GIR_MergeMemOperands: { int64_t InsnID = MatchTable[CurrentIdx++]; assert(OutMIs[InsnID] && "Attempted to add to undefined instruction"); - for (const auto *FromMI : State.MIs) - for (const auto &MMO : FromMI->memoperands()) - OutMIs[InsnID].addMemOperand(MMO); + DEBUG(dbgs() << CurrentIdx << ": GIR_MergeMemOperands(OutMIs[" << InsnID - << "])\n"); + << "]"); + int64_t MergeInsnID = -1; + while ((MergeInsnID = MatchTable[CurrentIdx++]) != -1) { + DEBUG(dbgs() << ", MIs[" << MergeInsnID << "]"); + for (const auto &MMO : State.MIs[MergeInsnID]->memoperands()) + OutMIs[InsnID].addMemOperand(MMO); + } + DEBUG(dbgs() << ")\n"); break; } case GIR_EraseFromParent: { Index: utils/TableGen/GlobalISelEmitter.cpp =================================================================== --- utils/TableGen/GlobalISelEmitter.cpp +++ utils/TableGen/GlobalISelEmitter.cpp @@ -460,9 +460,11 @@ /// have succeeded. std::vector> Actions; + typedef std::map + DefinedInsnVariablesMap; /// A map of instruction matchers to the local variables created by /// emitCaptureOpcodes(). - std::map InsnVariableIDs; + DefinedInsnVariablesMap InsnVariableIDs; /// ID for the next instruction variable defined with defineInsnVar() unsigned NextInsnVarID; @@ -488,6 +490,16 @@ unsigned defineInsnVar(MatchTable &Table, const InstructionMatcher &Matcher, unsigned InsnVarID, unsigned OpIdx); unsigned getInsnVarID(const InstructionMatcher &InsnMatcher) const; + DefinedInsnVariablesMap::const_iterator defined_insn_vars_begin() const { + return InsnVariableIDs.begin(); + } + DefinedInsnVariablesMap::const_iterator defined_insn_vars_end() const { + return InsnVariableIDs.end(); + } + iterator_range + defined_insn_vars() const { + return make_range(defined_insn_vars_begin(), defined_insn_vars_end()); + } void emitCaptureOpcodes(MatchTable &Table); @@ -1452,6 +1464,17 @@ Table << MatchTable::Opcode("GIR_MergeMemOperands") << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID) + << MatchTable::Comment("MergeInsnID's"); + // Emit the ID's for all the instructions that are matched by this rule. + // TODO: Limit this to matched instructions that mayLoad/mayStore or have + // some other means of having a memoperand. Also limit this to emitted + // instructions that expect to have a memoperand too. For example, + // (G_SEXT (G_LOAD x)) that results in separate load and sign-extend + // instructions shouldn't put the memoperand on the sign-extend since + // it has no effect there. + for (const auto &IDMatcherPair : Rule.defined_insn_vars()) + Table << MatchTable::IntValue(IDMatcherPair.second); + Table << MatchTable::Comment("EOL") << MatchTable::IntValue(-1) << MatchTable::LineBreak << MatchTable::Opcode("GIR_EraseFromParent") << MatchTable::Comment("InsnID") << MatchTable::IntValue(RecycleInsnID) << MatchTable::LineBreak;