mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-27 15:29:51 +00:00
Don't eliminate objc_retainBlock calls on stack objects if the
objc_retainBlock call is potentially responsible for copying the block to the heap to extend its lifetime. rdar://10209613. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@140814 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
026fa8782c
commit
597fece886
@ -2338,6 +2338,11 @@ ObjCARCOpt::VisitBottomUp(BasicBlock *BB,
|
|||||||
S.SetAtLeastOneRefCount();
|
S.SetAtLeastOneRefCount();
|
||||||
S.DecrementNestCount();
|
S.DecrementNestCount();
|
||||||
|
|
||||||
|
// An objc_retainBlock call with just a use still needs to be kept,
|
||||||
|
// because it may be copying a block from the stack to the heap.
|
||||||
|
if (Class == IC_RetainBlock && S.GetSeq() == S_Use)
|
||||||
|
S.SetSeq(S_CanRelease);
|
||||||
|
|
||||||
switch (S.GetSeq()) {
|
switch (S.GetSeq()) {
|
||||||
case S_Stop:
|
case S_Stop:
|
||||||
case S_Release:
|
case S_Release:
|
||||||
@ -2406,14 +2411,14 @@ ObjCARCOpt::VisitBottomUp(BasicBlock *BB,
|
|||||||
case S_Release:
|
case S_Release:
|
||||||
case S_MovableRelease:
|
case S_MovableRelease:
|
||||||
if (CanUse(Inst, Ptr, PA, Class)) {
|
if (CanUse(Inst, Ptr, PA, Class)) {
|
||||||
S.RRI.ReverseInsertPts.clear();
|
assert(S.RRI.ReverseInsertPts.empty());
|
||||||
S.RRI.ReverseInsertPts.insert(Inst);
|
S.RRI.ReverseInsertPts.insert(Inst);
|
||||||
S.SetSeq(S_Use);
|
S.SetSeq(S_Use);
|
||||||
} else if (Seq == S_Release &&
|
} else if (Seq == S_Release &&
|
||||||
(Class == IC_User || Class == IC_CallOrUser)) {
|
(Class == IC_User || Class == IC_CallOrUser)) {
|
||||||
// Non-movable releases depend on any possible objc pointer use.
|
// Non-movable releases depend on any possible objc pointer use.
|
||||||
S.SetSeq(S_Stop);
|
S.SetSeq(S_Stop);
|
||||||
S.RRI.ReverseInsertPts.clear();
|
assert(S.RRI.ReverseInsertPts.empty());
|
||||||
S.RRI.ReverseInsertPts.insert(Inst);
|
S.RRI.ReverseInsertPts.insert(Inst);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -2566,7 +2571,7 @@ ObjCARCOpt::VisitTopDown(BasicBlock *BB,
|
|||||||
switch (Seq) {
|
switch (Seq) {
|
||||||
case S_Retain:
|
case S_Retain:
|
||||||
S.SetSeq(S_CanRelease);
|
S.SetSeq(S_CanRelease);
|
||||||
S.RRI.ReverseInsertPts.clear();
|
assert(S.RRI.ReverseInsertPts.empty());
|
||||||
S.RRI.ReverseInsertPts.insert(Inst);
|
S.RRI.ReverseInsertPts.insert(Inst);
|
||||||
|
|
||||||
// One call can't cause a transition from S_Retain to S_CanRelease
|
// One call can't cause a transition from S_Retain to S_CanRelease
|
||||||
@ -2590,8 +2595,18 @@ ObjCARCOpt::VisitTopDown(BasicBlock *BB,
|
|||||||
if (CanUse(Inst, Ptr, PA, Class))
|
if (CanUse(Inst, Ptr, PA, Class))
|
||||||
S.SetSeq(S_Use);
|
S.SetSeq(S_Use);
|
||||||
break;
|
break;
|
||||||
case S_Use:
|
|
||||||
case S_Retain:
|
case S_Retain:
|
||||||
|
// An objc_retainBlock call may be responsible for copying the block
|
||||||
|
// data from the stack to the heap. Model this by moving it straight
|
||||||
|
// from S_Retain to S_Use.
|
||||||
|
if (S.RRI.IsRetainBlock &&
|
||||||
|
CanUse(Inst, Ptr, PA, Class)) {
|
||||||
|
assert(S.RRI.ReverseInsertPts.empty());
|
||||||
|
S.RRI.ReverseInsertPts.insert(Inst);
|
||||||
|
S.SetSeq(S_Use);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case S_Use:
|
||||||
case S_None:
|
case S_None:
|
||||||
break;
|
break;
|
||||||
case S_Stop:
|
case S_Stop:
|
||||||
@ -2743,17 +2758,23 @@ ObjCARCOpt::PerformCodePlacement(DenseMap<const BasicBlock *, BBState>
|
|||||||
SmallVector<Instruction *, 8> DeadInsts;
|
SmallVector<Instruction *, 8> DeadInsts;
|
||||||
|
|
||||||
for (MapVector<Value *, RRInfo>::const_iterator I = Retains.begin(),
|
for (MapVector<Value *, RRInfo>::const_iterator I = Retains.begin(),
|
||||||
E = Retains.end(); I != E; ) {
|
E = Retains.end(); I != E; ++I) {
|
||||||
Value *V = (I++)->first;
|
Value *V = I->first;
|
||||||
if (!V) continue; // blotted
|
if (!V) continue; // blotted
|
||||||
|
|
||||||
Instruction *Retain = cast<Instruction>(V);
|
Instruction *Retain = cast<Instruction>(V);
|
||||||
Value *Arg = GetObjCArg(Retain);
|
Value *Arg = GetObjCArg(Retain);
|
||||||
|
|
||||||
// If the object being released is in static or stack storage, we know it's
|
// If the object being released is in static storage, we know it's
|
||||||
// not being managed by ObjC reference counting, so we can delete pairs
|
// not being managed by ObjC reference counting, so we can delete pairs
|
||||||
// regardless of what possible decrements or uses lie between them.
|
// regardless of what possible decrements or uses lie between them.
|
||||||
bool KnownSafe = isa<Constant>(Arg) || isa<AllocaInst>(Arg);
|
bool KnownSafe = isa<Constant>(Arg);
|
||||||
|
|
||||||
|
// Same for stack storage, unless this is an objc_retainBlock call,
|
||||||
|
// which is responsible for copying the block data from the stack to
|
||||||
|
// the heap.
|
||||||
|
if (!I->second.IsRetainBlock && isa<AllocaInst>(Arg))
|
||||||
|
KnownSafe = true;
|
||||||
|
|
||||||
// A constant pointer can't be pointing to an object on the heap. It may
|
// A constant pointer can't be pointing to an object on the heap. It may
|
||||||
// be reference-counted, but it won't be deleted.
|
// be reference-counted, but it won't be deleted.
|
||||||
|
54
test/Transforms/ObjCARC/retain-block-alloca.ll
Normal file
54
test/Transforms/ObjCARC/retain-block-alloca.ll
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
; RUN: opt -S -objc-arc < %s | FileCheck %s
|
||||||
|
; rdar://10209613
|
||||||
|
|
||||||
|
; CHECK: define void @test
|
||||||
|
; CHECK: %3 = call i8* @objc_retainBlock(i8* %2) nounwind
|
||||||
|
; CHECK: @objc_msgSend
|
||||||
|
; CHECK-NEXT: @objc_release(i8* %3)
|
||||||
|
|
||||||
|
%0 = type opaque
|
||||||
|
%struct.__block_descriptor = type { i64, i64 }
|
||||||
|
|
||||||
|
@_NSConcreteStackBlock = external global i8*
|
||||||
|
@__block_descriptor_tmp = external hidden constant { i64, i64, i8*, i8*, i8*, i8* }
|
||||||
|
@"\01L_OBJC_SELECTOR_REFERENCES_" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
|
||||||
|
|
||||||
|
define void @test(%0* %array) uwtable {
|
||||||
|
entry:
|
||||||
|
%block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>, align 8
|
||||||
|
%0 = bitcast %0* %array to i8*
|
||||||
|
%1 = tail call i8* @objc_retain(i8* %0) nounwind
|
||||||
|
%block.isa = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 0
|
||||||
|
store i8* bitcast (i8** @_NSConcreteStackBlock to i8*), i8** %block.isa, align 8
|
||||||
|
%block.flags = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 1
|
||||||
|
store i32 1107296256, i32* %block.flags, align 8
|
||||||
|
%block.reserved = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 2
|
||||||
|
store i32 0, i32* %block.reserved, align 4
|
||||||
|
%block.invoke = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 3
|
||||||
|
store i8* bitcast (void (i8*)* @__test_block_invoke_0 to i8*), i8** %block.invoke, align 8
|
||||||
|
%block.descriptor = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 4
|
||||||
|
store %struct.__block_descriptor* bitcast ({ i64, i64, i8*, i8*, i8*, i8* }* @__block_descriptor_tmp to %struct.__block_descriptor*), %struct.__block_descriptor** %block.descriptor, align 8
|
||||||
|
%block.captured = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 5
|
||||||
|
store %0* %array, %0** %block.captured, align 8
|
||||||
|
%2 = bitcast <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block to i8*
|
||||||
|
%3 = call i8* @objc_retainBlock(i8* %2) nounwind
|
||||||
|
%tmp2 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
|
||||||
|
call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8*)*)(i8* %0, i8* %tmp2, i8* %3)
|
||||||
|
call void @objc_release(i8* %3) nounwind
|
||||||
|
%strongdestroy = load %0** %block.captured, align 8
|
||||||
|
%4 = bitcast %0* %strongdestroy to i8*
|
||||||
|
call void @objc_release(i8* %4) nounwind, !clang.imprecise_release !0
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare i8* @objc_retain(i8*)
|
||||||
|
|
||||||
|
declare void @__test_block_invoke_0(i8* nocapture) uwtable
|
||||||
|
|
||||||
|
declare i8* @objc_retainBlock(i8*)
|
||||||
|
|
||||||
|
declare i8* @objc_msgSend(i8*, i8*, ...) nonlazybind
|
||||||
|
|
||||||
|
declare void @objc_release(i8*)
|
||||||
|
|
||||||
|
!0 = metadata !{}
|
Loading…
Reference in New Issue
Block a user