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