blob: 334628dbd5d5719638c40f7f8fa367b446ae21ea [file] [log] [blame]
//===--- RCStateTransition.cpp --------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "arc-sequence-opts"
#include "RCStateTransition.h"
#include "swift/SIL/SILInstruction.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Debug.h"
using namespace swift;
//===----------------------------------------------------------------------===//
// Utility
//===----------------------------------------------------------------------===//
static bool isAutoreleasePoolCall(SILInstruction *I) {
auto *AI = dyn_cast<ApplyInst>(I);
if (!AI)
return false;
auto *Fn = AI->getReferencedFunction();
if (!Fn)
return false;
return llvm::StringSwitch<bool>(Fn->getName())
.Case("objc_autoreleasePoolPush", true)
.Case("objc_autoreleasePoolPop", true)
.Default(false);
}
//===----------------------------------------------------------------------===//
// RCStateTransitionKind
//===----------------------------------------------------------------------===//
RCStateTransitionKind swift::getRCStateTransitionKind(SILNode *N) {
switch (N->getKind()) {
case SILNodeKind::StrongRetainInst:
case SILNodeKind::RetainValueInst:
return RCStateTransitionKind::StrongIncrement;
case SILNodeKind::StrongReleaseInst:
case SILNodeKind::ReleaseValueInst:
return RCStateTransitionKind::StrongDecrement;
case SILNodeKind::SILFunctionArgument: {
auto *Arg = cast<SILFunctionArgument>(N);
if (Arg->hasConvention(SILArgumentConvention::Direct_Owned))
return RCStateTransitionKind::StrongEntrance;
return RCStateTransitionKind::Unknown;
}
case SILNodeKind::ApplyInst: {
auto *AI = cast<ApplyInst>(N);
if (isAutoreleasePoolCall(AI))
return RCStateTransitionKind::AutoreleasePoolCall;
// If we have an @owned return value. This AI is a strong entrance for its
// return value.
//
// TODO: When we support pairing retains with @owned parameters, we will
// need to be able to handle the potential of multiple state transition
// kinds.
for (auto result : AI->getSubstCalleeConv().getDirectSILResults()) {
if (result.getConvention() == ResultConvention::Owned)
return RCStateTransitionKind::StrongEntrance;
}
return RCStateTransitionKind::Unknown;
}
// Alloc* are always allocating new classes so they are introducing new
// values at +1.
case SILNodeKind::AllocRefInst:
case SILNodeKind::AllocRefDynamicInst:
case SILNodeKind::AllocBoxInst:
return RCStateTransitionKind::StrongEntrance;
case SILNodeKind::PartialApplyInst:
// Partial apply boxes are introduced at +1.
return RCStateTransitionKind::StrongEntrance;
default:
return RCStateTransitionKind::Unknown;
}
}
/// Define test functions for all of our abstract value kinds.
#define ABSTRACT_VALUE(Name, StartKind, EndKind) \
bool swift::isRCStateTransition ## Name(RCStateTransitionKind Kind) { \
return unsigned(RCStateTransitionKind::StartKind) <= unsigned(Kind) && \
unsigned(RCStateTransitionKind::EndKind) >= unsigned(Kind); \
}
#include "RCStateTransition.def"
raw_ostream &llvm::operator<<(raw_ostream &os, RCStateTransitionKind Kind) {
switch (Kind) {
#define KIND(K) \
case RCStateTransitionKind::K: \
return os << #K;
#include "RCStateTransition.def"
}
llvm_unreachable("Covered switch isn't covered?!");
}
//===----------------------------------------------------------------------===//
// RCStateTransition
//===----------------------------------------------------------------------===//
#define ABSTRACT_VALUE(Name, Start, End) \
bool RCStateTransition::is ## Name() const { \
return isRCStateTransition ## Name(getKind()); \
}
#include "RCStateTransition.def"
bool RCStateTransition::matchingInst(SILInstruction *Inst) const {
// We only pair mutators for now.
if (!isMutator())
return false;
if (Kind == RCStateTransitionKind::StrongIncrement) {
auto InstTransKind = getRCStateTransitionKind(Inst);
return InstTransKind == RCStateTransitionKind::StrongDecrement;
}
if (Kind == RCStateTransitionKind::StrongDecrement) {
auto InstTransKind = getRCStateTransitionKind(Inst);
return InstTransKind == RCStateTransitionKind::StrongIncrement;
}
return false;
}
bool RCStateTransition::merge(const RCStateTransition &Other) {
// If our kinds do not match, bail. We don't cross the streams.
if (Kind != Other.Kind)
return false;
// If we are not a mutator, there is nothing further to do here.
if (!isMutator())
return true;
Mutators = Mutators->merge(Other.Mutators);
return true;
}