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 
16 #include "llvm/ADT/SmallString.h"
17 #include "llvm/IR/Module.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 = 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