13d7fc25cSRafael Espindola //===-- GlobalStatus.cpp - Compute status info for globals -----------------==//
23d7fc25cSRafael Espindola //
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
63d7fc25cSRafael Espindola //
73d7fc25cSRafael Espindola //===----------------------------------------------------------------------===//
83d7fc25cSRafael Espindola 
96bda14b3SChandler Carruth #include "llvm/Transforms/Utils/GlobalStatus.h"
103d7fc25cSRafael Espindola #include "llvm/ADT/SmallPtrSet.h"
113d7fc25cSRafael Espindola #include "llvm/IR/BasicBlock.h"
125fa43960SEugene Zelenko #include "llvm/IR/Constant.h"
135fa43960SEugene Zelenko #include "llvm/IR/Constants.h"
145fa43960SEugene Zelenko #include "llvm/IR/GlobalValue.h"
153d7fc25cSRafael Espindola #include "llvm/IR/GlobalVariable.h"
165fa43960SEugene Zelenko #include "llvm/IR/InstrTypes.h"
175fa43960SEugene Zelenko #include "llvm/IR/Instruction.h"
185fa43960SEugene Zelenko #include "llvm/IR/Instructions.h"
193d7fc25cSRafael Espindola #include "llvm/IR/IntrinsicInst.h"
205fa43960SEugene Zelenko #include "llvm/IR/Use.h"
215fa43960SEugene Zelenko #include "llvm/IR/User.h"
225fa43960SEugene Zelenko #include "llvm/IR/Value.h"
235fa43960SEugene Zelenko #include "llvm/Support/AtomicOrdering.h"
245fa43960SEugene Zelenko #include "llvm/Support/Casting.h"
255fa43960SEugene Zelenko #include <algorithm>
265fa43960SEugene Zelenko #include <cassert>
273d7fc25cSRafael Espindola 
283d7fc25cSRafael Espindola using namespace llvm;
293d7fc25cSRafael Espindola 
303d7fc25cSRafael Espindola /// Return the stronger of the two ordering. If the two orderings are acquire
313d7fc25cSRafael Espindola /// and release, then return AcquireRelease.
323d7fc25cSRafael Espindola ///
strongerOrdering(AtomicOrdering X,AtomicOrdering Y)333d7fc25cSRafael Espindola static AtomicOrdering strongerOrdering(AtomicOrdering X, AtomicOrdering Y) {
34c3e0ce8fSDavide Italiano   if ((X == AtomicOrdering::Acquire && Y == AtomicOrdering::Release) ||
35c3e0ce8fSDavide Italiano       (Y == AtomicOrdering::Acquire && X == AtomicOrdering::Release))
36800f87a8SJF Bastien     return AtomicOrdering::AcquireRelease;
37800f87a8SJF Bastien   return (AtomicOrdering)std::max((unsigned)X, (unsigned)Y);
383d7fc25cSRafael Espindola }
393d7fc25cSRafael Espindola 
403d7fc25cSRafael Espindola /// It is safe to destroy a constant iff it is only used by constants itself.
41f8d72100SNikita Popov /// Note that while constants cannot be cyclic, they can be tree-like, so we
42f8d72100SNikita Popov /// should keep a visited set to avoid exponential runtime.
isSafeToDestroyConstant(const Constant * C)433d7fc25cSRafael Espindola bool llvm::isSafeToDestroyConstant(const Constant *C) {
44f8d72100SNikita Popov   SmallVector<const Constant *, 8> Worklist;
45f8d72100SNikita Popov   SmallPtrSet<const Constant *, 8> Visited;
46f8d72100SNikita Popov   Worklist.push_back(C);
47f8d72100SNikita Popov   while (!Worklist.empty()) {
48f8d72100SNikita Popov     const Constant *C = Worklist.pop_back_val();
49f8d72100SNikita Popov     if (!Visited.insert(C).second)
50f8d72100SNikita Popov       continue;
51f8d72100SNikita Popov     if (isa<GlobalValue>(C) || isa<ConstantData>(C))
523d7fc25cSRafael Espindola       return false;
533d7fc25cSRafael Espindola 
54f8d72100SNikita Popov     for (const User *U : C->users()) {
55f8d72100SNikita Popov       if (const Constant *CU = dyn_cast<Constant>(U))
56f8d72100SNikita Popov         Worklist.push_back(CU);
57f8d72100SNikita Popov       else
58e2a1fa35SBruno Cardoso Lopes         return false;
59f8d72100SNikita Popov     }
60f8d72100SNikita Popov   }
613d7fc25cSRafael Espindola   return true;
623d7fc25cSRafael Espindola }
633d7fc25cSRafael Espindola 
analyzeGlobalAux(const Value * V,GlobalStatus & GS,SmallPtrSetImpl<const Value * > & VisitedUsers)643d7fc25cSRafael Espindola static bool analyzeGlobalAux(const Value *V, GlobalStatus &GS,
6579d297abSEli Friedman                              SmallPtrSetImpl<const Value *> &VisitedUsers) {
66939724cdSOliver Stannard   if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(V))
67939724cdSOliver Stannard     if (GV->isExternallyInitialized())
68939724cdSOliver Stannard       GS.StoredType = GlobalStatus::StoredOnce;
69939724cdSOliver Stannard 
70cdf47884SChandler Carruth   for (const Use &U : V->uses()) {
71cdf47884SChandler Carruth     const User *UR = U.getUser();
72236fbf57SNikita Popov     if (const Constant *C = dyn_cast<Constant>(UR)) {
73236fbf57SNikita Popov       const ConstantExpr *CE = dyn_cast<ConstantExpr>(C);
74236fbf57SNikita Popov       if (CE && isa<PointerType>(CE->getType())) {
75236fbf57SNikita Popov         // Recursively analyze pointer-typed constant expressions.
7679d297abSEli Friedman         // FIXME: Do we need to add constexpr selects to VisitedUsers?
7779d297abSEli Friedman         if (analyzeGlobalAux(CE, GS, VisitedUsers))
783d7fc25cSRafael Espindola           return true;
79236fbf57SNikita Popov       } else {
80236fbf57SNikita Popov         // Ignore dead constant users.
81236fbf57SNikita Popov         if (!isSafeToDestroyConstant(C))
82236fbf57SNikita Popov           return true;
83236fbf57SNikita Popov       }
84cdf47884SChandler Carruth     } else if (const Instruction *I = dyn_cast<Instruction>(UR)) {
853d7fc25cSRafael Espindola       if (!GS.HasMultipleAccessingFunctions) {
863d7fc25cSRafael Espindola         const Function *F = I->getParent()->getParent();
87f40110f4SCraig Topper         if (!GS.AccessingFunction)
883d7fc25cSRafael Espindola           GS.AccessingFunction = F;
893d7fc25cSRafael Espindola         else if (GS.AccessingFunction != F)
903d7fc25cSRafael Espindola           GS.HasMultipleAccessingFunctions = true;
913d7fc25cSRafael Espindola       }
923d7fc25cSRafael Espindola       if (const LoadInst *LI = dyn_cast<LoadInst>(I)) {
933d7fc25cSRafael Espindola         GS.IsLoaded = true;
943d7fc25cSRafael Espindola         // Don't hack on volatile loads.
953d7fc25cSRafael Espindola         if (LI->isVolatile())
963d7fc25cSRafael Espindola           return true;
973d7fc25cSRafael Espindola         GS.Ordering = strongerOrdering(GS.Ordering, LI->getOrdering());
983d7fc25cSRafael Espindola       } else if (const StoreInst *SI = dyn_cast<StoreInst>(I)) {
993d7fc25cSRafael Espindola         // Don't allow a store OF the address, only stores TO the address.
1003d7fc25cSRafael Espindola         if (SI->getOperand(0) == V)
1013d7fc25cSRafael Espindola           return true;
1023d7fc25cSRafael Espindola 
1033d7fc25cSRafael Espindola         // Don't hack on volatile stores.
1043d7fc25cSRafael Espindola         if (SI->isVolatile())
1053d7fc25cSRafael Espindola           return true;
1063d7fc25cSRafael Espindola 
107*e422c0d3SArthur Eubanks         ++GS.NumStores;
108*e422c0d3SArthur Eubanks 
1093d7fc25cSRafael Espindola         GS.Ordering = strongerOrdering(GS.Ordering, SI->getOrdering());
1103d7fc25cSRafael Espindola 
1113d7fc25cSRafael Espindola         // If this is a direct store to the global (i.e., the global is a scalar
1123d7fc25cSRafael Espindola         // value, not an aggregate), keep more specific information about
1133d7fc25cSRafael Espindola         // stores.
1143d7fc25cSRafael Espindola         if (GS.StoredType != GlobalStatus::Stored) {
11594d62633SNikita Popov           const Value *Ptr = SI->getPointerOperand()->stripPointerCasts();
116732b0555SShimin Cui           if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(Ptr)) {
1173d7fc25cSRafael Espindola             Value *StoredVal = SI->getOperand(0);
1183d7fc25cSRafael Espindola 
1193d7fc25cSRafael Espindola             if (Constant *C = dyn_cast<Constant>(StoredVal)) {
1203d7fc25cSRafael Espindola               if (C->isThreadDependent()) {
1213d7fc25cSRafael Espindola                 // The stored value changes between threads; don't track it.
1223d7fc25cSRafael Espindola                 return true;
1233d7fc25cSRafael Espindola               }
1243d7fc25cSRafael Espindola             }
1253d7fc25cSRafael Espindola 
12696efdd61SPeter Collingbourne             if (GV->hasInitializer() && StoredVal == GV->getInitializer()) {
1273d7fc25cSRafael Espindola               if (GS.StoredType < GlobalStatus::InitializerStored)
1283d7fc25cSRafael Espindola                 GS.StoredType = GlobalStatus::InitializerStored;
1293d7fc25cSRafael Espindola             } else if (isa<LoadInst>(StoredVal) &&
1303d7fc25cSRafael Espindola                        cast<LoadInst>(StoredVal)->getOperand(0) == GV) {
1313d7fc25cSRafael Espindola               if (GS.StoredType < GlobalStatus::InitializerStored)
1323d7fc25cSRafael Espindola                 GS.StoredType = GlobalStatus::InitializerStored;
1333d7fc25cSRafael Espindola             } else if (GS.StoredType < GlobalStatus::StoredOnce) {
1343d7fc25cSRafael Espindola               GS.StoredType = GlobalStatus::StoredOnce;
135c09fbbdcSJohannes Doerfert               GS.StoredOnceStore = SI;
1363d7fc25cSRafael Espindola             } else if (GS.StoredType == GlobalStatus::StoredOnce &&
137c09fbbdcSJohannes Doerfert                        GS.getStoredOnceValue() == StoredVal) {
1383d7fc25cSRafael Espindola               // noop.
1393d7fc25cSRafael Espindola             } else {
1403d7fc25cSRafael Espindola               GS.StoredType = GlobalStatus::Stored;
1413d7fc25cSRafael Espindola             }
1423d7fc25cSRafael Espindola           } else {
1433d7fc25cSRafael Espindola             GS.StoredType = GlobalStatus::Stored;
1443d7fc25cSRafael Espindola           }
1453d7fc25cSRafael Espindola         }
14698f25496SMichael Liao       } else if (isa<BitCastInst>(I) || isa<GetElementPtrInst>(I) ||
14798f25496SMichael Liao                  isa<AddrSpaceCastInst>(I)) {
14879d297abSEli Friedman         // Skip over bitcasts and GEPs; we don't care about the type or offset
14979d297abSEli Friedman         // of the pointer.
15079d297abSEli Friedman         if (analyzeGlobalAux(I, GS, VisitedUsers))
1513d7fc25cSRafael Espindola           return true;
15279d297abSEli Friedman       } else if (isa<SelectInst>(I) || isa<PHINode>(I)) {
15379d297abSEli Friedman         // Look through selects and PHIs to find if the pointer is
15479d297abSEli Friedman         // conditionally accessed. Make sure we only visit an instruction
15579d297abSEli Friedman         // once; otherwise, we can get infinite recursion or exponential
15679d297abSEli Friedman         // compile time.
15779d297abSEli Friedman         if (VisitedUsers.insert(I).second)
15879d297abSEli Friedman           if (analyzeGlobalAux(I, GS, VisitedUsers))
1593d7fc25cSRafael Espindola             return true;
1603d7fc25cSRafael Espindola       } else if (isa<CmpInst>(I)) {
1613d7fc25cSRafael Espindola         GS.IsCompared = true;
1623d7fc25cSRafael Espindola       } else if (const MemTransferInst *MTI = dyn_cast<MemTransferInst>(I)) {
1633d7fc25cSRafael Espindola         if (MTI->isVolatile())
1643d7fc25cSRafael Espindola           return true;
1653d7fc25cSRafael Espindola         if (MTI->getArgOperand(0) == V)
1663d7fc25cSRafael Espindola           GS.StoredType = GlobalStatus::Stored;
1673d7fc25cSRafael Espindola         if (MTI->getArgOperand(1) == V)
1683d7fc25cSRafael Espindola           GS.IsLoaded = true;
1693d7fc25cSRafael Espindola       } else if (const MemSetInst *MSI = dyn_cast<MemSetInst>(I)) {
1703d7fc25cSRafael Espindola         assert(MSI->getArgOperand(0) == V && "Memset only takes one pointer!");
1713d7fc25cSRafael Espindola         if (MSI->isVolatile())
1723d7fc25cSRafael Espindola           return true;
1733d7fc25cSRafael Espindola         GS.StoredType = GlobalStatus::Stored;
17481c5e83fSCraig Topper       } else if (const auto *CB = dyn_cast<CallBase>(I)) {
17581c5e83fSCraig Topper         if (!CB->isCallee(&U))
1767749d7ccSRafael Espindola           return true;
1777749d7ccSRafael Espindola         GS.IsLoaded = true;
1783d7fc25cSRafael Espindola       } else {
1793d7fc25cSRafael Espindola         return true; // Any other non-load instruction might take address!
1803d7fc25cSRafael Espindola       }
1813d7fc25cSRafael Espindola     } else {
1823d7fc25cSRafael Espindola       // Otherwise must be some other user.
1833d7fc25cSRafael Espindola       return true;
1843d7fc25cSRafael Espindola     }
1853d7fc25cSRafael Espindola   }
1863d7fc25cSRafael Espindola 
1873d7fc25cSRafael Espindola   return false;
1883d7fc25cSRafael Espindola }
1893d7fc25cSRafael Espindola 
1905fa43960SEugene Zelenko GlobalStatus::GlobalStatus() = default;
1915fa43960SEugene Zelenko 
analyzeGlobal(const Value * V,GlobalStatus & GS)1923d7fc25cSRafael Espindola bool GlobalStatus::analyzeGlobal(const Value *V, GlobalStatus &GS) {
19379d297abSEli Friedman   SmallPtrSet<const Value *, 16> VisitedUsers;
19479d297abSEli Friedman   return analyzeGlobalAux(V, GS, VisitedUsers);
1953d7fc25cSRafael Espindola }
196