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 | M.getFunction(Name: Intrinsic::getName(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 | M.getFunction(Name: Intrinsic::getName(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 | M.getFunction(Name: Intrinsic::getName(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 = M.getFunction( |
150 | Name: Intrinsic::getName(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 | std::string ModuleId = getUniqueModuleId(M: &M); |
279 | if (ModuleId.empty()) { |
280 | assert(!enableUnifiedLTO(M)); |
281 | // We couldn't generate a module ID for this module, write it out as a |
282 | // regular LTO module with an index for summary-based dead stripping. |
283 | ProfileSummaryInfo PSI(M); |
284 | M.addModuleFlag(Behavior: Module::Error, Key: "ThinLTO" , Val: uint32_t(0)); |
285 | ModuleSummaryIndex Index = buildModuleSummaryIndex(M, GetBFICallback: nullptr, PSI: &PSI); |
286 | WriteBitcodeToFile(M, Out&: OS, /*ShouldPreserveUseListOrder=*/false, Index: &Index, |
287 | /*UnifiedLTO=*/GenerateHash: false); |
288 | |
289 | if (ThinLinkOS) |
290 | // We don't have a ThinLTO part, but still write the module to the |
291 | // ThinLinkOS if requested so that the expected output file is produced. |
292 | WriteBitcodeToFile(M, Out&: *ThinLinkOS, /*ShouldPreserveUseListOrder=*/false, |
293 | Index: &Index, /*UnifiedLTO=*/GenerateHash: false); |
294 | |
295 | return; |
296 | } |
297 | |
298 | promoteTypeIds(M, ModuleId); |
299 | |
300 | // Returns whether a global or its associated global has attached type |
301 | // metadata. The former may participate in CFI or whole-program |
302 | // devirtualization, so they need to appear in the merged module instead of |
303 | // the thin LTO module. Similarly, globals that are associated with globals |
304 | // with type metadata need to appear in the merged module because they will |
305 | // reference the global's section directly. |
306 | auto HasTypeMetadata = [](const GlobalObject *GO) { |
307 | if (MDNode *MD = GO->getMetadata(KindID: LLVMContext::MD_associated)) |
308 | if (auto *AssocVM = dyn_cast_or_null<ValueAsMetadata>(Val: MD->getOperand(I: 0))) |
309 | if (auto *AssocGO = dyn_cast<GlobalObject>(Val: AssocVM->getValue())) |
310 | if (AssocGO->hasMetadata(KindID: LLVMContext::MD_type)) |
311 | return true; |
312 | return GO->hasMetadata(KindID: LLVMContext::MD_type); |
313 | }; |
314 | |
315 | // Collect the set of virtual functions that are eligible for virtual constant |
316 | // propagation. Each eligible function must not access memory, must return |
317 | // an integer of width <=64 bits, must take at least one argument, must not |
318 | // use its first argument (assumed to be "this") and all arguments other than |
319 | // the first one must be of <=64 bit integer type. |
320 | // |
321 | // Note that we test whether this copy of the function is readnone, rather |
322 | // than testing function attributes, which must hold for any copy of the |
323 | // function, even a less optimized version substituted at link time. This is |
324 | // sound because the virtual constant propagation optimizations effectively |
325 | // inline all implementations of the virtual function into each call site, |
326 | // rather than using function attributes to perform local optimization. |
327 | DenseSet<const Function *> EligibleVirtualFns; |
328 | // If any member of a comdat lives in MergedM, put all members of that |
329 | // comdat in MergedM to keep the comdat together. |
330 | DenseSet<const Comdat *> MergedMComdats; |
331 | for (GlobalVariable &GV : M.globals()) |
332 | if (!GV.isDeclaration() && HasTypeMetadata(&GV)) { |
333 | if (const auto *C = GV.getComdat()) |
334 | MergedMComdats.insert(V: C); |
335 | forEachVirtualFunction(C: GV.getInitializer(), Fn: [&](Function *F) { |
336 | auto *RT = dyn_cast<IntegerType>(Val: F->getReturnType()); |
337 | if (!RT || RT->getBitWidth() > 64 || F->arg_empty() || |
338 | !F->arg_begin()->use_empty()) |
339 | return; |
340 | for (auto &Arg : drop_begin(RangeOrContainer: F->args())) { |
341 | auto *ArgT = dyn_cast<IntegerType>(Val: Arg.getType()); |
342 | if (!ArgT || ArgT->getBitWidth() > 64) |
343 | return; |
344 | } |
345 | if (!F->isDeclaration() && |
346 | computeFunctionBodyMemoryAccess(F&: *F, AAR&: AARGetter(*F)) |
347 | .doesNotAccessMemory()) |
348 | EligibleVirtualFns.insert(V: F); |
349 | }); |
350 | } |
351 | |
352 | ValueToValueMapTy VMap; |
353 | std::unique_ptr<Module> MergedM( |
354 | CloneModule(M, VMap, ShouldCloneDefinition: [&](const GlobalValue *GV) -> bool { |
355 | if (const auto *C = GV->getComdat()) |
356 | if (MergedMComdats.count(V: C)) |
357 | return true; |
358 | if (auto *F = dyn_cast<Function>(Val: GV)) |
359 | return EligibleVirtualFns.count(V: F); |
360 | if (auto *GVar = |
361 | dyn_cast_or_null<GlobalVariable>(Val: GV->getAliaseeObject())) |
362 | return HasTypeMetadata(GVar); |
363 | return false; |
364 | })); |
365 | StripDebugInfo(M&: *MergedM); |
366 | MergedM->setModuleInlineAsm("" ); |
367 | |
368 | // Clone any llvm.*used globals to ensure the included values are |
369 | // not deleted. |
370 | cloneUsedGlobalVariables(SrcM: M, DestM&: *MergedM, /*CompilerUsed*/ false); |
371 | cloneUsedGlobalVariables(SrcM: M, DestM&: *MergedM, /*CompilerUsed*/ true); |
372 | |
373 | for (Function &F : *MergedM) |
374 | if (!F.isDeclaration()) { |
375 | // Reset the linkage of all functions eligible for virtual constant |
376 | // propagation. The canonical definitions live in the thin LTO module so |
377 | // that they can be imported. |
378 | F.setLinkage(GlobalValue::AvailableExternallyLinkage); |
379 | F.setComdat(nullptr); |
380 | } |
381 | |
382 | SetVector<GlobalValue *> CfiFunctions; |
383 | for (auto &F : M) |
384 | if ((!F.hasLocalLinkage() || F.hasAddressTaken()) && HasTypeMetadata(&F)) |
385 | CfiFunctions.insert(X: &F); |
386 | |
387 | // Remove all globals with type metadata, globals with comdats that live in |
388 | // MergedM, and aliases pointing to such globals from the thin LTO module. |
389 | filterModule(M: &M, ShouldKeepDefinition: [&](const GlobalValue *GV) { |
390 | if (auto *GVar = dyn_cast_or_null<GlobalVariable>(Val: GV->getAliaseeObject())) |
391 | if (HasTypeMetadata(GVar)) |
392 | return false; |
393 | if (const auto *C = GV->getComdat()) |
394 | if (MergedMComdats.count(V: C)) |
395 | return false; |
396 | return true; |
397 | }); |
398 | |
399 | promoteInternals(ExportM&: *MergedM, ImportM&: M, ModuleId, PromoteExtra&: CfiFunctions); |
400 | promoteInternals(ExportM&: M, ImportM&: *MergedM, ModuleId, PromoteExtra&: CfiFunctions); |
401 | |
402 | auto &Ctx = MergedM->getContext(); |
403 | SmallVector<MDNode *, 8> CfiFunctionMDs; |
404 | for (auto *V : CfiFunctions) { |
405 | Function &F = *cast<Function>(Val: V); |
406 | SmallVector<MDNode *, 2> Types; |
407 | F.getMetadata(KindID: LLVMContext::MD_type, MDs&: Types); |
408 | |
409 | SmallVector<Metadata *, 4> Elts; |
410 | Elts.push_back(Elt: MDString::get(Context&: Ctx, Str: F.getName())); |
411 | CfiFunctionLinkage Linkage; |
412 | if (lowertypetests::isJumpTableCanonical(F: &F)) |
413 | Linkage = CFL_Definition; |
414 | else if (F.hasExternalWeakLinkage()) |
415 | Linkage = CFL_WeakDeclaration; |
416 | else |
417 | Linkage = CFL_Declaration; |
418 | Elts.push_back(Elt: ConstantAsMetadata::get( |
419 | C: llvm::ConstantInt::get(Ty: Type::getInt8Ty(C&: Ctx), V: Linkage))); |
420 | append_range(C&: Elts, R&: Types); |
421 | CfiFunctionMDs.push_back(Elt: MDTuple::get(Context&: Ctx, MDs: Elts)); |
422 | } |
423 | |
424 | if(!CfiFunctionMDs.empty()) { |
425 | NamedMDNode *NMD = MergedM->getOrInsertNamedMetadata(Name: "cfi.functions" ); |
426 | for (auto *MD : CfiFunctionMDs) |
427 | NMD->addOperand(M: MD); |
428 | } |
429 | |
430 | SmallVector<MDNode *, 8> FunctionAliases; |
431 | for (auto &A : M.aliases()) { |
432 | if (!isa<Function>(Val: A.getAliasee())) |
433 | continue; |
434 | |
435 | auto *F = cast<Function>(Val: A.getAliasee()); |
436 | |
437 | Metadata *Elts[] = { |
438 | MDString::get(Context&: Ctx, Str: A.getName()), |
439 | MDString::get(Context&: Ctx, Str: F->getName()), |
440 | ConstantAsMetadata::get( |
441 | C: ConstantInt::get(Ty: Type::getInt8Ty(C&: Ctx), V: A.getVisibility())), |
442 | ConstantAsMetadata::get( |
443 | C: ConstantInt::get(Ty: Type::getInt8Ty(C&: Ctx), V: A.isWeakForLinker())), |
444 | }; |
445 | |
446 | FunctionAliases.push_back(Elt: MDTuple::get(Context&: Ctx, MDs: Elts)); |
447 | } |
448 | |
449 | if (!FunctionAliases.empty()) { |
450 | NamedMDNode *NMD = MergedM->getOrInsertNamedMetadata(Name: "aliases" ); |
451 | for (auto *MD : FunctionAliases) |
452 | NMD->addOperand(M: MD); |
453 | } |
454 | |
455 | SmallVector<MDNode *, 8> Symvers; |
456 | ModuleSymbolTable::CollectAsmSymvers(M, AsmSymver: [&](StringRef Name, StringRef Alias) { |
457 | Function *F = M.getFunction(Name); |
458 | if (!F || F->use_empty()) |
459 | return; |
460 | |
461 | Symvers.push_back(Elt: MDTuple::get( |
462 | Context&: Ctx, MDs: {MDString::get(Context&: Ctx, Str: Name), MDString::get(Context&: Ctx, Str: Alias)})); |
463 | }); |
464 | |
465 | if (!Symvers.empty()) { |
466 | NamedMDNode *NMD = MergedM->getOrInsertNamedMetadata(Name: "symvers" ); |
467 | for (auto *MD : Symvers) |
468 | NMD->addOperand(M: MD); |
469 | } |
470 | |
471 | simplifyExternals(M&: *MergedM); |
472 | |
473 | // FIXME: Try to re-use BSI and PFI from the original module here. |
474 | ProfileSummaryInfo PSI(M); |
475 | ModuleSummaryIndex Index = buildModuleSummaryIndex(M, GetBFICallback: nullptr, PSI: &PSI); |
476 | |
477 | // Mark the merged module as requiring full LTO. We still want an index for |
478 | // it though, so that it can participate in summary-based dead stripping. |
479 | MergedM->addModuleFlag(Behavior: Module::Error, Key: "ThinLTO" , Val: uint32_t(0)); |
480 | ModuleSummaryIndex MergedMIndex = |
481 | buildModuleSummaryIndex(M: *MergedM, GetBFICallback: nullptr, PSI: &PSI); |
482 | |
483 | SmallVector<char, 0> Buffer; |
484 | |
485 | BitcodeWriter W(Buffer); |
486 | // Save the module hash produced for the full bitcode, which will |
487 | // be used in the backends, and use that in the minimized bitcode |
488 | // produced for the full link. |
489 | ModuleHash ModHash = {._M_elems: {0}}; |
490 | W.writeModule(M, /*ShouldPreserveUseListOrder=*/false, Index: &Index, |
491 | /*GenerateHash=*/true, ModHash: &ModHash); |
492 | W.writeModule(M: *MergedM, /*ShouldPreserveUseListOrder=*/false, Index: &MergedMIndex); |
493 | W.writeSymtab(); |
494 | W.writeStrtab(); |
495 | OS << Buffer; |
496 | |
497 | // If a minimized bitcode module was requested for the thin link, only |
498 | // the information that is needed by thin link will be written in the |
499 | // given OS (the merged module will be written as usual). |
500 | if (ThinLinkOS) { |
501 | Buffer.clear(); |
502 | BitcodeWriter W2(Buffer); |
503 | StripDebugInfo(M); |
504 | W2.writeThinLinkBitcode(M, Index, ModHash); |
505 | W2.writeModule(M: *MergedM, /*ShouldPreserveUseListOrder=*/false, |
506 | Index: &MergedMIndex); |
507 | W2.writeSymtab(); |
508 | W2.writeStrtab(); |
509 | *ThinLinkOS << Buffer; |
510 | } |
511 | } |
512 | |
513 | // Check if the LTO Unit splitting has been enabled. |
514 | bool enableSplitLTOUnit(Module &M) { |
515 | bool EnableSplitLTOUnit = false; |
516 | if (auto *MD = mdconst::extract_or_null<ConstantInt>( |
517 | MD: M.getModuleFlag(Key: "EnableSplitLTOUnit" ))) |
518 | EnableSplitLTOUnit = MD->getZExtValue(); |
519 | return EnableSplitLTOUnit; |
520 | } |
521 | |
522 | // Returns whether this module needs to be split because it uses type metadata. |
523 | bool hasTypeMetadata(Module &M) { |
524 | for (auto &GO : M.global_objects()) { |
525 | if (GO.hasMetadata(KindID: LLVMContext::MD_type)) |
526 | return true; |
527 | } |
528 | return false; |
529 | } |
530 | |
531 | bool writeThinLTOBitcode(raw_ostream &OS, raw_ostream *ThinLinkOS, |
532 | function_ref<AAResults &(Function &)> AARGetter, |
533 | Module &M, const ModuleSummaryIndex *Index) { |
534 | std::unique_ptr<ModuleSummaryIndex> NewIndex = nullptr; |
535 | // See if this module has any type metadata. If so, we try to split it |
536 | // or at least promote type ids to enable WPD. |
537 | if (hasTypeMetadata(M)) { |
538 | if (enableSplitLTOUnit(M)) { |
539 | splitAndWriteThinLTOBitcode(OS, ThinLinkOS, AARGetter, M); |
540 | return true; |
541 | } |
542 | // Promote type ids as needed for index-based WPD. |
543 | std::string ModuleId = getUniqueModuleId(M: &M); |
544 | if (!ModuleId.empty()) { |
545 | promoteTypeIds(M, ModuleId); |
546 | // Need to rebuild the index so that it contains type metadata |
547 | // for the newly promoted type ids. |
548 | // FIXME: Probably should not bother building the index at all |
549 | // in the caller of writeThinLTOBitcode (which does so via the |
550 | // ModuleSummaryIndexAnalysis pass), since we have to rebuild it |
551 | // anyway whenever there is type metadata (here or in |
552 | // splitAndWriteThinLTOBitcode). Just always build it once via the |
553 | // buildModuleSummaryIndex when Module(s) are ready. |
554 | ProfileSummaryInfo PSI(M); |
555 | NewIndex = std::make_unique<ModuleSummaryIndex>( |
556 | args: buildModuleSummaryIndex(M, GetBFICallback: nullptr, PSI: &PSI)); |
557 | Index = NewIndex.get(); |
558 | } |
559 | } |
560 | |
561 | // Write it out as an unsplit ThinLTO module. |
562 | |
563 | // Save the module hash produced for the full bitcode, which will |
564 | // be used in the backends, and use that in the minimized bitcode |
565 | // produced for the full link. |
566 | ModuleHash ModHash = {._M_elems: {0}}; |
567 | WriteBitcodeToFile(M, Out&: OS, /*ShouldPreserveUseListOrder=*/false, Index, |
568 | /*GenerateHash=*/true, ModHash: &ModHash); |
569 | // If a minimized bitcode module was requested for the thin link, only |
570 | // the information that is needed by thin link will be written in the |
571 | // given OS. |
572 | if (ThinLinkOS && Index) |
573 | writeThinLinkBitcodeToFile(M, Out&: *ThinLinkOS, Index: *Index, ModHash); |
574 | return false; |
575 | } |
576 | |
577 | } // anonymous namespace |
578 | extern bool WriteNewDbgInfoFormatToBitcode; |
579 | PreservedAnalyses |
580 | llvm::ThinLTOBitcodeWriterPass::run(Module &M, ModuleAnalysisManager &AM) { |
581 | FunctionAnalysisManager &FAM = |
582 | AM.getResult<FunctionAnalysisManagerModuleProxy>(IR&: M).getManager(); |
583 | |
584 | ScopedDbgInfoFormatSetter FormatSetter(M, M.IsNewDbgInfoFormat && |
585 | WriteNewDbgInfoFormatToBitcode); |
586 | if (M.IsNewDbgInfoFormat) |
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 | |
596 | return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all(); |
597 | } |
598 | |