mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-25 03:30:37 +00:00
[RewriteStatepointsForGC] Fix a bug on creating gc_relocate for pointer to vector of pointers
Summary: In RewriteStatepointsForGC pass, we create a gc_relocate intrinsic for each relocated pointer, and the gc_relocate has the same type with the pointer. During the creation of gc_relocate intrinsic, llvm requires to mangle its type. However, llvm does not support mangling of all possible types. RewriteStatepointsForGC will hit an assertion failure when it tries to create a gc_relocate for pointer to vector of pointers because mangling for vector of pointers is not supported. This patch changes the way RewriteStatepointsForGC pass creates gc_relocate. For each relocated pointer, we erase the type of pointers and create an unified gc_relocate of type i8 addrspace(1)*. Then a bitcast is inserted to convert the gc_relocate to the correct type. In this way, gc_relocate does not need to deal with different types of pointers and the unsupported type mangling is no longer a problem. This change would also ease further merge when LLVM erases types of pointers and introduces an unified pointer type. Some minor changes are also introduced to gc_relocate related part in InstCombineCalls, CodeGenPrepare, and Verifier accordingly. Patch by Chen Li! Reviewers: reames, AndyAyers, sanjoy Reviewed By: sanjoy Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D9592 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@237009 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
948b20ecb3
commit
5b5782c20e
@ -600,13 +600,51 @@ simplifyRelocatesOffABase(IntrinsicInst *RelocatedBase,
|
||||
// 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<Instruction>(Builder.CreateBitCast(RelocatedBase, Base->getType()));
|
||||
ActualRelocatedBase->removeFromParent();
|
||||
ActualRelocatedBase->insertAfter(cast<Instruction>(RelocatedBase));
|
||||
}
|
||||
Value *Replacement = Builder.CreateGEP(
|
||||
Derived->getSourceElementType(), RelocatedBase, makeArrayRef(OffsetV));
|
||||
Derived->getSourceElementType(), ActualRelocatedBase, makeArrayRef(OffsetV));
|
||||
Instruction *ReplacementInst = cast<Instruction>(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<Instruction>(Builder.CreateBitCast(ReplacementInst, ToReplace->getType()));
|
||||
ActualReplacement->removeFromParent();
|
||||
ActualReplacement->insertAfter(ReplacementInst);
|
||||
}
|
||||
ToReplace->replaceAllUsesWith(ActualReplacement);
|
||||
ToReplace->eraseFromParent();
|
||||
|
||||
MadeChange = true;
|
||||
|
@ -3384,10 +3384,8 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) {
|
||||
"'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;
|
||||
}
|
||||
};
|
||||
|
@ -1202,6 +1202,7 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
|
||||
// preserve relocation semantics.
|
||||
GCRelocateOperands Operands(II);
|
||||
Value *DerivedPtr = Operands.getDerivedPtr();
|
||||
auto *GCRelocateType = cast<PointerType>(II->getType());
|
||||
|
||||
// Remove the relocation if unused, note that this check is required
|
||||
// to prevent the cases below from looping forever.
|
||||
@ -1212,14 +1213,18 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
|
||||
// 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<UndefValue>(DerivedPtr))
|
||||
return ReplaceInstUsesWith(*II, DerivedPtr);
|
||||
if (isa<UndefValue>(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<ConstantPointerNull>(DerivedPtr))
|
||||
return ReplaceInstUsesWith(*II, DerivedPtr);
|
||||
if (isa<ConstantPointerNull>(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))
|
||||
|
@ -1075,7 +1075,10 @@ static void CreateGCRelocates(ArrayRef<llvm::Value *> liveVariables,
|
||||
// the IR, but removes the need for argument bitcasts which shrinks the IR
|
||||
// greatly and makes it much more readable.
|
||||
SmallVector<Type *, 1> 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 @@ insertRelocationStores(iterator_range<Value::user_iterator> gcRelocs,
|
||||
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<AllocaInst>(alloca)->getAllocatedType(),
|
||||
relocatedValue->hasName() ? relocatedValue->getName() + ".casted" : "");
|
||||
|
||||
StoreInst *store = new StoreInst(CastedRelocatedValue, alloca);
|
||||
store->insertAfter(cast<Instruction>(CastedRelocatedValue));
|
||||
|
||||
#ifndef NDEBUG
|
||||
visitedLiveValues.insert(originalValue);
|
||||
|
@ -12,11 +12,11 @@ entry:
|
||||
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)
|
||||
|
@ -13,7 +13,7 @@ entry:
|
||||
|
||||
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 @@ loop: ; preds = %loop, %entry
|
||||
; 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
|
||||
|
@ -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
|
||||
}
|
@ -7,7 +7,8 @@ define i64 addrspace(1)* @test(i64 addrspace(1)* %obj) gc "statepoint-example" {
|
||||
; 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 @@ define <2 x i64 addrspace(1)*> @test2(<2 x i64 addrspace(1)*> %obj) gc "statepoi
|
||||
; 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 @@ define <2 x i64 addrspace(1)*> @test3(<2 x i64 addrspace(1)*>* %ptr) gc "statepo
|
||||
; 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 @@ entry:
|
||||
|
||||
; 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
|
||||
|
@ -13,7 +13,8 @@ entry:
|
||||
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 @@ taken:
|
||||
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 @@ taken:
|
||||
; 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 @@ taken:
|
||||
; 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 @@ entry:
|
||||
; 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 @@ entry:
|
||||
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
|
||||
|
@ -13,8 +13,9 @@ next:
|
||||
; 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)
|
||||
|
@ -23,7 +23,8 @@ unwind_dest:
|
||||
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
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ entry:
|
||||
|
||||
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 @@ use:
|
||||
|
||||
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 @@ entry:
|
||||
|
||||
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 @@ entry:
|
||||
; 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 @@ callbb:
|
||||
|
||||
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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user