xref: /freebsd/contrib/llvm-project/llvm/lib/Transforms/Utils/NameAnonGlobals.cpp (revision 18054d0220cfc8df9c9568c437bd6fbb59d53c3c)
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