[llvm] a0ff0f3 - [InstCombine] Move statepoint intrinsic handling from visitCall to visitCallBase

Serguei Katkov via llvm-commits llvm-commits at lists.llvm.org
Wed Mar 3 20:00:49 PST 2021


Author: Serguei Katkov
Date: 2021-03-04T11:00:22+07:00
New Revision: a0ff0f30dfca8c9a5e3de3a82abfdbf097a90943

URL: https://github.com/llvm/llvm-project/commit/a0ff0f30dfca8c9a5e3de3a82abfdbf097a90943
DIFF: https://github.com/llvm/llvm-project/commit/a0ff0f30dfca8c9a5e3de3a82abfdbf097a90943.diff

LOG: [InstCombine] Move statepoint intrinsic handling from visitCall to visitCallBase

statepoint intrinsic can be used in invoke context,
so it should be handled in visitCallBase to cover both call and invoke.

Reviewers: reames, dantrushin
Reviewed By: reames
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D97833

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
    llvm/test/Transforms/InstCombine/statepoint-cleanup.ll
    llvm/test/Transforms/InstCombine/statepoint.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 1a512414a41b..24f5eba1a15e 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -1672,99 +1672,6 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
     AC.updateAffectedValues(II);
     break;
   }
-  case Intrinsic::experimental_gc_statepoint: {
-    GCStatepointInst &GCSP = *cast<GCStatepointInst>(II);
-    SmallPtrSet<Value *, 32> LiveGcValues;
-    for (const GCRelocateInst *Reloc : GCSP.getGCRelocates()) {
-      GCRelocateInst &GCR = *const_cast<GCRelocateInst *>(Reloc);
-
-      // Remove the relocation if unused.
-      if (GCR.use_empty()) {
-        eraseInstFromFunction(GCR);
-        continue;
-      }
-
-      Value *DerivedPtr = GCR.getDerivedPtr();
-      Value *BasePtr = GCR.getBasePtr();
-
-      // Undef is undef, even after relocation.
-      if (isa<UndefValue>(DerivedPtr) || isa<UndefValue>(BasePtr)) {
-        replaceInstUsesWith(GCR, UndefValue::get(GCR.getType()));
-        eraseInstFromFunction(GCR);
-        continue;
-      }
-
-      if (auto *PT = dyn_cast<PointerType>(GCR.getType())) {
-        // The relocation of null will be null for most any collector.
-        // TODO: provide a hook for this in GCStrategy.  There might be some
-        // weird collector this property does not hold for.
-        if (isa<ConstantPointerNull>(DerivedPtr)) {
-          // Use null-pointer of gc_relocate's type to replace it.
-          replaceInstUsesWith(GCR, ConstantPointerNull::get(PT));
-          eraseInstFromFunction(GCR);
-          continue;
-        }
-
-        // isKnownNonNull -> nonnull attribute
-        if (!GCR.hasRetAttr(Attribute::NonNull) &&
-            isKnownNonZero(DerivedPtr, DL, 0, &AC, II, &DT)) {
-          GCR.addAttribute(AttributeList::ReturnIndex, Attribute::NonNull);
-          // We discovered new fact, re-check users.
-          Worklist.pushUsersToWorkList(GCR);
-        }
-      }
-
-      // If we have two copies of the same pointer in the statepoint argument
-      // list, canonicalize to one.  This may let us common gc.relocates.
-      if (GCR.getBasePtr() == GCR.getDerivedPtr() &&
-          GCR.getBasePtrIndex() != GCR.getDerivedPtrIndex()) {
-        auto *OpIntTy = GCR.getOperand(2)->getType();
-        GCR.setOperand(2, ConstantInt::get(OpIntTy, GCR.getBasePtrIndex()));
-      }
-
-      // TODO: bitcast(relocate(p)) -> relocate(bitcast(p))
-      // Canonicalize on the type from the uses to the defs
-
-      // TODO: relocate((gep p, C, C2, ...)) -> gep(relocate(p), C, C2, ...)
-      LiveGcValues.insert(BasePtr);
-      LiveGcValues.insert(DerivedPtr);
-    }
-    Optional<OperandBundleUse> Bundle =
-        GCSP.getOperandBundle(LLVMContext::OB_gc_live);
-    unsigned NumOfGCLives = LiveGcValues.size();
-    if (!Bundle.hasValue() || NumOfGCLives == Bundle->Inputs.size())
-      break;
-    // We can reduce the size of gc live bundle.
-    DenseMap<Value *, unsigned> Val2Idx;
-    std::vector<Value *> NewLiveGc;
-    for (unsigned I = 0, E = Bundle->Inputs.size(); I < E; ++I) {
-      Value *V = Bundle->Inputs[I];
-      if (Val2Idx.count(V))
-        continue;
-      if (LiveGcValues.count(V)) {
-        Val2Idx[V] = NewLiveGc.size();
-        NewLiveGc.push_back(V);
-      } else
-        Val2Idx[V] = NumOfGCLives;
-    }
-    // Update all gc.relocates
-    for (const GCRelocateInst *Reloc : GCSP.getGCRelocates()) {
-      GCRelocateInst &GCR = *const_cast<GCRelocateInst *>(Reloc);
-      Value *BasePtr = GCR.getBasePtr();
-      assert(Val2Idx.count(BasePtr) && Val2Idx[BasePtr] != NumOfGCLives &&
-             "Missed live gc for base pointer");
-      auto *OpIntTy1 = GCR.getOperand(1)->getType();
-      GCR.setOperand(1, ConstantInt::get(OpIntTy1, Val2Idx[BasePtr]));
-      Value *DerivedPtr = GCR.getDerivedPtr();
-      assert(Val2Idx.count(DerivedPtr) && Val2Idx[DerivedPtr] != NumOfGCLives &&
-             "Missed live gc for derived pointer");
-      auto *OpIntTy2 = GCR.getOperand(2)->getType();
-      GCR.setOperand(2, ConstantInt::get(OpIntTy2, Val2Idx[DerivedPtr]));
-    }
-    // Create new statepoint instruction.
-    OperandBundleDef NewBundle("gc-live", NewLiveGc);
-    return CallBase::Create(II, NewBundle);
-  }
   case Intrinsic::experimental_guard: {
     // Is this guard followed by another guard?  We scan forward over a small
     // fixed window of instructions to handle common cases with conditions
@@ -1900,6 +1807,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
     break;
   }
   }
+  // Some intrinsics (like experimental_gc_statepoint) can be used in invoke
+  // context, so it is handled in visitCallBase and we should trigger it.
   return visitCallBase(*II);
 }
 
@@ -2262,6 +2171,104 @@ Instruction *InstCombinerImpl::visitCallBase(CallBase &Call) {
   if (isAllocLikeFn(&Call, &TLI))
     return visitAllocSite(Call);
 
+  // Handle intrinsics which can be used in both call and invoke context.
+  switch (Call.getIntrinsicID()) {
+  case Intrinsic::experimental_gc_statepoint: {
+    GCStatepointInst &GCSP = *cast<GCStatepointInst>(&Call);
+    SmallPtrSet<Value *, 32> LiveGcValues;
+    for (const GCRelocateInst *Reloc : GCSP.getGCRelocates()) {
+      GCRelocateInst &GCR = *const_cast<GCRelocateInst *>(Reloc);
+
+      // Remove the relocation if unused.
+      if (GCR.use_empty()) {
+        eraseInstFromFunction(GCR);
+        continue;
+      }
+
+      Value *DerivedPtr = GCR.getDerivedPtr();
+      Value *BasePtr = GCR.getBasePtr();
+
+      // Undef is undef, even after relocation.
+      if (isa<UndefValue>(DerivedPtr) || isa<UndefValue>(BasePtr)) {
+        replaceInstUsesWith(GCR, UndefValue::get(GCR.getType()));
+        eraseInstFromFunction(GCR);
+        continue;
+      }
+
+      if (auto *PT = dyn_cast<PointerType>(GCR.getType())) {
+        // The relocation of null will be null for most any collector.
+        // TODO: provide a hook for this in GCStrategy.  There might be some
+        // weird collector this property does not hold for.
+        if (isa<ConstantPointerNull>(DerivedPtr)) {
+          // Use null-pointer of gc_relocate's type to replace it.
+          replaceInstUsesWith(GCR, ConstantPointerNull::get(PT));
+          eraseInstFromFunction(GCR);
+          continue;
+        }
+
+        // isKnownNonNull -> nonnull attribute
+        if (!GCR.hasRetAttr(Attribute::NonNull) &&
+            isKnownNonZero(DerivedPtr, DL, 0, &AC, &Call, &DT)) {
+          GCR.addAttribute(AttributeList::ReturnIndex, Attribute::NonNull);
+          // We discovered new fact, re-check users.
+          Worklist.pushUsersToWorkList(GCR);
+        }
+      }
+
+      // If we have two copies of the same pointer in the statepoint argument
+      // list, canonicalize to one.  This may let us common gc.relocates.
+      if (GCR.getBasePtr() == GCR.getDerivedPtr() &&
+          GCR.getBasePtrIndex() != GCR.getDerivedPtrIndex()) {
+        auto *OpIntTy = GCR.getOperand(2)->getType();
+        GCR.setOperand(2, ConstantInt::get(OpIntTy, GCR.getBasePtrIndex()));
+      }
+
+      // TODO: bitcast(relocate(p)) -> relocate(bitcast(p))
+      // Canonicalize on the type from the uses to the defs
+
+      // TODO: relocate((gep p, C, C2, ...)) -> gep(relocate(p), C, C2, ...)
+      LiveGcValues.insert(BasePtr);
+      LiveGcValues.insert(DerivedPtr);
+    }
+    Optional<OperandBundleUse> Bundle =
+        GCSP.getOperandBundle(LLVMContext::OB_gc_live);
+    unsigned NumOfGCLives = LiveGcValues.size();
+    if (!Bundle.hasValue() || NumOfGCLives == Bundle->Inputs.size())
+      break;
+    // We can reduce the size of gc live bundle.
+    DenseMap<Value *, unsigned> Val2Idx;
+    std::vector<Value *> NewLiveGc;
+    for (unsigned I = 0, E = Bundle->Inputs.size(); I < E; ++I) {
+      Value *V = Bundle->Inputs[I];
+      if (Val2Idx.count(V))
+        continue;
+      if (LiveGcValues.count(V)) {
+        Val2Idx[V] = NewLiveGc.size();
+        NewLiveGc.push_back(V);
+      } else
+        Val2Idx[V] = NumOfGCLives;
+    }
+    // Update all gc.relocates
+    for (const GCRelocateInst *Reloc : GCSP.getGCRelocates()) {
+      GCRelocateInst &GCR = *const_cast<GCRelocateInst *>(Reloc);
+      Value *BasePtr = GCR.getBasePtr();
+      assert(Val2Idx.count(BasePtr) && Val2Idx[BasePtr] != NumOfGCLives &&
+             "Missed live gc for base pointer");
+      auto *OpIntTy1 = GCR.getOperand(1)->getType();
+      GCR.setOperand(1, ConstantInt::get(OpIntTy1, Val2Idx[BasePtr]));
+      Value *DerivedPtr = GCR.getDerivedPtr();
+      assert(Val2Idx.count(DerivedPtr) && Val2Idx[DerivedPtr] != NumOfGCLives &&
+             "Missed live gc for derived pointer");
+      auto *OpIntTy2 = GCR.getOperand(2)->getType();
+      GCR.setOperand(2, ConstantInt::get(OpIntTy2, Val2Idx[DerivedPtr]));
+    }
+    // Create new statepoint instruction.
+    OperandBundleDef NewBundle("gc-live", NewLiveGc);
+    return CallBase::Create(&Call, NewBundle);
+  }
+  default: { break; }
+  }
+
   return Changed ? &Call : nullptr;
 }
 

diff  --git a/llvm/test/Transforms/InstCombine/statepoint-cleanup.ll b/llvm/test/Transforms/InstCombine/statepoint-cleanup.ll
index 003f25b4ff7a..1b8404c9ac3f 100644
--- a/llvm/test/Transforms/InstCombine/statepoint-cleanup.ll
+++ b/llvm/test/Transforms/InstCombine/statepoint-cleanup.ll
@@ -4,6 +4,7 @@
 ; pointers being relocated at a statepoint.
 
 
+declare i32* @fake_personality_function()
 declare void @func()
 
 define void @test(i32 addrspace(1)* %b) gc "statepoint-example" {
@@ -86,5 +87,169 @@ entry:
   ret void
 }
 
+define void @test_invoke(i32 addrspace(1)* %b) gc "statepoint-example" personality i32* ()* @fake_personality_function {
+; CHECK-LABEL: @test_invoke(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[D:%.*]] = getelementptr i32, i32 addrspace(1)* [[B:%.*]], i64 16
+; CHECK-NEXT:    [[SAFEPOINT_TOKEN:%.*]] = invoke token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* nonnull @func, i32 0, i32 0, i32 0, i32 0) [ "gc-live"(i32 addrspace(1)* [[B]], i32 addrspace(1)* [[D]]) ]
+; CHECK-NEXT:    to label [[NORMAL_DEST:%.*]] unwind label [[UNWIND_DEST:%.*]]
+; CHECK:       normal_dest:
+; CHECK-NEXT:    [[B_NEW_1:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[SAFEPOINT_TOKEN]], i32 0, i32 0)
+; CHECK-NEXT:    [[B_NEW_2:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[SAFEPOINT_TOKEN]], i32 0, i32 0)
+; CHECK-NEXT:    [[D_NEW_1:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[SAFEPOINT_TOKEN]], i32 0, i32 1)
+; CHECK-NEXT:    [[D_NEW_2:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[SAFEPOINT_TOKEN]], i32 0, i32 1)
+; CHECK-NEXT:    [[D_NEW_3:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[SAFEPOINT_TOKEN]], i32 0, i32 1)
+; CHECK-NEXT:    [[D_NEW_4:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[SAFEPOINT_TOKEN]], i32 0, i32 1)
+; CHECK-NEXT:    store i32 1, i32 addrspace(1)* [[B_NEW_1]], align 4
+; CHECK-NEXT:    store i32 1, i32 addrspace(1)* [[B_NEW_2]], align 4
+; CHECK-NEXT:    store i32 1, i32 addrspace(1)* [[D_NEW_1]], align 4
+; CHECK-NEXT:    store i32 1, i32 addrspace(1)* [[D_NEW_2]], align 4
+; CHECK-NEXT:    store i32 1, i32 addrspace(1)* [[D_NEW_3]], align 4
+; CHECK-NEXT:    store i32 1, i32 addrspace(1)* [[D_NEW_4]], align 4
+; CHECK-NEXT:    ret void
+; CHECK:       unwind_dest:
+; CHECK-NEXT:    [[LPAD:%.*]] = landingpad token
+; CHECK-NEXT:    cleanup
+; CHECK-NEXT:    [[LPB_NEW_1:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[LPAD]], i32 0, i32 0)
+; CHECK-NEXT:    [[LPB_NEW_2:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[LPAD]], i32 0, i32 0)
+; CHECK-NEXT:    [[LPD_NEW_1:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[LPAD]], i32 0, i32 1)
+; CHECK-NEXT:    [[LPD_NEW_2:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[LPAD]], i32 0, i32 1)
+; CHECK-NEXT:    [[LPD_NEW_3:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[LPAD]], i32 0, i32 1)
+; CHECK-NEXT:    [[LPD_NEW_4:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[LPAD]], i32 0, i32 1)
+; CHECK-NEXT:    store i32 2, i32 addrspace(1)* [[LPB_NEW_1]], align 4
+; CHECK-NEXT:    store i32 2, i32 addrspace(1)* [[LPB_NEW_2]], align 4
+; CHECK-NEXT:    store i32 2, i32 addrspace(1)* [[LPD_NEW_1]], align 4
+; CHECK-NEXT:    store i32 2, i32 addrspace(1)* [[LPD_NEW_2]], align 4
+; CHECK-NEXT:    store i32 2, i32 addrspace(1)* [[LPD_NEW_3]], align 4
+; CHECK-NEXT:    store i32 2, i32 addrspace(1)* [[LPD_NEW_4]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  %d = getelementptr i32, i32 addrspace(1)* %b, i64 16
+  %safepoint_token = invoke token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (i32 addrspace(1)* %b, i32 addrspace(1)* %b, i32 addrspace(1)* %d, i32 addrspace(1)* %d)]
+  to label %normal_dest unwind label %unwind_dest
+
+normal_dest:
+  %b.new.1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 0)
+  %b.new.2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 1)
+  %d.new.1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 2)
+  %d.new.2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 3)
+  %d.new.3 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 1, i32 2)
+  %d.new.4 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 1, i32 3)
+  store i32 1, i32 addrspace(1)* %b.new.1
+  store i32 1, i32 addrspace(1)* %b.new.2
+  store i32 1, i32 addrspace(1)* %d.new.1
+  store i32 1, i32 addrspace(1)* %d.new.2
+  store i32 1, i32 addrspace(1)* %d.new.3
+  store i32 1, i32 addrspace(1)* %d.new.4
+  ret void
+
+unwind_dest:
+  %lpad = landingpad token
+  cleanup
+  %lpb.new.1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %lpad,  i32 0, i32 0)
+  %lpb.new.2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %lpad,  i32 0, i32 1)
+  %lpd.new.1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %lpad,  i32 0, i32 2)
+  %lpd.new.2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %lpad,  i32 0, i32 3)
+  %lpd.new.3 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %lpad,  i32 1, i32 2)
+  %lpd.new.4 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %lpad,  i32 1, i32 3)
+  store i32 2, i32 addrspace(1)* %lpb.new.1
+  store i32 2, i32 addrspace(1)* %lpb.new.2
+  store i32 2, i32 addrspace(1)* %lpd.new.1
+  store i32 2, i32 addrspace(1)* %lpd.new.2
+  store i32 2, i32 addrspace(1)* %lpd.new.3
+  store i32 2, i32 addrspace(1)* %lpd.new.4
+  ret void
+}
+
+define void @test_no_derived_use_invoke(i32 addrspace(1)* %b) gc "statepoint-example" personality i32* ()* @fake_personality_function {
+; CHECK-LABEL: @test_no_derived_use_invoke(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SAFEPOINT_TOKEN:%.*]] = invoke token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* nonnull @func, i32 0, i32 0, i32 0, i32 0) [ "gc-live"(i32 addrspace(1)* [[B:%.*]]) ]
+; CHECK-NEXT:    to label [[NORMAL_DEST:%.*]] unwind label [[UNWIND_DEST:%.*]]
+; CHECK:       normal_dest:
+; CHECK-NEXT:    [[B_NEW_1:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[SAFEPOINT_TOKEN]], i32 0, i32 0)
+; CHECK-NEXT:    store i32 1, i32 addrspace(1)* [[B_NEW_1]], align 4
+; CHECK-NEXT:    ret void
+; CHECK:       unwind_dest:
+; CHECK-NEXT:    [[LPAD:%.*]] = landingpad token
+; CHECK-NEXT:    cleanup
+; CHECK-NEXT:    [[LPB_NEW_1:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[LPAD]], i32 0, i32 0)
+; CHECK-NEXT:    store i32 2, i32 addrspace(1)* [[LPB_NEW_1]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  %d = getelementptr i32, i32 addrspace(1)* %b, i64 16
+  %safepoint_token = invoke token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (i32 addrspace(1)* %b, i32 addrspace(1)* %b, i32 addrspace(1)* %d, i32 addrspace(1)* %d)]
+  to label %normal_dest unwind label %unwind_dest
+
+normal_dest:
+  %b.new.1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 0)
+  %b.new.2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 1)
+  %d.new.1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 2)
+  %d.new.2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 3)
+  %d.new.3 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 1, i32 2)
+  %d.new.4 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 1, i32 3)
+  store i32 1, i32 addrspace(1)* %b.new.1
+  ret void
+
+unwind_dest:
+  %lpad = landingpad token
+  cleanup
+  %lpb.new.1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %lpad,  i32 0, i32 0)
+  %lpb.new.2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %lpad,  i32 0, i32 1)
+  %lpd.new.1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %lpad,  i32 0, i32 2)
+  %lpd.new.2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %lpad,  i32 0, i32 3)
+  %lpd.new.3 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %lpad,  i32 1, i32 2)
+  %lpd.new.4 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %lpad,  i32 1, i32 3)
+  store i32 2, i32 addrspace(1)* %lpb.new.1
+  ret void
+}
+
+define void @test_no_base_use_invoke(i32 addrspace(1)* %b) gc "statepoint-example" personality i32* ()* @fake_personality_function {
+; CHECK-LABEL: @test_no_base_use_invoke(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[D:%.*]] = getelementptr i32, i32 addrspace(1)* [[B:%.*]], i64 16
+; CHECK-NEXT:    [[SAFEPOINT_TOKEN:%.*]] = invoke token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* nonnull @func, i32 0, i32 0, i32 0, i32 0) [ "gc-live"(i32 addrspace(1)* [[B]], i32 addrspace(1)* [[D]]) ]
+; CHECK-NEXT:    to label [[NORMAL_DEST:%.*]] unwind label [[UNWIND_DEST:%.*]]
+; CHECK:       normal_dest:
+; CHECK-NEXT:    [[D_NEW_1:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[SAFEPOINT_TOKEN]], i32 0, i32 1)
+; CHECK-NEXT:    store i32 1, i32 addrspace(1)* [[D_NEW_1]], align 4
+; CHECK-NEXT:    ret void
+; CHECK:       unwind_dest:
+; CHECK-NEXT:    [[LPAD:%.*]] = landingpad token
+; CHECK-NEXT:    cleanup
+; CHECK-NEXT:    [[LPD_NEW_1:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[LPAD]], i32 0, i32 1)
+; CHECK-NEXT:    store i32 2, i32 addrspace(1)* [[LPD_NEW_1]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  %d = getelementptr i32, i32 addrspace(1)* %b, i64 16
+  %safepoint_token = invoke token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (i32 addrspace(1)* %b, i32 addrspace(1)* %b, i32 addrspace(1)* %d, i32 addrspace(1)* %d)]
+  to label %normal_dest unwind label %unwind_dest
+
+normal_dest:
+  %b.new.1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 0)
+  %b.new.2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 1)
+  %d.new.1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 2)
+  %d.new.2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 3)
+  %d.new.3 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 1, i32 2)
+  %d.new.4 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 1, i32 3)
+  store i32 1, i32 addrspace(1)* %d.new.1
+  ret void
+
+unwind_dest:
+  %lpad = landingpad token
+  cleanup
+  %lpb.new.1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %lpad,  i32 0, i32 0)
+  %lpb.new.2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %lpad,  i32 0, i32 1)
+  %lpd.new.1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %lpad,  i32 0, i32 2)
+  %lpd.new.2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %lpad,  i32 0, i32 3)
+  %lpd.new.3 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %lpad,  i32 1, i32 2)
+  %lpd.new.4 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %lpad,  i32 1, i32 3)
+  store i32 2, i32 addrspace(1)* %lpd.new.1
+  ret void
+}
+
 declare token @llvm.experimental.gc.statepoint.p0f_isVoidf(i64, i32, void ()*, i32, i32, ...)
 declare i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token, i32, i32)

diff  --git a/llvm/test/Transforms/InstCombine/statepoint.ll b/llvm/test/Transforms/InstCombine/statepoint.ll
index 67333447f644..5db8e560d2e5 100644
--- a/llvm/test/Transforms/InstCombine/statepoint.ll
+++ b/llvm/test/Transforms/InstCombine/statepoint.ll
@@ -1,51 +1,180 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt < %s -instcombine -S | FileCheck %s
 ; These tests check the optimizations specific to
 ; pointers being relocated at a statepoint.
 
 
+declare i32* @fake_personality_function()
 declare void @func()
 
 define i1 @test_negative(i32 addrspace(1)* %p) gc "statepoint-example" {
+; CHECK-LABEL: @test_negative(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SAFEPOINT_TOKEN:%.*]] = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* nonnull @func, i32 0, i32 0, i32 0, i32 0) [ "gc-live"(i32 addrspace(1)* [[P:%.*]]) ]
+; CHECK-NEXT:    [[PNEW:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[SAFEPOINT_TOKEN]], i32 0, i32 0)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 addrspace(1)* [[PNEW]], null
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
 entry:
   %safepoint_token = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["gc-live"(i32 addrspace(1)* %p)]
   %pnew = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 0)
   %cmp = icmp eq i32 addrspace(1)* %pnew, null
   ret i1 %cmp
-; CHECK-LABEL: test_negative
-; CHECK: %pnew = call i32 addrspace(1)*
-; CHECK: ret i1 %cmp
 }
 
 define i1 @test_nonnull(i32 addrspace(1)* nonnull %p) gc "statepoint-example" {
+; CHECK-LABEL: @test_nonnull(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SAFEPOINT_TOKEN:%.*]] = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* nonnull @func, i32 0, i32 0, i32 0, i32 0) [ "gc-live"() ]
+; CHECK-NEXT:    ret i1 false
+;
 entry:
   %safepoint_token = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["gc-live"(i32 addrspace(1)* %p)]
   %pnew = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 0)
   %cmp = icmp eq i32 addrspace(1)* %pnew, null
   ret i1 %cmp
-; CHECK-LABEL: test_nonnull
-; CHECK: ret i1 false
 }
 
 define i1 @test_null() gc "statepoint-example" {
+; CHECK-LABEL: @test_null(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SAFEPOINT_TOKEN:%.*]] = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* nonnull @func, i32 0, i32 0, i32 0, i32 0) [ "gc-live"() ]
+; CHECK-NEXT:    ret i1 true
+;
 entry:
   %safepoint_token = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["gc-live"(i32 addrspace(1)* null)]
   %pnew = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 0)
   %cmp = icmp eq i32 addrspace(1)* %pnew, null
   ret i1 %cmp
-; CHECK-LABEL: test_null
-; CHECK-NOT: %pnew
-; CHECK: ret i1 true
 }
 
 define i1 @test_undef() gc "statepoint-example" {
+; CHECK-LABEL: @test_undef(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SAFEPOINT_TOKEN:%.*]] = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* nonnull @func, i32 0, i32 0, i32 0, i32 0) [ "gc-live"() ]
+; CHECK-NEXT:    ret i1 undef
+;
 entry:
   %safepoint_token = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["gc-live"(i32 addrspace(1)* undef)]
   %pnew = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 0)
   %cmp = icmp eq i32 addrspace(1)* %pnew, null
   ret i1 %cmp
-; CHECK-LABEL: test_undef
-; CHECK-NOT: %pnew
-; CHECK: ret i1 undef
+}
+
+define i1 @test_negative_invoke(i32 addrspace(1)* %p) gc "statepoint-example" personality i32* ()* @fake_personality_function {
+; CHECK-LABEL: @test_negative_invoke(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SAFEPOINT_TOKEN:%.*]] = invoke token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* nonnull @func, i32 0, i32 0, i32 0, i32 0) [ "gc-live"(i32 addrspace(1)* [[P:%.*]]) ]
+; CHECK-NEXT:    to label [[NORMAL_DEST:%.*]] unwind label [[UNWIND_DEST:%.*]]
+; CHECK:       normal_dest:
+; CHECK-NEXT:    [[PNEW:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[SAFEPOINT_TOKEN]], i32 0, i32 0)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 addrspace(1)* [[PNEW]], null
+; CHECK-NEXT:    ret i1 [[CMP]]
+; CHECK:       unwind_dest:
+; CHECK-NEXT:    [[LPAD:%.*]] = landingpad token
+; CHECK-NEXT:    cleanup
+; CHECK-NEXT:    [[PNEW2:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[LPAD]], i32 0, i32 0)
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ne i32 addrspace(1)* [[PNEW2]], null
+; CHECK-NEXT:    ret i1 [[CMP2]]
+;
+entry:
+  %safepoint_token = invoke token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["gc-live"(i32 addrspace(1)* %p)]
+  to label %normal_dest unwind label %unwind_dest
+
+normal_dest:
+  %pnew = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 0)
+  %cmp = icmp eq i32 addrspace(1)* %pnew, null
+  ret i1 %cmp
+unwind_dest:
+  %lpad = landingpad token
+  cleanup
+  %pnew2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %lpad,  i32 0, i32 0)
+  %cmp2 = icmp ne i32 addrspace(1)* %pnew2, null
+  ret i1 %cmp2
+}
+
+define i1 @test_nonnull_invoke(i32 addrspace(1)* nonnull %p) gc "statepoint-example" personality i32* ()* @fake_personality_function {
+; CHECK-LABEL: @test_nonnull_invoke(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SAFEPOINT_TOKEN:%.*]] = invoke token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* nonnull @func, i32 0, i32 0, i32 0, i32 0) [ "gc-live"() ]
+; CHECK-NEXT:    to label [[NORMAL_DEST:%.*]] unwind label [[UNWIND_DEST:%.*]]
+; CHECK:       normal_dest:
+; CHECK-NEXT:    ret i1 false
+; CHECK:       unwind_dest:
+; CHECK-NEXT:    [[LPAD:%.*]] = landingpad token
+; CHECK-NEXT:    cleanup
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  %safepoint_token = invoke token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["gc-live"(i32 addrspace(1)* %p)]
+  to label %normal_dest unwind label %unwind_dest
+
+normal_dest:
+  %pnew = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 0)
+  %cmp = icmp eq i32 addrspace(1)* %pnew, null
+  ret i1 %cmp
+unwind_dest:
+  %lpad = landingpad token
+  cleanup
+  %pnew2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %lpad,  i32 0, i32 0)
+  %cmp2 = icmp ne i32 addrspace(1)* %pnew2, null
+  ret i1 %cmp2
+}
+
+define i1 @test_null_invoke() gc "statepoint-example" personality i32* ()* @fake_personality_function {
+; CHECK-LABEL: @test_null_invoke(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SAFEPOINT_TOKEN:%.*]] = invoke token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* nonnull @func, i32 0, i32 0, i32 0, i32 0) [ "gc-live"() ]
+; CHECK-NEXT:    to label [[NORMAL_DEST:%.*]] unwind label [[UNWIND_DEST:%.*]]
+; CHECK:       normal_dest:
+; CHECK-NEXT:    ret i1 true
+; CHECK:       unwind_dest:
+; CHECK-NEXT:    [[LPAD:%.*]] = landingpad token
+; CHECK-NEXT:    cleanup
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  %safepoint_token = invoke token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["gc-live"(i32 addrspace(1)* null)]
+  to label %normal_dest unwind label %unwind_dest
+
+normal_dest:
+  %pnew = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 0)
+  %cmp = icmp eq i32 addrspace(1)* %pnew, null
+  ret i1 %cmp
+unwind_dest:
+  %lpad = landingpad token
+  cleanup
+  %pnew2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %lpad,  i32 0, i32 0)
+  %cmp2 = icmp ne i32 addrspace(1)* %pnew2, null
+  ret i1 %cmp2
+}
+
+define i1 @test_undef_invoke() gc "statepoint-example" personality i32* ()* @fake_personality_function {
+; CHECK-LABEL: @test_undef_invoke(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SAFEPOINT_TOKEN:%.*]] = invoke token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* nonnull @func, i32 0, i32 0, i32 0, i32 0) [ "gc-live"() ]
+; CHECK-NEXT:    to label [[NORMAL_DEST:%.*]] unwind label [[UNWIND_DEST:%.*]]
+; CHECK:       normal_dest:
+; CHECK-NEXT:    ret i1 undef
+; CHECK:       unwind_dest:
+; CHECK-NEXT:    [[LPAD:%.*]] = landingpad token
+; CHECK-NEXT:    cleanup
+; CHECK-NEXT:    ret i1 undef
+;
+entry:
+  %safepoint_token = invoke token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["gc-live"(i32 addrspace(1)* undef)]
+  to label %normal_dest unwind label %unwind_dest
+
+normal_dest:
+  %pnew = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 0)
+  %cmp = icmp eq i32 addrspace(1)* %pnew, null
+  ret i1 %cmp
+unwind_dest:
+  %lpad = landingpad token
+  cleanup
+  %pnew2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %lpad,  i32 0, i32 0)
+  %cmp2 = icmp ne i32 addrspace(1)* %pnew2, null
+  ret i1 %cmp2
 }
 
 declare token @llvm.experimental.gc.statepoint.p0f_isVoidf(i64, i32, void ()*, i32, i32, ...)


        


More information about the llvm-commits mailing list