gollvm: fold deref(addr(X)) => X

The existing implementation folds addr(deref(X)) => X only. This
change makes it also work the opposite way.

Updates golang/go#51648

Change-Id: Idc1996d431827fb2c410e4d9fdd99625c1d2dfa6
Reviewed-on: https://go-review.googlesource.com/c/gollvm/+/393295
Trust: Eli Benderskyā€ˇ <eliben@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
diff --git a/bridge/go-llvm-materialize.cpp b/bridge/go-llvm-materialize.cpp
index 49aaad3..8e89288 100644
--- a/bridge/go-llvm-materialize.cpp
+++ b/bridge/go-llvm-materialize.cpp
@@ -1942,7 +1942,7 @@
     if (expr && expr->value())
       return std::make_pair(ContinueWalk, node);
 
-    // Fold addr(deref(X)) => X
+    // Fold addr(deref(X)) and deref(addr(X)) => X
     if (node->flavor() == N_Address) {
       std::vector<Bexpression *> akids = expr->getChildExprs();
       if (akids[0]->flavor() == N_Deref) {
@@ -1959,6 +1959,22 @@
         // Return result
         expr = dkids[0];
       }
+    } else if (node->flavor() == N_Deref) {
+      std::vector<Bexpression *> dkids = expr->getChildExprs();
+      if (dkids[0]->flavor() == N_Address) {
+        Bexpression *address = dkids[0];
+
+        // Extract children and delete first the deref node, then the
+        // addr node. Order is important; if we delete the addr first
+        // then the integrity visitor will wind up trying to access the
+        // deleted addr.
+        be_->nodeBuilder().extractChildenAndDestroy(expr);
+        std::vector<Bexpression *> akids =
+            be_->nodeBuilder().extractChildenAndDestroy(address);
+
+        // Return result
+        expr = akids[0];
+      }
     }
     return std::make_pair(ContinueWalk, expr);
   }