brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.8 KiB · 538755e Raw
173 lines · cpp
1//===- ElimAvailExtern.cpp - DCE unreachable internal functions -----------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This transform is designed to eliminate available external global10// definitions from the program, turning them into declarations.11//12//===----------------------------------------------------------------------===//13 14#include "llvm/Transforms/IPO/ElimAvailExtern.h"15#include "llvm/ADT/STLExtras.h"16#include "llvm/ADT/Statistic.h"17#include "llvm/Analysis/CtxProfAnalysis.h"18#include "llvm/IR/Constant.h"19#include "llvm/IR/DebugInfoMetadata.h"20#include "llvm/IR/Function.h"21#include "llvm/IR/GlobalValue.h"22#include "llvm/IR/GlobalVariable.h"23#include "llvm/IR/MDBuilder.h"24#include "llvm/IR/Module.h"25#include "llvm/Support/CommandLine.h"26#include "llvm/Transforms/Utils/GlobalStatus.h"27#include "llvm/Transforms/Utils/ModuleUtils.h"28 29using namespace llvm;30 31#define DEBUG_TYPE "elim-avail-extern"32 33static cl::opt<bool> ConvertToLocal(34    "avail-extern-to-local", cl::Hidden,35    cl::desc("Convert available_externally into locals, renaming them "36             "to avoid link-time clashes."));37 38// This option was originally introduced to correctly support the lowering of39// LDS variables for AMDGPU when ThinLTO is enabled. It can be utilized for40// other purposes, but make sure it is safe to do so, as privatizing global41// variables is generally not safe.42static cl::opt<unsigned> ConvertGlobalVariableInAddrSpace(43    "avail-extern-gv-in-addrspace-to-local", cl::Hidden,44    cl::desc(45        "Convert available_externally global variables into locals if they are "46        "in specificed addrspace, renaming them to avoid link-time clashes."));47 48STATISTIC(NumRemovals, "Number of functions removed");49STATISTIC(NumFunctionsConverted, "Number of functions converted");50STATISTIC(NumGlobalVariablesConverted, "Number of global variables converted");51STATISTIC(NumVariables, "Number of global variables removed");52 53void deleteFunction(Function &F) {54  // This will set the linkage to external55  F.deleteBody();56  ++NumRemovals;57}58 59static std::string getNewName(Module &M, const GlobalValue &GV) {60  return GV.getName().str() + ".__uniq" + getUniqueModuleId(&M);61}62 63/// Create a copy of the thinlto import, mark it local, and redirect direct64/// calls to the copy. Only direct calls are replaced, so that e.g. indirect65/// call function pointer tests would use the global identity of the function.66///67/// Currently, Value Profiling ("VP") MD_prof data isn't updated to refer to the68/// clone's GUID (which will be different, because the name and linkage is69/// different), under the assumption that the last consumer of this data is70/// upstream the pipeline (e.g. ICP).71static void convertToLocalCopy(Module &M, Function &F) {72  assert(F.hasAvailableExternallyLinkage());73  assert(!F.isDeclaration());74  // If we can't find a single use that's a call, just delete the function.75  if (F.uses().end() == llvm::find_if(F.uses(), [&](Use &U) {76        return isa<CallBase>(U.getUser());77      }))78    return deleteFunction(F);79 80  auto OrigName = F.getName().str();81  // Build a new name. We still need the old name (see below).82  // We could just rely on internal linking allowing 2 modules have internal83  // functions with the same name, but that just creates more trouble than84  // necessary e.g. distinguishing profiles or debugging. Instead, we append the85  // module identifier.86  std::string NewName = getNewName(M, F);87  F.setName(NewName);88  if (auto *SP = F.getSubprogram())89    SP->replaceLinkageName(MDString::get(F.getParent()->getContext(), NewName));90 91  F.setLinkage(GlobalValue::InternalLinkage);92  // Now make a declaration for the old name. We'll use it if there are non-call93  // uses. For those, it would be incorrect to replace them with the local copy:94  // for example, one such use could be taking the address of the function and95  // passing it to an external function, which, in turn, might compare the96  // function pointer to the original (non-local) function pointer, e.g. as part97  // of indirect call promotion.98  auto *Decl =99      Function::Create(F.getFunctionType(), GlobalValue::ExternalLinkage,100                       F.getAddressSpace(), OrigName, F.getParent());101  F.replaceUsesWithIf(Decl,102                      [&](Use &U) { return !isa<CallBase>(U.getUser()); });103  ++NumFunctionsConverted;104}105 106/// Similar to the function above, this is to convert an externally available107/// global variable to local.108static void convertToLocalCopy(Module &M, GlobalVariable &GV) {109  assert(GV.hasAvailableExternallyLinkage());110  GV.setName(getNewName(M, GV));111  GV.setLinkage(GlobalValue::InternalLinkage);112  ++NumGlobalVariablesConverted;113}114 115static bool eliminateAvailableExternally(Module &M, bool Convert) {116  bool Changed = false;117 118  // If a global variable is available externally and in the specified address119  // space, convert it to local linkage; otherwise, drop its initializer.120  for (GlobalVariable &GV : M.globals()) {121    if (!GV.hasAvailableExternallyLinkage())122      continue;123    if (ConvertGlobalVariableInAddrSpace.getNumOccurrences() &&124        GV.getAddressSpace() == ConvertGlobalVariableInAddrSpace &&125        !GV.use_empty()) {126      convertToLocalCopy(M, GV);127      Changed = true;128      continue;129    }130    if (GV.hasInitializer()) {131      Constant *Init = GV.getInitializer();132      GV.setInitializer(nullptr);133      if (isSafeToDestroyConstant(Init))134        Init->destroyConstant();135    }136    GV.removeDeadConstantUsers();137    GV.setLinkage(GlobalValue::ExternalLinkage);138    ++NumVariables;139    Changed = true;140  }141 142  // Drop the bodies of available externally functions.143  for (Function &F : llvm::make_early_inc_range(M)) {144    if (F.isDeclaration() || !F.hasAvailableExternallyLinkage())145      continue;146 147    if (Convert || ConvertToLocal)148      convertToLocalCopy(M, F);149    else150      deleteFunction(F);151 152    F.removeDeadConstantUsers();153    Changed = true;154  }155 156  return Changed;157}158 159PreservedAnalyses160EliminateAvailableExternallyPass::run(Module &M, ModuleAnalysisManager &MAM) {161  auto *CtxProf = MAM.getCachedResult<CtxProfAnalysis>(M);162  // Convert to local instead of eliding if we use contextual profiling in this163  // module. This is because the IPO decisions performed with contextual164  // information will likely differ from decisions made without. For a function165  // that's imported, its optimizations will, thus, differ, and be specialized166  // for this contextual information. Eliding it in favor of the original would167  // undo these optimizations.168  if (!eliminateAvailableExternally(169          M, /*Convert=*/(CtxProf && CtxProf->isInSpecializedModule())))170    return PreservedAnalyses::all();171  return PreservedAnalyses::none();172}173