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