llvm-6502/lib/Transforms/ObjCARC/ProvenanceAnalysis.cpp
Chandler Carruth 1e3557de0d [PM/AA] Hoist the AliasResult enum out of the AliasAnalysis class.
This will allow classes to implement the AA interface without deriving
from the class or referencing an internal enum of some other class as
their return types.

Also, to a pretty fundamental extent, concepts such as 'NoAlias',
'MayAlias', and 'MustAlias' are first class concepts in LLVM and we
aren't saving anything by scoping them heavily.

My mild preference would have been to use a scoped enum, but that
feature is essentially completely broken AFAICT. I'm extremely
disappointed. For example, we cannot through any reasonable[1] means
construct an enum class (or analog) which has scoped names but converts
to a boolean in order to test for the possibility of aliasing.

[1]: Richard Smith came up with a "solution", but it requires class
templates, and lots of boilerplate setting up the enumeration multiple
times. Something like Boost.PP could potentially bundle this up, but
even that would be quite painful and it doesn't seem realistically worth
it. The enum class solution would probably work without the need for
a bool conversion.

Differential Revision: http://reviews.llvm.org/D10495

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@240255 91177308-0d34-0410-b5e6-96231b3b80d8
2015-06-22 02:16:51 +00:00

178 lines
6.0 KiB
C++

//===- ProvenanceAnalysis.cpp - ObjC ARC Optimization ---------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/// \file
///
/// This file defines a special form of Alias Analysis called ``Provenance
/// Analysis''. The word ``provenance'' refers to the history of the ownership
/// of an object. Thus ``Provenance Analysis'' is an analysis which attempts to
/// use various techniques to determine if locally
///
/// WARNING: This file knows about certain library functions. It recognizes them
/// by name, and hardwires knowledge of their semantics.
///
/// WARNING: This file knows about how certain Objective-C library functions are
/// used. Naive LLVM IR transformations which would otherwise be
/// behavior-preserving may break these assumptions.
///
//===----------------------------------------------------------------------===//
#include "ObjCARC.h"
#include "ProvenanceAnalysis.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
using namespace llvm;
using namespace llvm::objcarc;
bool ProvenanceAnalysis::relatedSelect(const SelectInst *A,
const Value *B) {
const DataLayout &DL = A->getModule()->getDataLayout();
// If the values are Selects with the same condition, we can do a more precise
// check: just check for relations between the values on corresponding arms.
if (const SelectInst *SB = dyn_cast<SelectInst>(B))
if (A->getCondition() == SB->getCondition())
return related(A->getTrueValue(), SB->getTrueValue(), DL) ||
related(A->getFalseValue(), SB->getFalseValue(), DL);
// Check both arms of the Select node individually.
return related(A->getTrueValue(), B, DL) ||
related(A->getFalseValue(), B, DL);
}
bool ProvenanceAnalysis::relatedPHI(const PHINode *A,
const Value *B) {
const DataLayout &DL = A->getModule()->getDataLayout();
// If the values are PHIs in the same block, we can do a more precise as well
// as efficient check: just check for relations between the values on
// corresponding edges.
if (const PHINode *PNB = dyn_cast<PHINode>(B))
if (PNB->getParent() == A->getParent()) {
for (unsigned i = 0, e = A->getNumIncomingValues(); i != e; ++i)
if (related(A->getIncomingValue(i),
PNB->getIncomingValueForBlock(A->getIncomingBlock(i)), DL))
return true;
return false;
}
// Check each unique source of the PHI node against B.
SmallPtrSet<const Value *, 4> UniqueSrc;
for (Value *PV1 : A->incoming_values()) {
if (UniqueSrc.insert(PV1).second && related(PV1, B, DL))
return true;
}
// All of the arms checked out.
return false;
}
/// Test if the value of P, or any value covered by its provenance, is ever
/// stored within the function (not counting callees).
static bool IsStoredObjCPointer(const Value *P) {
SmallPtrSet<const Value *, 8> Visited;
SmallVector<const Value *, 8> Worklist;
Worklist.push_back(P);
Visited.insert(P);
do {
P = Worklist.pop_back_val();
for (const Use &U : P->uses()) {
const User *Ur = U.getUser();
if (isa<StoreInst>(Ur)) {
if (U.getOperandNo() == 0)
// The pointer is stored.
return true;
// The pointed is stored through.
continue;
}
if (isa<CallInst>(Ur))
// The pointer is passed as an argument, ignore this.
continue;
if (isa<PtrToIntInst>(P))
// Assume the worst.
return true;
if (Visited.insert(Ur).second)
Worklist.push_back(Ur);
}
} while (!Worklist.empty());
// Everything checked out.
return false;
}
bool ProvenanceAnalysis::relatedCheck(const Value *A, const Value *B,
const DataLayout &DL) {
// Skip past provenance pass-throughs.
A = GetUnderlyingObjCPtr(A, DL);
B = GetUnderlyingObjCPtr(B, DL);
// Quick check.
if (A == B)
return true;
// Ask regular AliasAnalysis, for a first approximation.
switch (AA->alias(A, B)) {
case NoAlias:
return false;
case MustAlias:
case PartialAlias:
return true;
case MayAlias:
break;
}
bool AIsIdentified = IsObjCIdentifiedObject(A);
bool BIsIdentified = IsObjCIdentifiedObject(B);
// An ObjC-Identified object can't alias a load if it is never locally stored.
if (AIsIdentified) {
// Check for an obvious escape.
if (isa<LoadInst>(B))
return IsStoredObjCPointer(A);
if (BIsIdentified) {
// Check for an obvious escape.
if (isa<LoadInst>(A))
return IsStoredObjCPointer(B);
// Both pointers are identified and escapes aren't an evident problem.
return false;
}
} else if (BIsIdentified) {
// Check for an obvious escape.
if (isa<LoadInst>(A))
return IsStoredObjCPointer(B);
}
// Special handling for PHI and Select.
if (const PHINode *PN = dyn_cast<PHINode>(A))
return relatedPHI(PN, B);
if (const PHINode *PN = dyn_cast<PHINode>(B))
return relatedPHI(PN, A);
if (const SelectInst *S = dyn_cast<SelectInst>(A))
return relatedSelect(S, B);
if (const SelectInst *S = dyn_cast<SelectInst>(B))
return relatedSelect(S, A);
// Conservative.
return true;
}
bool ProvenanceAnalysis::related(const Value *A, const Value *B,
const DataLayout &DL) {
// Begin by inserting a conservative value into the map. If the insertion
// fails, we have the answer already. If it succeeds, leave it there until we
// compute the real answer to guard against recursive queries.
if (A > B) std::swap(A, B);
std::pair<CachedResultsTy::iterator, bool> Pair =
CachedResults.insert(std::make_pair(ValuePairTy(A, B), true));
if (!Pair.second)
return Pair.first->second;
bool Result = relatedCheck(A, B, DL);
CachedResults[ValuePairTy(A, B)] = Result;
return Result;
}