Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/Utils/GlobalStatus.cpp
35271 views
//===-- GlobalStatus.cpp - Compute status info for globals -----------------==//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/Transforms/Utils/GlobalStatus.h"9#include "llvm/ADT/SmallPtrSet.h"10#include "llvm/IR/BasicBlock.h"11#include "llvm/IR/Constant.h"12#include "llvm/IR/Constants.h"13#include "llvm/IR/GlobalValue.h"14#include "llvm/IR/GlobalVariable.h"15#include "llvm/IR/InstrTypes.h"16#include "llvm/IR/Instruction.h"17#include "llvm/IR/Instructions.h"18#include "llvm/IR/IntrinsicInst.h"19#include "llvm/IR/Use.h"20#include "llvm/IR/User.h"21#include "llvm/IR/Value.h"22#include "llvm/Support/AtomicOrdering.h"23#include "llvm/Support/Casting.h"24#include <algorithm>25#include <cassert>2627using namespace llvm;2829/// Return the stronger of the two ordering. If the two orderings are acquire30/// and release, then return AcquireRelease.31///32static AtomicOrdering strongerOrdering(AtomicOrdering X, AtomicOrdering Y) {33if ((X == AtomicOrdering::Acquire && Y == AtomicOrdering::Release) ||34(Y == AtomicOrdering::Acquire && X == AtomicOrdering::Release))35return AtomicOrdering::AcquireRelease;36return (AtomicOrdering)std::max((unsigned)X, (unsigned)Y);37}3839/// It is safe to destroy a constant iff it is only used by constants itself.40/// Note that while constants cannot be cyclic, they can be tree-like, so we41/// should keep a visited set to avoid exponential runtime.42bool llvm::isSafeToDestroyConstant(const Constant *C) {43SmallVector<const Constant *, 8> Worklist;44SmallPtrSet<const Constant *, 8> Visited;45Worklist.push_back(C);46while (!Worklist.empty()) {47const Constant *C = Worklist.pop_back_val();48if (!Visited.insert(C).second)49continue;50if (isa<GlobalValue>(C) || isa<ConstantData>(C))51return false;5253for (const User *U : C->users()) {54if (const Constant *CU = dyn_cast<Constant>(U))55Worklist.push_back(CU);56else57return false;58}59}60return true;61}6263static bool analyzeGlobalAux(const Value *V, GlobalStatus &GS,64SmallPtrSetImpl<const Value *> &VisitedUsers) {65if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(V))66if (GV->isExternallyInitialized())67GS.StoredType = GlobalStatus::StoredOnce;6869for (const Use &U : V->uses()) {70const User *UR = U.getUser();71if (const Constant *C = dyn_cast<Constant>(UR)) {72const ConstantExpr *CE = dyn_cast<ConstantExpr>(C);73if (CE && isa<PointerType>(CE->getType())) {74// Recursively analyze pointer-typed constant expressions.75// FIXME: Do we need to add constexpr selects to VisitedUsers?76if (analyzeGlobalAux(CE, GS, VisitedUsers))77return true;78} else {79// Ignore dead constant users.80if (!isSafeToDestroyConstant(C))81return true;82}83} else if (const Instruction *I = dyn_cast<Instruction>(UR)) {84if (!GS.HasMultipleAccessingFunctions) {85const Function *F = I->getParent()->getParent();86if (!GS.AccessingFunction)87GS.AccessingFunction = F;88else if (GS.AccessingFunction != F)89GS.HasMultipleAccessingFunctions = true;90}91if (const LoadInst *LI = dyn_cast<LoadInst>(I)) {92GS.IsLoaded = true;93// Don't hack on volatile loads.94if (LI->isVolatile())95return true;96GS.Ordering = strongerOrdering(GS.Ordering, LI->getOrdering());97} else if (const StoreInst *SI = dyn_cast<StoreInst>(I)) {98// Don't allow a store OF the address, only stores TO the address.99if (SI->getOperand(0) == V)100return true;101102// Don't hack on volatile stores.103if (SI->isVolatile())104return true;105106++GS.NumStores;107108GS.Ordering = strongerOrdering(GS.Ordering, SI->getOrdering());109110// If this is a direct store to the global (i.e., the global is a scalar111// value, not an aggregate), keep more specific information about112// stores.113if (GS.StoredType != GlobalStatus::Stored) {114const Value *Ptr = SI->getPointerOperand()->stripPointerCasts();115if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(Ptr)) {116Value *StoredVal = SI->getOperand(0);117118if (Constant *C = dyn_cast<Constant>(StoredVal)) {119if (C->isThreadDependent()) {120// The stored value changes between threads; don't track it.121return true;122}123}124125if (GV->hasInitializer() && StoredVal == GV->getInitializer()) {126if (GS.StoredType < GlobalStatus::InitializerStored)127GS.StoredType = GlobalStatus::InitializerStored;128} else if (isa<LoadInst>(StoredVal) &&129cast<LoadInst>(StoredVal)->getOperand(0) == GV) {130if (GS.StoredType < GlobalStatus::InitializerStored)131GS.StoredType = GlobalStatus::InitializerStored;132} else if (GS.StoredType < GlobalStatus::StoredOnce) {133GS.StoredType = GlobalStatus::StoredOnce;134GS.StoredOnceStore = SI;135} else if (GS.StoredType == GlobalStatus::StoredOnce &&136GS.getStoredOnceValue() == StoredVal) {137// noop.138} else {139GS.StoredType = GlobalStatus::Stored;140}141} else {142GS.StoredType = GlobalStatus::Stored;143}144}145} else if (isa<BitCastInst>(I) || isa<GetElementPtrInst>(I) ||146isa<AddrSpaceCastInst>(I)) {147// Skip over bitcasts and GEPs; we don't care about the type or offset148// of the pointer.149if (analyzeGlobalAux(I, GS, VisitedUsers))150return true;151} else if (isa<SelectInst>(I) || isa<PHINode>(I)) {152// Look through selects and PHIs to find if the pointer is153// conditionally accessed. Make sure we only visit an instruction154// once; otherwise, we can get infinite recursion or exponential155// compile time.156if (VisitedUsers.insert(I).second)157if (analyzeGlobalAux(I, GS, VisitedUsers))158return true;159} else if (isa<CmpInst>(I)) {160GS.IsCompared = true;161} else if (const MemTransferInst *MTI = dyn_cast<MemTransferInst>(I)) {162if (MTI->isVolatile())163return true;164if (MTI->getArgOperand(0) == V)165GS.StoredType = GlobalStatus::Stored;166if (MTI->getArgOperand(1) == V)167GS.IsLoaded = true;168} else if (const MemSetInst *MSI = dyn_cast<MemSetInst>(I)) {169assert(MSI->getArgOperand(0) == V && "Memset only takes one pointer!");170if (MSI->isVolatile())171return true;172GS.StoredType = GlobalStatus::Stored;173} else if (const auto *CB = dyn_cast<CallBase>(I)) {174if (CB->getIntrinsicID() == Intrinsic::threadlocal_address) {175if (analyzeGlobalAux(I, GS, VisitedUsers))176return true;177} else {178if (!CB->isCallee(&U))179return true;180GS.IsLoaded = true;181}182} else {183return true; // Any other non-load instruction might take address!184}185} else {186// Otherwise must be some other user.187return true;188}189}190191return false;192}193194GlobalStatus::GlobalStatus() = default;195196bool GlobalStatus::analyzeGlobal(const Value *V, GlobalStatus &GS) {197SmallPtrSet<const Value *, 16> VisitedUsers;198return analyzeGlobalAux(V, GS, VisitedUsers);199}200201202