llvm.org GIT mirror llvm / 4a6d99b
Internalize: internalize comdat members as a group, and drop comdat on such members. Internalizing an individual comdat group member without also internalizing the other members of the comdat can break comdat semantics. For example, if a module contains a reference to an internalized comdat member, and the linker chooses a comdat group from a different object file, this will break the reference to the internalized member. This change causes the internalizer to only internalize comdat members if all other members of the comdat are not externally visible. Once a comdat group has been fully internalized, there is no need to apply comdat rules to its members; later optimization passes (e.g. globaldce) can legally drop individual members of the comdat. So we drop the comdat attribute from all comdat members. Differential Revision: http://reviews.llvm.org/D10679 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@242423 91177308-0d34-0410-b5e6-96231b3b80d8 Peter Collingbourne 4 years ago
2 changed file(s) with 124 addition(s) and 27 deletion(s). Raw diff Collapse all Expand all
5959 explicit InternalizePass();
6060 explicit InternalizePass(ArrayRef ExportList);
6161 void LoadFile(const char *Filename);
62 bool maybeInternalize(GlobalValue &GV,
63 const std::set &ExternalComdats);
64 void checkComdatVisibility(GlobalValue &GV,
65 std::set &ExternalComdats);
6266 bool runOnModule(Module &M) override;
6367
6468 void getAnalysisUsage(AnalysisUsage &AU) const override {
104108 }
105109 }
106110
107 static bool shouldInternalize(const GlobalValue &GV,
108 const std::set &ExternalNames) {
111 static bool isExternallyVisible(const GlobalValue &GV,
112 const std::set &ExternalNames) {
109113 // Function must be defined here
110114 if (GV.isDeclaration())
111 return false;
115 return true;
112116
113117 // Available externally is really just a "declaration with a body".
114118 if (GV.hasAvailableExternallyLinkage())
115 return false;
119 return true;
116120
117121 // Assume that dllexported symbols are referenced elsewhere
118122 if (GV.hasDLLExportStorageClass())
119 return false;
120
121 // Already has internal linkage
122 if (GV.hasLocalLinkage())
123 return false;
123 return true;
124124
125125 // Marked to keep external?
126 if (ExternalNames.count(GV.getName()))
127 return false;
128
126 if (!GV.hasLocalLinkage() && ExternalNames.count(GV.getName()))
127 return true;
128
129 return false;
130 }
131
132 // Internalize GV if it is possible to do so, i.e. it is not externally visible
133 // and is not a member of an externally visible comdat.
134 bool InternalizePass::maybeInternalize(
135 GlobalValue &GV, const std::set &ExternalComdats) {
136 if (Comdat *C = GV.getComdat()) {
137 if (ExternalComdats.count(C))
138 return false;
139
140 // If a comdat is not externally visible we can drop it.
141 if (auto GO = dyn_cast(&GV))
142 GO->setComdat(nullptr);
143
144 if (GV.hasLocalLinkage())
145 return false;
146 } else {
147 if (GV.hasLocalLinkage())
148 return false;
149
150 if (isExternallyVisible(GV, ExternalNames))
151 return false;
152 }
153
154 GV.setVisibility(GlobalValue::DefaultVisibility);
155 GV.setLinkage(GlobalValue::InternalLinkage);
129156 return true;
157 }
158
159 // If GV is part of a comdat and is externally visible, keep track of its
160 // comdat so that we don't internalize any of its members.
161 void InternalizePass::checkComdatVisibility(
162 GlobalValue &GV, std::set &ExternalComdats) {
163 Comdat *C = GV.getComdat();
164 if (!C)
165 return;
166
167 if (isExternallyVisible(GV, ExternalNames))
168 ExternalComdats.insert(C);
130169 }
131170
132171 bool InternalizePass::runOnModule(Module &M) {
133172 CallGraphWrapperPass *CGPass = getAnalysisIfAvailable();
134173 CallGraph *CG = CGPass ? &CGPass->getCallGraph() : nullptr;
135174 CallGraphNode *ExternalNode = CG ? CG->getExternalCallingNode() : nullptr;
136 bool Changed = false;
137175
138176 SmallPtrSet Used;
139177 collectUsedGlobalVariables(M, Used, false);
178
179 // Collect comdat visiblity information for the module.
180 std::set ExternalComdats;
181 if (!M.getComdatSymbolTable().empty()) {
182 for (Function &F : M)
183 checkComdatVisibility(F, ExternalComdats);
184 for (GlobalVariable &GV : M.globals())
185 checkComdatVisibility(GV, ExternalComdats);
186 for (GlobalAlias &GA : M.aliases())
187 checkComdatVisibility(GA, ExternalComdats);
188 }
140189
141190 // We must assume that globals in llvm.used have a reference that not even
142191 // the linker can see, so we don't internalize them.
153202
154203 // Mark all functions not in the api as internal.
155204 for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) {
156 if (!shouldInternalize(*I, ExternalNames))
205 if (!maybeInternalize(*I, ExternalComdats))
157206 continue;
158
159 I->setVisibility(GlobalValue::DefaultVisibility);
160 I->setLinkage(GlobalValue::InternalLinkage);
161207
162208 if (ExternalNode)
163209 // Remove a callgraph edge from the external node to this function.
164210 ExternalNode->removeOneAbstractEdgeTo((*CG)[I]);
165211
166 Changed = true;
167212 ++NumFunctions;
168213 DEBUG(dbgs() << "Internalizing func " << I->getName() << "\n");
169214 }
190235 // internal as well.
191236 for (Module::global_iterator I = M.global_begin(), E = M.global_end();
192237 I != E; ++I) {
193 if (!shouldInternalize(*I, ExternalNames))
238 if (!maybeInternalize(*I, ExternalComdats))
194239 continue;
195240
196 I->setVisibility(GlobalValue::DefaultVisibility);
197 I->setLinkage(GlobalValue::InternalLinkage);
198 Changed = true;
199241 ++NumGlobals;
200242 DEBUG(dbgs() << "Internalized gvar " << I->getName() << "\n");
201243 }
203245 // Mark all aliases that are not in the api as internal as well.
204246 for (Module::alias_iterator I = M.alias_begin(), E = M.alias_end();
205247 I != E; ++I) {
206 if (!shouldInternalize(*I, ExternalNames))
248 if (!maybeInternalize(*I, ExternalComdats))
207249 continue;
208250
209 I->setVisibility(GlobalValue::DefaultVisibility);
210 I->setLinkage(GlobalValue::InternalLinkage);
211 Changed = true;
212251 ++NumAliases;
213252 DEBUG(dbgs() << "Internalized alias " << I->getName() << "\n");
214253 }
215254
216 return Changed;
255 // We do not keep track of whether this pass changed the module because
256 // it adds unnecessary complexity:
257 // 1) This pass will generally be near the start of the pass pipeline, so
258 // there will be no analyses to invalidate.
259 // 2) This pass will most likely end up changing the module and it isn't worth
260 // worrying about optimizing the case where the module is unchanged.
261 return true;
217262 }
218263
219264 ModulePass *llvm::createInternalizePass() { return new InternalizePass(); }
0 ; RUN: opt < %s -internalize -internalize-public-api-list c1 -internalize-public-api-list c2 -internalize-public-api-list c3 -internalize-public-api-list c4 -S | FileCheck %s
1
2 $c1 = comdat any
3 $c2 = comdat any
4 $c3 = comdat any
5 $c4 = comdat any
6
7 ; CHECK: @c1_c = global i32 0, comdat($c1)
8 @c1_c = global i32 0, comdat($c1)
9
10 ; CHECK: @c2_b = internal global i32 0{{$}}
11 @c2_b = global i32 0, comdat($c2)
12
13 ; CHECK: @c3 = global i32 0, comdat{{$}}
14 @c3 = global i32 0, comdat
15
16 ; CHECK: @c4_a = internal global i32 0, comdat($c4)
17 @c4_a = internal global i32 0, comdat($c4)
18
19 ; CHECK: @c1_d = alias i32* @c1_c
20 @c1_d = alias i32* @c1_c
21
22 ; CHECK: @c2_c = internal alias i32* @c2_b
23 @c2_c = alias i32* @c2_b
24
25 ; CHECK: @c4 = alias i32* @c4_a
26 @c4 = alias i32* @c4_a
27
28 ; CHECK: define void @c1() comdat {
29 define void @c1() comdat {
30 ret void
31 }
32
33 ; CHECK: define void @c1_a() comdat($c1) {
34 define void @c1_a() comdat($c1) {
35 ret void
36 }
37
38 ; CHECK: define internal void @c2() {
39 define internal void @c2() comdat {
40 ret void
41 }
42
43 ; CHECK: define internal void @c2_a() {
44 define void @c2_a() comdat($c2) {
45 ret void
46 }
47
48 ; CHECK: define void @c3_a() comdat($c3) {
49 define void @c3_a() comdat($c3) {
50 ret void
51 }