ARCAnalysis: Teach ARC analysis about certain objective c methods that are not may-release

This enables it to move retain about critical objective c method calls such as
objectAtIndex and count used by Array.

Improves DeltaBlue by 35% at -O.

radar://20147568

Swift SVN r26082
This commit is contained in:
Arnold Schwaighofer
2015-03-13 02:19:54 +00:00
parent 752c402dc2
commit a25b271c94
4 changed files with 144 additions and 1 deletions

View File

@@ -29,6 +29,56 @@ using namespace swift;
// Decrement Analysis
//===----------------------------------------------------------------------===//
/// \brief Test whether this is an Objective C method of a specific protocol.
static bool isObjCProtocolMethod(WitnessMethodInst *WMI, ProtocolDecl *Protocol,
StringRef MethodName) {
// Must be an objc method.
auto Member = WMI->getMember();
if (!Member.isForeign)
return false;
if (Protocol != WMI->getLookupProtocol())
return false;
auto *Method = Member.getFuncDecl();
if (!Method || Method->getName().empty())
return false;
if (!Method->getName().str().equals(MethodName))
return false;
return true;
}
/// \brief Test whether this is an Objective C getter of a specific protocol.
static bool isObjCProtocolGetter(WitnessMethodInst *WMI, ProtocolDecl *Protocol,
StringRef VarName) {
// Must be an objc method.
auto Member = WMI->getMember();
if (!Member.isForeign)
return false;
if (Protocol != WMI->getLookupProtocol())
return false;
auto *Method = Member.getFuncDecl();
if (!Method || !Method->isGetter())
return false;
auto *Storage = Method->getAccessorStorageDecl();
if (!Storage || Storage->getName().empty())
return false;
if (!Storage->getName().str().equals(VarName))
return false;
return true;
}
static bool isKnownToNotDecrementRefCount(FunctionRefInst *FRI) {
return llvm::StringSwitch<bool>(FRI->getReferencedFunction()->getName())
.Case("swift_keepAlive", true)
@@ -36,6 +86,37 @@ static bool isKnownToNotDecrementRefCount(FunctionRefInst *FRI) {
.Default(false);
}
/// \brief Check whether this is an Objective C method that only has balanced
/// retain/releases. The method is known not to decrement a reference count
/// before incrementing it.
static bool isObjCMethodKnownToNotDecrementRefCount(ApplyInst *AI) {
auto *WMI = dyn_cast<WitnessMethodInst>(AI->getCallee());
if (!WMI)
return false;
auto &Ctx = AI->getFunction()->getModule().getASTContext();
auto *ArrayProtocol = Ctx.getProtocol(KnownProtocolKind::_NSArrayCoreType);
// If we don't have the _NSArrayCoreType we will not have an
// _NSDictionaryCoreType either.
if (!ArrayProtocol)
return false;
if (isObjCProtocolMethod(WMI, ArrayProtocol, "objectAtIndex"))
return true;
if (isObjCProtocolGetter(WMI, ArrayProtocol, "count"))
return true;
auto *DictionaryProtocol =
Ctx.getProtocol(KnownProtocolKind::_NSDictionaryCoreType);
if (isObjCProtocolMethod(WMI, DictionaryProtocol, "objectForKey"))
return true;
if (isObjCProtocolGetter(WMI, DictionaryProtocol, "count"))
return true;
return false;
}
static bool canApplyDecrementRefCount(OperandValueArrayRef Ops, SILValue Ptr,
AliasAnalysis *AA) {
// Ok, this apply *MAY* decrement ref counts. Now our strategy is to attempt
@@ -91,6 +172,9 @@ static bool canApplyDecrementRefCount(ApplyInst *AI, SILValue Ptr,
if (Call && !Call.isMayRelease())
return false;
if (isObjCMethodKnownToNotDecrementRefCount(AI))
return false;
return canApplyDecrementRefCount(AI->getArgumentsWithoutIndirectResult(),
Ptr, AA);
}
@@ -432,6 +516,9 @@ mayGuaranteedUseValue(SILInstruction *User, SILValue Ptr, AliasAnalysis *AA) {
if (Call && !Call.isMayRelease())
return false;
if (isObjCMethodKnownToNotDecrementRefCount(AI))
return false;
// Ok, we have an apply with arguments. Look at the function type and iterate
// through the function parameters. If any of the parameters are guaranteed,
// attempt to prove that the passed in parameter can not alias Ptr. If we