Skip to content

[arc] A value loaded from an @in_guaranteed parameter is @guaranteed. #1662

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 39 additions & 17 deletions lib/SILOptimizer/ARC/RCStateTransitionVisitors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,43 @@ visitAutoreleasePoolCall(ValueBase *V) {
return DataflowResult(RCStateTransitionDataflowResultKind::NoEffects);
}

// private helper method since C++ does not have extensions... *sigh*.
//
// TODO: This needs a better name.
template <class ARCState>
static bool isKnownSafe(BottomUpDataflowRCStateVisitor<ARCState> *State,
SILInstruction *I, SILValue Op) {
// If we are running with 'frozen' owned arg releases, check if we have a
// frozen use in the side table. If so, this release must be known safe.
if (State->FreezeOwnedArgEpilogueReleases)
if (auto *OwnedRelease =
State->EpilogueReleaseMatcher.getSingleReleaseForArgument(Op))
if (I != OwnedRelease)
return true;

// A guaranteed function argument is guaranteed to outlive the function we are
// processing. So bottom up for such a parameter, we are always known safe.
if (auto *Arg = dyn_cast<SILArgument>(Op)) {
if (Arg->isFunctionArg() &&
Arg->hasConvention(SILArgumentConvention::Direct_Guaranteed)) {
return true;
}
}

// If Op is a load from an in_guaranteed parameter, it is guaranteed as well.
if (auto *LI = dyn_cast<LoadInst>(Op)) {
SILValue RCIdentity = State->RCFI->getRCIdentityRoot(LI->getOperand());
if (auto *Arg = dyn_cast<SILArgument>(RCIdentity)) {
if (Arg->isFunctionArg() &&
Arg->hasConvention(SILArgumentConvention::Indirect_In_Guaranteed)) {
return true;
}
}
}

return false;
}

template <class ARCState>
typename BottomUpDataflowRCStateVisitor<ARCState>::DataflowResult
BottomUpDataflowRCStateVisitor<ARCState>::visitStrongDecrement(ValueBase *V) {
Expand All @@ -70,23 +107,8 @@ BottomUpDataflowRCStateVisitor<ARCState>::visitStrongDecrement(ValueBase *V) {
BottomUpRefCountState &State = DataflowState.getBottomUpRefCountState(Op);
bool NestingDetected = State.initWithMutatorInst(SetFactory.get(I), RCFI);

// If we are running with 'frozen' owned arg releases, check if we have a
// frozen use in the side table. If so, this release must be known safe.
if (FreezeOwnedArgEpilogueReleases) {
if (auto *OwnedRelease = EpilogueReleaseMatcher.getSingleReleaseForArgument(Op)) {
if (I != OwnedRelease) {
State.updateKnownSafe(true);
}
}
}

// A guaranteed function argument is guaranteed to outlive the function we are
// processing. So bottom up for such a parameter, we are always known safe.
if (auto *Arg = dyn_cast<SILArgument>(Op)) {
if (Arg->isFunctionArg() &&
Arg->hasConvention(SILArgumentConvention::Direct_Guaranteed)) {
State.updateKnownSafe(true);
}
if (isKnownSafe(this, I, Op)) {
State.updateKnownSafe(true);
}

DEBUG(llvm::dbgs() << " REF COUNT DECREMENT! Known Safe: "
Expand Down
16 changes: 16 additions & 0 deletions test/SILOptimizer/arcsequenceopts.sil
Original file line number Diff line number Diff line change
Expand Up @@ -2130,4 +2130,20 @@ bb0(%0 : $Builtin.NativeObject):
apply %1(%0) : $@convention(thin) (Builtin.NativeObject) -> ()
strong_release %0 : $Builtin.NativeObject
return undef : $()
}

// CHECK-LABEL: sil @in_guaranteed_always_known_safe_bu : $@convention(thin) (@in_guaranteed Builtin.NativeObject) -> () {
// CHECK: strong_retain
// CHECK-NOT: strong_retain
// CHECK-NOT: strong_release
sil @in_guaranteed_always_known_safe_bu : $@convention(thin) (@in_guaranteed Builtin.NativeObject) -> () {
bb0(%0 : $*Builtin.NativeObject):
%1 = load %0 : $*Builtin.NativeObject
strong_retain %1 : $Builtin.NativeObject
strong_retain %1 : $Builtin.NativeObject
%2 = function_ref @use : $@convention(thin) (Builtin.NativeObject) -> ()
apply %2(%1) : $@convention(thin) (Builtin.NativeObject) -> ()
apply %2(%1) : $@convention(thin) (Builtin.NativeObject) -> ()
strong_release %1 : $Builtin.NativeObject
return undef : $()
}