[PATCH] D36094: [globalisel][tablegen] Do not merge memoperands from instructions that weren't in the match.

Daniel Sanders via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 31 09:56:24 PDT 2017


dsanders created this revision.
Herald added subscribers: igorb, kristof.beyls.

Fix a bug discovered in an out-of-tree target where memoperands from
pseudo-instructions that weren't part of the match were being merged into the
result instructions as part of GIR_MergeMemOperands.

This bug was caused by a change to the handling of State.MIs between rules when
the state machine tables were fused into a single table. Previously, each rule
would reset State.MIs using State.MIs.resize(1) but this is no longer done, as a
result stale data is occasionally left in some elements of State.MIs. Most
opcodes aren't affected by this but GIR_MergeMemOperands merges all memoperands
from the intructions recorded in State.MIs into the result instruction.

Suppose for example, we processed but rejected the following pattern:

  (signextend (load x))

at this point, State.MIs contains the signextend and the load. Now suppose we
process and accept this pattern:

  (add x, y)

at this point, State.MIs contains the add as well as the (now irrelevant) load.
When GIR_MergeMemOperands is processed, the memoperands from that irrelevant
load will be merged into the result instruction even though it was not part of
the match.

Bringing back the State.MIs.resize(1) would fix the problem but it would limit
our ability to optimize the table in the future. Instead, this patch fixes the
problem by explicitly stating which instructions should be merged into the result.

I'm not sure this is possible to test in the upstream targets since most ways to
trigger the bug involve load/store which is not importable yet. Even when they
are importable, a test case would be brittle since it would require knowledge of
the rejected matches leading up to the successful one.


https://reviews.llvm.org/D36094

Files:
  include/llvm/CodeGen/GlobalISel/InstructionSelector.h
  include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h
  utils/TableGen/GlobalISelEmitter.cpp


Index: utils/TableGen/GlobalISelEmitter.cpp
===================================================================
--- utils/TableGen/GlobalISelEmitter.cpp
+++ utils/TableGen/GlobalISelEmitter.cpp
@@ -460,9 +460,11 @@
   /// have succeeded.
   std::vector<std::unique_ptr<MatchAction>> Actions;
 
+  typedef std::map<const InstructionMatcher *, unsigned>
+      DefinedInsnVariablesMap;
   /// A map of instruction matchers to the local variables created by
   /// emitCaptureOpcodes().
-  std::map<const InstructionMatcher *, unsigned> 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<typename DefinedInsnVariablesMap::const_iterator>
+  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;
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: 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


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D36094.108943.patch
Type: text/x-patch
Size: 4241 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20170731/a09b3d21/attachment.bin>


More information about the llvm-commits mailing list