mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-03-02 22:32:08 +00:00
[objc-arc] Make sure that multiple owners is propogated correctly through the pass via the usage of a global data structure.
rdar://13750319 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@182669 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
36fe3f2b56
commit
35e88e57ea
@ -30,6 +30,7 @@
|
||||
#include "ObjCARCAliasAnalysis.h"
|
||||
#include "ProvenanceAnalysis.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
@ -454,18 +455,8 @@ namespace {
|
||||
/// sequence.
|
||||
SmallPtrSet<Instruction *, 2> ReverseInsertPts;
|
||||
|
||||
/// Does this pointer have multiple owners?
|
||||
///
|
||||
/// In the presence of multiple owners with the same provenance caused by
|
||||
/// allocas, we can not assume that the frontend will emit balanced code
|
||||
/// since it could put the release on the pointer loaded from the
|
||||
/// alloca. This confuses the optimizer so we must be more conservative in
|
||||
/// that case.
|
||||
bool MultipleOwners;
|
||||
|
||||
RRInfo() :
|
||||
KnownSafe(false), IsTailCallRelease(false), ReleaseMetadata(0),
|
||||
MultipleOwners(false) {}
|
||||
KnownSafe(false), IsTailCallRelease(false), ReleaseMetadata(0) {}
|
||||
|
||||
void clear();
|
||||
|
||||
@ -478,7 +469,6 @@ namespace {
|
||||
void RRInfo::clear() {
|
||||
KnownSafe = false;
|
||||
IsTailCallRelease = false;
|
||||
MultipleOwners = false;
|
||||
ReleaseMetadata = 0;
|
||||
Calls.clear();
|
||||
ReverseInsertPts.clear();
|
||||
@ -569,7 +559,6 @@ PtrState::Merge(const PtrState &Other, bool TopDown) {
|
||||
RRI.IsTailCallRelease = RRI.IsTailCallRelease &&
|
||||
Other.RRI.IsTailCallRelease;
|
||||
RRI.Calls.insert(Other.RRI.Calls.begin(), Other.RRI.Calls.end());
|
||||
RRI.MultipleOwners |= Other.RRI.MultipleOwners;
|
||||
|
||||
// Merge the insert point sets. If there are any differences,
|
||||
// that makes this a partial merge.
|
||||
@ -1058,6 +1047,9 @@ namespace {
|
||||
bool Changed;
|
||||
ProvenanceAnalysis PA;
|
||||
|
||||
// This is used to track if a pointer is stored into an alloca.
|
||||
DenseSet<const Value *> MultiOwnersSet;
|
||||
|
||||
/// A flag indicating whether this optimization pass should run.
|
||||
bool Run;
|
||||
|
||||
@ -1943,7 +1935,7 @@ ObjCARCOpt::VisitInstructionBottomUp(Instruction *Inst,
|
||||
BBState::ptr_iterator I = MyStates.findPtrBottomUpState(
|
||||
StripPointerCastsAndObjCCalls(SI->getValueOperand()));
|
||||
if (I != MyStates.bottom_up_ptr_end())
|
||||
I->second.RRI.MultipleOwners = true;
|
||||
MultiOwnersSet.insert(I->first);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -2515,7 +2507,8 @@ ObjCARCOpt::ConnectTDBUTraversals(DenseMap<const BasicBlock *, BBState>
|
||||
assert(It != Retains.end());
|
||||
const RRInfo &NewRetainRRI = It->second;
|
||||
KnownSafeTD &= NewRetainRRI.KnownSafe;
|
||||
MultipleOwners |= NewRetainRRI.MultipleOwners;
|
||||
MultipleOwners =
|
||||
MultipleOwners || MultiOwnersSet.count(GetObjCArg(NewRetain));
|
||||
for (SmallPtrSet<Instruction *, 2>::const_iterator
|
||||
LI = NewRetainRRI.Calls.begin(),
|
||||
LE = NewRetainRRI.Calls.end(); LI != LE; ++LI) {
|
||||
@ -2903,8 +2896,14 @@ bool ObjCARCOpt::OptimizeSequences(Function &F) {
|
||||
bool NestingDetected = Visit(F, BBStates, Retains, Releases);
|
||||
|
||||
// Transform.
|
||||
return PerformCodePlacement(BBStates, Retains, Releases, F.getParent()) &&
|
||||
NestingDetected;
|
||||
bool AnyPairsCompletelyEliminated = PerformCodePlacement(BBStates, Retains,
|
||||
Releases,
|
||||
F.getParent());
|
||||
|
||||
// Cleanup.
|
||||
MultiOwnersSet.clear();
|
||||
|
||||
return AnyPairsCompletelyEliminated && NestingDetected;
|
||||
}
|
||||
|
||||
/// Check if there is a dependent call earlier that does not have anything in
|
||||
|
@ -197,6 +197,103 @@ entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Make sure that if a store is in a different basic block we handle known safe
|
||||
; conservatively.
|
||||
|
||||
|
||||
; CHECK: define void @test2a(i8* %x)
|
||||
; CHECK: @objc_retain(i8* %x)
|
||||
; CHECK: @objc_retain(i8* %x)
|
||||
; CHECK: @objc_release(i8* %y)
|
||||
; CHECK: @objc_release(i8* %x)
|
||||
; CHECK: ret void
|
||||
; CHECK: }
|
||||
define void @test2a(i8* %x) {
|
||||
entry:
|
||||
%A = alloca i8*
|
||||
store i8* %x, i8** %A, align 8
|
||||
%y = load i8** %A
|
||||
br label %bb1
|
||||
|
||||
bb1:
|
||||
br label %bb2
|
||||
|
||||
bb2:
|
||||
br label %bb3
|
||||
|
||||
bb3:
|
||||
tail call i8* @objc_retain(i8* %x)
|
||||
tail call i8* @objc_retain(i8* %x)
|
||||
call void @use_alloca(i8** %A)
|
||||
call void @objc_release(i8* %y), !clang.imprecise_release !0
|
||||
call void @use_pointer(i8* %x)
|
||||
call void @objc_release(i8* %x), !clang.imprecise_release !0
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK: define void @test2b(i8* %x)
|
||||
; CHECK: @objc_retain(i8* %x)
|
||||
; CHECK: @objc_retain(i8* %x)
|
||||
; CHECK: @objc_release(i8* %y)
|
||||
; CHECK: @objc_release(i8* %x)
|
||||
; CHECK: ret void
|
||||
; CHECK: }
|
||||
define void @test2b(i8* %x) {
|
||||
entry:
|
||||
%A = alloca i8*
|
||||
%gep1 = getelementptr i8** %A, i32 0
|
||||
store i8* %x, i8** %gep1, align 8
|
||||
%gep2 = getelementptr i8** %A, i32 0
|
||||
%y = load i8** %gep2
|
||||
br label %bb1
|
||||
|
||||
bb1:
|
||||
br label %bb2
|
||||
|
||||
bb2:
|
||||
br label %bb3
|
||||
|
||||
bb3:
|
||||
tail call i8* @objc_retain(i8* %x)
|
||||
tail call i8* @objc_retain(i8* %x)
|
||||
call void @use_alloca(i8** %A)
|
||||
call void @objc_release(i8* %y), !clang.imprecise_release !0
|
||||
call void @use_pointer(i8* %x)
|
||||
call void @objc_release(i8* %x), !clang.imprecise_release !0
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK: define void @test2c(i8* %x)
|
||||
; CHECK: @objc_retain(i8* %x)
|
||||
; CHECK: @objc_retain(i8* %x)
|
||||
; CHECK: @objc_release(i8* %y)
|
||||
; CHECK: @objc_release(i8* %x)
|
||||
; CHECK: ret void
|
||||
; CHECK: }
|
||||
define void @test2c(i8* %x) {
|
||||
entry:
|
||||
%A = alloca i8*, i32 3
|
||||
%gep1 = getelementptr i8** %A, i32 2
|
||||
store i8* %x, i8** %gep1, align 8
|
||||
%gep2 = getelementptr i8** %A, i32 2
|
||||
%y = load i8** %gep2
|
||||
tail call i8* @objc_retain(i8* %x)
|
||||
br label %bb1
|
||||
|
||||
bb1:
|
||||
br label %bb2
|
||||
|
||||
bb2:
|
||||
br label %bb3
|
||||
|
||||
bb3:
|
||||
tail call i8* @objc_retain(i8* %x)
|
||||
call void @use_alloca(i8** %A)
|
||||
call void @objc_release(i8* %y), !clang.imprecise_release !0
|
||||
call void @use_pointer(i8* %x)
|
||||
call void @objc_release(i8* %x), !clang.imprecise_release !0
|
||||
ret void
|
||||
}
|
||||
|
||||
!0 = metadata !{}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user