1//===- NameAnonGlobals.cpp - ThinLTO Support: Name Unnamed Globals --------===// 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-exception 6// 7//===----------------------------------------------------------------------===// 8// 9// This file implements naming anonymous globals to make sure they can be 10// referred to by ThinLTO. 11// 12//===----------------------------------------------------------------------===// 13 14#include "llvm/Transforms/Utils/NameAnonGlobals.h" 15#include "llvm/ADT/SmallString.h" 16#include "llvm/IR/Module.h" 17#include "llvm/InitializePasses.h" 18#include "llvm/Support/MD5.h" 19#include "llvm/Transforms/Utils/ModuleUtils.h" 20 21using namespace llvm; 22 23namespace { 24// Compute a "unique" hash for the module based on the name of the public 25// globals. 26class ModuleHasher { 27 Module &TheModule; 28 std::string TheHash; 29 30public: 31 ModuleHasher(Module &M) : TheModule(M) {} 32 33 /// Return the lazily computed hash. 34 std::string &get() { 35 if (!TheHash.empty()) 36 // Cache hit :) 37 return TheHash; 38 39 MD5 Hasher; 40 for (auto &F : TheModule) { 41 if (F.isDeclaration() || F.hasLocalLinkage() || !F.hasName()) 42 continue; 43 auto Name = F.getName(); 44 Hasher.update(Name); 45 } 46 for (auto &GV : TheModule.globals()) { 47 if (GV.isDeclaration() || GV.hasLocalLinkage() || !GV.hasName()) 48 continue; 49 auto Name = GV.getName(); 50 Hasher.update(Name); 51 } 52 53 // Now return the result. 54 MD5::MD5Result Hash; 55 Hasher.final(Hash); 56 SmallString<32> Result; 57 MD5::stringifyResult(Hash, Result); 58 TheHash = Result.str(); 59 return TheHash; 60 } 61}; 62} // end anonymous namespace 63 64// Rename all the anon globals in the module 65bool llvm::nameUnamedGlobals(Module &M) { 66 bool Changed = false; 67 ModuleHasher ModuleHash(M); 68 int count = 0; 69 auto RenameIfNeed = [&](GlobalValue &GV) { 70 if (GV.hasName()) 71 return; 72 GV.setName(Twine("anon.") + ModuleHash.get() + "." + Twine(count++)); 73 Changed = true; 74 }; 75 for (auto &GO : M.global_objects()) 76 RenameIfNeed(GO); 77 for (auto &GA : M.aliases()) 78 RenameIfNeed(GA); 79 80 return Changed; 81} 82 83namespace { 84 85// Legacy pass that provides a name to every anon globals. 86class NameAnonGlobalLegacyPass : public ModulePass { 87 88public: 89 /// Pass identification, replacement for typeid 90 static char ID; 91 92 /// Specify pass name for debug output 93 StringRef getPassName() const override { return "Name Anon Globals"; } 94 95 explicit NameAnonGlobalLegacyPass() : ModulePass(ID) {} 96 97 bool runOnModule(Module &M) override { return nameUnamedGlobals(M); } 98}; 99char NameAnonGlobalLegacyPass::ID = 0; 100 101} // anonymous namespace 102 103PreservedAnalyses NameAnonGlobalPass::run(Module &M, 104 ModuleAnalysisManager &AM) { 105 if (!nameUnamedGlobals(M)) 106 return PreservedAnalyses::all(); 107 108 return PreservedAnalyses::none(); 109} 110 111INITIALIZE_PASS_BEGIN(NameAnonGlobalLegacyPass, "name-anon-globals", 112 "Provide a name to nameless globals", false, false) 113INITIALIZE_PASS_END(NameAnonGlobalLegacyPass, "name-anon-globals", 114 "Provide a name to nameless globals", false, false) 115 116namespace llvm { 117ModulePass *createNameAnonGlobalPass() { 118 return new NameAnonGlobalLegacyPass(); 119} 120} 121