[StatepointsForGC] Rematerialize in the presence of PHIs
authorAnna Thomas <anna@azul.com>
Mon, 29 Aug 2016 15:41:59 +0000 (15:41 +0000)
committerAnna Thomas <anna@azul.com>
Mon, 29 Aug 2016 15:41:59 +0000 (15:41 +0000)
Summary:
While walking the use chain for identifying rematerializable values in RS4GC,
add the case where the current value and base value are the same PHI nodes.

This will aid rematerialization of geps and casts instead of relocating.

Reviewers: sanjoy, reames, igor

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D23920

llvm-svn: 279975

llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp
llvm/test/Transforms/RewriteStatepointsForGC/rematerialize-derived-pointers.ll

index 9179834..6726e0e 100644 (file)
@@ -1797,6 +1797,41 @@ static bool findRematerializableChainToBasePointer(
     return true;
   }
 
+  // Check for same values, when both BaseValue and CurrentValue are phi nodes.
+  // PHI nodes that have the same incoming values, and belonging to the same
+  // basic blocks are essentially the same SSA value.  Such an example of same
+  // BaseValue, CurrentValue phis is created by findBasePointer, when a phi has
+  // incoming values with different base pointers. This phi is marked as
+  // conflict, and hence an additional phi with the same incoming values get
+  // generated. We need to identify the BaseValue (.base version of phi) and
+  // CurrentValue (the phi node itself) as the same, so that we can
+  // rematerialize the gep and casts below.
+  if (PHINode *CurrentPhi = dyn_cast<PHINode>(CurrentValue))
+    if (PHINode *BasePhi = dyn_cast<PHINode>(BaseValue)) {
+      auto PhiNum = CurrentPhi->getNumIncomingValues();
+      if (PhiNum != BasePhi->getNumIncomingValues() ||
+          CurrentPhi->getParent() != BasePhi->getParent())
+        return false;
+      // Map of incoming values and their corresponding basic blocks of
+      // CurrentPhi.
+      SmallDenseMap<Value *, BasicBlock *, 8> CurrentIncomingValues;
+      for (unsigned i = 0; i < PhiNum; i++)
+        CurrentIncomingValues[CurrentPhi->getIncomingValue(i)] =
+            CurrentPhi->getIncomingBlock(i);
+
+      // Both current and base PHIs should have same incoming values and
+      // the same basic blocks corresponding to the incoming values.
+      for (unsigned i = 0; i < PhiNum; i++) {
+        auto CIVI = CurrentIncomingValues.find(BasePhi->getIncomingValue(i));
+        if (CIVI == CurrentIncomingValues.end())
+          return false;
+        BasicBlock *CurrentIncomingBB = CIVI->second;
+        if (CurrentIncomingBB != BasePhi->getIncomingBlock(i))
+          return false;
+      }
+      return true;
+    }
+
   if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(CurrentValue)) {
     ChainToBase.push_back(GEP);
     return findRematerializableChainToBasePointer(ChainToBase,
index c4ec2ce..84eb512 100644 (file)
@@ -259,3 +259,40 @@ entry:
   call void @use_obj32(i32 addrspace(1)* %ptr.gep11)
   ret void
 }
+
+
+declare i32 addrspace(1)* @new_instance() nounwind "gc-leaf-function"
+
+; remat the gep in presence of base pointer which is a phi node.
+; FIXME: We should remove the extra basephi.base as well.
+define void @contains_basephi(i1 %cond) gc "statepoint-example" {
+; CHECK-LABEL: contains_basephi
+entry:
+  %base1 = call i32 addrspace(1)* @new_instance()
+  %base2 = call i32 addrspace(1)* @new_instance()
+  br i1 %cond, label %here, label %there
+
+here:
+  br label %merge
+
+there:
+  br label %merge
+
+merge:
+  ; CHECK: %basephi.base = phi i32 addrspace(1)* [ %base1, %here ], [ %base2, %there ], !is_base_value !0
+  ; CHECK: %basephi = phi i32 addrspace(1)* [ %base1, %here ], [ %base2, %there ]
+  ; CHECK: %ptr.gep = getelementptr i32, i32 addrspace(1)* %basephi, i32 15
+  ; CHECK: %statepoint_token = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint
+  ; CHECK: %basephi.base.relocated = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token %statepoint_token, i32 7, i32 7) ; (%basephi.base, %basephi.base)
+  ; CHECK: %basephi.base.relocated.casted = bitcast i8 addrspace(1)* %basephi.base.relocated to i32 addrspace(1)*
+  ; CHECK: %ptr.gep.remat = getelementptr i32, i32 addrspace(1)* %basephi, i32 15
+  ; CHECK: call void @use_obj32(i32 addrspace(1)* %ptr.gep.remat)
+
+
+
+  %basephi = phi i32 addrspace(1)* [ %base1, %here ], [ %base2, %there ]
+  %ptr.gep = getelementptr i32, i32 addrspace(1)* %basephi, i32 15
+  call void @do_safepoint() ["deopt"() ]
+  call void @use_obj32(i32 addrspace(1)* %ptr.gep)
+  ret void
+}