Fix PR1975: dag isel emitter produces patterns that isel wrong flag result.
[oota-llvm.git] / utils / TableGen / DAGISelEmitter.cpp
index 1f568ad5ee6738522a14f9be42ae6f81b2a7ea3b..7a1920ceac7b2e11bbcdf4fbbe51075ec3481ed7 100644 (file)
@@ -305,18 +305,14 @@ private:
   std::map<std::string, std::string> VariableMap;
   // Node to operator mapping
   std::map<std::string, Record*> OperatorMap;
+  // Name of the folded node which produces a flag.
+  std::pair<std::string, unsigned> FoldedFlag;
   // Names of all the folded nodes which produce chains.
   std::vector<std::pair<std::string, unsigned> > FoldedChains;
   // Original input chain(s).
   std::vector<std::pair<std::string, std::string> > OrigChains;
   std::set<std::string> Duplicates;
 
-  /// LSI - Load/Store information.
-  /// Save loads/stores matched by a pattern, and generate a MemOperandSDNode
-  /// for each memory access. This facilitates the use of AliasAnalysis in
-  /// the backend.
-  std::vector<std::string> LSI;
-
   /// GeneratedCode - This is the buffer that we emit code to.  The first int
   /// indicates whether this is an exit predicate (something that should be
   /// tested, and if true, the match fails) [when 1], or normal code to emit
@@ -377,15 +373,6 @@ public:
   void EmitMatchCode(TreePatternNode *N, TreePatternNode *P,
                      const std::string &RootName, const std::string &ChainSuffix,
                      bool &FoundChain) {
-
-    // Save loads/stores matched by a pattern.
-    if (!N->isLeaf() && N->getName().empty() &&
-        ((N->getOperator()->getName() == "ld") ||
-          (N->getOperator()->getName() == "st") ||
-          (N->getOperator()->getName() == "ist"))) {
-      LSI.push_back(RootName);
-    }
-
     bool isRoot = (P == NULL);
     // Emit instruction predicates. Each predicate is just a string for now.
     if (isRoot) {
@@ -602,8 +589,17 @@ public:
       emitCheck(RootName + ".getOpcode() == " +
                 CInfo.getEnumName());
       EmitMatchCode(Child, Parent, RootName, ChainSuffix, FoundChain);
-      if (NodeHasProperty(Child, SDNPHasChain, CGP))
+      bool HasChain = false;
+      if (NodeHasProperty(Child, SDNPHasChain, CGP)) {
+        HasChain = true;
         FoldedChains.push_back(std::make_pair(RootName, CInfo.getNumResults()));
+      }
+      if (NodeHasProperty(Child, SDNPOutFlag, CGP)) {
+        assert(FoldedFlag.first == "" && FoldedFlag.second == 0 &&
+               "Pattern folded multiple nodes which produce flags?");
+        FoldedFlag = std::make_pair(RootName,
+                                    CInfo.getNumResults() + (unsigned)HasChain);
+      }
     } else {
       // If this child has a name associated with it, capture it in VarMap. If
       // we already saw this in the pattern, emit code to verify dagness.
@@ -948,18 +944,6 @@ public:
         }
       }
 
-      // Generate MemOperandSDNodes nodes for each memory accesses covered by this
-      // pattern.
-      if (isRoot) {
-        std::vector<std::string>::const_iterator mi, mie;
-        for (mi = LSI.begin(), mie = LSI.end(); mi != mie; ++mi) {
-          emitCode("SDOperand LSI_" + *mi + " = "
-                   "CurDAG->getMemOperand(cast<LSBaseSDNode>(" +
-                   *mi + ")->getMemOperand());");
-          AllOps.push_back("LSI_" + *mi);
-        }
-      }
-
       // Emit all the chain and CopyToReg stuff.
       bool ChainEmitted = NodeHasChain;
       if (NodeHasChain)
@@ -1132,9 +1116,15 @@ public:
         }
 
         if (NodeHasOutFlag) {
-          emitCode("ReplaceUses(SDOperand(N.Val, " +
-                   utostr(NumPatResults + (unsigned)InputHasChain)
-                   +"), InFlag);");
+          if (FoldedFlag.first != "") {
+            emitCode("ReplaceUses(SDOperand(" + FoldedFlag.first + ".Val, " +
+                     utostr(FoldedFlag.second) + "), InFlag);");
+          } else {
+            assert(NodeHasProperty(Pattern, SDNPOutFlag, CGP));
+            emitCode("ReplaceUses(SDOperand(N.Val, " +
+                     utostr(NumPatResults + (unsigned)InputHasChain)
+                     +"), InFlag);");
+          }
           NeedReplace = true;
         }
 
@@ -1795,12 +1785,36 @@ void DAGISelEmitter::EmitInstructionSelector(std::ostream &OS) {
   OS << "SDNode *Select_LABEL(const SDOperand &N) {\n"
      << "  SDOperand Chain = N.getOperand(0);\n"
      << "  SDOperand N1 = N.getOperand(1);\n"
-     << "  unsigned C = cast<ConstantSDNode>(N1)->getValue();\n"
-     << "  SDOperand Tmp = CurDAG->getTargetConstant(C, MVT::i32);\n"
+     << "  SDOperand N2 = N.getOperand(2);\n"
+     << "  unsigned C1 = cast<ConstantSDNode>(N1)->getValue();\n"
+     << "  unsigned C2 = cast<ConstantSDNode>(N2)->getValue();\n"
+     << "  SDOperand Tmp1 = CurDAG->getTargetConstant(C1, MVT::i32);\n"
+     << "  SDOperand Tmp2 = CurDAG->getTargetConstant(C2, MVT::i32);\n"
      << "  AddToISelQueue(Chain);\n"
-     << "  SDOperand Ops[] = { Tmp, Chain };\n"
+     << "  SDOperand Ops[] = { Tmp1, Tmp2, Chain };\n"
      << "  return CurDAG->getTargetNode(TargetInstrInfo::LABEL,\n"
-     << "                               MVT::Other, Ops, 2);\n"
+     << "                               MVT::Other, Ops, 3);\n"
+     << "}\n\n";
+
+  OS << "SDNode *Select_DECLARE(const SDOperand &N) {\n"
+     << "  SDOperand Chain = N.getOperand(0);\n"
+     << "  SDOperand N1 = N.getOperand(1);\n"
+     << "  SDOperand N2 = N.getOperand(2);\n"
+     << "  if (!isa<FrameIndexSDNode>(N1) || !isa<GlobalAddressSDNode>(N2)) {\n"
+     << "    cerr << \"Cannot yet select llvm.dbg.declare: \";\n"
+     << "    N.Val->dump(CurDAG);\n"
+     << "    abort();\n"
+     << "  }\n"
+     << "  int FI = cast<FrameIndexSDNode>(N1)->getIndex();\n"
+     << "  GlobalValue *GV = cast<GlobalAddressSDNode>(N2)->getGlobal();\n"
+     << "  SDOperand Tmp1 = "
+     << "CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy());\n"
+     << "  SDOperand Tmp2 = "
+     << "CurDAG->getTargetGlobalAddress(GV, TLI.getPointerTy());\n"
+     << "  AddToISelQueue(Chain);\n"
+     << "  SDOperand Ops[] = { Tmp1, Tmp2, Chain };\n"
+     << "  return CurDAG->getTargetNode(TargetInstrInfo::DECLARE,\n"
+     << "                               MVT::Other, Ops, 3);\n"
      << "}\n\n";
 
   OS << "SDNode *Select_EXTRACT_SUBREG(const SDOperand &N) {\n"
@@ -1870,6 +1884,7 @@ void DAGISelEmitter::EmitInstructionSelector(std::ostream &OS) {
      << "  }\n"
      << "  case ISD::INLINEASM: return Select_INLINEASM(N);\n"
      << "  case ISD::LABEL: return Select_LABEL(N);\n"
+     << "  case ISD::DECLARE: return Select_DECLARE(N);\n"
      << "  case ISD::EXTRACT_SUBREG: return Select_EXTRACT_SUBREG(N);\n"
      << "  case ISD::INSERT_SUBREG:  return Select_INSERT_SUBREG(N);\n";
 
@@ -1951,16 +1966,13 @@ void DAGISelEmitter::run(std::ostream &OS) {
      << "// *** instruction selector class.  These functions are really "
      << "methods.\n\n";
   
-  OS << "#include \"llvm/Support/Compiler.h\"\n";
-
   OS << "// Instruction selector priority queue:\n"
      << "std::vector<SDNode*> ISelQueue;\n";
   OS << "/// Keep track of nodes which have already been added to queue.\n"
      << "unsigned char *ISelQueued;\n";
   OS << "/// Keep track of nodes which have already been selected.\n"
      << "unsigned char *ISelSelected;\n";
-  OS << "/// Dummy parameter to ReplaceAllUsesOfValueWith().\n"
-     << "std::vector<SDNode*> ISelKilled;\n\n";
+
 
   OS << "/// IsChainCompatible - Returns true if Chain is Op or Chain does\n";
   OS << "/// not reach Op.\n";
@@ -2008,37 +2020,52 @@ void DAGISelEmitter::run(std::ostream &OS) {
   OS << "  }\n";
   OS << "}\n\n";
 
-  OS << "inline void RemoveKilled() {\n";
-OS << "  unsigned NumKilled = ISelKilled.size();\n";
-  OS << "  if (NumKilled) {\n";
-  OS << "    for (unsigned i = 0; i != NumKilled; ++i) {\n";
-  OS << "      SDNode *Temp = ISelKilled[i];\n";
-  OS << "      ISelQueue.erase(std::remove(ISelQueue.begin(), ISelQueue.end(), "
-     << "Temp), ISelQueue.end());\n";
-  OS << "    };\n";
- OS << "    std::make_heap(ISelQueue.begin(), ISelQueue.end(), isel_sort());\n";
-  OS << "    ISelKilled.clear();\n";
-  OS << "  }\n";
+  
+  OS << "class VISIBILITY_HIDDEN ISelQueueUpdater :\n";
+  OS << "  public SelectionDAG::DAGUpdateListener {\n";
+  OS << "    std::vector<SDNode*> &ISelQueue;\n";
+  OS << "    bool HadDelete;\n";
+  OS << "  public:\n";
+  OS << "    ISelQueueUpdater(std::vector<SDNode*> &isq)\n";
+  OS << "      : ISelQueue(isq), HadDelete(false) {}\n";
+  OS << "    \n";
+  OS << "    bool hadDelete() const { return HadDelete; }\n";
+  OS << "    \n";
+  OS << "    virtual void NodeDeleted(SDNode *N) {\n";
+  OS << "      ISelQueue.erase(std::remove(ISelQueue.begin(), ISelQueue.end(),";
+  OS << " N),\n                      ISelQueue.end());\n";
+  OS << "      HadDelete = true;\n";
+  OS << "    }\n";
+  OS << "    \n";
+  OS << "    // Ignore updates.\n";
+  OS << "    virtual void NodeUpdated(SDNode *N) {}\n";
+  OS << "  };\n";
+  
+  OS << "inline void UpdateQueue(const ISelQueueUpdater &ISQU) {\n";
+  OS << "  if (ISQU.hadDelete())\n";
+  OS << "    std::make_heap(ISelQueue.begin(), ISelQueue.end(),isel_sort());\n";
   OS << "}\n\n";
 
   OS << "void ReplaceUses(SDOperand F, SDOperand T) DISABLE_INLINE {\n";
-  OS << "  CurDAG->ReplaceAllUsesOfValueWith(F, T, &ISelKilled);\n";
+  OS << "  ISelQueueUpdater ISQU(ISelQueue);\n";
+  OS << "  CurDAG->ReplaceAllUsesOfValueWith(F, T, &ISQU);\n";
   OS << "  setSelected(F.Val->getNodeId());\n";
-  OS << "  RemoveKilled();\n";
+  OS << "  UpdateQueue(ISQU);\n";
   OS << "}\n";
   OS << "void ReplaceUses(SDNode *F, SDNode *T) DISABLE_INLINE {\n";
   OS << "  unsigned FNumVals = F->getNumValues();\n";
   OS << "  unsigned TNumVals = T->getNumValues();\n";
+  OS << "  ISelQueueUpdater ISQU(ISelQueue);\n";
   OS << "  if (FNumVals != TNumVals) {\n";
   OS << "    for (unsigned i = 0, e = std::min(FNumVals, TNumVals); "
      << "i < e; ++i)\n";
   OS << "      CurDAG->ReplaceAllUsesOfValueWith(SDOperand(F, i), "
-     << "SDOperand(T, i), &ISelKilled);\n";
+     << "SDOperand(T, i), &ISQU);\n";
   OS << "  } else {\n";
-  OS << "    CurDAG->ReplaceAllUsesWith(F, T, &ISelKilled);\n";
+  OS << "    CurDAG->ReplaceAllUsesWith(F, T, &ISQU);\n";
   OS << "  }\n";
   OS << "  setSelected(F->getNodeId());\n";
-  OS << "  RemoveKilled();\n";
+  OS << "  UpdateQueue(ISQU);\n";
   OS << "}\n\n";
 
   OS << "// SelectRoot - Top level entry to DAG isel.\n";
@@ -2065,8 +2092,9 @@ OS << "  unsigned NumKilled = ISelKilled.size();\n";
   OS << "        if (ResNode)\n";
   OS << "          ReplaceUses(Node, ResNode);\n";
   OS << "        if (Node->use_empty()) { // Don't delete EntryToken, etc.\n";
-  OS << "          CurDAG->RemoveDeadNode(Node, ISelKilled);\n";
-  OS << "          RemoveKilled();\n";
+  OS << "          ISelQueueUpdater ISQU(ISelQueue);\n";
+  OS << "          CurDAG->RemoveDeadNode(Node, &ISQU);\n";
+  OS << "          UpdateQueue(ISQU);\n";
   OS << "        }\n";
   OS << "      }\n";
   OS << "    }\n";