1 | //===- ThinLTOBitcodeWriter.cpp - Bitcode writing pass for ThinLTO --------===// |
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 | #include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h" |
10 | #include "llvm/Analysis/BasicAliasAnalysis.h" |
11 | #include "llvm/Analysis/ModuleSummaryAnalysis.h" |
12 | #include "llvm/Analysis/ProfileSummaryInfo.h" |
13 | #include "llvm/Analysis/TypeMetadataUtils.h" |
14 | #include "llvm/Bitcode/BitcodeWriter.h" |
15 | #include "llvm/IR/Constants.h" |
16 | #include "llvm/IR/DebugInfo.h" |
17 | #include "llvm/IR/Instructions.h" |
18 | #include "llvm/IR/Intrinsics.h" |
19 | #include "llvm/IR/Module.h" |
20 | #include "llvm/IR/PassManager.h" |
21 | #include "llvm/Object/ModuleSymbolTable.h" |
22 | #include "llvm/Support/raw_ostream.h" |
23 | #include "llvm/Transforms/IPO.h" |
24 | #include "llvm/Transforms/IPO/FunctionAttrs.h" |
25 | #include "llvm/Transforms/IPO/FunctionImport.h" |
26 | #include "llvm/Transforms/IPO/LowerTypeTests.h" |
27 | #include "llvm/Transforms/Utils/Cloning.h" |
28 | #include "llvm/Transforms/Utils/ModuleUtils.h" |
29 | using namespace llvm; |
30 | |
31 | namespace { |
32 | |
33 | // Determine if a promotion alias should be created for a symbol name. |
34 | static bool allowPromotionAlias(const std::string &Name) { |
35 | // Promotion aliases are used only in inline assembly. It's safe to |
36 | // simply skip unusual names. Subset of MCAsmInfo::isAcceptableChar() |
37 | // and MCAsmInfoXCOFF::isAcceptableChar(). |
38 | for (const char &C : Name) { |
39 | if (isAlnum(C) || C == '_' || C == '.') |
40 | continue; |
41 | return false; |
42 | } |
43 | return true; |
44 | } |
45 | |
46 | // Promote each local-linkage entity defined by ExportM and used by ImportM by |
47 | // changing visibility and appending the given ModuleId. |
48 | void promoteInternals(Module &ExportM, Module &ImportM, StringRef ModuleId, |
49 | SetVector<GlobalValue *> &) { |
50 | DenseMap<const Comdat *, Comdat *> RenamedComdats; |
51 | for (auto &ExportGV : ExportM.global_values()) { |
52 | if (!ExportGV.hasLocalLinkage()) |
53 | continue; |
54 | |
55 | auto Name = ExportGV.getName(); |
56 | GlobalValue *ImportGV = nullptr; |
57 | if (!PromoteExtra.count(key: &ExportGV)) { |
58 | ImportGV = ImportM.getNamedValue(Name); |
59 | if (!ImportGV) |
60 | continue; |
61 | ImportGV->removeDeadConstantUsers(); |
62 | if (ImportGV->use_empty()) { |
63 | ImportGV->eraseFromParent(); |
64 | continue; |
65 | } |
66 | } |
67 | |
68 | std::string OldName = Name.str(); |
69 | std::string NewName = (Name + ModuleId).str(); |
70 | |
71 | if (const auto *C = ExportGV.getComdat()) |
72 | if (C->getName() == Name) |
73 | RenamedComdats.try_emplace(Key: C, Args: ExportM.getOrInsertComdat(Name: NewName)); |
74 | |
75 | ExportGV.setName(NewName); |
76 | ExportGV.setLinkage(GlobalValue::ExternalLinkage); |
77 | ExportGV.setVisibility(GlobalValue::HiddenVisibility); |
78 | |
79 | if (ImportGV) { |
80 | ImportGV->setName(NewName); |
81 | ImportGV->setVisibility(GlobalValue::HiddenVisibility); |
82 | } |
83 | |
84 | if (isa<Function>(Val: &ExportGV) && allowPromotionAlias(Name: OldName)) { |
85 | // Create a local alias with the original name to avoid breaking |
86 | // references from inline assembly. |
87 | std::string Alias = |
88 | ".lto_set_conditional " + OldName + "," + NewName + "\n" ; |
89 | ExportM.appendModuleInlineAsm(Asm: Alias); |
90 | } |
91 | } |
92 | |
93 | if (!RenamedComdats.empty()) |
94 | for (auto &GO : ExportM.global_objects()) |
95 | if (auto *C = GO.getComdat()) { |
96 | auto Replacement = RenamedComdats.find(Val: C); |
97 | if (Replacement != RenamedComdats.end()) |
98 | GO.setComdat(Replacement->second); |
99 | } |
100 | } |
101 | |
102 | // Promote all internal (i.e. distinct) type ids used by the module by replacing |
103 | // them with external type ids formed using the module id. |
104 | // |
105 | // Note that this needs to be done before we clone the module because each clone |
106 | // will receive its own set of distinct metadata nodes. |
107 | void promoteTypeIds(Module &M, StringRef ModuleId) { |
108 | DenseMap<Metadata *, Metadata *> LocalToGlobal; |
109 | auto ExternalizeTypeId = [&](CallInst *CI, unsigned ArgNo) { |
110 | Metadata *MD = |
111 | cast<MetadataAsValue>(Val: CI->getArgOperand(i: ArgNo))->getMetadata(); |
112 | |
113 | if (isa<MDNode>(Val: MD) && cast<MDNode>(Val: MD)->isDistinct()) { |
114 | Metadata *&GlobalMD = LocalToGlobal[MD]; |
115 | if (!GlobalMD) { |
116 | std::string NewName = (Twine(LocalToGlobal.size()) + ModuleId).str(); |
117 | GlobalMD = MDString::get(Context&: M.getContext(), Str: NewName); |
118 | } |
119 | |
120 | CI->setArgOperand(i: ArgNo, |
121 | v: MetadataAsValue::get(Context&: M.getContext(), MD: GlobalMD)); |
122 | } |
123 | }; |
124 | |
125 | if (Function *TypeTestFunc = |
126 | Intrinsic::getDeclarationIfExists(M: &M, id: Intrinsic::type_test)) { |
127 | for (const Use &U : TypeTestFunc->uses()) { |
128 | auto CI = cast<CallInst>(Val: U.getUser()); |
129 | ExternalizeTypeId(CI, 1); |
130 | } |
131 | } |
132 | |
133 | if (Function *PublicTypeTestFunc = |
134 | Intrinsic::getDeclarationIfExists(M: &M, id: Intrinsic::public_type_test)) { |
135 | for (const Use &U : PublicTypeTestFunc->uses()) { |
136 | auto CI = cast<CallInst>(Val: U.getUser()); |
137 | ExternalizeTypeId(CI, 1); |
138 | } |
139 | } |
140 | |
141 | if (Function *TypeCheckedLoadFunc = |
142 | Intrinsic::getDeclarationIfExists(M: &M, id: Intrinsic::type_checked_load)) { |
143 | for (const Use &U : TypeCheckedLoadFunc->uses()) { |
144 | auto CI = cast<CallInst>(Val: U.getUser()); |
145 | ExternalizeTypeId(CI, 2); |
146 | } |
147 | } |
148 | |
149 | if (Function *TypeCheckedLoadRelativeFunc = Intrinsic::getDeclarationIfExists( |
150 | M: &M, id: Intrinsic::type_checked_load_relative)) { |
151 | for (const Use &U : TypeCheckedLoadRelativeFunc->uses()) { |
152 | auto CI = cast<CallInst>(Val: U.getUser()); |
153 | ExternalizeTypeId(CI, 2); |
154 | } |
155 | } |
156 | |
157 | for (GlobalObject &GO : M.global_objects()) { |
158 | SmallVector<MDNode *, 1> MDs; |
159 | GO.getMetadata(KindID: LLVMContext::MD_type, MDs); |
160 | |
161 | GO.eraseMetadata(KindID: LLVMContext::MD_type); |
162 | for (auto *MD : MDs) { |
163 | auto I = LocalToGlobal.find(Val: MD->getOperand(I: 1)); |
164 | if (I == LocalToGlobal.end()) { |
165 | GO.addMetadata(KindID: LLVMContext::MD_type, MD&: *MD); |
166 | continue; |
167 | } |
168 | GO.addMetadata( |
169 | KindID: LLVMContext::MD_type, |
170 | MD&: *MDNode::get(Context&: M.getContext(), MDs: {MD->getOperand(I: 0), I->second})); |
171 | } |
172 | } |
173 | } |
174 | |
175 | // Drop unused globals, and drop type information from function declarations. |
176 | // FIXME: If we made functions typeless then there would be no need to do this. |
177 | void simplifyExternals(Module &M) { |
178 | FunctionType *EmptyFT = |
179 | FunctionType::get(Result: Type::getVoidTy(C&: M.getContext()), isVarArg: false); |
180 | |
181 | for (Function &F : llvm::make_early_inc_range(Range&: M)) { |
182 | if (F.isDeclaration() && F.use_empty()) { |
183 | F.eraseFromParent(); |
184 | continue; |
185 | } |
186 | |
187 | if (!F.isDeclaration() || F.getFunctionType() == EmptyFT || |
188 | // Changing the type of an intrinsic may invalidate the IR. |
189 | F.getName().starts_with(Prefix: "llvm." )) |
190 | continue; |
191 | |
192 | Function *NewF = |
193 | Function::Create(Ty: EmptyFT, Linkage: GlobalValue::ExternalLinkage, |
194 | AddrSpace: F.getAddressSpace(), N: "" , M: &M); |
195 | NewF->copyAttributesFrom(Src: &F); |
196 | // Only copy function attribtues. |
197 | NewF->setAttributes(AttributeList::get(C&: M.getContext(), |
198 | Index: AttributeList::FunctionIndex, |
199 | Attrs: F.getAttributes().getFnAttrs())); |
200 | NewF->takeName(V: &F); |
201 | F.replaceAllUsesWith(V: NewF); |
202 | F.eraseFromParent(); |
203 | } |
204 | |
205 | for (GlobalIFunc &I : llvm::make_early_inc_range(Range: M.ifuncs())) { |
206 | if (I.use_empty()) |
207 | I.eraseFromParent(); |
208 | else |
209 | assert(I.getResolverFunction() && "ifunc misses its resolver function" ); |
210 | } |
211 | |
212 | for (GlobalVariable &GV : llvm::make_early_inc_range(Range: M.globals())) { |
213 | if (GV.isDeclaration() && GV.use_empty()) { |
214 | GV.eraseFromParent(); |
215 | continue; |
216 | } |
217 | } |
218 | } |
219 | |
220 | static void |
221 | filterModule(Module *M, |
222 | function_ref<bool(const GlobalValue *)> ShouldKeepDefinition) { |
223 | std::vector<GlobalValue *> V; |
224 | for (GlobalValue &GV : M->global_values()) |
225 | if (!ShouldKeepDefinition(&GV)) |
226 | V.push_back(x: &GV); |
227 | |
228 | for (GlobalValue *GV : V) |
229 | if (!convertToDeclaration(GV&: *GV)) |
230 | GV->eraseFromParent(); |
231 | } |
232 | |
233 | void forEachVirtualFunction(Constant *C, function_ref<void(Function *)> Fn) { |
234 | if (auto *F = dyn_cast<Function>(Val: C)) |
235 | return Fn(F); |
236 | if (isa<GlobalValue>(Val: C)) |
237 | return; |
238 | for (Value *Op : C->operands()) |
239 | forEachVirtualFunction(C: cast<Constant>(Val: Op), Fn); |
240 | } |
241 | |
242 | // Clone any @llvm[.compiler].used over to the new module and append |
243 | // values whose defs were cloned into that module. |
244 | static void cloneUsedGlobalVariables(const Module &SrcM, Module &DestM, |
245 | bool CompilerUsed) { |
246 | SmallVector<GlobalValue *, 4> Used, NewUsed; |
247 | // First collect those in the llvm[.compiler].used set. |
248 | collectUsedGlobalVariables(M: SrcM, Vec&: Used, CompilerUsed); |
249 | // Next build a set of the equivalent values defined in DestM. |
250 | for (auto *V : Used) { |
251 | auto *GV = DestM.getNamedValue(Name: V->getName()); |
252 | if (GV && !GV->isDeclaration()) |
253 | NewUsed.push_back(Elt: GV); |
254 | } |
255 | // Finally, add them to a llvm[.compiler].used variable in DestM. |
256 | if (CompilerUsed) |
257 | appendToCompilerUsed(M&: DestM, Values: NewUsed); |
258 | else |
259 | appendToUsed(M&: DestM, Values: NewUsed); |
260 | } |
261 | |
262 | #ifndef NDEBUG |
263 | static bool enableUnifiedLTO(Module &M) { |
264 | bool UnifiedLTO = false; |
265 | if (auto *MD = |
266 | mdconst::extract_or_null<ConstantInt>(M.getModuleFlag("UnifiedLTO" ))) |
267 | UnifiedLTO = MD->getZExtValue(); |
268 | return UnifiedLTO; |
269 | } |
270 | #endif |
271 | |
272 | // If it's possible to split M into regular and thin LTO parts, do so and write |
273 | // a multi-module bitcode file with the two parts to OS. Otherwise, write only a |
274 | // regular LTO bitcode file to OS. |
275 | void splitAndWriteThinLTOBitcode( |
276 | raw_ostream &OS, raw_ostream *ThinLinkOS, |
277 | function_ref<AAResults &(Function &)> AARGetter, Module &M, |
278 | const bool ShouldPreserveUseListOrder) { |
279 | std::string ModuleId = getUniqueModuleId(M: &M); |
280 | if (ModuleId.empty()) { |
281 | assert(!enableUnifiedLTO(M)); |
282 | // We couldn't generate a module ID for this module, write it out as a |
283 | // regular LTO module with an index for summary-based dead stripping. |
284 | ProfileSummaryInfo PSI(M); |
285 | M.addModuleFlag(Behavior: Module::Error, Key: "ThinLTO" , Val: uint32_t(0)); |
286 | ModuleSummaryIndex Index = buildModuleSummaryIndex(M, GetBFICallback: nullptr, PSI: &PSI); |
287 | WriteBitcodeToFile(M, Out&: OS, ShouldPreserveUseListOrder, Index: &Index, |
288 | /*UnifiedLTO=*/GenerateHash: false); |
289 | |
290 | if (ThinLinkOS) |
291 | // We don't have a ThinLTO part, but still write the module to the |
292 | // ThinLinkOS if requested so that the expected output file is produced. |
293 | WriteBitcodeToFile(M, Out&: *ThinLinkOS, ShouldPreserveUseListOrder, Index: &Index, |
294 | /*UnifiedLTO=*/GenerateHash: false); |
295 | |
296 | return; |
297 | } |
298 | |
299 | promoteTypeIds(M, ModuleId); |
300 | |
301 | // Returns whether a global or its associated global has attached type |
302 | // metadata. The former may participate in CFI or whole-program |
303 | // devirtualization, so they need to appear in the merged module instead of |
304 | // the thin LTO module. Similarly, globals that are associated with globals |
305 | // with type metadata need to appear in the merged module because they will |
306 | // reference the global's section directly. |
307 | auto HasTypeMetadata = [](const GlobalObject *GO) { |
308 | if (MDNode *MD = GO->getMetadata(KindID: LLVMContext::MD_associated)) |
309 | if (auto *AssocVM = dyn_cast_or_null<ValueAsMetadata>(Val: MD->getOperand(I: 0))) |
310 | if (auto *AssocGO = dyn_cast<GlobalObject>(Val: AssocVM->getValue())) |
311 | if (AssocGO->hasMetadata(KindID: LLVMContext::MD_type)) |
312 | return true; |
313 | return GO->hasMetadata(KindID: LLVMContext::MD_type); |
314 | }; |
315 | |
316 | // Collect the set of virtual functions that are eligible for virtual constant |
317 | // propagation. Each eligible function must not access memory, must return |
318 | // an integer of width <=64 bits, must take at least one argument, must not |
319 | // use its first argument (assumed to be "this") and all arguments other than |
320 | // the first one must be of <=64 bit integer type. |
321 | // |
322 | // Note that we test whether this copy of the function is readnone, rather |
323 | // than testing function attributes, which must hold for any copy of the |
324 | // function, even a less optimized version substituted at link time. This is |
325 | // sound because the virtual constant propagation optimizations effectively |
326 | // inline all implementations of the virtual function into each call site, |
327 | // rather than using function attributes to perform local optimization. |
328 | DenseSet<const Function *> EligibleVirtualFns; |
329 | // If any member of a comdat lives in MergedM, put all members of that |
330 | // comdat in MergedM to keep the comdat together. |
331 | DenseSet<const Comdat *> MergedMComdats; |
332 | for (GlobalVariable &GV : M.globals()) |
333 | if (!GV.isDeclaration() && HasTypeMetadata(&GV)) { |
334 | if (const auto *C = GV.getComdat()) |
335 | MergedMComdats.insert(V: C); |
336 | forEachVirtualFunction(C: GV.getInitializer(), Fn: [&](Function *F) { |
337 | auto *RT = dyn_cast<IntegerType>(Val: F->getReturnType()); |
338 | if (!RT || RT->getBitWidth() > 64 || F->arg_empty() || |
339 | !F->arg_begin()->use_empty()) |
340 | return; |
341 | for (auto &Arg : drop_begin(RangeOrContainer: F->args())) { |
342 | auto *ArgT = dyn_cast<IntegerType>(Val: Arg.getType()); |
343 | if (!ArgT || ArgT->getBitWidth() > 64) |
344 | return; |
345 | } |
346 | if (!F->isDeclaration() && |
347 | computeFunctionBodyMemoryAccess(F&: *F, AAR&: AARGetter(*F)) |
348 | .doesNotAccessMemory()) |
349 | EligibleVirtualFns.insert(V: F); |
350 | }); |
351 | } |
352 | |
353 | ValueToValueMapTy VMap; |
354 | std::unique_ptr<Module> MergedM( |
355 | CloneModule(M, VMap, ShouldCloneDefinition: [&](const GlobalValue *GV) -> bool { |
356 | if (const auto *C = GV->getComdat()) |
357 | if (MergedMComdats.count(V: C)) |
358 | return true; |
359 | if (auto *F = dyn_cast<Function>(Val: GV)) |
360 | return EligibleVirtualFns.count(V: F); |
361 | if (auto *GVar = |
362 | dyn_cast_or_null<GlobalVariable>(Val: GV->getAliaseeObject())) |
363 | return HasTypeMetadata(GVar); |
364 | return false; |
365 | })); |
366 | StripDebugInfo(M&: *MergedM); |
367 | MergedM->setModuleInlineAsm("" ); |
368 | |
369 | // Clone any llvm.*used globals to ensure the included values are |
370 | // not deleted. |
371 | cloneUsedGlobalVariables(SrcM: M, DestM&: *MergedM, /*CompilerUsed*/ false); |
372 | cloneUsedGlobalVariables(SrcM: M, DestM&: *MergedM, /*CompilerUsed*/ true); |
373 | |
374 | for (Function &F : *MergedM) |
375 | if (!F.isDeclaration()) { |
376 | // Reset the linkage of all functions eligible for virtual constant |
377 | // propagation. The canonical definitions live in the thin LTO module so |
378 | // that they can be imported. |
379 | F.setLinkage(GlobalValue::AvailableExternallyLinkage); |
380 | F.setComdat(nullptr); |
381 | } |
382 | |
383 | SetVector<GlobalValue *> CfiFunctions; |
384 | for (auto &F : M) |
385 | if ((!F.hasLocalLinkage() || F.hasAddressTaken()) && HasTypeMetadata(&F)) |
386 | CfiFunctions.insert(X: &F); |
387 | |
388 | // Remove all globals with type metadata, globals with comdats that live in |
389 | // MergedM, and aliases pointing to such globals from the thin LTO module. |
390 | filterModule(M: &M, ShouldKeepDefinition: [&](const GlobalValue *GV) { |
391 | if (auto *GVar = dyn_cast_or_null<GlobalVariable>(Val: GV->getAliaseeObject())) |
392 | if (HasTypeMetadata(GVar)) |
393 | return false; |
394 | if (const auto *C = GV->getComdat()) |
395 | if (MergedMComdats.count(V: C)) |
396 | return false; |
397 | return true; |
398 | }); |
399 | |
400 | promoteInternals(ExportM&: *MergedM, ImportM&: M, ModuleId, PromoteExtra&: CfiFunctions); |
401 | promoteInternals(ExportM&: M, ImportM&: *MergedM, ModuleId, PromoteExtra&: CfiFunctions); |
402 | |
403 | auto &Ctx = MergedM->getContext(); |
404 | SmallVector<MDNode *, 8> CfiFunctionMDs; |
405 | for (auto *V : CfiFunctions) { |
406 | Function &F = *cast<Function>(Val: V); |
407 | SmallVector<MDNode *, 2> Types; |
408 | F.getMetadata(KindID: LLVMContext::MD_type, MDs&: Types); |
409 | |
410 | SmallVector<Metadata *, 4> Elts; |
411 | Elts.push_back(Elt: MDString::get(Context&: Ctx, Str: F.getName())); |
412 | CfiFunctionLinkage Linkage; |
413 | if (lowertypetests::isJumpTableCanonical(F: &F)) |
414 | Linkage = CFL_Definition; |
415 | else if (F.hasExternalWeakLinkage()) |
416 | Linkage = CFL_WeakDeclaration; |
417 | else |
418 | Linkage = CFL_Declaration; |
419 | Elts.push_back(Elt: ConstantAsMetadata::get( |
420 | C: llvm::ConstantInt::get(Ty: Type::getInt8Ty(C&: Ctx), V: Linkage))); |
421 | append_range(C&: Elts, R&: Types); |
422 | CfiFunctionMDs.push_back(Elt: MDTuple::get(Context&: Ctx, MDs: Elts)); |
423 | } |
424 | |
425 | if(!CfiFunctionMDs.empty()) { |
426 | NamedMDNode *NMD = MergedM->getOrInsertNamedMetadata(Name: "cfi.functions" ); |
427 | for (auto *MD : CfiFunctionMDs) |
428 | NMD->addOperand(M: MD); |
429 | } |
430 | |
431 | SmallVector<MDNode *, 8> FunctionAliases; |
432 | for (auto &A : M.aliases()) { |
433 | if (!isa<Function>(Val: A.getAliasee())) |
434 | continue; |
435 | |
436 | auto *F = cast<Function>(Val: A.getAliasee()); |
437 | |
438 | Metadata *Elts[] = { |
439 | MDString::get(Context&: Ctx, Str: A.getName()), |
440 | MDString::get(Context&: Ctx, Str: F->getName()), |
441 | ConstantAsMetadata::get( |
442 | C: ConstantInt::get(Ty: Type::getInt8Ty(C&: Ctx), V: A.getVisibility())), |
443 | ConstantAsMetadata::get( |
444 | C: ConstantInt::get(Ty: Type::getInt8Ty(C&: Ctx), V: A.isWeakForLinker())), |
445 | }; |
446 | |
447 | FunctionAliases.push_back(Elt: MDTuple::get(Context&: Ctx, MDs: Elts)); |
448 | } |
449 | |
450 | if (!FunctionAliases.empty()) { |
451 | NamedMDNode *NMD = MergedM->getOrInsertNamedMetadata(Name: "aliases" ); |
452 | for (auto *MD : FunctionAliases) |
453 | NMD->addOperand(M: MD); |
454 | } |
455 | |
456 | SmallVector<MDNode *, 8> Symvers; |
457 | ModuleSymbolTable::CollectAsmSymvers(M, AsmSymver: [&](StringRef Name, StringRef Alias) { |
458 | Function *F = M.getFunction(Name); |
459 | if (!F || F->use_empty()) |
460 | return; |
461 | |
462 | Symvers.push_back(Elt: MDTuple::get( |
463 | Context&: Ctx, MDs: {MDString::get(Context&: Ctx, Str: Name), MDString::get(Context&: Ctx, Str: Alias)})); |
464 | }); |
465 | |
466 | if (!Symvers.empty()) { |
467 | NamedMDNode *NMD = MergedM->getOrInsertNamedMetadata(Name: "symvers" ); |
468 | for (auto *MD : Symvers) |
469 | NMD->addOperand(M: MD); |
470 | } |
471 | |
472 | simplifyExternals(M&: *MergedM); |
473 | |
474 | // FIXME: Try to re-use BSI and PFI from the original module here. |
475 | ProfileSummaryInfo PSI(M); |
476 | ModuleSummaryIndex Index = buildModuleSummaryIndex(M, GetBFICallback: nullptr, PSI: &PSI); |
477 | |
478 | // Mark the merged module as requiring full LTO. We still want an index for |
479 | // it though, so that it can participate in summary-based dead stripping. |
480 | MergedM->addModuleFlag(Behavior: Module::Error, Key: "ThinLTO" , Val: uint32_t(0)); |
481 | ModuleSummaryIndex MergedMIndex = |
482 | buildModuleSummaryIndex(M: *MergedM, GetBFICallback: nullptr, PSI: &PSI); |
483 | |
484 | SmallVector<char, 0> Buffer; |
485 | |
486 | BitcodeWriter W(Buffer); |
487 | // Save the module hash produced for the full bitcode, which will |
488 | // be used in the backends, and use that in the minimized bitcode |
489 | // produced for the full link. |
490 | ModuleHash ModHash = {._M_elems: {0}}; |
491 | W.writeModule(M, ShouldPreserveUseListOrder, Index: &Index, |
492 | /*GenerateHash=*/true, ModHash: &ModHash); |
493 | W.writeModule(M: *MergedM, ShouldPreserveUseListOrder, Index: &MergedMIndex); |
494 | W.writeSymtab(); |
495 | W.writeStrtab(); |
496 | OS << Buffer; |
497 | |
498 | // If a minimized bitcode module was requested for the thin link, only |
499 | // the information that is needed by thin link will be written in the |
500 | // given OS (the merged module will be written as usual). |
501 | if (ThinLinkOS) { |
502 | Buffer.clear(); |
503 | BitcodeWriter W2(Buffer); |
504 | StripDebugInfo(M); |
505 | W2.writeThinLinkBitcode(M, Index, ModHash); |
506 | W2.writeModule(M: *MergedM, /*ShouldPreserveUseListOrder=*/false, |
507 | Index: &MergedMIndex); |
508 | W2.writeSymtab(); |
509 | W2.writeStrtab(); |
510 | *ThinLinkOS << Buffer; |
511 | } |
512 | } |
513 | |
514 | // Check if the LTO Unit splitting has been enabled. |
515 | bool enableSplitLTOUnit(Module &M) { |
516 | bool EnableSplitLTOUnit = false; |
517 | if (auto *MD = mdconst::extract_or_null<ConstantInt>( |
518 | MD: M.getModuleFlag(Key: "EnableSplitLTOUnit" ))) |
519 | EnableSplitLTOUnit = MD->getZExtValue(); |
520 | return EnableSplitLTOUnit; |
521 | } |
522 | |
523 | // Returns whether this module needs to be split because it uses type metadata. |
524 | bool hasTypeMetadata(Module &M) { |
525 | for (auto &GO : M.global_objects()) { |
526 | if (GO.hasMetadata(KindID: LLVMContext::MD_type)) |
527 | return true; |
528 | } |
529 | return false; |
530 | } |
531 | |
532 | bool writeThinLTOBitcode(raw_ostream &OS, raw_ostream *ThinLinkOS, |
533 | function_ref<AAResults &(Function &)> AARGetter, |
534 | Module &M, const ModuleSummaryIndex *Index, |
535 | const bool ShouldPreserveUseListOrder) { |
536 | std::unique_ptr<ModuleSummaryIndex> NewIndex = nullptr; |
537 | // See if this module has any type metadata. If so, we try to split it |
538 | // or at least promote type ids to enable WPD. |
539 | if (hasTypeMetadata(M)) { |
540 | if (enableSplitLTOUnit(M)) { |
541 | splitAndWriteThinLTOBitcode(OS, ThinLinkOS, AARGetter, M, |
542 | ShouldPreserveUseListOrder); |
543 | return true; |
544 | } |
545 | // Promote type ids as needed for index-based WPD. |
546 | std::string ModuleId = getUniqueModuleId(M: &M); |
547 | if (!ModuleId.empty()) { |
548 | promoteTypeIds(M, ModuleId); |
549 | // Need to rebuild the index so that it contains type metadata |
550 | // for the newly promoted type ids. |
551 | // FIXME: Probably should not bother building the index at all |
552 | // in the caller of writeThinLTOBitcode (which does so via the |
553 | // ModuleSummaryIndexAnalysis pass), since we have to rebuild it |
554 | // anyway whenever there is type metadata (here or in |
555 | // splitAndWriteThinLTOBitcode). Just always build it once via the |
556 | // buildModuleSummaryIndex when Module(s) are ready. |
557 | ProfileSummaryInfo PSI(M); |
558 | NewIndex = std::make_unique<ModuleSummaryIndex>( |
559 | args: buildModuleSummaryIndex(M, GetBFICallback: nullptr, PSI: &PSI)); |
560 | Index = NewIndex.get(); |
561 | } |
562 | } |
563 | |
564 | // Write it out as an unsplit ThinLTO module. |
565 | |
566 | // Save the module hash produced for the full bitcode, which will |
567 | // be used in the backends, and use that in the minimized bitcode |
568 | // produced for the full link. |
569 | ModuleHash ModHash = {._M_elems: {0}}; |
570 | WriteBitcodeToFile(M, Out&: OS, ShouldPreserveUseListOrder, Index, |
571 | /*GenerateHash=*/true, ModHash: &ModHash); |
572 | // If a minimized bitcode module was requested for the thin link, only |
573 | // the information that is needed by thin link will be written in the |
574 | // given OS. |
575 | if (ThinLinkOS && Index) |
576 | writeThinLinkBitcodeToFile(M, Out&: *ThinLinkOS, Index: *Index, ModHash); |
577 | return false; |
578 | } |
579 | |
580 | } // anonymous namespace |
581 | |
582 | PreservedAnalyses |
583 | llvm::ThinLTOBitcodeWriterPass::run(Module &M, ModuleAnalysisManager &AM) { |
584 | FunctionAnalysisManager &FAM = |
585 | AM.getResult<FunctionAnalysisManagerModuleProxy>(IR&: M).getManager(); |
586 | |
587 | M.removeDebugIntrinsicDeclarations(); |
588 | |
589 | bool Changed = writeThinLTOBitcode( |
590 | OS, ThinLinkOS, |
591 | AARGetter: [&FAM](Function &F) -> AAResults & { |
592 | return FAM.getResult<AAManager>(IR&: F); |
593 | }, |
594 | M, Index: &AM.getResult<ModuleSummaryIndexAnalysis>(IR&: M), |
595 | ShouldPreserveUseListOrder); |
596 | |
597 | return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all(); |
598 | } |
599 | |