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