gollvm: remove references to deleted instructions in integrity checker

When dead instruction is deleted, the integrity checker may
still keep its reference. If the memory is reused for another
instruction, the integrity checker will fail. This CL fixes
this.

Change-Id: I6fb7f7e99c590e5a916ab7196e29b020e6366d17
Reviewed-on: https://go-review.googlesource.com/48250
Reviewed-by: Than McIntosh <thanm@google.com>
diff --git a/llvm-gofrontend/go-llvm-bnode.cpp b/llvm-gofrontend/go-llvm-bnode.cpp
index 71a3a0e..25822a5 100644
--- a/llvm-gofrontend/go-llvm-bnode.cpp
+++ b/llvm-gofrontend/go-llvm-bnode.cpp
@@ -267,14 +267,15 @@
     kid->osdump(os, ilevel + 2, linemap, terse);
 }
 
-void BnodeBuilder::destroy(Bnode *node, WhichDel which)
+void BnodeBuilder::destroy(Bnode *node, WhichDel which, bool recursive)
 {
   std::set<Bnode *> visited;
-  destroyRec(node, which, visited);
+  destroyRec(node, which, recursive, visited);
 }
 
 void BnodeBuilder::destroyRec(Bnode *node,
                               WhichDel which,
+                              bool recursive,
                               std::set<Bnode *> &visited)
 {
   if (visited.find(node) != visited.end())
@@ -283,14 +284,19 @@
   if (which != DelWrappers) {
     Bexpression *expr = node->castToBexpression();
     if (expr) {
-      for (auto inst : expr->instructions())
+      unsigned idx = 0;
+      for (auto inst : expr->instructions()) {
+        integrityVisitor_->unsetParent(inst, expr, idx);
         inst->dropAllReferences();
+      }
       for (auto inst : expr->instructions())
         inst->deleteValue();
+      expr->clear();
     }
   }
-  for (auto &kid : node->kids_)
-    destroyRec(kid, which, visited);
+  if (recursive)
+    for (auto &kid : node->kids_)
+      destroyRec(kid, which, true, visited);
   if (which != DelInstructions)
     freeNode(node);
 }
diff --git a/llvm-gofrontend/go-llvm-bnode.h b/llvm-gofrontend/go-llvm-bnode.h
index 16d5ec5..3751f63 100644
--- a/llvm-gofrontend/go-llvm-bnode.h
+++ b/llvm-gofrontend/go-llvm-bnode.h
@@ -345,7 +345,8 @@
   // LLVM instructions found in the subtree), DelWrappers (deletes
   // Bnodes but not instructions), or DelBoth (gets rid of nodes and
   // instructions).
-  void destroy(Bnode *node, WhichDel which = DelWrappers);
+  // If recursive is true, also delete its children recursively.
+  void destroy(Bnode *node, WhichDel which = DelWrappers, bool recursive = true);
 
   // Clone an expression subtree.
   Bexpression *cloneSubtree(Bexpression *expr);
@@ -378,7 +379,8 @@
   Bexpression *cloneSub(Bexpression *expr,
                         std::map<llvm::Value *, llvm::Value *> &vm);
   void checkTreeInteg(Bnode *node);
-  void destroyRec(Bnode *node, WhichDel which, std::set<Bnode *> &visited);
+  void destroyRec(Bnode *node, WhichDel which, bool recursive,
+                  std::set<Bnode *> &visited);
 
  private:
   std::unique_ptr<Bstatement> errorStatement_;
diff --git a/llvm-gofrontend/go-llvm-tree-integrity.cpp b/llvm-gofrontend/go-llvm-tree-integrity.cpp
index 0d57d1f..405ab49 100644
--- a/llvm-gofrontend/go-llvm-tree-integrity.cpp
+++ b/llvm-gofrontend/go-llvm-tree-integrity.cpp
@@ -92,6 +92,20 @@
     nparent_.erase(it);
 }
 
+void IntegrityVisitor::unsetParent(llvm::Instruction *inst,
+                                   Bexpression *exprParent,
+                                   unsigned slot)
+{
+  auto it = iparent_.find(inst);
+  if (it == iparent_.end())
+    return;
+  parslot pps = it->second;
+  Bnode *prevParent = pps.first;
+  unsigned prevSlot = pps.second;
+  if (prevParent == exprParent || prevSlot == slot)
+    iparent_.erase(it);
+}
+
 void IntegrityVisitor::setParent(Bnode *child, Bnode *parent, unsigned slot)
 {
   if (! shouldBeTracked(child))
diff --git a/llvm-gofrontend/go-llvm-tree-integrity.h b/llvm-gofrontend/go-llvm-tree-integrity.h
index 6cf8b6f..aa7347c 100644
--- a/llvm-gofrontend/go-llvm-tree-integrity.h
+++ b/llvm-gofrontend/go-llvm-tree-integrity.h
@@ -94,6 +94,11 @@
   // relationship (used when node child is deleted or repurposed).
   void unsetParent(Bnode *child, Bnode *parent, unsigned slot);
 
+  // Same as above, for instruction.
+  void unsetParent(llvm::Instruction *inst,
+                   Bexpression *exprParent,
+                   unsigned slot);
+
   // Tell the IntegrityVisitor we're about to delete the specified
   // node, so please remove any outstanding references to it.
   void deletePending(Bnode *node);
diff --git a/llvm-gofrontend/go-llvm.cpp b/llvm-gofrontend/go-llvm.cpp
index 56f9dbb..99febaa 100644
--- a/llvm-gofrontend/go-llvm.cpp
+++ b/llvm-gofrontend/go-llvm.cpp
@@ -2456,13 +2456,8 @@
   // Delete dead instructions before visiting the children,
   // as they may use values defined in the children. Uses
   // need to be deleted before deleting definition.
-  if (!curblock) {
-    for (auto originst : expr->instructions())
-      originst->dropAllReferences();
-    for (auto originst : expr->instructions())
-      originst->deleteValue();
-    expr->clear();
-  }
+  if (!curblock)
+    be_->nodeBuilder().destroy(expr, DelInstructions, false);
 
   // Visit children first
   const std::vector<Bnode *> &kids = expr->children();
@@ -2470,13 +2465,8 @@
     curblock = walk(child, curblock);
 
   // In case it becomes dead after visiting some child...
-  if (!curblock) {
-    for (auto originst : expr->instructions())
-      originst->dropAllReferences();
-    for (auto originst : expr->instructions())
-      originst->deleteValue();
-    expr->clear();
-  }
+  if (!curblock)
+    be_->nodeBuilder().destroy(expr, DelInstructions, false);
 
   // Now visit instructions for this expr
   // TODO: currently the control flow won't change from