blob: 595ee733bca587c2fd0a288f7c7e37058a21a47e [file] [log] [blame]
//===--- RCIdentityAnalysis.h -----------------------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This is an analysis that determines the ref count identity (i.e. gc root) of
// a pointer. Any values with the same ref count identity are able to be
// retained and released interchangeably.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SILOPTIMIZER_ANALYSIS_RCIDENTITYANALYSIS_H
#define SWIFT_SILOPTIMIZER_ANALYSIS_RCIDENTITYANALYSIS_H
#include "swift/SIL/SILValue.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SILOptimizer/Analysis/Analysis.h"
#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h"
#include "swift/SILOptimizer/PassManager/PassManager.h"
namespace swift {
/// Limit the size of the rc identity cache. We keep a cache per function.
constexpr unsigned MaxRCIdentityCacheSize = 64;
class DominanceAnalysis;
/// This class is a simple wrapper around an identity cache.
class RCIdentityFunctionInfo {
llvm::DenseSet<SILArgument *> VisitedArgs;
// RC identity cache.
llvm::DenseMap<SILValue, SILValue> RCCache;
DominanceAnalysis *DA;
/// This number is arbitrary and conservative. At some point if compile time
/// is not an issue, this value should be made more aggressive (i.e. greater).
enum { MaxRecursionDepth = 16 };
public:
RCIdentityFunctionInfo(DominanceAnalysis *D) : VisitedArgs(),
DA(D) {}
SILValue getRCIdentityRoot(SILValue V);
/// Return all recursive users of V, looking through users which propagate
/// RCIdentity. *NOTE* This ignores obvious ARC escapes where the a potential
/// user of the RC is not managed by ARC. For instance
/// unchecked_trivial_bit_cast.
void getRCUsers(SILValue V, llvm::SmallVectorImpl<SILInstruction *> &Users);
void handleDeleteNotification(SILNode *node) {
auto value = dyn_cast<ValueBase>(node);
if (!value)
return;
// Check the cache. If we don't find it, there is nothing to do.
auto Iter = RCCache.find(SILValue(value));
if (Iter == RCCache.end())
return;
// Then erase Iter from the cache.
RCCache.erase(Iter);
}
private:
SILValue getRCIdentityRootInner(SILValue V, unsigned RecursionDepth);
SILValue stripRCIdentityPreservingOps(SILValue V, unsigned RecursionDepth);
SILValue stripRCIdentityPreservingArgs(SILValue V, unsigned RecursionDepth);
SILValue stripOneRCIdentityIncomingValue(SILArgument *Arg, SILValue V);
bool findDominatingNonPayloadedEdge(SILBasicBlock *IncomingEdgeBB,
SILValue RCIdentity);
};
class RCIdentityAnalysis : public FunctionAnalysisBase<RCIdentityFunctionInfo> {
DominanceAnalysis *DA;
public:
RCIdentityAnalysis(SILModule *)
: FunctionAnalysisBase<RCIdentityFunctionInfo>(AnalysisKind::RCIdentity),
DA(nullptr) {}
RCIdentityAnalysis(const RCIdentityAnalysis &) = delete;
RCIdentityAnalysis &operator=(const RCIdentityAnalysis &) = delete;
virtual void handleDeleteNotification(SILNode *node) override {
// If the parent function of this instruction was just turned into an
// external declaration, bail. This happens during SILFunction destruction.
SILFunction *F = node->getFunction();
if (F->isExternalDeclaration()) {
return;
}
get(F)->handleDeleteNotification(node);
}
virtual bool needsNotifications() override { return true; }
static bool classof(const SILAnalysis *S) {
return S->getKind() == AnalysisKind::RCIdentity;
}
virtual void initialize(SILPassManager *PM) override;
virtual RCIdentityFunctionInfo *newFunctionAnalysis(SILFunction *F) override {
return new RCIdentityFunctionInfo(DA);
}
virtual bool shouldInvalidate(SILAnalysis::InvalidationKind K) override {
return true;
}
};
} // end swift namespace
#endif