Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/ObjCARC/ProvenanceAnalysis.cpp
35269 views
//===- ProvenanceAnalysis.cpp - ObjC ARC Optimization ---------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8/// \file9///10/// This file defines a special form of Alias Analysis called ``Provenance11/// Analysis''. The word ``provenance'' refers to the history of the ownership12/// of an object. Thus ``Provenance Analysis'' is an analysis which attempts to13/// use various techniques to determine if locally14///15/// WARNING: This file knows about certain library functions. It recognizes them16/// by name, and hardwires knowledge of their semantics.17///18/// WARNING: This file knows about how certain Objective-C library functions are19/// used. Naive LLVM IR transformations which would otherwise be20/// behavior-preserving may break these assumptions.21//22//===----------------------------------------------------------------------===//2324#include "ProvenanceAnalysis.h"25#include "llvm/ADT/SmallPtrSet.h"26#include "llvm/ADT/SmallVector.h"27#include "llvm/Analysis/AliasAnalysis.h"28#include "llvm/Analysis/ObjCARCAnalysisUtils.h"29#include "llvm/IR/Instructions.h"30#include "llvm/IR/Module.h"31#include "llvm/IR/Use.h"32#include "llvm/IR/User.h"33#include "llvm/IR/Value.h"34#include "llvm/Support/Casting.h"35#include <utility>3637using namespace llvm;38using namespace llvm::objcarc;3940bool ProvenanceAnalysis::relatedSelect(const SelectInst *A,41const Value *B) {42// If the values are Selects with the same condition, we can do a more precise43// check: just check for relations between the values on corresponding arms.44if (const SelectInst *SB = dyn_cast<SelectInst>(B))45if (A->getCondition() == SB->getCondition())46return related(A->getTrueValue(), SB->getTrueValue()) ||47related(A->getFalseValue(), SB->getFalseValue());4849// Check both arms of the Select node individually.50return related(A->getTrueValue(), B) || related(A->getFalseValue(), B);51}5253bool ProvenanceAnalysis::relatedPHI(const PHINode *A,54const Value *B) {55// If the values are PHIs in the same block, we can do a more precise as well56// as efficient check: just check for relations between the values on57// corresponding edges.58if (const PHINode *PNB = dyn_cast<PHINode>(B))59if (PNB->getParent() == A->getParent()) {60for (unsigned i = 0, e = A->getNumIncomingValues(); i != e; ++i)61if (related(A->getIncomingValue(i),62PNB->getIncomingValueForBlock(A->getIncomingBlock(i))))63return true;64return false;65}6667// Check each unique source of the PHI node against B.68SmallPtrSet<const Value *, 4> UniqueSrc;69for (Value *PV1 : A->incoming_values()) {70if (UniqueSrc.insert(PV1).second && related(PV1, B))71return true;72}7374// All of the arms checked out.75return false;76}7778/// Test if the value of P, or any value covered by its provenance, is ever79/// stored within the function (not counting callees).80static bool IsStoredObjCPointer(const Value *P) {81SmallPtrSet<const Value *, 8> Visited;82SmallVector<const Value *, 8> Worklist;83Worklist.push_back(P);84Visited.insert(P);85do {86P = Worklist.pop_back_val();87for (const Use &U : P->uses()) {88const User *Ur = U.getUser();89if (isa<StoreInst>(Ur)) {90if (U.getOperandNo() == 0)91// The pointer is stored.92return true;93// The pointed is stored through.94continue;95}96if (isa<CallInst>(Ur))97// The pointer is passed as an argument, ignore this.98continue;99if (isa<PtrToIntInst>(P))100// Assume the worst.101return true;102if (Visited.insert(Ur).second)103Worklist.push_back(Ur);104}105} while (!Worklist.empty());106107// Everything checked out.108return false;109}110111bool ProvenanceAnalysis::relatedCheck(const Value *A, const Value *B) {112// Ask regular AliasAnalysis, for a first approximation.113switch (AA->alias(A, B)) {114case AliasResult::NoAlias:115return false;116case AliasResult::MustAlias:117case AliasResult::PartialAlias:118return true;119case AliasResult::MayAlias:120break;121}122123bool AIsIdentified = IsObjCIdentifiedObject(A);124bool BIsIdentified = IsObjCIdentifiedObject(B);125126// An ObjC-Identified object can't alias a load if it is never locally stored.127if (AIsIdentified) {128// Check for an obvious escape.129if (isa<LoadInst>(B))130return IsStoredObjCPointer(A);131if (BIsIdentified) {132// Check for an obvious escape.133if (isa<LoadInst>(A))134return IsStoredObjCPointer(B);135// Both pointers are identified and escapes aren't an evident problem.136return false;137}138} else if (BIsIdentified) {139// Check for an obvious escape.140if (isa<LoadInst>(A))141return IsStoredObjCPointer(B);142}143144// Special handling for PHI and Select.145if (const PHINode *PN = dyn_cast<PHINode>(A))146return relatedPHI(PN, B);147if (const PHINode *PN = dyn_cast<PHINode>(B))148return relatedPHI(PN, A);149if (const SelectInst *S = dyn_cast<SelectInst>(A))150return relatedSelect(S, B);151if (const SelectInst *S = dyn_cast<SelectInst>(B))152return relatedSelect(S, A);153154// Conservative.155return true;156}157158bool ProvenanceAnalysis::related(const Value *A, const Value *B) {159A = GetUnderlyingObjCPtrCached(A, UnderlyingObjCPtrCache);160B = GetUnderlyingObjCPtrCached(B, UnderlyingObjCPtrCache);161162// Quick check.163if (A == B)164return true;165166// Begin by inserting a conservative value into the map. If the insertion167// fails, we have the answer already. If it succeeds, leave it there until we168// compute the real answer to guard against recursive queries.169std::pair<CachedResultsTy::iterator, bool> Pair =170CachedResults.insert(std::make_pair(ValuePairTy(A, B), true));171if (!Pair.second)172return Pair.first->second;173174bool Result = relatedCheck(A, B);175CachedResults[ValuePairTy(A, B)] = Result;176return Result;177}178179180