mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[g-arc-opts] Allow removing of increment, decrement pairs after seeing partial merges, ensuring that we still will not move them.
This enables us to handle significantly crazier control flow without needing to worry about control dependency issues relating to different groups of insertion points potentially not being control dependent which can cause incorrect behavior in the optimizer. Swift SVN r18861
This commit is contained in:
@@ -15,6 +15,7 @@
|
|||||||
#include "swift/Basic/BlotMapVector.h"
|
#include "swift/Basic/BlotMapVector.h"
|
||||||
#include "ReferenceCountState.h"
|
#include "ReferenceCountState.h"
|
||||||
#include "GlobalARCSequenceDataflow.h"
|
#include "GlobalARCSequenceDataflow.h"
|
||||||
|
#include "swift/Basic/Optional.h"
|
||||||
#include "swift/Basic/Fallthrough.h"
|
#include "swift/Basic/Fallthrough.h"
|
||||||
#include "swift/SIL/SILBuilder.h"
|
#include "swift/SIL/SILBuilder.h"
|
||||||
#include "swift/SIL/SILVisitor.h"
|
#include "swift/SIL/SILVisitor.h"
|
||||||
@@ -34,7 +35,12 @@ using namespace swift::arc;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
enum class IncrementDecrementMatchResult { Fail, KnownSafe, NotKnownSafe };
|
struct MatchingSetFlags {
|
||||||
|
bool KnownSafe;
|
||||||
|
bool Partial;
|
||||||
|
};
|
||||||
|
static_assert(std::is_pod<MatchingSetFlags>::value,
|
||||||
|
"MatchingSetFlags should be a pod.");
|
||||||
|
|
||||||
struct ARCMatchingSetBuilder {
|
struct ARCMatchingSetBuilder {
|
||||||
using TDMapTy = BlotMapVector<SILInstruction *, TopDownRefCountState>;
|
using TDMapTy = BlotMapVector<SILInstruction *, TopDownRefCountState>;
|
||||||
@@ -74,17 +80,18 @@ public:
|
|||||||
bool matchedPair() const { return MatchedPair; }
|
bool matchedPair() const { return MatchedPair; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IncrementDecrementMatchResult matchIncrementsToDecrements();
|
/// Returns .Some(MatchingSetFlags) on success and .None on failure.
|
||||||
IncrementDecrementMatchResult matchDecrementsToIncrements();
|
Optional<MatchingSetFlags> matchIncrementsToDecrements();
|
||||||
|
Optional<MatchingSetFlags> matchDecrementsToIncrements();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
|
|
||||||
/// Match retains to releases and return whether or not all of the releases
|
/// Match retains to releases and return whether or not all of the releases
|
||||||
/// were known safe.
|
/// were known safe.
|
||||||
IncrementDecrementMatchResult
|
Optional<MatchingSetFlags>
|
||||||
ARCMatchingSetBuilder::matchIncrementsToDecrements() {
|
ARCMatchingSetBuilder::matchIncrementsToDecrements() {
|
||||||
bool KnownSafe = true;
|
MatchingSetFlags Flags = { true, false };
|
||||||
|
|
||||||
// For each increment in our list of new increments.
|
// For each increment in our list of new increments.
|
||||||
//
|
//
|
||||||
@@ -97,7 +104,7 @@ ARCMatchingSetBuilder::matchIncrementsToDecrements() {
|
|||||||
if (BURefCountState == BUMap.end()) {
|
if (BURefCountState == BUMap.end()) {
|
||||||
DEBUG(llvm::dbgs() << " FAILURE! Could not find state for "
|
DEBUG(llvm::dbgs() << " FAILURE! Could not find state for "
|
||||||
"increment!\n");
|
"increment!\n");
|
||||||
return IncrementDecrementMatchResult::Fail;
|
return Nothing_t::Nothing;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG(llvm::dbgs() << " SUCCESS! Found state for increment.\n");
|
DEBUG(llvm::dbgs() << " SUCCESS! Found state for increment.\n");
|
||||||
@@ -112,7 +119,11 @@ ARCMatchingSetBuilder::matchIncrementsToDecrements() {
|
|||||||
|
|
||||||
// We need to be known safe over all increments/decrements we are matching up
|
// We need to be known safe over all increments/decrements we are matching up
|
||||||
// to ignore insertion points.
|
// to ignore insertion points.
|
||||||
KnownSafe &= BURefCountState->second.isKnownSafe();
|
Flags.KnownSafe &= BURefCountState->second.isKnownSafe();
|
||||||
|
|
||||||
|
// We can only move instructions if we know that we are not partial. We can
|
||||||
|
// still delete instructions in such cases though.
|
||||||
|
Flags.Partial |= BURefCountState->second.isPartial();
|
||||||
|
|
||||||
// Now that we know we have an inst, grab the decrement.
|
// Now that we know we have an inst, grab the decrement.
|
||||||
for (auto DecIter : BURefCountState->second.getInstructions()) {
|
for (auto DecIter : BURefCountState->second.getInstructions()) {
|
||||||
@@ -125,7 +136,7 @@ ARCMatchingSetBuilder::matchIncrementsToDecrements() {
|
|||||||
if (TDRefCountState == TDMap.end()) {
|
if (TDRefCountState == TDMap.end()) {
|
||||||
DEBUG(llvm::dbgs() << " FAILURE! Could not find state for "
|
DEBUG(llvm::dbgs() << " FAILURE! Could not find state for "
|
||||||
"decrement.\n");
|
"decrement.\n");
|
||||||
return IncrementDecrementMatchResult::Fail;
|
return Nothing_t::Nothing;
|
||||||
}
|
}
|
||||||
DEBUG(llvm::dbgs() << " SUCCESS! Found state for decrement.\n");
|
DEBUG(llvm::dbgs() << " SUCCESS! Found state for decrement.\n");
|
||||||
|
|
||||||
@@ -135,7 +146,7 @@ ARCMatchingSetBuilder::matchIncrementsToDecrements() {
|
|||||||
!TDRefCountState->second.containsInstruction(Increment)) {
|
!TDRefCountState->second.containsInstruction(Increment)) {
|
||||||
DEBUG(llvm::dbgs() << " FAILURE! Not tracking instruction or "
|
DEBUG(llvm::dbgs() << " FAILURE! Not tracking instruction or "
|
||||||
"found increment that did not match.\n");
|
"found increment that did not match.\n");
|
||||||
return IncrementDecrementMatchResult::Fail;
|
return Nothing_t::Nothing;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the decrement to the decrement to move set. If we don't insert
|
// Add the decrement to the decrement to move set. If we don't insert
|
||||||
@@ -153,15 +164,12 @@ ARCMatchingSetBuilder::matchIncrementsToDecrements() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!KnownSafe)
|
return Flags;
|
||||||
return IncrementDecrementMatchResult::NotKnownSafe;
|
|
||||||
|
|
||||||
return IncrementDecrementMatchResult::KnownSafe;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IncrementDecrementMatchResult
|
Optional<MatchingSetFlags>
|
||||||
ARCMatchingSetBuilder::matchDecrementsToIncrements() {
|
ARCMatchingSetBuilder::matchDecrementsToIncrements() {
|
||||||
bool KnownSafe = true;
|
MatchingSetFlags Flags = { true, false };
|
||||||
|
|
||||||
// For each increment in our list of new increments.
|
// For each increment in our list of new increments.
|
||||||
//
|
//
|
||||||
@@ -174,7 +182,7 @@ ARCMatchingSetBuilder::matchDecrementsToIncrements() {
|
|||||||
if (TDRefCountState == TDMap.end()) {
|
if (TDRefCountState == TDMap.end()) {
|
||||||
DEBUG(llvm::dbgs() << " FAILURE! Could not find state for "
|
DEBUG(llvm::dbgs() << " FAILURE! Could not find state for "
|
||||||
"increment!\n");
|
"increment!\n");
|
||||||
return IncrementDecrementMatchResult::Fail;
|
return Nothing_t::Nothing;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG(llvm::dbgs() << " SUCCESS! Found state for decrement.\n");
|
DEBUG(llvm::dbgs() << " SUCCESS! Found state for decrement.\n");
|
||||||
@@ -189,7 +197,11 @@ ARCMatchingSetBuilder::matchDecrementsToIncrements() {
|
|||||||
|
|
||||||
// We need to be known safe over all increments/decrements we are matching up
|
// We need to be known safe over all increments/decrements we are matching up
|
||||||
// to ignore insertion points.
|
// to ignore insertion points.
|
||||||
KnownSafe &= TDRefCountState->second.isKnownSafe();
|
Flags.KnownSafe &= TDRefCountState->second.isKnownSafe();
|
||||||
|
|
||||||
|
// We can only move instructions if we know that we are not partial. We can
|
||||||
|
// still delete instructions in such cases though.
|
||||||
|
Flags.Partial |= TDRefCountState->second.isPartial();
|
||||||
|
|
||||||
// Now that we know we have an inst, grab the decrement.
|
// Now that we know we have an inst, grab the decrement.
|
||||||
for (auto IncIter : TDRefCountState->second.getInstructions()) {
|
for (auto IncIter : TDRefCountState->second.getInstructions()) {
|
||||||
@@ -202,7 +214,7 @@ ARCMatchingSetBuilder::matchDecrementsToIncrements() {
|
|||||||
if (BURefCountState == BUMap.end()) {
|
if (BURefCountState == BUMap.end()) {
|
||||||
DEBUG(llvm::dbgs() << " FAILURE! Could not find state for "
|
DEBUG(llvm::dbgs() << " FAILURE! Could not find state for "
|
||||||
"increment.\n");
|
"increment.\n");
|
||||||
return IncrementDecrementMatchResult::Fail;
|
return Nothing_t::Nothing;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG(llvm::dbgs() << " SUCCESS! Found state for increment.\n");
|
DEBUG(llvm::dbgs() << " SUCCESS! Found state for increment.\n");
|
||||||
@@ -213,7 +225,7 @@ ARCMatchingSetBuilder::matchDecrementsToIncrements() {
|
|||||||
!BURefCountState->second.containsInstruction(Decrement)) {
|
!BURefCountState->second.containsInstruction(Decrement)) {
|
||||||
DEBUG(llvm::dbgs() << " FAILURE! Not tracking instruction or "
|
DEBUG(llvm::dbgs() << " FAILURE! Not tracking instruction or "
|
||||||
"found increment that did not match.\n");
|
"found increment that did not match.\n");
|
||||||
return IncrementDecrementMatchResult::Fail;
|
return Nothing_t::Nothing;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the decrement to the decrement to move set. If we don't insert
|
// Add the decrement to the decrement to move set. If we don't insert
|
||||||
@@ -231,9 +243,7 @@ ARCMatchingSetBuilder::matchDecrementsToIncrements() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!KnownSafe)
|
return Flags;
|
||||||
return IncrementDecrementMatchResult::NotKnownSafe;
|
|
||||||
return IncrementDecrementMatchResult::KnownSafe;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Visit each retain/release that is matched up to our operand over and over
|
/// Visit each retain/release that is matched up to our operand over and over
|
||||||
@@ -243,20 +253,25 @@ ARCMatchingSetBuilder::matchDecrementsToIncrements() {
|
|||||||
bool ARCMatchingSetBuilder::matchUpIncDecSetsForPtr() {
|
bool ARCMatchingSetBuilder::matchUpIncDecSetsForPtr() {
|
||||||
bool KnownSafeTD = true;
|
bool KnownSafeTD = true;
|
||||||
bool KnownSafeBU = true;
|
bool KnownSafeBU = true;
|
||||||
|
bool Partial = false;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
DEBUG(llvm::dbgs() << "Attempting to match up increments -> decrements:\n");
|
DEBUG(llvm::dbgs() << "Attempting to match up increments -> decrements:\n");
|
||||||
// For each increment in our list of new increments, attempt to match them up
|
// For each increment in our list of new increments, attempt to match them up
|
||||||
// with decrements and gather the insertion points of the decrements.
|
// with decrements and gather the insertion points of the decrements.
|
||||||
auto Result = matchIncrementsToDecrements();
|
auto Result = matchIncrementsToDecrements();
|
||||||
if (Result == IncrementDecrementMatchResult::Fail) {
|
if (!Result) {
|
||||||
DEBUG(llvm::dbgs() << " FAILED TO MATCH INCREMENTS -> DECREMENTS!\n");
|
DEBUG(llvm::dbgs() << " FAILED TO MATCH INCREMENTS -> DECREMENTS!\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (Result == IncrementDecrementMatchResult::NotKnownSafe) {
|
if (!Result->KnownSafe) {
|
||||||
DEBUG(llvm::dbgs() << " NOT KNOWN SAFE!\n");
|
DEBUG(llvm::dbgs() << " NOT KNOWN SAFE!\n");
|
||||||
KnownSafeTD = false;
|
KnownSafeTD = false;
|
||||||
}
|
}
|
||||||
|
if (Result->Partial) {
|
||||||
|
DEBUG(llvm::dbgs() << " IS PARTIAL!\n");
|
||||||
|
Partial = true;
|
||||||
|
}
|
||||||
NewIncrements.clear();
|
NewIncrements.clear();
|
||||||
|
|
||||||
// If we do not have any decrements to attempt to match up with, bail.
|
// If we do not have any decrements to attempt to match up with, bail.
|
||||||
@@ -265,14 +280,18 @@ bool ARCMatchingSetBuilder::matchUpIncDecSetsForPtr() {
|
|||||||
|
|
||||||
DEBUG(llvm::dbgs() << "Attempting to match up decrements -> increments:\n");
|
DEBUG(llvm::dbgs() << "Attempting to match up decrements -> increments:\n");
|
||||||
Result = matchDecrementsToIncrements();
|
Result = matchDecrementsToIncrements();
|
||||||
if (Result == IncrementDecrementMatchResult::Fail) {
|
if (!Result) {
|
||||||
DEBUG(llvm::dbgs() << " FAILED TO MATCH DECREMENTS -> INCREMENTS!\n");
|
DEBUG(llvm::dbgs() << " FAILED TO MATCH DECREMENTS -> INCREMENTS!\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (Result == IncrementDecrementMatchResult::NotKnownSafe) {
|
if (!Result->KnownSafe) {
|
||||||
DEBUG(llvm::dbgs() << " NOT KNOWN SAFE!\n");
|
DEBUG(llvm::dbgs() << " NOT KNOWN SAFE!\n");
|
||||||
KnownSafeBU = false;
|
KnownSafeBU = false;
|
||||||
}
|
}
|
||||||
|
if (Result->Partial) {
|
||||||
|
DEBUG(llvm::dbgs() << " IS PARTIAL!\n");
|
||||||
|
Partial = true;
|
||||||
|
}
|
||||||
NewDecrements.clear();
|
NewDecrements.clear();
|
||||||
|
|
||||||
// If we do not have any increment to attempt to match up with again, bail.
|
// If we do not have any increment to attempt to match up with again, bail.
|
||||||
@@ -287,13 +306,21 @@ bool ARCMatchingSetBuilder::matchUpIncDecSetsForPtr() {
|
|||||||
MatchSet.DecrementInsertPts.clear();
|
MatchSet.DecrementInsertPts.clear();
|
||||||
} else {
|
} else {
|
||||||
DEBUG(llvm::dbgs() << "NOT UNCONDITIONALLY SAFE!\n");
|
DEBUG(llvm::dbgs() << "NOT UNCONDITIONALLY SAFE!\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we have insertion points and partial merges, return false to avoid
|
||||||
|
// control dependency issues.
|
||||||
|
if ((!MatchSet.IncrementInsertPts.empty() ||
|
||||||
|
!MatchSet.DecrementInsertPts.empty()) &&
|
||||||
|
Partial)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (MatchSet.IncrementInsertPts.empty() && !MatchSet.Increments.empty())
|
if (MatchSet.IncrementInsertPts.empty() && !MatchSet.Increments.empty())
|
||||||
MatchedPair = true;
|
MatchedPair = true;
|
||||||
|
|
||||||
DEBUG(llvm::dbgs() << "SUCCESS! We can move, remove things.\n");
|
|
||||||
// Success!
|
// Success!
|
||||||
|
DEBUG(llvm::dbgs() << "SUCCESS! We can move, remove things.\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -219,10 +219,9 @@ bool TopDownRefCountState::merge(const TopDownRefCountState &Other) {
|
|||||||
// conservatively drop the sequence, to avoid doing partial RR
|
// conservatively drop the sequence, to avoid doing partial RR
|
||||||
// elimination. If the branch predicates for the two merge differ, mixing
|
// elimination. If the branch predicates for the two merge differ, mixing
|
||||||
// them is unsafe since they are not control dependent.
|
// them is unsafe since they are not control dependent.
|
||||||
if (LatState == TopDownRefCountState::LatticeState::None || Partial ||
|
if (LatState == TopDownRefCountState::LatticeState::None) {
|
||||||
Other.Partial) {
|
|
||||||
RefCountState<TopDownRefCountState>::clear();
|
RefCountState<TopDownRefCountState>::clear();
|
||||||
DEBUG(llvm::dbgs() << " Found LatticeState::None or Partial. "
|
DEBUG(llvm::dbgs() << " Found LatticeState::None. "
|
||||||
"Clearing State!\n");
|
"Clearing State!\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -238,16 +237,10 @@ bool TopDownRefCountState::merge(const TopDownRefCountState &Other) {
|
|||||||
|
|
||||||
Increments.insert(Other.Increments.begin(), Other.Increments.end());
|
Increments.insert(Other.Increments.begin(), Other.Increments.end());
|
||||||
|
|
||||||
Partial = InsertPts.size() != Other.InsertPts.size();
|
Partial |= InsertPts.size() != Other.InsertPts.size();
|
||||||
for (auto *SI : Other.InsertPts)
|
for (auto *SI : Other.InsertPts)
|
||||||
Partial |= InsertPts.insert(SI);
|
Partial |= InsertPts.insert(SI);
|
||||||
|
|
||||||
if (Partial) {
|
|
||||||
DEBUG(llvm::dbgs() << " Found partial, clearing state!\n");
|
|
||||||
RefCountState<TopDownRefCountState>::clear();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,9 +257,8 @@ bool BottomUpRefCountState::merge(const BottomUpRefCountState &Other) {
|
|||||||
// conservatively drop the sequence, to avoid doing partial RR
|
// conservatively drop the sequence, to avoid doing partial RR
|
||||||
// elimination. If the branch predicates for the two merge differ, mixing
|
// elimination. If the branch predicates for the two merge differ, mixing
|
||||||
// them is unsafe since they are not control dependent.
|
// them is unsafe since they are not control dependent.
|
||||||
if (LatState == BottomUpRefCountState::LatticeState::None || Partial ||
|
if (LatState == BottomUpRefCountState::LatticeState::None) {
|
||||||
Other.Partial) {
|
DEBUG(llvm::dbgs() << " Found LatticeState::None. "
|
||||||
DEBUG(llvm::dbgs() << " Found LatticeState::None or Partial. "
|
|
||||||
"Clearing State!\n");
|
"Clearing State!\n");
|
||||||
RefCountState<BottomUpRefCountState>::clear();
|
RefCountState<BottomUpRefCountState>::clear();
|
||||||
return false;
|
return false;
|
||||||
@@ -274,16 +266,10 @@ bool BottomUpRefCountState::merge(const BottomUpRefCountState &Other) {
|
|||||||
|
|
||||||
Decrements.insert(Other.Decrements.begin(), Other.Decrements.end());
|
Decrements.insert(Other.Decrements.begin(), Other.Decrements.end());
|
||||||
|
|
||||||
Partial = InsertPts.size() != Other.InsertPts.size();
|
Partial |= InsertPts.size() != Other.InsertPts.size();
|
||||||
for (auto *SI : Other.InsertPts)
|
for (auto *SI : Other.InsertPts)
|
||||||
Partial |= InsertPts.insert(SI);
|
Partial |= InsertPts.insert(SI);
|
||||||
|
|
||||||
if (Partial) {
|
|
||||||
DEBUG(llvm::dbgs() << " Found partial, clearing state!\n");
|
|
||||||
RefCountState<BottomUpRefCountState>::clear();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -178,6 +178,11 @@ struct RefCountState {
|
|||||||
/// increments.
|
/// increments.
|
||||||
bool isKnownSafe() const { return KnownSafe; }
|
bool isKnownSafe() const { return KnownSafe; }
|
||||||
|
|
||||||
|
/// This reference count state is partial if we found a partial merge of
|
||||||
|
/// insertion points. This stymies our ability to move instructions due to
|
||||||
|
/// potential control dependency issues.
|
||||||
|
bool isPartial() const { return Partial; }
|
||||||
|
|
||||||
/// Check if PotentialDecrement can decrement the reference count associated
|
/// Check if PotentialDecrement can decrement the reference count associated
|
||||||
/// with the value we are tracking. If so advance the state's sequence
|
/// with the value we are tracking. If so advance the state's sequence
|
||||||
/// appropriately and return true. Otherwise return false.
|
/// appropriately and return true. Otherwise return false.
|
||||||
|
|||||||
@@ -1038,3 +1038,49 @@ bb2:
|
|||||||
%3 = apply %2() : $@thin @noreturn @callee_owned () -> ()
|
%3 = apply %2() : $@thin @noreturn @callee_owned () -> ()
|
||||||
unreachable
|
unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CHECK: sil @dont_move_values_in_face_of_partial_merges : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
// CHECK: strong_retain
|
||||||
|
// CHECK: strong_release
|
||||||
|
sil @dont_move_values_in_face_of_partial_merges : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
bb0(%0 : $Builtin.NativeObject):
|
||||||
|
%1 = function_ref @user : $@thin (Builtin.NativeObject) -> ()
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
cond_br undef, bb1, bb2
|
||||||
|
|
||||||
|
bb1:
|
||||||
|
apply %1(%0) : $@thin (Builtin.NativeObject) -> ()
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb2:
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb3:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
%2 = tuple()
|
||||||
|
return %2 : $()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: sil @do_remove_values_in_face_of_partial_merges : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
// CHECK: strong_retain
|
||||||
|
// CHECK-NOT: strong_release
|
||||||
|
// CHECK-NOT: strong_release
|
||||||
|
sil @do_remove_values_in_face_of_partial_merges : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
bb0(%0 : $Builtin.NativeObject):
|
||||||
|
%1 = function_ref @user : $@thin (Builtin.NativeObject) -> ()
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
cond_br undef, bb1, bb2
|
||||||
|
|
||||||
|
bb1:
|
||||||
|
apply %1(%0) : $@thin (Builtin.NativeObject) -> ()
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb2:
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb3:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
%2 = tuple()
|
||||||
|
return %2 : $()
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user