mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
This is part of a series of commits to remove reference forwarding for some of the ARC entry points. rdar://22724641.
After this commit, swift_retain will return no reference and LLVMARCContract pass is modified NOT to rewrite swift_retain_noresult to old swift_retain which forwarded the reference. Swift SVN r32075
This commit is contained in:
@@ -137,7 +137,6 @@ extern "C" void swift_slowDealloc(void *ptr, size_t bytes, size_t alignMask);
|
||||
/// Atomically increments the retain count of an object.
|
||||
///
|
||||
/// \param object - may be null, in which case this is a no-op
|
||||
/// \return its argument value exactly
|
||||
///
|
||||
/// POSSIBILITIES: We may end up wanting a bunch of different variants:
|
||||
/// - the general version which correctly handles null values, swift
|
||||
@@ -147,16 +146,15 @@ extern "C" void swift_slowDealloc(void *ptr, size_t bytes, size_t alignMask);
|
||||
/// - maybe a variant that can assume a non-null object
|
||||
/// It may also prove worthwhile to have this use a custom CC
|
||||
/// which preserves a larger set of registers.
|
||||
extern "C" HeapObject *swift_retain(HeapObject *object);
|
||||
extern "C" void swift_retain(HeapObject *object);
|
||||
extern "C" void swift_retain_noresult(HeapObject *object);
|
||||
|
||||
extern "C" HeapObject *swift_retain_n(HeapObject *object, uint32_t n);
|
||||
extern "C" void swift_retain_n(HeapObject *object, uint32_t n);
|
||||
|
||||
static inline HeapObject *_swift_retain_inlined(HeapObject *object) {
|
||||
static inline void _swift_retain_inlined(HeapObject *object) {
|
||||
if (object) {
|
||||
object->refCount.increment();
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
/// Atomically increments the reference count of an object, unless it has
|
||||
@@ -327,7 +325,9 @@ public:
|
||||
swift_release(object);
|
||||
}
|
||||
|
||||
SwiftRAII(const SwiftRAII &other) : object(swift_retain(*other)) {
|
||||
SwiftRAII(const SwiftRAII &other) {
|
||||
swift_retain(*other);
|
||||
object = *other;
|
||||
;
|
||||
}
|
||||
SwiftRAII(SwiftRAII &&other) : object(*other) {
|
||||
@@ -336,7 +336,8 @@ public:
|
||||
SwiftRAII &operator=(const SwiftRAII &other) {
|
||||
if (object)
|
||||
swift_release(object);
|
||||
object = swift_retain(*other);
|
||||
swift_retain(*other);
|
||||
object = *other;
|
||||
return *this;
|
||||
}
|
||||
SwiftRAII &operator=(SwiftRAII &&other) {
|
||||
|
||||
@@ -26,8 +26,8 @@ extern "C" HeapObject *(*_swift_allocObject)(HeapMetadata const *metadata,
|
||||
|
||||
extern "C" BoxPair::Return (*_swift_allocBox)(Metadata const *type);
|
||||
|
||||
extern "C" HeapObject *(*_swift_retain)(HeapObject *object);
|
||||
extern "C" HeapObject *(*_swift_retain_n)(HeapObject *object, uint32_t n);
|
||||
extern "C" void (*_swift_retain)(HeapObject *object);
|
||||
extern "C" void (*_swift_retain_n)(HeapObject *object, uint32_t n);
|
||||
extern "C" HeapObject *(*_swift_tryRetain)(HeapObject *object);
|
||||
extern "C" bool (*_swift_isDeallocating)(HeapObject *object);
|
||||
extern "C" void (*_swift_release)(HeapObject *object);
|
||||
|
||||
@@ -129,7 +129,8 @@ private:
|
||||
auto &M = getModule();
|
||||
auto AttrList = AttributeSet::get(
|
||||
M.getContext(), AttributeSet::FunctionIndex, Attribute::NoUnwind);
|
||||
Retain = M.getOrInsertFunction("swift_retain", AttrList, ObjectPtrTy,
|
||||
Retain = M.getOrInsertFunction("swift_retain", AttrList,
|
||||
Type::getVoidTy(M.getContext()),
|
||||
ObjectPtrTy, nullptr);
|
||||
return Retain.get();
|
||||
}
|
||||
@@ -174,7 +175,8 @@ private:
|
||||
auto *Int32Ty = Type::getInt32Ty(M.getContext());
|
||||
auto AttrList = AttributeSet::get(
|
||||
M.getContext(), AttributeSet::FunctionIndex, Attribute::NoUnwind);
|
||||
RetainN = M.getOrInsertFunction("swift_retain_n", AttrList, ObjectPtrTy,
|
||||
RetainN = M.getOrInsertFunction("swift_retain_n", AttrList,
|
||||
Type::getVoidTy(M.getContext()),
|
||||
ObjectPtrTy, Int32Ty, nullptr);
|
||||
return RetainN.get();
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ STATISTIC(NumRetainReleasesEliminatedByMergingIntoRetainReleaseN,
|
||||
namespace {
|
||||
|
||||
struct LocalState {
|
||||
Value *CurrentLocalUpdate;
|
||||
TinyPtrVector<CallInst *> RetainList;
|
||||
TinyPtrVector<CallInst *> ReleaseList;
|
||||
};
|
||||
@@ -46,9 +45,6 @@ struct LocalState {
|
||||
///
|
||||
/// Optimizations include:
|
||||
///
|
||||
/// - Lowering "retain no return" calls to swift_retain (which return the
|
||||
/// retained argument) to lower register pressure.
|
||||
///
|
||||
/// - Merging together retain and release calls into retain_n, release_n
|
||||
/// - calls.
|
||||
///
|
||||
@@ -63,18 +59,6 @@ class SwiftARCContractImpl {
|
||||
|
||||
/// The entry point builder that is used to construct ARC entry points.
|
||||
ARCEntryPointBuilder B;
|
||||
|
||||
/// Since all of the calls are canonicalized, we know that we can just walk
|
||||
/// through the function and collect the interesting heap object definitions
|
||||
/// by getting the argument to these functions.
|
||||
DenseMap<Value *, TinyPtrVector<Instruction *>> DefsOfValue;
|
||||
|
||||
/// Keep track of which order we see values in since iteration over a densemap
|
||||
/// isn't in a deterministic order, and isn't efficient anyway.
|
||||
///
|
||||
/// TODO: Maybe this should be merged into DefsOfValue in a MapVector?
|
||||
SmallVector<Value *, 16> DefOrder;
|
||||
|
||||
public:
|
||||
SwiftARCContractImpl(Function &InF) : Changed(false), F(InF), B(F) {}
|
||||
|
||||
@@ -82,12 +66,6 @@ public:
|
||||
bool run();
|
||||
|
||||
private:
|
||||
/// Perform single basic block optimizations.
|
||||
///
|
||||
/// This means changing retain_no_return into retains, finding return values,
|
||||
/// and merging retains, releases.
|
||||
void performSingleBBOpts();
|
||||
|
||||
/// Perform the RRN Optimization given the current state that we are
|
||||
/// tracking. This is called at the end of BBs and if we run into an unknown
|
||||
/// call.
|
||||
@@ -107,22 +85,11 @@ performRRNOptimization(DenseMap<Value *, LocalState> &PtrToLocalStateMap) {
|
||||
if (RetainList.size() > 1) {
|
||||
// Create the retainN call right by the first retain.
|
||||
B.setInsertPoint(RetainList[0]);
|
||||
auto &CI = *B.createRetainN(RetainList[0]->getArgOperand(0),
|
||||
RetainList.size());
|
||||
|
||||
// Change the Local Entry to be the new retainN call.
|
||||
P.second.CurrentLocalUpdate = &CI;
|
||||
|
||||
// Change GlobalEntry to track the new retainN instruction instead of
|
||||
// the last retain that was seen.
|
||||
TinyPtrVector<Instruction *> &GlobalEntry = DefsOfValue[ArgVal];
|
||||
GlobalEntry.pop_back();
|
||||
GlobalEntry.push_back(&CI);
|
||||
B.createRetainN(RetainList[0]->getArgOperand(0), RetainList.size());
|
||||
|
||||
// Replace all uses of the retain instructions with our new retainN and
|
||||
// then delete them.
|
||||
for (auto *Inst : RetainList) {
|
||||
Inst->replaceAllUsesWith(&CI);
|
||||
Inst->eraseFromParent();
|
||||
NumRetainReleasesEliminatedByMergingIntoRetainReleaseN++;
|
||||
}
|
||||
@@ -150,11 +117,9 @@ performRRNOptimization(DenseMap<Value *, LocalState> &PtrToLocalStateMap) {
|
||||
}
|
||||
}
|
||||
|
||||
void SwiftARCContractImpl::performSingleBBOpts() {
|
||||
// Do a first pass over the function, collecting all interesting definitions.
|
||||
|
||||
// In this pass, we rewrite any intra-block uses that we can, since the
|
||||
// SSAUpdater doesn't handle them.
|
||||
bool SwiftARCContractImpl::run() {
|
||||
// intra-BB retain/release merging.
|
||||
DenseMap<Value *, LocalState> PtrToLocalStateMap;
|
||||
for (BasicBlock &BB : F) {
|
||||
for (auto II = BB.begin(), IE = BB.end(); II != IE; ) {
|
||||
@@ -172,38 +137,11 @@ void SwiftARCContractImpl::performSingleBBOpts() {
|
||||
case RT_Retain:
|
||||
llvm_unreachable("This should be canonicalized away!");
|
||||
case RT_RetainNoResult: {
|
||||
auto *ArgVal = cast<CallInst>(Inst).getArgOperand(0);
|
||||
|
||||
B.setInsertPoint(&Inst);
|
||||
CallInst &CI = *B.createRetain(ArgVal);
|
||||
Inst.eraseFromParent();
|
||||
|
||||
if (!isa<Instruction>(ArgVal) && !isa<Argument>(ArgVal))
|
||||
continue;
|
||||
|
||||
TinyPtrVector<Instruction *> &GlobalEntry = DefsOfValue[ArgVal];
|
||||
|
||||
// If this is the first definition of a value for the argument that
|
||||
// we've seen, keep track of it in DefOrder.
|
||||
if (GlobalEntry.empty())
|
||||
DefOrder.push_back(ArgVal);
|
||||
auto *CI = cast<CallInst>(&Inst);
|
||||
auto *ArgVal = CI->getArgOperand(0);
|
||||
|
||||
LocalState &LocalEntry = PtrToLocalStateMap[ArgVal];
|
||||
|
||||
// Check to see if there is already an entry for this basic block. If
|
||||
// there is another local entry, switch to using the local value and
|
||||
// remove the previous value from the GlobalEntry.
|
||||
if (LocalEntry.CurrentLocalUpdate) {
|
||||
Changed = true;
|
||||
CI.setArgOperand(0, LocalEntry.CurrentLocalUpdate);
|
||||
assert(GlobalEntry.back() == LocalEntry.CurrentLocalUpdate &&
|
||||
"Local/Global mismatch?");
|
||||
GlobalEntry.pop_back();
|
||||
}
|
||||
|
||||
LocalEntry.CurrentLocalUpdate = &CI;
|
||||
LocalEntry.RetainList.push_back(&CI);
|
||||
GlobalEntry.push_back(&CI);
|
||||
LocalEntry.RetainList.push_back(CI);
|
||||
continue;
|
||||
}
|
||||
case RT_Release: {
|
||||
@@ -226,22 +164,9 @@ void SwiftARCContractImpl::performSingleBBOpts() {
|
||||
case RT_CheckUnowned:
|
||||
case RT_ObjCRelease:
|
||||
case RT_ObjCRetain:
|
||||
// Just remap any uses in the value.
|
||||
break;
|
||||
}
|
||||
|
||||
// Check to see if there are any uses of a value in the LocalUpdates
|
||||
// map. If so, remap it now to the locally defined version.
|
||||
for (unsigned i = 0, e = Inst.getNumOperands(); i != e; ++i) {
|
||||
auto Iter = PtrToLocalStateMap.find(Inst.getOperand(i));
|
||||
if (Iter != PtrToLocalStateMap.end()) {
|
||||
if (Value *V = Iter->second.CurrentLocalUpdate) {
|
||||
Changed = true;
|
||||
Inst.setOperand(i, V);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Kind != RT_Unknown)
|
||||
continue;
|
||||
|
||||
@@ -271,64 +196,6 @@ void SwiftARCContractImpl::performSingleBBOpts() {
|
||||
performRRNOptimization(PtrToLocalStateMap);
|
||||
PtrToLocalStateMap.clear();
|
||||
}
|
||||
}
|
||||
|
||||
bool SwiftARCContractImpl::run() {
|
||||
// Perform single BB optimizations and gather information in prepration for
|
||||
// the multiple BB optimizations.
|
||||
performSingleBBOpts();
|
||||
|
||||
// Now that we've collected all of the interesting heap object values that are
|
||||
// passed into argument-returning functions, rewrite uses of these pointers
|
||||
// with optimized lifetime-shorted versions of it.
|
||||
for (Value *Ptr : DefOrder) {
|
||||
// If Ptr is an instruction, remember its block. If not, use the entry
|
||||
// block as its block (it must be an argument, constant, etc).
|
||||
BasicBlock *PtrBlock;
|
||||
if (auto *PI = dyn_cast<Instruction>(Ptr))
|
||||
PtrBlock = PI->getParent();
|
||||
else
|
||||
PtrBlock = &F.getEntryBlock();
|
||||
|
||||
TinyPtrVector<Instruction *> &Defs = DefsOfValue[Ptr];
|
||||
// This is the same problem as SSA construction, so we just use LLVM's
|
||||
// SSAUpdater, with each retain as a definition of the virtual value.
|
||||
SSAUpdater Updater;
|
||||
Updater.Initialize(Ptr->getType(), Ptr->getName());
|
||||
|
||||
// Set the return value of each of these calls as a definition of the
|
||||
// virtual value.
|
||||
for (auto *D : Defs)
|
||||
Updater.AddAvailableValue(D->getParent(), D);
|
||||
|
||||
// If we didn't add a definition for Ptr's block, then Ptr itself is
|
||||
// available in its block.
|
||||
if (!Updater.HasValueForBlock(PtrBlock))
|
||||
Updater.AddAvailableValue(PtrBlock, Ptr);
|
||||
|
||||
// Rewrite uses of Ptr to their optimized forms.
|
||||
//
|
||||
// NOTE: We are assuming that our Ptrs are not constants meaning that we
|
||||
// know that users can not be constant expressions.
|
||||
for (auto UI = Ptr->user_begin(), E = Ptr->user_end(); UI != E; ) {
|
||||
// Make sure to increment the use iterator before potentially rewriting
|
||||
// it.
|
||||
Use &U = UI.getUse();
|
||||
++UI;
|
||||
|
||||
// If the use is in the same block that defines it and the User is not a
|
||||
// PHI node, then this is a local use that shouldn't be rewritten.
|
||||
auto *User = cast<Instruction>(U.getUser());
|
||||
if (User->getParent() == PtrBlock && !isa<PHINode>(User))
|
||||
continue;
|
||||
|
||||
// Otherwise, change it if profitable!
|
||||
Updater.RewriteUse(U);
|
||||
|
||||
if (U.get() != Ptr)
|
||||
Changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return Changed;
|
||||
}
|
||||
|
||||
@@ -95,7 +95,8 @@ swift::swift_getErrorValue(const SwiftError *errorObject,
|
||||
|
||||
SwiftError *
|
||||
swift::swift_errorRetain(SwiftError *object) {
|
||||
return static_cast<SwiftError*>(swift_retain(object));
|
||||
swift_retain(object);
|
||||
return static_cast<SwiftError*>(object);
|
||||
}
|
||||
|
||||
void swift::swift_errorRelease(SwiftError *object) {
|
||||
|
||||
@@ -281,24 +281,23 @@ swift::swift_retain_noresult(HeapObject *object) {
|
||||
swift_retain(object);
|
||||
}
|
||||
|
||||
HeapObject *swift::swift_retain(HeapObject *object) {
|
||||
void swift::swift_retain(HeapObject *object) {
|
||||
SWIFT_RETAIN();
|
||||
return _swift_retain(object);
|
||||
_swift_retain(object);
|
||||
}
|
||||
static HeapObject *_swift_retain_(HeapObject *object) {
|
||||
return _swift_retain_inlined(object);
|
||||
static void _swift_retain_(HeapObject *object) {
|
||||
_swift_retain_inlined(object);
|
||||
}
|
||||
auto swift::_swift_retain = _swift_retain_;
|
||||
|
||||
HeapObject *swift::swift_retain_n(HeapObject *object, uint32_t n) {
|
||||
void swift::swift_retain_n(HeapObject *object, uint32_t n) {
|
||||
SWIFT_RETAIN();
|
||||
return _swift_retain_n(object, n);
|
||||
_swift_retain_n(object, n);
|
||||
}
|
||||
static HeapObject *_swift_retain_n_(HeapObject *object, uint32_t n) {
|
||||
static void _swift_retain_n_(HeapObject *object, uint32_t n) {
|
||||
if (object) {
|
||||
object->refCount.increment(n);
|
||||
}
|
||||
return object;
|
||||
}
|
||||
auto swift::_swift_retain_n = _swift_retain_n_;
|
||||
|
||||
|
||||
@@ -273,7 +273,8 @@ template <class Impl, class T> struct RetainableBoxBase {
|
||||
struct SwiftRetainableBox :
|
||||
RetainableBoxBase<SwiftRetainableBox, HeapObject*> {
|
||||
static HeapObject *retain(HeapObject *obj) {
|
||||
return swift_retain(obj);
|
||||
swift_retain(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
static void release(HeapObject *obj) {
|
||||
@@ -443,7 +444,8 @@ struct UnknownRetainableBox : RetainableBoxBase<UnknownRetainableBox, void*> {
|
||||
#if SWIFT_OBJC_INTEROP
|
||||
return swift_unknownRetain(obj);
|
||||
#else
|
||||
return swift_retain(static_cast<HeapObject *>(obj));
|
||||
swift_retain(static_cast<HeapObject *>(obj));
|
||||
return static_cast<HeapObject *>(obj);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -569,8 +569,10 @@ static bool usesNativeSwiftReferenceCounting_unowned(const void *object) {
|
||||
void *swift::swift_unknownRetain_n(void *object, int n) {
|
||||
void *objc_ret = nullptr;
|
||||
if (isObjCTaggedPointerOrNull(object)) return object;
|
||||
if (usesNativeSwiftReferenceCounting_allocated(object))
|
||||
return swift_retain_n(static_cast<HeapObject *>(object), n);
|
||||
if (usesNativeSwiftReferenceCounting_allocated(object)) {
|
||||
swift_retain_n(static_cast<HeapObject *>(object), n);
|
||||
return static_cast<HeapObject *>(object);
|
||||
}
|
||||
for (int i = 0; i < n; ++i)
|
||||
objc_ret = objc_retain(static_cast<id>(object));
|
||||
return objc_ret;
|
||||
@@ -586,8 +588,10 @@ void swift::swift_unknownRelease_n(void *object, int n) {
|
||||
|
||||
void *swift::swift_unknownRetain(void *object) {
|
||||
if (isObjCTaggedPointerOrNull(object)) return object;
|
||||
if (usesNativeSwiftReferenceCounting_allocated(object))
|
||||
return swift_retain(static_cast<HeapObject *>(object));
|
||||
if (usesNativeSwiftReferenceCounting_allocated(object)) {
|
||||
swift_retain(static_cast<HeapObject *>(object));
|
||||
return static_cast<HeapObject *>(object);
|
||||
}
|
||||
return objc_retain(static_cast<id>(object));
|
||||
}
|
||||
|
||||
@@ -627,11 +631,14 @@ void *swift::swift_bridgeObjectRetain(void *object) {
|
||||
auto const objectRef = toPlainObject_unTagged_bridgeObject(object);
|
||||
|
||||
#if SWIFT_OBJC_INTEROP
|
||||
if (!isNonNative_unTagged_bridgeObject(object))
|
||||
return swift_retain(static_cast<HeapObject *>(objectRef));
|
||||
if (!isNonNative_unTagged_bridgeObject(object)) {
|
||||
swift_retain(static_cast<HeapObject *>(objectRef));
|
||||
return static_cast<HeapObject *>(objectRef);
|
||||
}
|
||||
return objc_retain(static_cast<id>(objectRef));
|
||||
#else
|
||||
return swift_retain(static_cast<HeapObject *>(objectRef));
|
||||
swift_retain(static_cast<HeapObject *>(objectRef));
|
||||
return static_cast<HeapObject *>(objectRef);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -662,13 +669,16 @@ void *swift::swift_bridgeObjectRetain_n(void *object, int n) {
|
||||
|
||||
#if SWIFT_OBJC_INTEROP
|
||||
void *objc_ret = nullptr;
|
||||
if (!isNonNative_unTagged_bridgeObject(object))
|
||||
return swift_retain_n(static_cast<HeapObject *>(objectRef), n);
|
||||
if (!isNonNative_unTagged_bridgeObject(object)) {
|
||||
swift_retain_n(static_cast<HeapObject *>(objectRef), n);
|
||||
return static_cast<HeapObject *>(objectRef);
|
||||
}
|
||||
for (int i = 0;i < n; ++i)
|
||||
objc_ret = objc_retain(static_cast<id>(objectRef));
|
||||
return objc_ret;
|
||||
#else
|
||||
return swift_retain_n(static_cast<HeapObject *>(objectRef), n);
|
||||
swift_retain_n(static_cast<HeapObject *>(objectRef), n);
|
||||
return static_cast<HeapObject *>(objectRef);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ target triple = "x86_64-apple-macosx10.9"
|
||||
|
||||
declare %swift.refcounted* @swift_allocObject(%swift.heapmetadata* , i64, i64) nounwind
|
||||
declare void @swift_release(%swift.refcounted* nocapture)
|
||||
declare %swift.refcounted* @swift_retain(%swift.refcounted* ) nounwind
|
||||
declare void @swift_retain(%swift.refcounted* ) nounwind
|
||||
declare void @swift_retain_noresult(%swift.refcounted* nocapture) nounwind
|
||||
declare void @swift_fixLifetime(%swift.refcounted*)
|
||||
declare void @noread_user(%swift.refcounted*) readnone
|
||||
@@ -23,32 +23,22 @@ entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
; CHECK-LABEL: define void @swift_contractNoresultTest
|
||||
; CHECK: call %swift.refcounted* @swift_retain(%swift.refcounted* %A), !dbg
|
||||
define void @swift_contractNoresultTest(%swift.refcounted* %A) {
|
||||
tail call void @swift_retain_noresult(%swift.refcounted* %A), !dbg !0
|
||||
tail call void @swift_release(%swift.refcounted* %A) nounwind
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: define %swift.refcounted* @swift_contractRetainN(%swift.refcounted* %A) {
|
||||
; CHECK: entry:
|
||||
; CHECK-NEXT: br i1 undef
|
||||
; CHECK: bb1:
|
||||
; CHECK-NEXT: [[RET1:%.+]] = tail call %swift.refcounted* @swift_retain_n(%swift.refcounted* %A, i32 2)
|
||||
; CHECK-NEXT: call void @noread_user(%swift.refcounted* [[RET1]])
|
||||
; CHECK-NEXT: call void @noread_user(%swift.refcounted* [[RET1]])
|
||||
; CHECK-NEXT: tail call void @swift_retain_n(%swift.refcounted* %A, i32 2)
|
||||
; CHECK-NEXT: call void @noread_user(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: call void @noread_user(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: br label %bb3
|
||||
; CHECK: bb2:
|
||||
; CHECK-NEXT: call void @noread_user(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: [[RET2:%.+]] = tail call %swift.refcounted* @swift_retain(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: call void @noread_user(%swift.refcounted* [[RET2]])
|
||||
; CHECK-NEXT: tail call void @swift_retain_noresult(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: call void @noread_user(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: br label %bb3
|
||||
; CHECK: bb3:
|
||||
; CHECK-NEXT: [[PHIRESULT:%.+]] = phi %swift.refcounted* [ [[RET2]], %bb2 ], [ [[RET1]], %bb1 ]
|
||||
; CHECK-NEXT: [[RET3:%.+]] = tail call %swift.refcounted* @swift_retain(%swift.refcounted* [[PHIRESULT]])
|
||||
; CHECK-NEXT: ret %swift.refcounted* [[RET3]]
|
||||
; CHECK-NEXT: tail call void @swift_retain_noresult(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: ret %swift.refcounted* %A
|
||||
define %swift.refcounted* @swift_contractRetainN(%swift.refcounted* %A) {
|
||||
entry:
|
||||
br i1 undef, label %bb1, label %bb2
|
||||
@@ -163,27 +153,26 @@ bb3:
|
||||
; But do make sure that we can form retainN, releaseN in between such uses
|
||||
; CHECK-LABEL: define %swift.refcounted* @swift_contractRetainNInterleavedWithUnknown(%swift.refcounted* %A) {
|
||||
; CHECK: bb1:
|
||||
; CHECK: [[RET1:%.*]] = tail call %swift.refcounted* @swift_retain(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: call void @user(%swift.refcounted* [[RET1]])
|
||||
; CHECK-NEXT: [[RET2:%.*]] = tail call %swift.refcounted* @swift_retain_n(%swift.refcounted* [[RET1]], i32 3)
|
||||
; CHECK-NEXT: call void @noread_user(%swift.refcounted* [[RET2]])
|
||||
; CHECK-NEXT: call void @noread_user(%swift.refcounted* [[RET2]])
|
||||
; CHECK-NEXT: call void @user(%swift.refcounted* [[RET2]])
|
||||
; CHECK-NEXT: [[RET3:%.*]] = tail call %swift.refcounted* @swift_retain_n(%swift.refcounted* [[RET2]], i32 2)
|
||||
; CHECK-NEXT: call void @user(%swift.refcounted* [[RET3]])
|
||||
; CHECK-NEXT: [[RET4:%.*]] = tail call %swift.refcounted* @swift_retain(%swift.refcounted* [[RET3]])
|
||||
; CHECK: tail call void @swift_retain_noresult(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: call void @user(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: tail call void @swift_retain_n(%swift.refcounted* %A, i32 3)
|
||||
; CHECK-NEXT: call void @noread_user(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: call void @noread_user(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: call void @user(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: tail call void @swift_retain_n(%swift.refcounted* %A, i32 2)
|
||||
; CHECK-NEXT: call void @user(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: tail call void @swift_retain_noresult(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: br label %bb3
|
||||
|
||||
; CHECK: bb2:
|
||||
; CHECK-NEXT: call void @user(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: [[RET5:%.*]] = tail call %swift.refcounted* @swift_retain(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: call void @user(%swift.refcounted* [[RET5]])
|
||||
; CHECK-NEXT: tail call void @swift_retain_noresult(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: call void @user(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: br label %bb3
|
||||
|
||||
; CHECK: bb3:
|
||||
; CHECK-NEXT: [[PHIRET:%.*]] = phi %swift.refcounted* [ [[RET5]], %bb2 ], [ [[RET4]], %bb1 ]
|
||||
; CHECK-NEXT: [[FINALRET:%.*]] = tail call %swift.refcounted* @swift_retain(%swift.refcounted* [[PHIRET]])
|
||||
; CHECK-NEXT: ret %swift.refcounted* [[FINALRET]]
|
||||
; CHECK-NEXT: tail call void @swift_retain_noresult(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: ret %swift.refcounted* %A
|
||||
define %swift.refcounted* @swift_contractRetainNInterleavedWithUnknown(%swift.refcounted* %A) {
|
||||
entry:
|
||||
br i1 undef, label %bb1, label %bb2
|
||||
@@ -248,17 +237,17 @@ bb3:
|
||||
|
||||
; CHECK-LABEL: define %swift.refcounted* @swift_contractRetainReleaseNInterleavedWithUnknown(%swift.refcounted* %A) {
|
||||
; CHECK: bb1:
|
||||
; CHECK-NEXT: [[RET1:%.*]] = tail call %swift.refcounted* @swift_retain(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: call void @user(%swift.refcounted* [[RET1]])
|
||||
; CHECK-NEXT: call void @noread_user(%swift.refcounted* [[RET1]])
|
||||
; CHECK-NEXT: tail call void @swift_release_n(%swift.refcounted* [[RET1]], i32 2)
|
||||
; CHECK-NEXT: call void @user(%swift.refcounted* [[RET1]])
|
||||
; CHECK-NEXT: [[RET2:%.*]] = tail call %swift.refcounted* @swift_retain_n(%swift.refcounted* [[RET1]], i32 2)
|
||||
; CHECK-NEXT: tail call void @swift_release(%swift.refcounted* [[RET2]])
|
||||
; CHECK-NEXT: call void @user(%swift.refcounted* [[RET2]])
|
||||
; CHECK-NEXT: call void @noread_user(%swift.refcounted* [[RET2]])
|
||||
; CHECK-NEXT: tail call void @swift_release_n(%swift.refcounted* [[RET2]], i32 2)
|
||||
; CHECK-NEXT: call void @user(%swift.refcounted* [[RET2]])
|
||||
; CHECK-NEXT: tail call void @swift_retain_noresult(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: call void @user(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: call void @noread_user(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: tail call void @swift_release_n(%swift.refcounted* %A, i32 2)
|
||||
; CHECK-NEXT: call void @user(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: tail call void @swift_retain_n(%swift.refcounted* %A, i32 2)
|
||||
; CHECK-NEXT: tail call void @swift_release(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: call void @user(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: call void @noread_user(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: tail call void @swift_release_n(%swift.refcounted* %A, i32 2)
|
||||
; CHECK-NEXT: call void @user(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: br label %bb3
|
||||
; CHECK: bb2:
|
||||
; CHECK-NEXT: call void @user(%swift.refcounted* %A)
|
||||
@@ -267,9 +256,8 @@ bb3:
|
||||
; CHECK-NEXT: br label %bb3
|
||||
|
||||
; CHECK: bb3:
|
||||
; CHECK-NEXT: [[PHIRET:%.*]] = phi %swift.refcounted* [ %A, %bb2 ], [ [[RET2]], %bb1 ]
|
||||
; CHECK-NEXT: tail call void @swift_release(%swift.refcounted* [[PHIRET]])
|
||||
; CHECK-NEXT: ret %swift.refcounted* [[PHIRET]]
|
||||
; CHECK-NEXT: tail call void @swift_release(%swift.refcounted* %A)
|
||||
; CHECK-NEXT: ret %swift.refcounted* %A
|
||||
define %swift.refcounted* @swift_contractRetainReleaseNInterleavedWithUnknown(%swift.refcounted* %A) {
|
||||
entry:
|
||||
br i1 undef, label %bb1, label %bb2
|
||||
|
||||
@@ -59,8 +59,7 @@ TEST(RefcountingTest, retain_release) {
|
||||
size_t value = 0;
|
||||
auto object = allocTestObject(&value, 1);
|
||||
EXPECT_EQ(0u, value);
|
||||
auto retainResult = swift_retain(object);
|
||||
EXPECT_EQ(object, retainResult);
|
||||
swift_retain(object);
|
||||
EXPECT_EQ(0u, value);
|
||||
swift_release(object);
|
||||
EXPECT_EQ(0u, value);
|
||||
@@ -103,10 +102,8 @@ TEST(RefcountingTest, retain_release_n) {
|
||||
size_t value = 0;
|
||||
auto object = allocTestObject(&value, 1);
|
||||
EXPECT_EQ(0u, value);
|
||||
auto retainResult = swift_retain_n(object, 32);
|
||||
EXPECT_EQ(object, retainResult);
|
||||
retainResult = swift_retain(object);
|
||||
EXPECT_EQ(object, retainResult);
|
||||
swift_retain_n(object, 32);
|
||||
swift_retain(object);
|
||||
EXPECT_EQ(0u, value);
|
||||
EXPECT_EQ(34u, swift_retainCount(object));
|
||||
swift_release_n(object, 31);
|
||||
|
||||
Reference in New Issue
Block a user