NameAnonGlobals.cpp revision 341825
1//===- NameAnonGlobals.cpp - ThinLTO Support: Name Unnamed Globals --------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements naming anonymous globals to make sure they can be
11// referred to by ThinLTO.
12//
13//===----------------------------------------------------------------------===//
14
15#include "llvm/Transforms/Utils/NameAnonGlobals.h"
16
17#include "llvm/ADT/SmallString.h"
18#include "llvm/IR/Module.h"
19#include "llvm/Support/MD5.h"
20#include "llvm/Transforms/Utils/ModuleUtils.h"
21
22using namespace llvm;
23
24namespace {
25// Compute a "unique" hash for the module based on the name of the public
26// globals.
27class ModuleHasher {
28  Module &TheModule;
29  std::string TheHash;
30
31public:
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 = Result.str();
60    return TheHash;
61  }
62};
63} // end anonymous namespace
64
65// Rename all the anon globals in the module
66bool 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
84namespace {
85
86// Legacy pass that provides a name to every anon globals.
87class NameAnonGlobalLegacyPass : public ModulePass {
88
89public:
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};
100char NameAnonGlobalLegacyPass::ID = 0;
101
102} // anonymous namespace
103
104PreservedAnalyses NameAnonGlobalPass::run(Module &M,
105                                          ModuleAnalysisManager &AM) {
106  if (!nameUnamedGlobals(M))
107    return PreservedAnalyses::all();
108
109  return PreservedAnalyses::none();
110}
111
112INITIALIZE_PASS_BEGIN(NameAnonGlobalLegacyPass, "name-anon-globals",
113                      "Provide a name to nameless globals", false, false)
114INITIALIZE_PASS_END(NameAnonGlobalLegacyPass, "name-anon-globals",
115                    "Provide a name to nameless globals", false, false)
116
117namespace llvm {
118ModulePass *createNameAnonGlobalPass() {
119  return new NameAnonGlobalLegacyPass();
120}
121}
122