xref: /aosp_15_r20/external/llvm/lib/Transforms/Utils/GlobalStatus.cpp (revision 9880d6810fe72a1726cb53787c6711e909410d58)
1*9880d681SAndroid Build Coastguard Worker //===-- GlobalStatus.cpp - Compute status info for globals -----------------==//
2*9880d681SAndroid Build Coastguard Worker //
3*9880d681SAndroid Build Coastguard Worker //                     The LLVM Compiler Infrastructure
4*9880d681SAndroid Build Coastguard Worker //
5*9880d681SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*9880d681SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*9880d681SAndroid Build Coastguard Worker //
8*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*9880d681SAndroid Build Coastguard Worker 
10*9880d681SAndroid Build Coastguard Worker #include "llvm/ADT/SmallPtrSet.h"
11*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/BasicBlock.h"
12*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/CallSite.h"
13*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/GlobalVariable.h"
14*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/IntrinsicInst.h"
15*9880d681SAndroid Build Coastguard Worker #include "llvm/Transforms/Utils/GlobalStatus.h"
16*9880d681SAndroid Build Coastguard Worker 
17*9880d681SAndroid Build Coastguard Worker using namespace llvm;
18*9880d681SAndroid Build Coastguard Worker 
19*9880d681SAndroid Build Coastguard Worker /// Return the stronger of the two ordering. If the two orderings are acquire
20*9880d681SAndroid Build Coastguard Worker /// and release, then return AcquireRelease.
21*9880d681SAndroid Build Coastguard Worker ///
strongerOrdering(AtomicOrdering X,AtomicOrdering Y)22*9880d681SAndroid Build Coastguard Worker static AtomicOrdering strongerOrdering(AtomicOrdering X, AtomicOrdering Y) {
23*9880d681SAndroid Build Coastguard Worker   if (X == AtomicOrdering::Acquire && Y == AtomicOrdering::Release)
24*9880d681SAndroid Build Coastguard Worker     return AtomicOrdering::AcquireRelease;
25*9880d681SAndroid Build Coastguard Worker   if (Y == AtomicOrdering::Acquire && X == AtomicOrdering::Release)
26*9880d681SAndroid Build Coastguard Worker     return AtomicOrdering::AcquireRelease;
27*9880d681SAndroid Build Coastguard Worker   return (AtomicOrdering)std::max((unsigned)X, (unsigned)Y);
28*9880d681SAndroid Build Coastguard Worker }
29*9880d681SAndroid Build Coastguard Worker 
30*9880d681SAndroid Build Coastguard Worker /// It is safe to destroy a constant iff it is only used by constants itself.
31*9880d681SAndroid Build Coastguard Worker /// Note that constants cannot be cyclic, so this test is pretty easy to
32*9880d681SAndroid Build Coastguard Worker /// implement recursively.
33*9880d681SAndroid Build Coastguard Worker ///
isSafeToDestroyConstant(const Constant * C)34*9880d681SAndroid Build Coastguard Worker bool llvm::isSafeToDestroyConstant(const Constant *C) {
35*9880d681SAndroid Build Coastguard Worker   if (isa<GlobalValue>(C))
36*9880d681SAndroid Build Coastguard Worker     return false;
37*9880d681SAndroid Build Coastguard Worker 
38*9880d681SAndroid Build Coastguard Worker   if (isa<ConstantInt>(C) || isa<ConstantFP>(C))
39*9880d681SAndroid Build Coastguard Worker     return false;
40*9880d681SAndroid Build Coastguard Worker 
41*9880d681SAndroid Build Coastguard Worker   for (const User *U : C->users())
42*9880d681SAndroid Build Coastguard Worker     if (const Constant *CU = dyn_cast<Constant>(U)) {
43*9880d681SAndroid Build Coastguard Worker       if (!isSafeToDestroyConstant(CU))
44*9880d681SAndroid Build Coastguard Worker         return false;
45*9880d681SAndroid Build Coastguard Worker     } else
46*9880d681SAndroid Build Coastguard Worker       return false;
47*9880d681SAndroid Build Coastguard Worker   return true;
48*9880d681SAndroid Build Coastguard Worker }
49*9880d681SAndroid Build Coastguard Worker 
analyzeGlobalAux(const Value * V,GlobalStatus & GS,SmallPtrSetImpl<const PHINode * > & PhiUsers)50*9880d681SAndroid Build Coastguard Worker static bool analyzeGlobalAux(const Value *V, GlobalStatus &GS,
51*9880d681SAndroid Build Coastguard Worker                              SmallPtrSetImpl<const PHINode *> &PhiUsers) {
52*9880d681SAndroid Build Coastguard Worker   if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(V))
53*9880d681SAndroid Build Coastguard Worker     if (GV->isExternallyInitialized())
54*9880d681SAndroid Build Coastguard Worker       GS.StoredType = GlobalStatus::StoredOnce;
55*9880d681SAndroid Build Coastguard Worker 
56*9880d681SAndroid Build Coastguard Worker   for (const Use &U : V->uses()) {
57*9880d681SAndroid Build Coastguard Worker     const User *UR = U.getUser();
58*9880d681SAndroid Build Coastguard Worker     if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(UR)) {
59*9880d681SAndroid Build Coastguard Worker       GS.HasNonInstructionUser = true;
60*9880d681SAndroid Build Coastguard Worker 
61*9880d681SAndroid Build Coastguard Worker       // If the result of the constantexpr isn't pointer type, then we won't
62*9880d681SAndroid Build Coastguard Worker       // know to expect it in various places.  Just reject early.
63*9880d681SAndroid Build Coastguard Worker       if (!isa<PointerType>(CE->getType()))
64*9880d681SAndroid Build Coastguard Worker         return true;
65*9880d681SAndroid Build Coastguard Worker 
66*9880d681SAndroid Build Coastguard Worker       if (analyzeGlobalAux(CE, GS, PhiUsers))
67*9880d681SAndroid Build Coastguard Worker         return true;
68*9880d681SAndroid Build Coastguard Worker     } else if (const Instruction *I = dyn_cast<Instruction>(UR)) {
69*9880d681SAndroid Build Coastguard Worker       if (!GS.HasMultipleAccessingFunctions) {
70*9880d681SAndroid Build Coastguard Worker         const Function *F = I->getParent()->getParent();
71*9880d681SAndroid Build Coastguard Worker         if (!GS.AccessingFunction)
72*9880d681SAndroid Build Coastguard Worker           GS.AccessingFunction = F;
73*9880d681SAndroid Build Coastguard Worker         else if (GS.AccessingFunction != F)
74*9880d681SAndroid Build Coastguard Worker           GS.HasMultipleAccessingFunctions = true;
75*9880d681SAndroid Build Coastguard Worker       }
76*9880d681SAndroid Build Coastguard Worker       if (const LoadInst *LI = dyn_cast<LoadInst>(I)) {
77*9880d681SAndroid Build Coastguard Worker         GS.IsLoaded = true;
78*9880d681SAndroid Build Coastguard Worker         // Don't hack on volatile loads.
79*9880d681SAndroid Build Coastguard Worker         if (LI->isVolatile())
80*9880d681SAndroid Build Coastguard Worker           return true;
81*9880d681SAndroid Build Coastguard Worker         GS.Ordering = strongerOrdering(GS.Ordering, LI->getOrdering());
82*9880d681SAndroid Build Coastguard Worker       } else if (const StoreInst *SI = dyn_cast<StoreInst>(I)) {
83*9880d681SAndroid Build Coastguard Worker         // Don't allow a store OF the address, only stores TO the address.
84*9880d681SAndroid Build Coastguard Worker         if (SI->getOperand(0) == V)
85*9880d681SAndroid Build Coastguard Worker           return true;
86*9880d681SAndroid Build Coastguard Worker 
87*9880d681SAndroid Build Coastguard Worker         // Don't hack on volatile stores.
88*9880d681SAndroid Build Coastguard Worker         if (SI->isVolatile())
89*9880d681SAndroid Build Coastguard Worker           return true;
90*9880d681SAndroid Build Coastguard Worker 
91*9880d681SAndroid Build Coastguard Worker         GS.Ordering = strongerOrdering(GS.Ordering, SI->getOrdering());
92*9880d681SAndroid Build Coastguard Worker 
93*9880d681SAndroid Build Coastguard Worker         // If this is a direct store to the global (i.e., the global is a scalar
94*9880d681SAndroid Build Coastguard Worker         // value, not an aggregate), keep more specific information about
95*9880d681SAndroid Build Coastguard Worker         // stores.
96*9880d681SAndroid Build Coastguard Worker         if (GS.StoredType != GlobalStatus::Stored) {
97*9880d681SAndroid Build Coastguard Worker           if (const GlobalVariable *GV =
98*9880d681SAndroid Build Coastguard Worker                   dyn_cast<GlobalVariable>(SI->getOperand(1))) {
99*9880d681SAndroid Build Coastguard Worker             Value *StoredVal = SI->getOperand(0);
100*9880d681SAndroid Build Coastguard Worker 
101*9880d681SAndroid Build Coastguard Worker             if (Constant *C = dyn_cast<Constant>(StoredVal)) {
102*9880d681SAndroid Build Coastguard Worker               if (C->isThreadDependent()) {
103*9880d681SAndroid Build Coastguard Worker                 // The stored value changes between threads; don't track it.
104*9880d681SAndroid Build Coastguard Worker                 return true;
105*9880d681SAndroid Build Coastguard Worker               }
106*9880d681SAndroid Build Coastguard Worker             }
107*9880d681SAndroid Build Coastguard Worker 
108*9880d681SAndroid Build Coastguard Worker             if (GV->hasInitializer() && StoredVal == GV->getInitializer()) {
109*9880d681SAndroid Build Coastguard Worker               if (GS.StoredType < GlobalStatus::InitializerStored)
110*9880d681SAndroid Build Coastguard Worker                 GS.StoredType = GlobalStatus::InitializerStored;
111*9880d681SAndroid Build Coastguard Worker             } else if (isa<LoadInst>(StoredVal) &&
112*9880d681SAndroid Build Coastguard Worker                        cast<LoadInst>(StoredVal)->getOperand(0) == GV) {
113*9880d681SAndroid Build Coastguard Worker               if (GS.StoredType < GlobalStatus::InitializerStored)
114*9880d681SAndroid Build Coastguard Worker                 GS.StoredType = GlobalStatus::InitializerStored;
115*9880d681SAndroid Build Coastguard Worker             } else if (GS.StoredType < GlobalStatus::StoredOnce) {
116*9880d681SAndroid Build Coastguard Worker               GS.StoredType = GlobalStatus::StoredOnce;
117*9880d681SAndroid Build Coastguard Worker               GS.StoredOnceValue = StoredVal;
118*9880d681SAndroid Build Coastguard Worker             } else if (GS.StoredType == GlobalStatus::StoredOnce &&
119*9880d681SAndroid Build Coastguard Worker                        GS.StoredOnceValue == StoredVal) {
120*9880d681SAndroid Build Coastguard Worker               // noop.
121*9880d681SAndroid Build Coastguard Worker             } else {
122*9880d681SAndroid Build Coastguard Worker               GS.StoredType = GlobalStatus::Stored;
123*9880d681SAndroid Build Coastguard Worker             }
124*9880d681SAndroid Build Coastguard Worker           } else {
125*9880d681SAndroid Build Coastguard Worker             GS.StoredType = GlobalStatus::Stored;
126*9880d681SAndroid Build Coastguard Worker           }
127*9880d681SAndroid Build Coastguard Worker         }
128*9880d681SAndroid Build Coastguard Worker       } else if (isa<BitCastInst>(I)) {
129*9880d681SAndroid Build Coastguard Worker         if (analyzeGlobalAux(I, GS, PhiUsers))
130*9880d681SAndroid Build Coastguard Worker           return true;
131*9880d681SAndroid Build Coastguard Worker       } else if (isa<GetElementPtrInst>(I)) {
132*9880d681SAndroid Build Coastguard Worker         if (analyzeGlobalAux(I, GS, PhiUsers))
133*9880d681SAndroid Build Coastguard Worker           return true;
134*9880d681SAndroid Build Coastguard Worker       } else if (isa<SelectInst>(I)) {
135*9880d681SAndroid Build Coastguard Worker         if (analyzeGlobalAux(I, GS, PhiUsers))
136*9880d681SAndroid Build Coastguard Worker           return true;
137*9880d681SAndroid Build Coastguard Worker       } else if (const PHINode *PN = dyn_cast<PHINode>(I)) {
138*9880d681SAndroid Build Coastguard Worker         // PHI nodes we can check just like select or GEP instructions, but we
139*9880d681SAndroid Build Coastguard Worker         // have to be careful about infinite recursion.
140*9880d681SAndroid Build Coastguard Worker         if (PhiUsers.insert(PN).second) // Not already visited.
141*9880d681SAndroid Build Coastguard Worker           if (analyzeGlobalAux(I, GS, PhiUsers))
142*9880d681SAndroid Build Coastguard Worker             return true;
143*9880d681SAndroid Build Coastguard Worker       } else if (isa<CmpInst>(I)) {
144*9880d681SAndroid Build Coastguard Worker         GS.IsCompared = true;
145*9880d681SAndroid Build Coastguard Worker       } else if (const MemTransferInst *MTI = dyn_cast<MemTransferInst>(I)) {
146*9880d681SAndroid Build Coastguard Worker         if (MTI->isVolatile())
147*9880d681SAndroid Build Coastguard Worker           return true;
148*9880d681SAndroid Build Coastguard Worker         if (MTI->getArgOperand(0) == V)
149*9880d681SAndroid Build Coastguard Worker           GS.StoredType = GlobalStatus::Stored;
150*9880d681SAndroid Build Coastguard Worker         if (MTI->getArgOperand(1) == V)
151*9880d681SAndroid Build Coastguard Worker           GS.IsLoaded = true;
152*9880d681SAndroid Build Coastguard Worker       } else if (const MemSetInst *MSI = dyn_cast<MemSetInst>(I)) {
153*9880d681SAndroid Build Coastguard Worker         assert(MSI->getArgOperand(0) == V && "Memset only takes one pointer!");
154*9880d681SAndroid Build Coastguard Worker         if (MSI->isVolatile())
155*9880d681SAndroid Build Coastguard Worker           return true;
156*9880d681SAndroid Build Coastguard Worker         GS.StoredType = GlobalStatus::Stored;
157*9880d681SAndroid Build Coastguard Worker       } else if (auto C = ImmutableCallSite(I)) {
158*9880d681SAndroid Build Coastguard Worker         if (!C.isCallee(&U))
159*9880d681SAndroid Build Coastguard Worker           return true;
160*9880d681SAndroid Build Coastguard Worker         GS.IsLoaded = true;
161*9880d681SAndroid Build Coastguard Worker       } else {
162*9880d681SAndroid Build Coastguard Worker         return true; // Any other non-load instruction might take address!
163*9880d681SAndroid Build Coastguard Worker       }
164*9880d681SAndroid Build Coastguard Worker     } else if (const Constant *C = dyn_cast<Constant>(UR)) {
165*9880d681SAndroid Build Coastguard Worker       GS.HasNonInstructionUser = true;
166*9880d681SAndroid Build Coastguard Worker       // We might have a dead and dangling constant hanging off of here.
167*9880d681SAndroid Build Coastguard Worker       if (!isSafeToDestroyConstant(C))
168*9880d681SAndroid Build Coastguard Worker         return true;
169*9880d681SAndroid Build Coastguard Worker     } else {
170*9880d681SAndroid Build Coastguard Worker       GS.HasNonInstructionUser = true;
171*9880d681SAndroid Build Coastguard Worker       // Otherwise must be some other user.
172*9880d681SAndroid Build Coastguard Worker       return true;
173*9880d681SAndroid Build Coastguard Worker     }
174*9880d681SAndroid Build Coastguard Worker   }
175*9880d681SAndroid Build Coastguard Worker 
176*9880d681SAndroid Build Coastguard Worker   return false;
177*9880d681SAndroid Build Coastguard Worker }
178*9880d681SAndroid Build Coastguard Worker 
analyzeGlobal(const Value * V,GlobalStatus & GS)179*9880d681SAndroid Build Coastguard Worker bool GlobalStatus::analyzeGlobal(const Value *V, GlobalStatus &GS) {
180*9880d681SAndroid Build Coastguard Worker   SmallPtrSet<const PHINode *, 16> PhiUsers;
181*9880d681SAndroid Build Coastguard Worker   return analyzeGlobalAux(V, GS, PhiUsers);
182*9880d681SAndroid Build Coastguard Worker }
183*9880d681SAndroid Build Coastguard Worker 
GlobalStatus()184*9880d681SAndroid Build Coastguard Worker GlobalStatus::GlobalStatus()
185*9880d681SAndroid Build Coastguard Worker     : IsCompared(false), IsLoaded(false), StoredType(NotStored),
186*9880d681SAndroid Build Coastguard Worker       StoredOnceValue(nullptr), AccessingFunction(nullptr),
187*9880d681SAndroid Build Coastguard Worker       HasMultipleAccessingFunctions(false), HasNonInstructionUser(false),
188*9880d681SAndroid Build Coastguard Worker       Ordering(AtomicOrdering::NotAtomic) {}
189