passes: handle degenerate Phis in stack maps

A degenerate Phi of null pointer is recorded in the stack map as
constant 0. Previously we just ignored constant 0, since it
cannot be a valid pointer bitmap. However, with a type that is
larger than 32*8 bytes, constant 0 may still appear as part of
the multiword bitmap, so it is problematic to just ignore it.
Instead, filter degenerate Phis and don't record them in the
live set.

Change-Id: I2e39393c8eea8d5d1c515445b63d969796591524
Reviewed-on: https://go-review.googlesource.com/c/154738
Reviewed-by: Than McIntosh <thanm@google.com>
diff --git a/passes/GC.cpp b/passes/GC.cpp
index 21c8b1a..c754c50 100644
--- a/passes/GC.cpp
+++ b/passes/GC.cpp
@@ -79,11 +79,8 @@
 
       // If a slot is following a "Constant" location, it is an aggregate type
       // and that constant encodes the pointer bitmap.
-      // Constant 0 cannot be a pointer bitmap. Instead, it encodes a null pointer
-      // as live (happens with degenerated Phis).
       if (i+1 < n &&
-          CSLocs[i+1].Type == StackMaps::Location::Constant &&
-          CSLocs[i+1].Offset != 0) {
+          CSLocs[i+1].Type == StackMaps::Location::Constant) {
         // Make sure it is a local/arg slot, not a spill of in-register value.
         assert(Loc.Type == StackMaps::Location::Direct);
 
diff --git a/passes/GoStatepoints.cpp b/passes/GoStatepoints.cpp
index d4ba6d0..ae506d3 100644
--- a/passes/GoStatepoints.cpp
+++ b/passes/GoStatepoints.cpp
@@ -1379,6 +1379,9 @@
   // pointer fields.
   SmallVector<Value *, 64> PtrFields;
   for (Value *V : BasePtrs) {
+    if (auto *Phi = dyn_cast<PHINode>(V))
+      if (Phi->hasConstantValue())
+        continue;
     if (isa<AllocaInst>(V) ||
         (isa<Argument>(V) && cast<Argument>(V)->hasByValAttr())) {
       // Byval argument is at a fixed frame offset. Treat it the same as alloca.
@@ -1668,11 +1671,30 @@
 }
 
 static void
-fixBadPhiOperands(Function &F, SetVector<Value *> &BadLoads) {
+fixBadPhiOperands(Function &F, SetVector<Value *> &BadLoads,
+                  SetVector<Instruction *> &ToDel) {
   for (auto *I : BadLoads) {
     I->replaceAllUsesWith(Constant::getNullValue(I->getType()));
     cast<Instruction>(I)->eraseFromParent();
   }
+
+  // The replacement above may lead to degenerate Phis, which, if live,
+  // will be encoded as constants in the stack map, which is bad
+  // (confusing with pointer bitmaps). Clean them up.
+  // Don't delete them yet -- they may be referenced in the liveness
+  // map. We'll delete them at the end.
+  bool Changed = true;
+  while (Changed) {
+    Changed = false;
+    for (Instruction &I : instructions(F))
+      if (auto *Phi = dyn_cast<PHINode>(&I))
+        if (Value *V = Phi->hasConstantValue())
+          if (!ToDel.count(Phi)) {
+            Phi->replaceAllUsesWith(V);
+            ToDel.insert(Phi);
+            Changed = true;
+          }
+  }
 }
 
 static bool insertParsePoints(Function &F, DominatorTree &DT,
@@ -1720,7 +1742,8 @@
     findBasePointers(DT, DVCache, ToUpdate[i], info);
   }
 
-  fixBadPhiOperands(F, BadLoads);
+  SetVector<Instruction *> ToDel;
+  fixBadPhiOperands(F, BadLoads, ToDel);
 
   // It is possible that non-constant live variables have a constant base.  For
   // example, a GEP with a variable offset from a global.  In this case we can
@@ -1811,6 +1834,10 @@
 
   zeroAmbiguouslyLiveSlots(F, ToZero, AddrTakenAllocas);
 
+  // Delete dead Phis.
+  for (Instruction *I : ToDel)
+    I->eraseFromParent();
+
   return !Records.empty();
 }