[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