Index: lib/CodeGen/CodeGenPrepare.cpp =================================================================== --- lib/CodeGen/CodeGenPrepare.cpp +++ lib/CodeGen/CodeGenPrepare.cpp @@ -600,13 +600,51 @@ // Create a Builder and replace the target callsite with a gep IRBuilder<> Builder(ToReplace); Builder.SetCurrentDebugLocation(ToReplace->getDebugLoc()); + + // If gc_relocate does not match the actual type, cast it to the right type. + // In theory, there must be a bitcast after gc_relocate if the type does not + // match, and we should reuse it to get the derived pointer. But it could be + // cases like this: + // bb1: + // ... + // %g1 = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(...) + // br label %merge + // + // bb2: + // ... + // %g2 = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(...) + // br label %merge + // + // merge: + // %p1 = phi i8 addrspace(1)* [ %g1, %bb1 ], [ %g2, %bb2 ] + // %cast = bitcast i8 addrspace(1)* %p1 in to i32 addrspace(1)* + // + // In this case, we can not find the bitcast any more. So we insert a new bitcast + // no matter there is already one or not. In this way, we can handle all cases, and + // the extra bitcast should be optimized away in later passes. + Instruction *ActualRelocatedBase = RelocatedBase; + if (RelocatedBase->getType() != Base->getType()) { + ActualRelocatedBase = + cast(Builder.CreateBitCast(RelocatedBase, Base->getType())); + ActualRelocatedBase->removeFromParent(); + ActualRelocatedBase->insertAfter(cast(RelocatedBase)); + } Value *Replacement = Builder.CreateGEP( - Derived->getSourceElementType(), RelocatedBase, makeArrayRef(OffsetV)); + Derived->getSourceElementType(), ActualRelocatedBase, makeArrayRef(OffsetV)); Instruction *ReplacementInst = cast(Replacement); ReplacementInst->removeFromParent(); - ReplacementInst->insertAfter(RelocatedBase); + ReplacementInst->insertAfter(ActualRelocatedBase); Replacement->takeName(ToReplace); - ToReplace->replaceAllUsesWith(Replacement); + // If the newly generated derived pointer's type does not match the original derived + // pointer's type, cast the new derived pointer to match it. Same reasoning as above. + Instruction *ActualReplacement = ReplacementInst; + if (ReplacementInst->getType() != ToReplace->getType()) { + ActualReplacement = + cast(Builder.CreateBitCast(ReplacementInst, ToReplace->getType())); + ActualReplacement->removeFromParent(); + ActualReplacement->insertAfter(ReplacementInst); + } + ToReplace->replaceAllUsesWith(ActualReplacement); ToReplace->eraseFromParent(); MadeChange = true; Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -3384,10 +3384,8 @@ "'gc parameters' section of the statepoint call", &CI); - // Assert that the result type matches the type of the relocated pointer - GCRelocateOperands Operands(&CI); - Assert(Operands.getDerivedPtr()->getType() == CI.getType(), - "gc.relocate: relocating a pointer shouldn't change its type", &CI); + // gc_relocate does not need to be the same type as the relocated pointer. + // It can casted to the correct type later if it's desired break; } }; Index: lib/Transforms/InstCombine/InstCombineCalls.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCalls.cpp +++ lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -1197,6 +1197,7 @@ // preserve relocation semantics. GCRelocateOperands Operands(II); Value *DerivedPtr = Operands.getDerivedPtr(); + auto *GCRelocateType = cast(II->getType()); // Remove the relocation if unused, note that this check is required // to prevent the cases below from looping forever. @@ -1207,14 +1208,18 @@ // TODO: provide a hook for this in GCStrategy. This is clearly legal for // most practical collectors, but there was discussion in the review thread // about whether it was legal for all possible collectors. - if (isa(DerivedPtr)) - return ReplaceInstUsesWith(*II, DerivedPtr); + if (isa(DerivedPtr)) { + // gc_relocate is uncasted. Use undef of gc_relocate's type to replace it. + return ReplaceInstUsesWith(*II, UndefValue::get(GCRelocateType)); + } // 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(DerivedPtr)) - return ReplaceInstUsesWith(*II, DerivedPtr); + if (isa(DerivedPtr)) { + // gc_relocate is uncasted. Use null-pointer of gc_relocate's type to replace it. + return ReplaceInstUsesWith(*II, ConstantPointerNull::get(GCRelocateType)); + } // isKnownNonNull -> nonnull attribute if (isKnownNonNull(DerivedPtr)) Index: lib/Transforms/Scalar/RewriteStatepointsForGC.cpp =================================================================== --- lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ lib/Transforms/Scalar/RewriteStatepointsForGC.cpp @@ -1075,7 +1075,10 @@ // the IR, but removes the need for argument bitcasts which shrinks the IR // greatly and makes it much more readable. SmallVector types; // one per 'any' type - types.push_back(liveVariables[i]->getType()); // result type + // All gc_relocate are set to i8 addrspace(1)* type. This could help avoid + // cases where the actual value's type mangling is not supported by llvm. A + // bitcast is added later to convert gc_relocate to the actual value's type. + types.push_back(Type::getInt8PtrTy(M->getContext(), 1)); Value *gc_relocate_decl = Intrinsic::getDeclaration( M, Intrinsic::experimental_gc_relocate, types); @@ -1342,8 +1345,16 @@ Value *alloca = allocaMap[originalValue]; // Emit store into the related alloca - StoreInst *store = new StoreInst(relocatedValue, alloca); - store->insertAfter(relocatedValue); + // All gc_relocate are i8 addrspace(1)* typed, and it must be bitcasted to + // the correct type according to alloca. + assert(relocatedValue->getNextNode() && "Should always have one since it's not a terminator"); + IRBuilder<> Builder(relocatedValue->getNextNode()); + Value *CastedRelocatedValue = + Builder.CreateBitCast(relocatedValue, cast(alloca)->getAllocatedType(), + relocatedValue->hasName() ? relocatedValue->getName() + ".casted" : ""); + + StoreInst *store = new StoreInst(CastedRelocatedValue, alloca); + store->insertAfter(cast(CastedRelocatedValue)); #ifndef NDEBUG visitedLiveValues.insert(originalValue); Index: test/Transforms/RewriteStatepointsForGC/base-pointers-11.ll =================================================================== --- test/Transforms/RewriteStatepointsForGC/base-pointers-11.ll +++ test/Transforms/RewriteStatepointsForGC/base-pointers-11.ll @@ -12,11 +12,11 @@ loop: ; preds = %loop, %entry ; CHECK-LABEL: loop: ; CHECK: phi i64 addrspace(1)* -; CHECK-DAG: [ %base_obj.relocated, %loop ] +; CHECK-DAG: [ %base_obj.relocated.casted, %loop ] ; CHECK-DAG: [ %base_obj, %entry ] ; CHECK: %current = phi i64 addrspace(1)* ; CHECK-DAG: [ %obj, %entry ] -; CHECK-DAG: [ %next.relocated, %loop ] +; CHECK-DAG: [ %next.relocated.casted, %loop ] %current = phi i64 addrspace(1)* [ %obj, %entry ], [ %next, %loop ] %next = getelementptr i64, i64 addrspace(1)* %current, i32 1 %safepoint_token = call i32 (void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @do_safepoint, i32 0, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0) Index: test/Transforms/RewriteStatepointsForGC/base-pointers.ll =================================================================== --- test/Transforms/RewriteStatepointsForGC/base-pointers.ll +++ test/Transforms/RewriteStatepointsForGC/base-pointers.ll @@ -13,7 +13,7 @@ loop: ; CHECK: phi i64 addrspace(1)* -; CHECK-DAG: [ %obj.relocated, %loop ] +; CHECK-DAG: [ %obj.relocated.casted, %loop ] ; CHECK-DAG: [ %obj, %entry ] call void @use_obj(i64 addrspace(1)* %obj) %safepoint_token = call i32 (void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @do_safepoint, i32 0, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0) @@ -78,7 +78,7 @@ ; CHECK-DAG: [ %base_obj, %entry ] ; Given the two selects are equivelent, so are their base phis - ideally, ; we'd have commoned these, but that's a missed optimization, not correctness. -; CHECK-DAG: [ [[DISCARD:%base_select.*.relocated]], %loop ] +; CHECK-DAG: [ [[DISCARD:%base_select.*.relocated.casted]], %loop ] ; CHECK-NOT: base_phi2 ; CHECK: next = select ; CHECK: base_select Index: test/Transforms/RewriteStatepointsForGC/gc_relocate_creation.ll =================================================================== --- /dev/null +++ test/Transforms/RewriteStatepointsForGC/gc_relocate_creation.ll @@ -0,0 +1,20 @@ +; RUN: opt %s -rewrite-statepoints-for-gc -S 2>&1 | FileCheck %s +; This test is to verify gc.relocate can handle pointer to vector of +; pointers (<2 x i32 addrspace(1)*> addrspace(1)* in this case). +; The old scheme to create a gc.relocate of <2 x i32 addrspace(1)*> addrspace(1)* +; type will fail because llvm does not support mangling vector of pointers. +; The new scheme will create all gc.relocate to i8 addrspace(1)* type and +; then bitcast to the correct type. + +declare void @foo() +declare void @use(...) +declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()*, i32, i32, ...) + +define void @test1(<2 x i32 addrspace(1)*> addrspace(1)* %obj) gc "statepoint-example" { +entry: + %safepoint_token = call i32 (void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @foo, i32 0, i32 0, i32 0, i32 0) +; CHECK: %obj.relocated = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(i32 %safepoint_token, i32 5, i32 5) +; CHECK-NEXT: %obj.relocated.casted = bitcast i8 addrspace(1)* %obj.relocated to <2 x i32 addrspace(1)*> addrspace(1)* + call void (...) @use(<2 x i32 addrspace(1)*> addrspace(1)* %obj) + ret void +} \ No newline at end of file Index: test/Transforms/RewriteStatepointsForGC/live-vector.ll =================================================================== --- test/Transforms/RewriteStatepointsForGC/live-vector.ll +++ test/Transforms/RewriteStatepointsForGC/live-vector.ll @@ -7,7 +7,8 @@ ; CHECK-LABEL: test ; CHECK: gc.statepoint ; CHECK-NEXT: gc.relocate -; CHECK-NEXT: ret i64 addrspace(1)* %obj.relocated +; CHECK-NEXT: bitcast +; CHECK-NEXT: ret i64 addrspace(1)* %obj.relocated.casted entry: %safepoint_token = call i32 (void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @do_safepoint, i32 0, i32 0, i32 0, i32 0) ret i64 addrspace(1)* %obj @@ -20,10 +21,12 @@ ; CHECK-NEXT: extractelement ; CHECK-NEXT: gc.statepoint ; CHECK-NEXT: gc.relocate +; CHECK-NEXT: bitcast ; CHECK-NEXT: gc.relocate +; CHECK-NEXT: bitcast ; CHECK-NEXT: insertelement ; CHECK-NEXT: insertelement -; CHECK-NEXT: ret <2 x i64 addrspace(1)*> %5 +; CHECK-NEXT: ret <2 x i64 addrspace(1)*> %7 entry: %safepoint_token = call i32 (void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @do_safepoint, i32 0, i32 0, i32 0, i32 0) ret <2 x i64 addrspace(1)*> %obj @@ -37,10 +40,12 @@ ; CHECK-NEXT: extractelement ; CHECK-NEXT: gc.statepoint ; CHECK-NEXT: gc.relocate +; CHECK-NEXT: bitcast ; CHECK-NEXT: gc.relocate +; CHECK-NEXT: bitcast ; CHECK-NEXT: insertelement ; CHECK-NEXT: insertelement -; CHECK-NEXT: ret <2 x i64 addrspace(1)*> %5 +; CHECK-NEXT: ret <2 x i64 addrspace(1)*> %7 entry: %obj = load <2 x i64 addrspace(1)*>, <2 x i64 addrspace(1)*>* %ptr %safepoint_token = call i32 (void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @do_safepoint, i32 0, i32 0, i32 0, i32 0) @@ -63,19 +68,23 @@ ; CHECK-LABEL: normal_return: ; CHECK: gc.relocate +; CHECK-NEXT: bitcast ; CHECK-NEXT: gc.relocate +; CHECK-NEXT: bitcast ; CHECK-NEXT: insertelement ; CHECK-NEXT: insertelement -; CHECK-NEXT: ret <2 x i64 addrspace(1)*> %6 +; CHECK-NEXT: ret <2 x i64 addrspace(1)*> %8 normal_return: ; preds = %entry ret <2 x i64 addrspace(1)*> %obj ; CHECK-LABEL: exceptional_return: ; CHECK: gc.relocate +; CHECK-NEXT: bitcast ; CHECK-NEXT: gc.relocate +; CHECK-NEXT: bitcast ; CHECK-NEXT: insertelement ; CHECK-NEXT: insertelement -; CHECK-NEXT: ret <2 x i64 addrspace(1)*> %10 +; CHECK-NEXT: ret <2 x i64 addrspace(1)*> %14 exceptional_return: ; preds = %entry %landing_pad4 = landingpad { i8*, i32 } personality i32 ()* @fake_personality_function cleanup Index: test/Transforms/RewriteStatepointsForGC/liveness-basics.ll =================================================================== --- test/Transforms/RewriteStatepointsForGC/liveness-basics.ll +++ test/Transforms/RewriteStatepointsForGC/liveness-basics.ll @@ -13,7 +13,8 @@ taken: ; CHECK-LABEL: taken: ; CHECK-NEXT: gc.statepoint -; CHECK-NEXT: %obj.relocated = call coldcc i64 addrspace(1)* +; CHECK-NEXT: %obj.relocated = call coldcc i8 addrspace(1)* +; CHECK-NEXT: bitcast ; CHECK-NEXT: br label %merge call i32 (void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @foo, i32 0, i32 0, i32 0, i32 0) br label %merge @@ -21,14 +22,15 @@ untaken: ; CHECK-LABEL: untaken: ; CHECK-NEXT: gc.statepoint -; CHECK-NEXT: %obj.relocated1 = call coldcc i64 addrspace(1)* +; CHECK-NEXT: %obj.relocated1 = call coldcc i8 addrspace(1)* +; CHECK-NEXT: bitcast ; CHECK-NEXT: br label %merge call i32 (void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @foo, i32 0, i32 0, i32 0, i32 0) br label %merge merge: ; CHECK-LABEL: merge: -; CHECK-NEXT: %.0 = phi i64 addrspace(1)* [ %obj.relocated, %taken ], [ %obj.relocated1, %untaken ] +; CHECK-NEXT: %.0 = phi i64 addrspace(1)* [ %obj.relocated.casted, %taken ], [ %obj.relocated1.casted, %untaken ] ; CHECK-NEXT: ret i64 addrspace(1)* %.0 ret i64 addrspace(1)* %obj } @@ -48,7 +50,8 @@ ; CHECK-NEXT: %obj = load ; CHECK-NEXT: gc.statepoint ; CHECK-NEXT: gc.relocate -; CHECK-NEXT: ret i64 addrspace(1)* %obj.relocated +; CHECK-NEXT: bitcast +; CHECK-NEXT: ret i64 addrspace(1)* %obj.relocated.casted %obj = load i64 addrspace(1)*, i64 addrspace(1)** %loc call i32 (void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @foo, i32 0, i32 0, i32 0, i32 0) @@ -70,7 +73,8 @@ ; CHECK-NEXT: gc.statepoint ; CHECK-NEXT: %obj = load ; CHECK-NEXT: gc.statepoint -; CHECK-NEXT: %obj.relocated = call coldcc i64 addrspace(1)* +; CHECK-NEXT: %obj.relocated = call coldcc i8 addrspace(1)* +; CHECK-NEXT: bitcast ; CHECK-NEXT: br label %merge call i32 (void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @foo, i32 0, i32 0, i32 0, i32 0) %obj = load i64 addrspace(1)*, i64 addrspace(1)** %loc @@ -97,13 +101,17 @@ ; CHECK-LABEL: entry: ; CHECK-NEXT: %derived = getelementptr ; CHECK-NEXT: gc.statepoint -; CHECK-NEXT: %derived.relocated = +; CHECK-NEXT: %derived.relocated = +; CHECK-NEXT: bitcast ; CHECK-NEXT: %obj.relocated = +; CHECK-NEXT: bitcast ; CHECK-NEXT: gc.statepoint -; CHECK-NEXT: %derived.relocated1 = +; CHECK-NEXT: %derived.relocated1 = +; CHECK-NEXT: bitcast ; Note: It's legal to relocate obj again, but not strictly needed ; CHECK-NEXT: %obj.relocated2 = -; CHECK-NEXT: ret i64 addrspace(1)* %derived.relocated1 +; CHECK-NEXT: bitcast +; CHECK-NEXT: ret i64 addrspace(1)* %derived.relocated1.casted ; %derived = getelementptr i64, i64 addrspace(1)* %obj, i64 8 call i32 (void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @foo, i32 0, i32 0, i32 0, i32 0) @@ -125,7 +133,8 @@ taken: ; CHECK-LABEL: taken: ; CHECK-NEXT: gc.statepoint -; CHECK-NEXT: %obj.relocated = call coldcc i64 addrspace(1)* +; CHECK-NEXT: %obj.relocated = call coldcc i8 addrspace(1)* +; CHECK-NEXT: bitcast ; CHECK-NEXT: br label %merge call i32 (void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @foo, i32 0, i32 0, i32 0, i32 0) br label %merge Index: test/Transforms/RewriteStatepointsForGC/preprocess.ll =================================================================== --- test/Transforms/RewriteStatepointsForGC/preprocess.ll +++ test/Transforms/RewriteStatepointsForGC/preprocess.ll @@ -13,8 +13,9 @@ ; CHECK-LABEL: next: ; CHECK-NEXT: gc.statepoint ; CHECK-NEXT: gc.relocate -; CHECK-NEXT: @consume(i64 addrspace(1)* %obj.relocated) -; CHECK-NEXT: @consume(i64 addrspace(1)* %obj.relocated) +; CHECK-NEXT: bitcast +; CHECK-NEXT: @consume(i64 addrspace(1)* %obj.relocated.casted) +; CHECK-NEXT: @consume(i64 addrspace(1)* %obj.relocated.casted) %obj2 = phi i64 addrspace(1)* [ %obj, %entry ] call i32 (void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @foo, i32 0, i32 0, i32 0, i32 0) call void (...) @consume(i64 addrspace(1)* %obj2) Index: test/Transforms/RewriteStatepointsForGC/relocate_invoke_result.ll =================================================================== --- test/Transforms/RewriteStatepointsForGC/relocate_invoke_result.ll +++ test/Transforms/RewriteStatepointsForGC/relocate_invoke_result.ll @@ -23,7 +23,8 @@ normal_dest: ;; CHECK-LABEL: normal_dest: ;; CHECK-NEXT: gc.statepoint -;; CHECK-NEXT: %obj.relocated = call coldcc i64* addrspace(1)* +;; CHECK-NEXT: %obj.relocated = call coldcc i8 addrspace(1)* +;; CHECK-NEXT: bitcast %safepoint_token = call i32 (void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @gc_call, i32 0, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0) ret i64* addrspace(1)* %obj } Index: test/Transforms/RewriteStatepointsForGC/relocation.ll =================================================================== --- test/Transforms/RewriteStatepointsForGC/relocation.ll +++ test/Transforms/RewriteStatepointsForGC/relocation.ll @@ -14,7 +14,7 @@ joint: ; CHECK-LABEL: joint: -; CHECK: %phi1 = phi i64 addrspace(1)* [ %obj.relocated, %entry ], [ %obj3, %joint2 ] +; CHECK: %phi1 = phi i64 addrspace(1)* [ %obj.relocated.casted, %entry ], [ %obj3, %joint2 ] %phi1 = phi i64 addrspace(1)* [ %obj, %entry ], [ %obj3, %joint2 ] br i1 %condition, label %use, label %joint2 @@ -23,8 +23,8 @@ joint2: ; CHECK-LABEL: joint2: -; CHECK: %phi2 = phi i64 addrspace(1)* [ %obj.relocated, %use ], [ %obj2.relocated, %joint ] -; CHECK: %obj3 = getelementptr i64, i64 addrspace(1)* %obj2.relocated, i32 1 +; CHECK: %phi2 = phi i64 addrspace(1)* [ %obj.relocated.casted, %use ], [ %obj2.relocated.casted, %joint ] +; CHECK: %obj3 = getelementptr i64, i64 addrspace(1)* %obj2.relocated.casted, i32 1 %phi2 = phi i64 addrspace(1)* [ %obj, %use ], [ %obj2, %joint ] %obj3 = getelementptr i64, i64 addrspace(1)* %obj2, i32 1 br label %joint @@ -45,9 +45,9 @@ loop: ; CHECK: loop: -; CHECK-DAG: [ %obj_init.relocated, %loop.backedge ] +; CHECK-DAG: [ %obj_init.relocated.casted, %loop.backedge ] ; CHECK-DAG: [ %obj_init, %entry ] -; CHECK-DAG: [ %obj.relocated, %loop.backedge ] +; CHECK-DAG: [ %obj.relocated.casted, %loop.backedge ] ; CHECK-DAG: [ %obj, %entry ] %index = phi i32 [ 0, %entry ], [ %index.inc, %loop.backedge ] ; CHECK-NOT: %location = getelementptr i64, i64 addrspace(1)* %obj, i32 %index @@ -108,6 +108,7 @@ ; CHECK-LABEL: @test3 ; CHECK: gc.statepoint ; CHECK-NEXT: gc.relocate +; CHECK-NEXT: bitcast ; CHECK-NEXT: gc.statepoint %safepoint_token = call i32 (void (i64)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidi64f(void (i64)* undef, i32 1, i32 0, i64 undef, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0) %safepoint_token1 = call i32 (i32 (i64 addrspace(1)*)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i32p1i64f(i32 (i64 addrspace(1)*)* undef, i32 1, i32 0, i64 addrspace(1)* %obj, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0) @@ -262,10 +263,10 @@ join: ; CHECK-LABEL: join: -; CHECK: phi i64 addrspace(1)* [ %obj.relocated, %callbb ], [ %obj, %entry ] +; CHECK: phi i64 addrspace(1)* [ %obj.relocated.casted, %callbb ], [ %obj, %entry ] ; CHECK: phi i64 addrspace(1)* ; CHECK-DAG: [ %obj, %entry ] -; CHECK-DAG: [ %obj2.relocated, %callbb ] +; CHECK-DAG: [ %obj2.relocated.casted, %callbb ] ; This is a phi outside the dominator region of the new defs inserted by ; the safepoint, BUT we can't stop the search here or we miss the second ; phi below.