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 21 using namespace llvm; 22 23 namespace { 24 // Compute a "unique" hash for the module based on the name of the public 25 // globals. 26 class ModuleHasher { 27 Module &TheModule; 28 std::string TheHash; 29 30 public: 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 = std::string(Result.str()); 59 return TheHash; 60 } 61 }; 62 } // end anonymous namespace 63 64 // Rename all the anon globals in the module 65 bool 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 83 namespace { 84 85 // Legacy pass that provides a name to every anon globals. 86 class NameAnonGlobalLegacyPass : public ModulePass { 87 88 public: 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 }; 99 char NameAnonGlobalLegacyPass::ID = 0; 100 101 } // anonymous namespace 102 103 PreservedAnalyses NameAnonGlobalPass::run(Module &M, 104 ModuleAnalysisManager &AM) { 105 if (!nameUnamedGlobals(M)) 106 return PreservedAnalyses::all(); 107 108 return PreservedAnalyses::none(); 109 } 110 111 INITIALIZE_PASS_BEGIN(NameAnonGlobalLegacyPass, "name-anon-globals", 112 "Provide a name to nameless globals", false, false) 113 INITIALIZE_PASS_END(NameAnonGlobalLegacyPass, "name-anon-globals", 114 "Provide a name to nameless globals", false, false) 115 116 namespace llvm { 117 ModulePass *createNameAnonGlobalPass() { 118 return new NameAnonGlobalLegacyPass(); 119 } 120 } 121