1778138e9SMichael Gottesman //===- ProvenanceAnalysis.cpp - ObjC ARC Optimization ---------------------===//
2778138e9SMichael Gottesman //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6778138e9SMichael Gottesman //
7778138e9SMichael Gottesman //===----------------------------------------------------------------------===//
857bd5a02SEugene Zelenko //
9778138e9SMichael Gottesman /// \file
10778138e9SMichael Gottesman ///
11778138e9SMichael Gottesman /// This file defines a special form of Alias Analysis called ``Provenance
12778138e9SMichael Gottesman /// Analysis''. The word ``provenance'' refers to the history of the ownership
13778138e9SMichael Gottesman /// of an object. Thus ``Provenance Analysis'' is an analysis which attempts to
14778138e9SMichael Gottesman /// use various techniques to determine if locally
15778138e9SMichael Gottesman ///
16778138e9SMichael Gottesman /// WARNING: This file knows about certain library functions. It recognizes them
17778138e9SMichael Gottesman /// by name, and hardwires knowledge of their semantics.
18778138e9SMichael Gottesman ///
19778138e9SMichael Gottesman /// WARNING: This file knows about how certain Objective-C library functions are
20778138e9SMichael Gottesman /// used. Naive LLVM IR transformations which would otherwise be
21778138e9SMichael Gottesman /// behavior-preserving may break these assumptions.
2257bd5a02SEugene Zelenko //
23778138e9SMichael Gottesman //===----------------------------------------------------------------------===//
24778138e9SMichael Gottesman 
25778138e9SMichael Gottesman #include "ProvenanceAnalysis.h"
26278266faSMichael Gottesman #include "llvm/ADT/SmallPtrSet.h"
2757bd5a02SEugene Zelenko #include "llvm/ADT/SmallVector.h"
2857bd5a02SEugene Zelenko #include "llvm/Analysis/AliasAnalysis.h"
2957bd5a02SEugene Zelenko #include "llvm/Analysis/ObjCARCAnalysisUtils.h"
3057bd5a02SEugene Zelenko #include "llvm/IR/Instructions.h"
3157bd5a02SEugene Zelenko #include "llvm/IR/Module.h"
3257bd5a02SEugene Zelenko #include "llvm/IR/Use.h"
3357bd5a02SEugene Zelenko #include "llvm/IR/User.h"
3457bd5a02SEugene Zelenko #include "llvm/IR/Value.h"
3557bd5a02SEugene Zelenko #include "llvm/Support/Casting.h"
3657bd5a02SEugene Zelenko #include <utility>
37778138e9SMichael Gottesman 
38778138e9SMichael Gottesman using namespace llvm;
39778138e9SMichael Gottesman using namespace llvm::objcarc;
40778138e9SMichael Gottesman 
relatedSelect(const SelectInst * A,const Value * B)41778138e9SMichael Gottesman bool ProvenanceAnalysis::relatedSelect(const SelectInst *A,
42778138e9SMichael Gottesman                                        const Value *B) {
43778138e9SMichael Gottesman   // If the values are Selects with the same condition, we can do a more precise
44778138e9SMichael Gottesman   // check: just check for relations between the values on corresponding arms.
45778138e9SMichael Gottesman   if (const SelectInst *SB = dyn_cast<SelectInst>(B))
46778138e9SMichael Gottesman     if (A->getCondition() == SB->getCondition())
47b0f1d7d5SAkira Hatanaka       return related(A->getTrueValue(), SB->getTrueValue()) ||
48b0f1d7d5SAkira Hatanaka              related(A->getFalseValue(), SB->getFalseValue());
49778138e9SMichael Gottesman 
50778138e9SMichael Gottesman   // Check both arms of the Select node individually.
51b0f1d7d5SAkira Hatanaka   return related(A->getTrueValue(), B) || related(A->getFalseValue(), B);
52778138e9SMichael Gottesman }
53778138e9SMichael Gottesman 
relatedPHI(const PHINode * A,const Value * B)54778138e9SMichael Gottesman bool ProvenanceAnalysis::relatedPHI(const PHINode *A,
55778138e9SMichael Gottesman                                     const Value *B) {
56778138e9SMichael Gottesman   // If the values are PHIs in the same block, we can do a more precise as well
57778138e9SMichael Gottesman   // as efficient check: just check for relations between the values on
58778138e9SMichael Gottesman   // corresponding edges.
59778138e9SMichael Gottesman   if (const PHINode *PNB = dyn_cast<PHINode>(B))
60778138e9SMichael Gottesman     if (PNB->getParent() == A->getParent()) {
61778138e9SMichael Gottesman       for (unsigned i = 0, e = A->getNumIncomingValues(); i != e; ++i)
62778138e9SMichael Gottesman         if (related(A->getIncomingValue(i),
63b0f1d7d5SAkira Hatanaka                     PNB->getIncomingValueForBlock(A->getIncomingBlock(i))))
64778138e9SMichael Gottesman           return true;
65778138e9SMichael Gottesman       return false;
66778138e9SMichael Gottesman     }
67778138e9SMichael Gottesman 
68778138e9SMichael Gottesman   // Check each unique source of the PHI node against B.
69778138e9SMichael Gottesman   SmallPtrSet<const Value *, 4> UniqueSrc;
70833f34d8SPete Cooper   for (Value *PV1 : A->incoming_values()) {
71b0f1d7d5SAkira Hatanaka     if (UniqueSrc.insert(PV1).second && related(PV1, B))
72778138e9SMichael Gottesman       return true;
73778138e9SMichael Gottesman   }
74778138e9SMichael Gottesman 
75778138e9SMichael Gottesman   // All of the arms checked out.
76778138e9SMichael Gottesman   return false;
77778138e9SMichael Gottesman }
78778138e9SMichael Gottesman 
79778138e9SMichael Gottesman /// Test if the value of P, or any value covered by its provenance, is ever
80778138e9SMichael Gottesman /// stored within the function (not counting callees).
IsStoredObjCPointer(const Value * P)8127029f46SMichael Gottesman static bool IsStoredObjCPointer(const Value *P) {
82778138e9SMichael Gottesman   SmallPtrSet<const Value *, 8> Visited;
83778138e9SMichael Gottesman   SmallVector<const Value *, 8> Worklist;
84778138e9SMichael Gottesman   Worklist.push_back(P);
85778138e9SMichael Gottesman   Visited.insert(P);
86778138e9SMichael Gottesman   do {
87778138e9SMichael Gottesman     P = Worklist.pop_back_val();
88cdf47884SChandler Carruth     for (const Use &U : P->uses()) {
89cdf47884SChandler Carruth       const User *Ur = U.getUser();
90778138e9SMichael Gottesman       if (isa<StoreInst>(Ur)) {
91cdf47884SChandler Carruth         if (U.getOperandNo() == 0)
92778138e9SMichael Gottesman           // The pointer is stored.
93778138e9SMichael Gottesman           return true;
94778138e9SMichael Gottesman         // The pointed is stored through.
95778138e9SMichael Gottesman         continue;
96778138e9SMichael Gottesman       }
97778138e9SMichael Gottesman       if (isa<CallInst>(Ur))
98778138e9SMichael Gottesman         // The pointer is passed as an argument, ignore this.
99778138e9SMichael Gottesman         continue;
100778138e9SMichael Gottesman       if (isa<PtrToIntInst>(P))
101778138e9SMichael Gottesman         // Assume the worst.
102778138e9SMichael Gottesman         return true;
10370573dcdSDavid Blaikie       if (Visited.insert(Ur).second)
104778138e9SMichael Gottesman         Worklist.push_back(Ur);
105778138e9SMichael Gottesman     }
106778138e9SMichael Gottesman   } while (!Worklist.empty());
107778138e9SMichael Gottesman 
108778138e9SMichael Gottesman   // Everything checked out.
109778138e9SMichael Gottesman   return false;
110778138e9SMichael Gottesman }
111778138e9SMichael Gottesman 
relatedCheck(const Value * A,const Value * B)112b0f1d7d5SAkira Hatanaka bool ProvenanceAnalysis::relatedCheck(const Value *A, const Value *B) {
113778138e9SMichael Gottesman   // Ask regular AliasAnalysis, for a first approximation.
114778138e9SMichael Gottesman   switch (AA->alias(A, B)) {
115*d0660797Sdfukalov   case AliasResult::NoAlias:
116778138e9SMichael Gottesman     return false;
117*d0660797Sdfukalov   case AliasResult::MustAlias:
118*d0660797Sdfukalov   case AliasResult::PartialAlias:
119778138e9SMichael Gottesman     return true;
120*d0660797Sdfukalov   case AliasResult::MayAlias:
121778138e9SMichael Gottesman     break;
122778138e9SMichael Gottesman   }
123778138e9SMichael Gottesman 
124778138e9SMichael Gottesman   bool AIsIdentified = IsObjCIdentifiedObject(A);
125778138e9SMichael Gottesman   bool BIsIdentified = IsObjCIdentifiedObject(B);
126778138e9SMichael Gottesman 
127778138e9SMichael Gottesman   // An ObjC-Identified object can't alias a load if it is never locally stored.
128778138e9SMichael Gottesman   if (AIsIdentified) {
129778138e9SMichael Gottesman     // Check for an obvious escape.
130778138e9SMichael Gottesman     if (isa<LoadInst>(B))
13127029f46SMichael Gottesman       return IsStoredObjCPointer(A);
132778138e9SMichael Gottesman     if (BIsIdentified) {
133778138e9SMichael Gottesman       // Check for an obvious escape.
134778138e9SMichael Gottesman       if (isa<LoadInst>(A))
13527029f46SMichael Gottesman         return IsStoredObjCPointer(B);
136778138e9SMichael Gottesman       // Both pointers are identified and escapes aren't an evident problem.
137778138e9SMichael Gottesman       return false;
138778138e9SMichael Gottesman     }
139778138e9SMichael Gottesman   } else if (BIsIdentified) {
140778138e9SMichael Gottesman     // Check for an obvious escape.
141778138e9SMichael Gottesman     if (isa<LoadInst>(A))
14227029f46SMichael Gottesman       return IsStoredObjCPointer(B);
143778138e9SMichael Gottesman   }
144778138e9SMichael Gottesman 
145778138e9SMichael Gottesman    // Special handling for PHI and Select.
146778138e9SMichael Gottesman   if (const PHINode *PN = dyn_cast<PHINode>(A))
147778138e9SMichael Gottesman     return relatedPHI(PN, B);
148778138e9SMichael Gottesman   if (const PHINode *PN = dyn_cast<PHINode>(B))
149778138e9SMichael Gottesman     return relatedPHI(PN, A);
150778138e9SMichael Gottesman   if (const SelectInst *S = dyn_cast<SelectInst>(A))
151778138e9SMichael Gottesman     return relatedSelect(S, B);
152778138e9SMichael Gottesman   if (const SelectInst *S = dyn_cast<SelectInst>(B))
153778138e9SMichael Gottesman     return relatedSelect(S, A);
154778138e9SMichael Gottesman 
155778138e9SMichael Gottesman   // Conservative.
156778138e9SMichael Gottesman   return true;
157778138e9SMichael Gottesman }
158778138e9SMichael Gottesman 
related(const Value * A,const Value * B)159b0f1d7d5SAkira Hatanaka bool ProvenanceAnalysis::related(const Value *A, const Value *B) {
160b0eb40caSVitaly Buka   A = GetUnderlyingObjCPtrCached(A, UnderlyingObjCPtrCache);
161b0eb40caSVitaly Buka   B = GetUnderlyingObjCPtrCached(B, UnderlyingObjCPtrCache);
162a3d8ef0fSMichael Zolotukhin 
163a3d8ef0fSMichael Zolotukhin   // Quick check.
164a3d8ef0fSMichael Zolotukhin   if (A == B)
165a3d8ef0fSMichael Zolotukhin     return true;
166a3d8ef0fSMichael Zolotukhin 
167778138e9SMichael Gottesman   // Begin by inserting a conservative value into the map. If the insertion
168778138e9SMichael Gottesman   // fails, we have the answer already. If it succeeds, leave it there until we
169778138e9SMichael Gottesman   // compute the real answer to guard against recursive queries.
170778138e9SMichael Gottesman   if (A > B) std::swap(A, B);
171778138e9SMichael Gottesman   std::pair<CachedResultsTy::iterator, bool> Pair =
172778138e9SMichael Gottesman     CachedResults.insert(std::make_pair(ValuePairTy(A, B), true));
173778138e9SMichael Gottesman   if (!Pair.second)
174778138e9SMichael Gottesman     return Pair.first->second;
175778138e9SMichael Gottesman 
176b0f1d7d5SAkira Hatanaka   bool Result = relatedCheck(A, B);
177778138e9SMichael Gottesman   CachedResults[ValuePairTy(A, B)] = Result;
178778138e9SMichael Gottesman   return Result;
179778138e9SMichael Gottesman }
180