mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[g-arc-opts] Implement the merge functions to complete Stage 2 of global arc opts.
Also fixed a small bug related to how we handle arguments. We were not clearing the state of the argument when we saw a potential decrement of the argument. <rdar://problem/17013194> Swift SVN r18706
This commit is contained in:
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include "swift/SIL/SILValue.h"
|
#include "swift/SIL/SILValue.h"
|
||||||
#include "llvm/ADT/SmallPtrSet.h"
|
#include "llvm/ADT/SmallPtrSet.h"
|
||||||
|
#include "llvm/ADT/SetVector.h"
|
||||||
|
|
||||||
namespace swift {
|
namespace swift {
|
||||||
|
|
||||||
@@ -39,10 +40,10 @@ bool canUseValue(SILInstruction *User, SILValue Ptr, AliasAnalysis *AA);
|
|||||||
/// insertion pts, and decrement insertion pts.
|
/// insertion pts, and decrement insertion pts.
|
||||||
struct ARCMatchingSet {
|
struct ARCMatchingSet {
|
||||||
SILValue Ptr;
|
SILValue Ptr;
|
||||||
llvm::SmallPtrSet<SILInstruction *, 8> Increments;
|
llvm::SetVector<SILInstruction *> Increments;
|
||||||
llvm::SmallPtrSet<SILInstruction *, 8> IncrementInsertPts;
|
llvm::SetVector<SILInstruction *> IncrementInsertPts;
|
||||||
llvm::SmallPtrSet<SILInstruction *, 8> Decrements;
|
llvm::SetVector<SILInstruction *> Decrements;
|
||||||
llvm::SmallPtrSet<SILInstruction *, 8> DecrementInsertPts;
|
llvm::SetVector<SILInstruction *> DecrementInsertPts;
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
Ptr = SILValue();
|
Ptr = SILValue();
|
||||||
|
|||||||
@@ -76,41 +76,216 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
|
|||||||
}
|
}
|
||||||
} // end namespace llvm
|
} // end namespace llvm
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Lattice State Merging
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
static inline BottomUpRefCountState::LatticeState
|
||||||
|
MergeBottomUpLatticeStates(BottomUpRefCountState::LatticeState L1,
|
||||||
|
BottomUpRefCountState::LatticeState L2) {
|
||||||
|
using LatticeState = BottomUpRefCountState::LatticeState;
|
||||||
|
// If both states equal, return the first.
|
||||||
|
if (L1 == L2)
|
||||||
|
return L1;
|
||||||
|
|
||||||
|
// If either are none, return None.
|
||||||
|
if (L1 == LatticeState::None || L2 == LatticeState::None)
|
||||||
|
return LatticeState::None;
|
||||||
|
|
||||||
|
// Canonicalize.
|
||||||
|
if (unsigned(L1) > unsigned(L2))
|
||||||
|
std::swap(L1, L2);
|
||||||
|
|
||||||
|
// Choose the side further along in the sequence.
|
||||||
|
if ((L1 == LatticeState::Decremented || L1 == LatticeState::MightBeUsed) ||
|
||||||
|
(L2 == LatticeState::MightBeUsed ||
|
||||||
|
L2 == LatticeState::MightBeDecremented))
|
||||||
|
return L2;
|
||||||
|
|
||||||
|
// Otherwise, we don't know what happened, be conservative and return none.
|
||||||
|
return LatticeState::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline TopDownRefCountState::LatticeState
|
||||||
|
MergeTopDownLatticeStates(TopDownRefCountState::LatticeState L1,
|
||||||
|
TopDownRefCountState::LatticeState L2) {
|
||||||
|
using LatticeState = TopDownRefCountState::LatticeState;
|
||||||
|
// If both states equal, return the first.
|
||||||
|
if (L1 == L2)
|
||||||
|
return L1;
|
||||||
|
|
||||||
|
// If either are none, return None.
|
||||||
|
if (L1 == LatticeState::None || L2 == LatticeState::None)
|
||||||
|
return LatticeState::None;
|
||||||
|
|
||||||
|
// Canonicalize.
|
||||||
|
if (unsigned(L1) > unsigned(L2))
|
||||||
|
std::swap(L1, L2);
|
||||||
|
|
||||||
|
// Choose the side further along in the sequence.
|
||||||
|
if ((L1 == LatticeState::Incremented ||
|
||||||
|
L1 == LatticeState::MightBeDecremented) ||
|
||||||
|
(L2 == LatticeState::MightBeDecremented ||
|
||||||
|
L2 == LatticeState::MightBeUsed))
|
||||||
|
return L2;
|
||||||
|
|
||||||
|
// Otherwise, we don't know what happened, return none.
|
||||||
|
return LatticeState::None;
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// ARCBBState Implementation
|
// ARCBBState Implementation
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
/// Merge in the state of the successor basic block. This is currently a stub.
|
/// Merge in the state of the successor basic block. This is currently a stub.
|
||||||
void ARCBBState::mergeSuccBottomUp(ARCBBState &SuccBB) {
|
void ARCBBState::mergeSuccBottomUp(ARCBBState &SuccBB) {
|
||||||
|
// For each entry in the other set, if our set has an entry with the same key,
|
||||||
|
// merge the entires. Otherwise, copy the entry and merge it with an empty
|
||||||
|
// entry.
|
||||||
|
for (auto MI : SuccBB.getBottomupStates()) {
|
||||||
|
auto Pair = PtrToBottomUpState.insert(MI);
|
||||||
|
// If we fail to merge, bail.
|
||||||
|
if (!Pair.first->second.merge(Pair.second ? BottomUpRefCountState()
|
||||||
|
: MI.second)) {
|
||||||
|
clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto Pair : getBottomupStates()) {
|
||||||
|
if (SuccBB.PtrToBottomUpState.find(Pair.first) ==
|
||||||
|
SuccBB.PtrToBottomUpState.end())
|
||||||
|
// If we fail to merge, bail.
|
||||||
|
if (!Pair.second.merge(BottomUpRefCountState())) {
|
||||||
|
clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize this BB with the state of the successor basic block. This is
|
/// Initialize this BB with the state of the successor basic block. This is
|
||||||
/// called on a basic block's state and then any other successors states are
|
/// called on a basic block's state and then any other successors states are
|
||||||
/// merged in. This is currently a stub.
|
/// merged in. This is currently a stub.
|
||||||
void ARCBBState::initSuccBottomUp(ARCBBState &SuccBB) {
|
void ARCBBState::initSuccBottomUp(ARCBBState &SuccBB) {
|
||||||
|
PtrToBottomUpState = SuccBB.PtrToBottomUpState;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Merge in the state of the predecessor basic block. This is currently a stub.
|
/// Merge in the state of the predecessor basic block. This is currently a stub.
|
||||||
void ARCBBState::mergePredTopDown(ARCBBState &PredBB) {
|
void ARCBBState::mergePredTopDown(ARCBBState &PredBB) {
|
||||||
|
// For each entry in the other set, if our set has an entry with the same key,
|
||||||
|
// merge the entires. Otherwise, copy the entry and merge it with an empty
|
||||||
|
// entry.
|
||||||
|
for (auto MI : PredBB.getTopDownStates()) {
|
||||||
|
auto Pair = PtrToTopDownState.insert(MI);
|
||||||
|
// If we fail to merge, bail.
|
||||||
|
if (!Pair.first->second.merge(Pair.second ? TopDownRefCountState()
|
||||||
|
: MI.second)) {
|
||||||
|
clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto Pair : getTopDownStates()) {
|
||||||
|
if (PredBB.PtrToTopDownState.find(Pair.first) ==
|
||||||
|
PredBB.PtrToTopDownState.end())
|
||||||
|
// If we fail to merge, bail.
|
||||||
|
if (!Pair.second.merge(TopDownRefCountState())) {
|
||||||
|
clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize the state for this BB with the state of its predecessor
|
/// Initialize the state for this BB with the state of its predecessor
|
||||||
/// BB. Used to create an initial state before we merge in other
|
/// BB. Used to create an initial state before we merge in other
|
||||||
/// predecessors. This is currently a stub.
|
/// predecessors. This is currently a stub.
|
||||||
void ARCBBState::initPredTopDown(ARCBBState &PredBB) {
|
void ARCBBState::initPredTopDown(ARCBBState &PredBB) {
|
||||||
|
PtrToTopDownState = PredBB.PtrToTopDownState;
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Reference Count State Implementation
|
// Reference Count State Implementation
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
void TopDownRefCountState::merge(const TopDownRefCountState &Other) {}
|
bool TopDownRefCountState::merge(const TopDownRefCountState &Other) {
|
||||||
|
auto NewState = MergeTopDownLatticeStates(LatState, Other.LatState);
|
||||||
|
DEBUG(llvm::dbgs() << " Performing TopDown Merge.\n");
|
||||||
|
DEBUG(llvm::dbgs() << " Left: " << LatState << "; Right: "
|
||||||
|
<< Other.LatState << "; Result: " << NewState << "\n");
|
||||||
|
LatState = NewState;
|
||||||
|
KnownSafe &= KnownSafe;
|
||||||
|
|
||||||
void BottomUpRefCountState::merge(const BottomUpRefCountState &Other) {}
|
// If we're doing a merge on a path that's previously seen a partial merge,
|
||||||
|
// conservatively drop the sequence, to avoid doing partial RR
|
||||||
|
// elimination. If the branch predicates for the two merge differ, mixing
|
||||||
|
// them is unsafe since they are not control dependent.
|
||||||
|
if (LatState == TopDownRefCountState::LatticeState::None || Partial ||
|
||||||
|
Other.Partial) {
|
||||||
|
RefCountState<TopDownRefCountState>::clear();
|
||||||
|
DEBUG(llvm::dbgs() << " Found LatticeState::None or Partial. "
|
||||||
|
"Clearing State!\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We should never have an argument path merge with a non-argument path.
|
||||||
|
if (!Argument.isNull()) {
|
||||||
|
RefCountState<TopDownRefCountState>::clear();
|
||||||
|
DEBUG(
|
||||||
|
llvm::dbgs() << " Can not merge Argument with Non-Argument "
|
||||||
|
"path... Bailing!\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Increments.insert(Other.Increments.begin(), Other.Increments.end());
|
||||||
|
|
||||||
|
Partial = InsertPts.size() != Other.InsertPts.size();
|
||||||
|
for (auto *SI : Other.InsertPts)
|
||||||
|
Partial |= InsertPts.insert(SI);
|
||||||
|
|
||||||
|
if (Partial) {
|
||||||
|
DEBUG(llvm::dbgs() << " Found partial, clearing state!\n");
|
||||||
|
RefCountState<TopDownRefCountState>::clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BottomUpRefCountState::merge(const BottomUpRefCountState &Other) {
|
||||||
|
|
||||||
|
auto NewState = MergeBottomUpLatticeStates(LatState, Other.LatState);
|
||||||
|
DEBUG(llvm::dbgs() << " Performing BottomUp Merge.\n");
|
||||||
|
DEBUG(llvm::dbgs() << " Left: " << LatState << "; Right: "
|
||||||
|
<< Other.LatState << "; Result: " << NewState << "\n");
|
||||||
|
LatState = NewState;
|
||||||
|
KnownSafe &= KnownSafe;
|
||||||
|
|
||||||
|
// If we're doing a merge on a path that's previously seen a partial merge,
|
||||||
|
// conservatively drop the sequence, to avoid doing partial RR
|
||||||
|
// elimination. If the branch predicates for the two merge differ, mixing
|
||||||
|
// them is unsafe since they are not control dependent.
|
||||||
|
if (LatState == BottomUpRefCountState::LatticeState::None || Partial ||
|
||||||
|
Other.Partial) {
|
||||||
|
DEBUG(llvm::dbgs() << " Found LatticeState::None or Partial. "
|
||||||
|
"Clearing State!\n");
|
||||||
|
RefCountState<BottomUpRefCountState>::clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Decrements.insert(Other.Decrements.begin(), Other.Decrements.end());
|
||||||
|
|
||||||
|
Partial = InsertPts.size() != Other.InsertPts.size();
|
||||||
|
for (auto *SI : Other.InsertPts)
|
||||||
|
Partial |= InsertPts.insert(SI);
|
||||||
|
|
||||||
|
if (Partial) {
|
||||||
|
DEBUG(llvm::dbgs() << " Found partial, clearing state!\n");
|
||||||
|
RefCountState<BottomUpRefCountState>::clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Top Down Dataflow
|
// Top Down Dataflow
|
||||||
@@ -122,10 +297,9 @@ void BottomUpRefCountState::merge(const BottomUpRefCountState &Other) {}
|
|||||||
///
|
///
|
||||||
/// NestingDetected will be set to indicate that the block needs to be
|
/// NestingDetected will be set to indicate that the block needs to be
|
||||||
/// reanalyzed if code motion occurs.
|
/// reanalyzed if code motion occurs.
|
||||||
static bool
|
static bool processBBTopDown(
|
||||||
processBBTopDown(ARCBBState &BBState,
|
ARCBBState &BBState,
|
||||||
BlotMapVector<SILInstruction *,
|
BlotMapVector<SILInstruction *, TopDownRefCountState> &DecToIncStateMap,
|
||||||
TopDownRefCountState> &DecToIncStateMap,
|
|
||||||
AliasAnalysis *AA) {
|
AliasAnalysis *AA) {
|
||||||
DEBUG(llvm::dbgs() << ">>>> Top Down!\n");
|
DEBUG(llvm::dbgs() << ">>>> Top Down!\n");
|
||||||
|
|
||||||
@@ -205,8 +379,8 @@ processBBTopDown(ARCBBState &BBState,
|
|||||||
RefCountState.clear();
|
RefCountState.clear();
|
||||||
} else {
|
} else {
|
||||||
if (RefCountState.isTrackingRefCountInst()) {
|
if (RefCountState.isTrackingRefCountInst()) {
|
||||||
DEBUG(llvm::dbgs() << " FAILED MATCH INCREMENT:\n" <<
|
DEBUG(llvm::dbgs() << " FAILED MATCH INCREMENT:\n"
|
||||||
RefCountState.getValue());
|
<< RefCountState.getValue());
|
||||||
} else {
|
} else {
|
||||||
DEBUG(llvm::dbgs() << " FAILED MATCH. NO INCREMENT.\n");
|
DEBUG(llvm::dbgs() << " FAILED MATCH. NO INCREMENT.\n");
|
||||||
}
|
}
|
||||||
@@ -224,8 +398,8 @@ processBBTopDown(ARCBBState &BBState,
|
|||||||
if (Op && OtherState.first == Op)
|
if (Op && OtherState.first == Op)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// If we are tracking an argument, skip it.
|
// If the other state is not tracking anything, bail.
|
||||||
if (!OtherState.second.isTrackingRefCountInst())
|
if (!OtherState.second.isTrackingRefCount())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Check if the instruction we are visiting could potentially decrement
|
// Check if the instruction we are visiting could potentially decrement
|
||||||
@@ -249,8 +423,8 @@ processBBTopDown(ARCBBState &BBState,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
swift::arc::ARCSequenceDataflowEvaluator::
|
swift::arc::ARCSequenceDataflowEvaluator::mergePredecessors(ARCBBState &BBState,
|
||||||
mergePredecessors(ARCBBState &BBState, SILBasicBlock *BB) {
|
SILBasicBlock *BB) {
|
||||||
// For each successor of BB...
|
// For each successor of BB...
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
for (auto Pred : BB->getPreds()) {
|
for (auto Pred : BB->getPreds()) {
|
||||||
@@ -277,13 +451,18 @@ mergePredecessors(ARCBBState &BBState, SILBasicBlock *BB) {
|
|||||||
bool swift::arc::ARCSequenceDataflowEvaluator::processTopDown() {
|
bool swift::arc::ARCSequenceDataflowEvaluator::processTopDown() {
|
||||||
bool NestingDetected = false;
|
bool NestingDetected = false;
|
||||||
|
|
||||||
|
DEBUG(llvm::dbgs() << "<<<< Processing Bottom Up! >>>>\n");
|
||||||
|
|
||||||
// For each BB in our reverse post order...
|
// For each BB in our reverse post order...
|
||||||
for (auto *BB : reversed(PostOrder)) {
|
for (auto *BB : reversed(PostOrder)) {
|
||||||
|
|
||||||
|
DEBUG(llvm::dbgs() << "Processing BB#: " << BBToPostOrderID[BB] << "\n");
|
||||||
|
|
||||||
// Grab the BBState associated with it and set it to be the current BB.
|
// Grab the BBState associated with it and set it to be the current BB.
|
||||||
ARCBBState &BBState = TopDownBBStates[BB];
|
ARCBBState &BBState = TopDownBBStates[BB];
|
||||||
BBState.init(BB);
|
BBState.init(BB);
|
||||||
|
|
||||||
|
DEBUG(llvm::dbgs() << "Merging Predecessors!\n");
|
||||||
mergePredecessors(BBState, BB);
|
mergePredecessors(BBState, BB);
|
||||||
|
|
||||||
// Then perform the basic block optimization.
|
// Then perform the basic block optimization.
|
||||||
@@ -297,17 +476,15 @@ bool swift::arc::ARCSequenceDataflowEvaluator::processTopDown() {
|
|||||||
// Bottom Up Dataflow
|
// Bottom Up Dataflow
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
|
||||||
/// Analyze a single BB for refcount inc/dec instructions.
|
/// Analyze a single BB for refcount inc/dec instructions.
|
||||||
///
|
///
|
||||||
/// If anything was found it will be added to DecToIncStateMap.
|
/// If anything was found it will be added to DecToIncStateMap.
|
||||||
///
|
///
|
||||||
/// NestingDetected will be set to indicate that the block needs to be
|
/// NestingDetected will be set to indicate that the block needs to be
|
||||||
/// reanalyzed if code motion occurs.
|
/// reanalyzed if code motion occurs.
|
||||||
static bool
|
static bool processBBBottomUp(
|
||||||
processBBBottomUp(ARCBBState &BBState,
|
ARCBBState &BBState,
|
||||||
BlotMapVector<SILInstruction *,
|
BlotMapVector<SILInstruction *, BottomUpRefCountState> &IncToDecStateMap,
|
||||||
BottomUpRefCountState> &IncToDecStateMap,
|
|
||||||
AliasAnalysis *AA) {
|
AliasAnalysis *AA) {
|
||||||
DEBUG(llvm::dbgs() << ">>>> Bottom Up!\n");
|
DEBUG(llvm::dbgs() << ">>>> Bottom Up!\n");
|
||||||
SILBasicBlock &BB = BBState.getBB();
|
SILBasicBlock &BB = BBState.getBB();
|
||||||
@@ -367,8 +544,8 @@ processBBBottomUp(ARCBBState &BBState,
|
|||||||
RefCountState.clear();
|
RefCountState.clear();
|
||||||
} else {
|
} else {
|
||||||
if (RefCountState.isTrackingRefCountInst()) {
|
if (RefCountState.isTrackingRefCountInst()) {
|
||||||
DEBUG(llvm::dbgs() << " FAILED MATCH DECREMENT:"
|
DEBUG(llvm::dbgs()
|
||||||
<< RefCountState.getValue());
|
<< " FAILED MATCH DECREMENT:" << RefCountState.getValue());
|
||||||
} else {
|
} else {
|
||||||
DEBUG(llvm::dbgs() << " FAILED MATCH DECREMENT. Not tracking a "
|
DEBUG(llvm::dbgs() << " FAILED MATCH DECREMENT. Not tracking a "
|
||||||
"decrement.\n");
|
"decrement.\n");
|
||||||
@@ -387,8 +564,8 @@ processBBBottomUp(ARCBBState &BBState,
|
|||||||
if (Op && OtherState.first == Op)
|
if (Op && OtherState.first == Op)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// If we are tracking an argument, skip it.
|
// If this state is not tracking anything, skip it.
|
||||||
if (!OtherState.second.isTrackingRefCountInst())
|
if (!OtherState.second.isTrackingRefCount())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Check if the instruction we are visiting could potentially decrement
|
// Check if the instruction we are visiting could potentially decrement
|
||||||
@@ -412,8 +589,8 @@ processBBBottomUp(ARCBBState &BBState,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
swift::arc::ARCSequenceDataflowEvaluator::
|
swift::arc::ARCSequenceDataflowEvaluator::mergeSuccessors(ARCBBState &BBState,
|
||||||
mergeSuccessors(ARCBBState &BBState, SILBasicBlock *BB) {
|
SILBasicBlock *BB) {
|
||||||
// Grab the backedge set for our BB.
|
// Grab the backedge set for our BB.
|
||||||
auto &BackEdgeSet = BackedgeMap[BB];
|
auto &BackEdgeSet = BackedgeMap[BB];
|
||||||
|
|
||||||
@@ -449,13 +626,18 @@ mergeSuccessors(ARCBBState &BBState, SILBasicBlock *BB) {
|
|||||||
bool swift::arc::ARCSequenceDataflowEvaluator::processBottomUp() {
|
bool swift::arc::ARCSequenceDataflowEvaluator::processBottomUp() {
|
||||||
bool NestingDetected = false;
|
bool NestingDetected = false;
|
||||||
|
|
||||||
|
DEBUG(llvm::dbgs() << "<<<< Processing Bottom Up! >>>>\n");
|
||||||
|
|
||||||
// For each BB in our post order...
|
// For each BB in our post order...
|
||||||
for (auto *BB : PostOrder) {
|
for (auto *BB : PostOrder) {
|
||||||
|
|
||||||
|
DEBUG(llvm::dbgs() << "Processing BB#: " << BBToPostOrderID[BB] << "\n");
|
||||||
|
|
||||||
// Grab the BBState associated with it and set it to be the current BB.
|
// Grab the BBState associated with it and set it to be the current BB.
|
||||||
ARCBBState &BBState = BottomUpBBStates[BB];
|
ARCBBState &BBState = BottomUpBBStates[BB];
|
||||||
BBState.init(BB);
|
BBState.init(BB);
|
||||||
|
|
||||||
|
DEBUG(llvm::dbgs() << "Merging Successors!\n");
|
||||||
mergeSuccessors(BBState, BB);
|
mergeSuccessors(BBState, BB);
|
||||||
|
|
||||||
// Then perform the basic block optimization.
|
// Then perform the basic block optimization.
|
||||||
@@ -509,8 +691,7 @@ bool swift::arc::ARCSequenceDataflowEvaluator::run() {
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
bool swift::arc::performARCSequenceDataflow(
|
bool swift::arc::performARCSequenceDataflow(
|
||||||
SILFunction &F,
|
SILFunction &F, AliasAnalysis *AA,
|
||||||
AliasAnalysis *AA,
|
|
||||||
BlotMapVector<SILInstruction *, TopDownRefCountState> &DecToIncStateMap,
|
BlotMapVector<SILInstruction *, TopDownRefCountState> &DecToIncStateMap,
|
||||||
BlotMapVector<SILInstruction *, BottomUpRefCountState> &IncToDecStateMap) {
|
BlotMapVector<SILInstruction *, BottomUpRefCountState> &IncToDecStateMap) {
|
||||||
|
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ struct RefCountState {
|
|||||||
bool handlePotentialDecrement(SILInstruction *PotentialDecrement,
|
bool handlePotentialDecrement(SILInstruction *PotentialDecrement,
|
||||||
AliasAnalysis *AA) {
|
AliasAnalysis *AA) {
|
||||||
// If we are not tracking a ref count, just return false.
|
// If we are not tracking a ref count, just return false.
|
||||||
if (!isTrackingRefCountInst())
|
if (!isTrackingRefCount())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// If we can prove that Other can not use the pointer we are tracking,
|
// If we can prove that Other can not use the pointer we are tracking,
|
||||||
@@ -282,13 +282,13 @@ struct BottomUpRefCountState : public RefCountState<BottomUpRefCountState> {
|
|||||||
|
|
||||||
/// Is this ref count initialized and tracking a ref count ptr.
|
/// Is this ref count initialized and tracking a ref count ptr.
|
||||||
bool isTrackingRefCount() const {
|
bool isTrackingRefCount() const {
|
||||||
return !Decrements.empty();
|
return Decrements.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Are we tracking an instruction currently? This returns false when given an
|
/// Are we tracking an instruction currently? This returns false when given an
|
||||||
/// uninitialized ReferenceCountState.
|
/// uninitialized ReferenceCountState.
|
||||||
bool isTrackingRefCountInst() const {
|
bool isTrackingRefCountInst() const {
|
||||||
return !Decrements.empty();
|
return Decrements.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Are we tracking a source of ref counts? This currently means that we are
|
/// Are we tracking a source of ref counts? This currently means that we are
|
||||||
@@ -359,7 +359,7 @@ struct BottomUpRefCountState : public RefCountState<BottomUpRefCountState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void merge(const BottomUpRefCountState &Other);
|
bool merge(const BottomUpRefCountState &Other);
|
||||||
};
|
};
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
@@ -507,7 +507,7 @@ struct TopDownRefCountState : public RefCountState<TopDownRefCountState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void merge(const TopDownRefCountState &Other);
|
bool merge(const TopDownRefCountState &Other);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end arc namespace
|
} // end arc namespace
|
||||||
|
|||||||
125
test/SILPasses/global-arc-opts-loops.sil.gyb
Normal file
125
test/SILPasses/global-arc-opts-loops.sil.gyb
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
%# -*- mode: sil -*-
|
||||||
|
// RUN: rm -rf %t
|
||||||
|
// RUN: mkdir %t
|
||||||
|
// RUN: %gyb %s > %t/global-arc-opts-loops.sil
|
||||||
|
// RUN: sil-opt -global-arc-opts -verify %t/global-arc-opts-loops.sil | FileCheck %t/global-arc-opts-loops.sil
|
||||||
|
|
||||||
|
%# Ignore the following admonition; it applies to the resulting .sil
|
||||||
|
%# test file only.
|
||||||
|
// DO NOT MODIFY THIS TEST FILE. IT IS AUTOMATICALLY GENERATED BY GYB.
|
||||||
|
|
||||||
|
sil_stage canonical
|
||||||
|
|
||||||
|
import Builtin
|
||||||
|
|
||||||
|
// Utilities
|
||||||
|
|
||||||
|
sil @user : $@thin (Builtin.NativeObject) -> ()
|
||||||
|
|
||||||
|
// Loop form 1 consists of CFG of the following form:
|
||||||
|
//
|
||||||
|
// BB0 -> BB1
|
||||||
|
// BB1 -> BB1
|
||||||
|
// BB1 -> BB2
|
||||||
|
//
|
||||||
|
// Thus it is a simple loop without any interior basic blocks.
|
||||||
|
//
|
||||||
|
// We generate test retain release pairs at
|
||||||
|
% for i in range(16):
|
||||||
|
|
||||||
|
// CHECK-LABEL: sil @loop_form_1_${i} : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
sil @loop_form_1_${i} : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
// CHECK: bb0
|
||||||
|
bb0(%0 : $Builtin.NativeObject):
|
||||||
|
% if i & 1:
|
||||||
|
// CHECK-NEXT: strong_retain
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
% end
|
||||||
|
// CHECK-NEXT: br
|
||||||
|
br bb1
|
||||||
|
|
||||||
|
// CHECK: bb1:
|
||||||
|
bb1:
|
||||||
|
% if (i & 2) and not (i & 4):
|
||||||
|
// CHECK-NEXT: strong_retain
|
||||||
|
% end
|
||||||
|
% if i & 2:
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
% end
|
||||||
|
% if not (i & 2) and (i & 4):
|
||||||
|
// CHECK-NEXT: strong_release
|
||||||
|
% end
|
||||||
|
% if i & 4:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
% end
|
||||||
|
// CHECK-NEXT: cond_br
|
||||||
|
cond_br undef, bb1, bb2
|
||||||
|
|
||||||
|
// CHECK: bb2:
|
||||||
|
bb2:
|
||||||
|
% if i & 8:
|
||||||
|
// CHECK-NEXT: strong_release
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
% end
|
||||||
|
%%1 = tuple ()
|
||||||
|
return %1 : $()
|
||||||
|
}
|
||||||
|
% end
|
||||||
|
|
||||||
|
// Loop form 2 consists of CFGs of the following form:
|
||||||
|
//
|
||||||
|
// BB0 -> BB1
|
||||||
|
// BB1 -> BB2
|
||||||
|
// BB2 -> BB1
|
||||||
|
// BB2 -> BB3
|
||||||
|
//
|
||||||
|
// I.e. a loop with a body of 2 and the jump into the loop not at the
|
||||||
|
// latch.
|
||||||
|
|
||||||
|
% for i in range(3):
|
||||||
|
% for j in range(4):
|
||||||
|
|
||||||
|
sil @loop_form_2_${i}_${j} : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
// CHECK: bb0({{.*}}):
|
||||||
|
bb0(%0 : $Builtin.NativeObject):
|
||||||
|
% if i & 1:
|
||||||
|
// CHECK-NEXT: strong_retain
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
% end
|
||||||
|
br bb1
|
||||||
|
|
||||||
|
// CHECK: bb1:
|
||||||
|
bb1:
|
||||||
|
% if j == 0:
|
||||||
|
// CHECK-NEXT: strong_retain
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
% end
|
||||||
|
% if j == 1:
|
||||||
|
// CHECK-NEXT: strong_release
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
% end
|
||||||
|
br bb2
|
||||||
|
|
||||||
|
// CHECK: bb2:
|
||||||
|
bb2:
|
||||||
|
% if j == 2:
|
||||||
|
// CHECK-NEXT: strong_retain
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
% end
|
||||||
|
% if j == 3:
|
||||||
|
// CHECK-NEXT: strong_release
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
% end
|
||||||
|
cond_br undef, bb1, bb3
|
||||||
|
|
||||||
|
// CHECK: bb3:
|
||||||
|
bb3:
|
||||||
|
% if i & 2:
|
||||||
|
// CHECK-NEXT: strong_release
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
% end
|
||||||
|
%%1 = tuple ()
|
||||||
|
return %1 : $()
|
||||||
|
}
|
||||||
|
|
||||||
|
% end
|
||||||
@@ -4,6 +4,10 @@ sil_stage canonical
|
|||||||
|
|
||||||
import Builtin
|
import Builtin
|
||||||
|
|
||||||
|
// Utilities
|
||||||
|
|
||||||
|
sil @user : $@thin (Builtin.NativeObject) -> ()
|
||||||
|
|
||||||
/////////////////
|
/////////////////
|
||||||
// Basic Tests //
|
// Basic Tests //
|
||||||
/////////////////
|
/////////////////
|
||||||
@@ -94,8 +98,6 @@ bb0(%0 : $S, %1 : $Builtin.NativeObject):
|
|||||||
return %2 : $()
|
return %2 : $()
|
||||||
}
|
}
|
||||||
|
|
||||||
sil @user : $@thin (Builtin.NativeObject) -> ()
|
|
||||||
|
|
||||||
// CHECK-LABEL: sil @dont_delete_retain_over_decrement_use : $@thin (Builtin.NativeObject) -> ()
|
// CHECK-LABEL: sil @dont_delete_retain_over_decrement_use : $@thin (Builtin.NativeObject) -> ()
|
||||||
// CHECK: bb0
|
// CHECK: bb0
|
||||||
// CHECK: strong_retain
|
// CHECK: strong_retain
|
||||||
@@ -310,8 +312,15 @@ bb0(%0 : $*Builtin.Int32):
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CHECK-LABEL: sil @silargument_retain_iterated : $@thin (@owned Builtin.NativeObject) -> ()
|
// CHECK-LABEL: sil @silargument_retain_iterated : $@thin (@owned Builtin.NativeObject) -> ()
|
||||||
// CHECK-NOT: strong_retain
|
// CHECK: bb0
|
||||||
// CHECK-NOT: strong_release
|
// CHECK-NEXT: function_ref user
|
||||||
|
// CHECK-NEXT: function_ref @user
|
||||||
|
// CHECK-NEXT: apply
|
||||||
|
// CHECK-NEXT: apply
|
||||||
|
// CHECK-NEXT: strong_retain
|
||||||
|
// CHECK-NEXT: apply
|
||||||
|
// CHECK-NEXT: apply
|
||||||
|
// CHECK-NEXT: strong_release
|
||||||
sil @silargument_retain_iterated : $@thin (@owned Builtin.NativeObject) -> () {
|
sil @silargument_retain_iterated : $@thin (@owned Builtin.NativeObject) -> () {
|
||||||
bb0(%0 : $Builtin.NativeObject):
|
bb0(%0 : $Builtin.NativeObject):
|
||||||
%1 = function_ref @user : $@thin (Builtin.NativeObject) -> ()
|
%1 = function_ref @user : $@thin (Builtin.NativeObject) -> ()
|
||||||
@@ -441,3 +450,572 @@ bb0(%0 : $RetainUser, %1 : $Builtin.NativeObject):
|
|||||||
strong_release %0 : $RetainUser
|
strong_release %0 : $RetainUser
|
||||||
return %1 : $Builtin.NativeObject
|
return %1 : $Builtin.NativeObject
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
// Multi-BB tests //
|
||||||
|
////////////////////
|
||||||
|
|
||||||
|
//////////////
|
||||||
|
// Hammocks //
|
||||||
|
//////////////
|
||||||
|
|
||||||
|
// CHECK-LABEL: sil @hammock1 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
// CHECK-NOT: strong_retain
|
||||||
|
// CHECK-NOT: strong_release
|
||||||
|
sil @hammock1 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
bb0(%0 : $Builtin.NativeObject):
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
cond_br undef, bb1, bb2
|
||||||
|
|
||||||
|
bb1:
|
||||||
|
br bb2
|
||||||
|
|
||||||
|
bb2:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
%9999 = tuple()
|
||||||
|
return %9999 : $()
|
||||||
|
}
|
||||||
|
|
||||||
|
// This hammock can not be optimized.
|
||||||
|
// CHECK-LABEL: sil @hammock2 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
// CHECK: bb0
|
||||||
|
// CHECK-NEXT: strong_retain
|
||||||
|
// CHECK: bb1:
|
||||||
|
// CHECK-NEXT: strong_retain
|
||||||
|
// CHECK: bb2:
|
||||||
|
// CHECK-NEXT: strong_release
|
||||||
|
sil @hammock2 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
bb0(%0 : $Builtin.NativeObject):
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
cond_br undef, bb1, bb2
|
||||||
|
|
||||||
|
bb1:
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
br bb2
|
||||||
|
|
||||||
|
bb2:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
%9999 = tuple()
|
||||||
|
return %9999 : $()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This hammock can't be optimized.
|
||||||
|
// CHECK-LABEL: sil @hammock3 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
// CHECK: bb0
|
||||||
|
// CHECK-NEXT: strong_retain
|
||||||
|
// CHECK: bb1:
|
||||||
|
// CHECK-NEXT: strong_release
|
||||||
|
// CHECK: bb2:
|
||||||
|
// CHECK-NEXT: strong_release
|
||||||
|
sil @hammock3 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
bb0(%0 : $Builtin.NativeObject):
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
cond_br undef, bb1, bb2
|
||||||
|
|
||||||
|
bb1:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
br bb2
|
||||||
|
|
||||||
|
bb2:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
%9999 = tuple()
|
||||||
|
return %9999 : $()
|
||||||
|
}
|
||||||
|
|
||||||
|
// This should not be optimizable.
|
||||||
|
// CHECK-LABEL: sil @hammock4 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
// CHECK: bb0
|
||||||
|
// CHECK-NOT: strong_retain
|
||||||
|
// CHECK-NOT: strong_release
|
||||||
|
// CHECK: bb1:
|
||||||
|
// CHECK-NEXT: strong_retain
|
||||||
|
// CHECK: bb2:
|
||||||
|
// CHECK-NEXT: strong_release
|
||||||
|
sil @hammock4 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
bb0(%0 : $Builtin.NativeObject):
|
||||||
|
cond_br undef, bb1, bb2
|
||||||
|
|
||||||
|
bb1:
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
br bb2
|
||||||
|
|
||||||
|
bb2:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
%9999 = tuple()
|
||||||
|
return %9999 : $()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: sil @hammock5 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
// CHECK: bb0
|
||||||
|
// CHECK-NOT: strong_release
|
||||||
|
// CHECK-NOT: strong_retain
|
||||||
|
// CHECK: bb1:
|
||||||
|
// CHECK-NEXT: strong_release
|
||||||
|
// CHECK: bb2:
|
||||||
|
// CHECK-NEXT: strong_release
|
||||||
|
sil @hammock5 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
bb0(%0 : $Builtin.NativeObject):
|
||||||
|
cond_br undef, bb1, bb2
|
||||||
|
|
||||||
|
bb1:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
br bb2
|
||||||
|
|
||||||
|
bb2:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
%9999 = tuple()
|
||||||
|
return %9999 : $()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: sil @hammock6 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
// CHECK: bb0
|
||||||
|
// CHECK-NOT: strong_retain
|
||||||
|
// CHECK-NOT: strong_release
|
||||||
|
// CHECK: bb1:
|
||||||
|
// CHECK-NOT: strong_retain
|
||||||
|
// CHECK-NOT: strong_release
|
||||||
|
// CHECK: bb2:
|
||||||
|
// CHECK-NEXT: strong_release
|
||||||
|
sil @hammock6 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
bb0(%0 : $Builtin.NativeObject):
|
||||||
|
cond_br undef, bb1, bb2
|
||||||
|
|
||||||
|
bb1:
|
||||||
|
br bb2
|
||||||
|
|
||||||
|
bb2:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
%9999 = tuple()
|
||||||
|
return %9999 : $()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: sil @hammock7 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
// CHECK: bb0
|
||||||
|
// CHECK-NEXT: strong_retain
|
||||||
|
// CHECK: bb1:
|
||||||
|
// CHECK-NEXT: strong_retain
|
||||||
|
// CHECK: bb2:
|
||||||
|
// CHECK-NOT: strong_retain
|
||||||
|
// CHECK-NOT: strong_release
|
||||||
|
sil @hammock7 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
bb0(%0 : $Builtin.NativeObject):
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
cond_br undef, bb1, bb2
|
||||||
|
|
||||||
|
bb1:
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
br bb2
|
||||||
|
|
||||||
|
bb2:
|
||||||
|
%9999 = tuple()
|
||||||
|
return %9999 : $()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: sil @hammock8 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
// CHECK: bb0
|
||||||
|
// CHECK-NEXT: strong_retain
|
||||||
|
// CHECK-NOT: strong_release
|
||||||
|
// CHECK: bb1:
|
||||||
|
// CHECK-NEXT: strong_release
|
||||||
|
// CHECK-NOT: strong_retain
|
||||||
|
// CHECK: bb2:
|
||||||
|
// CHECK-NOT: strong_retain
|
||||||
|
// CHECK-NOT: strong_release
|
||||||
|
sil @hammock8 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
bb0(%0 : $Builtin.NativeObject):
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
cond_br undef, bb1, bb2
|
||||||
|
|
||||||
|
bb1:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
br bb2
|
||||||
|
|
||||||
|
bb2:
|
||||||
|
%9999 = tuple()
|
||||||
|
return %9999 : $()
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
// Double Hammock //
|
||||||
|
////////////////////
|
||||||
|
|
||||||
|
// Make sure we do not do anything in the presense of double partial
|
||||||
|
// applies. This is due to issues related to the two branches of the two
|
||||||
|
// diamonds not being control dependent.
|
||||||
|
// CHECK-LABEL: sil @double_hammock1 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
// CHECK: bb0
|
||||||
|
// CHECK-NEXT: function_ref user
|
||||||
|
// CHECK-NEXT: function_ref @user
|
||||||
|
// CHECK-NEXT: strong_retain
|
||||||
|
// CHECK-NEXT: cond_br
|
||||||
|
// CHECK: bb1:
|
||||||
|
// CHECK-NEXT: apply
|
||||||
|
// CHECK-NEXT: bb2
|
||||||
|
// CHECK: bb2:
|
||||||
|
// CHECK-NEXT: cond_br
|
||||||
|
// CHECK: bb3:
|
||||||
|
// CHECK-NEXT: apply
|
||||||
|
// CHECK-NEXT: br
|
||||||
|
// CHECK: bb4:
|
||||||
|
// CHECK-NEXT: strong_release
|
||||||
|
// CHECK-NEXT: tuple
|
||||||
|
// CHECK-NEXT: return
|
||||||
|
sil @double_hammock1 : $@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 bb2
|
||||||
|
|
||||||
|
bb2:
|
||||||
|
cond_br undef, bb3, bb4
|
||||||
|
|
||||||
|
bb3:
|
||||||
|
apply %1(%0) : $@thin (Builtin.NativeObject) -> ()
|
||||||
|
br bb4
|
||||||
|
|
||||||
|
bb4:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
%9999 = tuple()
|
||||||
|
return %9999 : $()
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////
|
||||||
|
// Diamonds //
|
||||||
|
//////////////
|
||||||
|
|
||||||
|
// CHECK-LABEL: sil @diamond1 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
// CHECK-NOT: strong_retain
|
||||||
|
// CHECK-NOT: strong_release
|
||||||
|
sil @diamond1 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
bb0(%0 : $Builtin.NativeObject):
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
cond_br undef, bb1, bb2
|
||||||
|
|
||||||
|
bb1:
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb2:
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb3:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
%1 = tuple()
|
||||||
|
return %1 : $()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: sil @diamond2 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
// CHECK: bb0
|
||||||
|
// CHECK-NEXT: strong_retain
|
||||||
|
// CHECK-NEXT: cond_br
|
||||||
|
// CHECK: bb1:
|
||||||
|
// CHECK-NEXT: br
|
||||||
|
// CHECK: bb2:
|
||||||
|
// CHECK-NEXT: strong_release
|
||||||
|
// CHECK-NEXT: br
|
||||||
|
// CHECK: bb3:
|
||||||
|
// CHECK-NEXT: tuple ()
|
||||||
|
// CHECK-NEXT: return
|
||||||
|
sil @diamond2 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
bb0(%0 : $Builtin.NativeObject):
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
cond_br undef, bb1, bb2
|
||||||
|
|
||||||
|
bb1:
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb2:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb3:
|
||||||
|
%1 = tuple()
|
||||||
|
return %1 : $()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: sil @diamond3 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
// CHECK: bb0
|
||||||
|
// CHECK-NEXT: strong_retain
|
||||||
|
// CHECK-NEXT: cond_br
|
||||||
|
// CHECK: bb1:
|
||||||
|
// CHECK-NEXT: strong_release
|
||||||
|
// CHECK-NEXT: br
|
||||||
|
// CHECK: bb2:
|
||||||
|
// CHECK-NEXT: br
|
||||||
|
// CHECK: bb3:
|
||||||
|
// CHECK-NEXT: tuple ()
|
||||||
|
// CHECK-NEXT: return
|
||||||
|
sil @diamond3 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
bb0(%0 : $Builtin.NativeObject):
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
cond_br undef, bb1, bb2
|
||||||
|
|
||||||
|
bb1:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb2:
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb3:
|
||||||
|
%1 = tuple()
|
||||||
|
return %1 : $()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: sil @diamond4 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
// CHECK-NOT: strong_retain
|
||||||
|
// CHECK-NOT: strong_release
|
||||||
|
sil @diamond4 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
bb0(%0 : $Builtin.NativeObject):
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
cond_br undef, bb1, bb2
|
||||||
|
|
||||||
|
bb1:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb2:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb3:
|
||||||
|
%1 = tuple()
|
||||||
|
return %1 : $()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: sil @diamond5 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
// CHECK: bb0
|
||||||
|
// CHECK-NEXT: strong_retain
|
||||||
|
// CHECK-NEXT: cond_br
|
||||||
|
// CHECK: bb1:
|
||||||
|
// CHECK-NEXT: strong_release
|
||||||
|
// CHECK-NEXT: br
|
||||||
|
// CHECK: bb2:
|
||||||
|
// CHECK-NEXT: br
|
||||||
|
// CHECK: bb3:
|
||||||
|
// CHECK-NEXT: strong_release
|
||||||
|
// CHECK-NEXT: tuple ()
|
||||||
|
// CHECK-NEXT: return
|
||||||
|
sil @diamond5 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
bb0(%0 : $Builtin.NativeObject):
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
cond_br undef, bb1, bb2
|
||||||
|
|
||||||
|
bb1:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb2:
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb3:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
%1 = tuple()
|
||||||
|
return %1 : $()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: sil @diamond6 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
// CHECK: bb0
|
||||||
|
// CHECK-NEXT: strong_retain
|
||||||
|
// CHECK-NEXT: cond_br
|
||||||
|
// CHECK: bb1:
|
||||||
|
// CHECK-NEXT: br
|
||||||
|
// CHECK: bb2:
|
||||||
|
// CHECK-NEXT: strong_release
|
||||||
|
// CHECK-NEXT: br
|
||||||
|
// CHECK: bb3:
|
||||||
|
// CHECK-NEXT: strong_release
|
||||||
|
// CHECK-NEXT: tuple ()
|
||||||
|
// CHECK-NEXT: return
|
||||||
|
sil @diamond6 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
bb0(%0 : $Builtin.NativeObject):
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
cond_br undef, bb1, bb2
|
||||||
|
|
||||||
|
bb1:
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb2:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb3:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
%1 = tuple()
|
||||||
|
return %1 : $()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: sil @diamond7 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
// CHECK: bb0
|
||||||
|
// CHECK-NEXT: cond_br
|
||||||
|
// CHECK: bb1:
|
||||||
|
// CHECK-NEXT: br
|
||||||
|
// CHECK: bb2:
|
||||||
|
// CHECK-NEXT: br
|
||||||
|
// CHECK: bb3:
|
||||||
|
// CHECK-NEXT: strong_release
|
||||||
|
// CHECK-NEXT: tuple ()
|
||||||
|
// CHECK-NEXT: return
|
||||||
|
sil @diamond7 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
bb0(%0 : $Builtin.NativeObject):
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
cond_br undef, bb1, bb2
|
||||||
|
|
||||||
|
bb1:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb2:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb3:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
%1 = tuple()
|
||||||
|
return %1 : $()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: sil @diamond8 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
// CHECK: bb0
|
||||||
|
// CHECK-NEXT: cond_br
|
||||||
|
// CHECK: bb1:
|
||||||
|
// CHECK-NEXT: strong_retain
|
||||||
|
// CHECK-NEXT: br
|
||||||
|
// CHECK: bb2:
|
||||||
|
// CHECK-NEXT: br
|
||||||
|
// CHECK: bb3:
|
||||||
|
// CHECK-NEXT: strong_release
|
||||||
|
// CHECK-NEXT: tuple ()
|
||||||
|
// CHECK-NEXT: return
|
||||||
|
sil @diamond8 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
bb0(%0 : $Builtin.NativeObject):
|
||||||
|
cond_br undef, bb1, bb2
|
||||||
|
|
||||||
|
bb1:
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb2:
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb3:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
%1 = tuple()
|
||||||
|
return %1 : $()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// CHECK-LABEL: sil @diamond9 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
// CHECK: bb0
|
||||||
|
// CHECK-NEXT: cond_br
|
||||||
|
// CHECK: bb1:
|
||||||
|
// CHECK-NEXT: br
|
||||||
|
// CHECK: bb2:
|
||||||
|
// CHECK-NEXT: strong_retain
|
||||||
|
// CHECK-NEXT: br
|
||||||
|
// CHECK: bb3:
|
||||||
|
// CHECK-NEXT: strong_release
|
||||||
|
// CHECK-NEXT: tuple ()
|
||||||
|
// CHECK-NEXT: return
|
||||||
|
sil @diamond9 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
bb0(%0 : $Builtin.NativeObject):
|
||||||
|
cond_br undef, bb1, bb2
|
||||||
|
|
||||||
|
bb1:
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb2:
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb3:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
%1 = tuple()
|
||||||
|
return %1 : $()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: sil @diamond10 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
// CHECK-NOT: strong_retain
|
||||||
|
// CHECK-NOT: strong_release
|
||||||
|
sil @diamond10 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
bb0(%0 : $Builtin.NativeObject):
|
||||||
|
cond_br undef, bb1, bb2
|
||||||
|
|
||||||
|
bb1:
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb2:
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb3:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
%1 = tuple()
|
||||||
|
return %1 : $()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// CHECK-LABEL: sil @diamond11 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
// CHECK: bb0
|
||||||
|
// CHECK-NEXT: strong_retain
|
||||||
|
// CHECK-NEXT: cond_br
|
||||||
|
// CHECK: bb1:
|
||||||
|
// CHECK-NEXT: strong_retain
|
||||||
|
// CHECK-NEXT: br
|
||||||
|
// CHECK: bb2:
|
||||||
|
// CHECK-NEXT: br
|
||||||
|
// CHECK: bb3:
|
||||||
|
// CHECK-NEXT: strong_release
|
||||||
|
// CHECK-NEXT: tuple ()
|
||||||
|
// CHECK-NEXT: return
|
||||||
|
sil @diamond11 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
bb0(%0 : $Builtin.NativeObject):
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
cond_br undef, bb1, bb2
|
||||||
|
|
||||||
|
bb1:
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb2:
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb3:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
%1 = tuple()
|
||||||
|
return %1 : $()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// CHECK-LABEL: sil @diamond12 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
// CHECK: bb0
|
||||||
|
// CHECK-NEXT: strong_retain
|
||||||
|
// CHECK-NEXT: cond_br
|
||||||
|
// CHECK: bb1:
|
||||||
|
// CHECK-NEXT: br
|
||||||
|
// CHECK: bb2:
|
||||||
|
// CHECK-NEXT: strong_retain
|
||||||
|
// CHECK-NEXT: br
|
||||||
|
// CHECK: bb3:
|
||||||
|
// CHECK-NEXT: strong_release
|
||||||
|
// CHECK-NEXT: tuple ()
|
||||||
|
// CHECK-NEXT: return
|
||||||
|
sil @diamond12 : $@thin (Builtin.NativeObject) -> () {
|
||||||
|
bb0(%0 : $Builtin.NativeObject):
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
cond_br undef, bb1, bb2
|
||||||
|
|
||||||
|
bb1:
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb2:
|
||||||
|
strong_retain %0 : $Builtin.NativeObject
|
||||||
|
br bb3
|
||||||
|
|
||||||
|
bb3:
|
||||||
|
strong_release %0 : $Builtin.NativeObject
|
||||||
|
%1 = tuple()
|
||||||
|
return %1 : $()
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user