]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
New upstream version 1.66.0+dfsg1
[rustc.git] / compiler / rustc_llvm / llvm-wrapper / PassWrapper.cpp
CommitLineData
1a4d82fc
JJ
1#include <stdio.h>
2
041b39d2 3#include <vector>
ff7c6d11 4#include <set>
041b39d2 5
1b1a35ee 6#include "LLVMWrapper.h"
970d7e83 7
6a06907d 8#include "llvm/Analysis/AliasAnalysis.h"
62682a34
SL
9#include "llvm/Analysis/TargetLibraryInfo.h"
10#include "llvm/Analysis/TargetTransformInfo.h"
0731742a 11#include "llvm/CodeGen/TargetSubtargetInfo.h"
dfeec247 12#include "llvm/InitializePasses.h"
5bcae85e 13#include "llvm/IR/AutoUpgrade.h"
041b39d2 14#include "llvm/IR/AssemblyAnnotationWriter.h"
0731742a 15#include "llvm/IR/IntrinsicInst.h"
74b04a01 16#include "llvm/IR/Verifier.h"
f9f354fc
XL
17#include "llvm/Object/ObjectFile.h"
18#include "llvm/Object/IRObjectFile.h"
74b04a01 19#include "llvm/Passes/PassBuilder.h"
a2a8927a 20#include "llvm/Passes/PassPlugin.h"
74b04a01 21#include "llvm/Passes/StandardInstrumentations.h"
32a655c1
SL
22#include "llvm/Support/CBindingWrapping.h"
23#include "llvm/Support/FileSystem.h"
24#include "llvm/Support/Host.h"
3c0e092e
XL
25#if LLVM_VERSION_LT(14, 0)
26#include "llvm/Support/TargetRegistry.h"
27#else
28#include "llvm/MC/TargetRegistry.h"
29#endif
c1a9b12d 30#include "llvm/Target/TargetMachine.h"
1a4d82fc 31#include "llvm/Transforms/IPO/PassManagerBuilder.h"
476ff2be 32#include "llvm/Transforms/IPO/AlwaysInliner.h"
ea8adc8c 33#include "llvm/Transforms/IPO/FunctionImport.h"
2b03887a 34#include "llvm/Transforms/IPO/Internalize.h"
f2b60f7d 35#include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h"
c295e0f8 36#include "llvm/Transforms/Utils/AddDiscriminators.h"
ea8adc8c
XL
37#include "llvm/Transforms/Utils/FunctionImportUtils.h"
38#include "llvm/LTO/LTO.h"
2b03887a 39#include "llvm/Bitcode/BitcodeWriter.h"
1a4d82fc 40#include "llvm-c/Transforms/PassManagerBuilder.h"
970d7e83 41
60c5eb7d 42#include "llvm/Transforms/Instrumentation.h"
60c5eb7d 43#include "llvm/Transforms/Instrumentation/AddressSanitizer.h"
74b04a01 44#include "llvm/Support/TimeProfiler.h"
17df50a5
XL
45#include "llvm/Transforms/Instrumentation/GCOVProfiler.h"
46#include "llvm/Transforms/Instrumentation/InstrProfiling.h"
60c5eb7d
XL
47#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
48#include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
6a06907d 49#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
74b04a01 50#include "llvm/Transforms/Utils/CanonicalizeAliases.h"
74b04a01 51#include "llvm/Transforms/Utils/NameAnonGlobals.h"
c295e0f8 52#include "llvm/Transforms/Utils.h"
60c5eb7d 53
1a4d82fc 54using namespace llvm;
970d7e83 55
1a4d82fc
JJ
56typedef struct LLVMOpaquePass *LLVMPassRef;
57typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef;
58
59DEFINE_STDCXX_CONVERSION_FUNCTIONS(Pass, LLVMPassRef)
60DEFINE_STDCXX_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef)
970d7e83 61
32a655c1 62extern "C" void LLVMInitializePasses() {
970d7e83
LB
63 PassRegistry &Registry = *PassRegistry::getPassRegistry();
64 initializeCore(Registry);
65 initializeCodeGen(Registry);
66 initializeScalarOpts(Registry);
67 initializeVectorization(Registry);
68 initializeIPO(Registry);
69 initializeAnalysis(Registry);
970d7e83
LB
70 initializeTransformUtils(Registry);
71 initializeInstCombine(Registry);
2b03887a 72#if LLVM_VERSION_LT(16, 0)
970d7e83 73 initializeInstrumentation(Registry);
2b03887a 74#endif
970d7e83
LB
75 initializeTarget(Registry);
76}
77
74b04a01 78extern "C" void LLVMTimeTraceProfilerInitialize() {
ba9703b0
XL
79 timeTraceProfilerInitialize(
80 /* TimeTraceGranularity */ 0,
81 /* ProcName */ "rustc");
74b04a01
XL
82}
83
3c0e092e
XL
84extern "C" void LLVMTimeTraceProfilerFinishThread() {
85 timeTraceProfilerFinishThread();
86}
87
74b04a01 88extern "C" void LLVMTimeTraceProfilerFinish(const char* FileName) {
74b04a01
XL
89 StringRef FN(FileName);
90 std::error_code EC;
91 raw_fd_ostream OS(FN, EC, sys::fs::CD_CreateAlways);
92
93 timeTraceProfilerWrite(OS);
94 timeTraceProfilerCleanup();
74b04a01
XL
95}
96
a7813a04
XL
97#ifdef LLVM_COMPONENT_X86
98#define SUBTARGET_X86 SUBTARGET(X86)
99#else
100#define SUBTARGET_X86
101#endif
102
103#ifdef LLVM_COMPONENT_ARM
104#define SUBTARGET_ARM SUBTARGET(ARM)
105#else
106#define SUBTARGET_ARM
107#endif
108
109#ifdef LLVM_COMPONENT_AARCH64
110#define SUBTARGET_AARCH64 SUBTARGET(AArch64)
111#else
112#define SUBTARGET_AARCH64
113#endif
114
f035d41b
XL
115#ifdef LLVM_COMPONENT_AVR
116#define SUBTARGET_AVR SUBTARGET(AVR)
117#else
118#define SUBTARGET_AVR
119#endif
120
c295e0f8
XL
121#ifdef LLVM_COMPONENT_M68k
122#define SUBTARGET_M68K SUBTARGET(M68k)
123#else
124#define SUBTARGET_M68K
125#endif
126
a7813a04
XL
127#ifdef LLVM_COMPONENT_MIPS
128#define SUBTARGET_MIPS SUBTARGET(Mips)
129#else
130#define SUBTARGET_MIPS
131#endif
132
133#ifdef LLVM_COMPONENT_POWERPC
134#define SUBTARGET_PPC SUBTARGET(PPC)
135#else
136#define SUBTARGET_PPC
137#endif
138
9e0c209e
SL
139#ifdef LLVM_COMPONENT_SYSTEMZ
140#define SUBTARGET_SYSTEMZ SUBTARGET(SystemZ)
141#else
142#define SUBTARGET_SYSTEMZ
143#endif
144
476ff2be
SL
145#ifdef LLVM_COMPONENT_MSP430
146#define SUBTARGET_MSP430 SUBTARGET(MSP430)
147#else
148#define SUBTARGET_MSP430
149#endif
150
b7449926
XL
151#ifdef LLVM_COMPONENT_RISCV
152#define SUBTARGET_RISCV SUBTARGET(RISCV)
153#else
154#define SUBTARGET_RISCV
155#endif
156
32a655c1
SL
157#ifdef LLVM_COMPONENT_SPARC
158#define SUBTARGET_SPARC SUBTARGET(Sparc)
159#else
160#define SUBTARGET_SPARC
161#endif
162
7cac9316
XL
163#ifdef LLVM_COMPONENT_HEXAGON
164#define SUBTARGET_HEXAGON SUBTARGET(Hexagon)
165#else
166#define SUBTARGET_HEXAGON
167#endif
168
32a655c1
SL
169#define GEN_SUBTARGETS \
170 SUBTARGET_X86 \
171 SUBTARGET_ARM \
172 SUBTARGET_AARCH64 \
f035d41b 173 SUBTARGET_AVR \
c295e0f8 174 SUBTARGET_M68K \
32a655c1
SL
175 SUBTARGET_MIPS \
176 SUBTARGET_PPC \
177 SUBTARGET_SYSTEMZ \
178 SUBTARGET_MSP430 \
7cac9316 179 SUBTARGET_SPARC \
b7449926
XL
180 SUBTARGET_HEXAGON \
181 SUBTARGET_RISCV \
32a655c1
SL
182
183#define SUBTARGET(x) \
184 namespace llvm { \
185 extern const SubtargetFeatureKV x##FeatureKV[]; \
186 extern const SubtargetFeatureKV x##SubTypeKV[]; \
a7813a04
XL
187 }
188
189GEN_SUBTARGETS
190#undef SUBTARGET
191
32a655c1
SL
192extern "C" bool LLVMRustHasFeature(LLVMTargetMachineRef TM,
193 const char *Feature) {
194 TargetMachine *Target = unwrap(TM);
195 const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo();
0531ce1d 196 return MCInfo->checkFeatures(std::string("+") + Feature);
a7813a04
XL
197}
198
5bcae85e 199enum class LLVMRustCodeModel {
f9f354fc 200 Tiny,
32a655c1
SL
201 Small,
202 Kernel,
203 Medium,
204 Large,
2c00a5a8 205 None,
5bcae85e
SL
206};
207
f9f354fc 208static Optional<CodeModel::Model> fromRust(LLVMRustCodeModel Model) {
32a655c1 209 switch (Model) {
f9f354fc
XL
210 case LLVMRustCodeModel::Tiny:
211 return CodeModel::Tiny;
32a655c1
SL
212 case LLVMRustCodeModel::Small:
213 return CodeModel::Small;
214 case LLVMRustCodeModel::Kernel:
215 return CodeModel::Kernel;
216 case LLVMRustCodeModel::Medium:
217 return CodeModel::Medium;
218 case LLVMRustCodeModel::Large:
219 return CodeModel::Large;
f9f354fc
XL
220 case LLVMRustCodeModel::None:
221 return None;
32a655c1 222 default:
ff7c6d11 223 report_fatal_error("Bad CodeModel.");
5bcae85e
SL
224 }
225}
226
227enum class LLVMRustCodeGenOptLevel {
32a655c1
SL
228 None,
229 Less,
230 Default,
231 Aggressive,
5bcae85e
SL
232};
233
32a655c1
SL
234static CodeGenOpt::Level fromRust(LLVMRustCodeGenOptLevel Level) {
235 switch (Level) {
236 case LLVMRustCodeGenOptLevel::None:
237 return CodeGenOpt::None;
238 case LLVMRustCodeGenOptLevel::Less:
239 return CodeGenOpt::Less;
240 case LLVMRustCodeGenOptLevel::Default:
241 return CodeGenOpt::Default;
242 case LLVMRustCodeGenOptLevel::Aggressive:
243 return CodeGenOpt::Aggressive;
244 default:
ff7c6d11 245 report_fatal_error("Bad CodeGenOptLevel.");
5bcae85e
SL
246 }
247}
248
74b04a01
XL
249enum class LLVMRustPassBuilderOptLevel {
250 O0,
251 O1,
252 O2,
253 O3,
254 Os,
255 Oz,
256};
257
94222f64
XL
258#if LLVM_VERSION_LT(14,0)
259using OptimizationLevel = PassBuilder::OptimizationLevel;
260#endif
261
262static OptimizationLevel fromRust(LLVMRustPassBuilderOptLevel Level) {
74b04a01
XL
263 switch (Level) {
264 case LLVMRustPassBuilderOptLevel::O0:
94222f64 265 return OptimizationLevel::O0;
74b04a01 266 case LLVMRustPassBuilderOptLevel::O1:
94222f64 267 return OptimizationLevel::O1;
74b04a01 268 case LLVMRustPassBuilderOptLevel::O2:
94222f64 269 return OptimizationLevel::O2;
74b04a01 270 case LLVMRustPassBuilderOptLevel::O3:
94222f64 271 return OptimizationLevel::O3;
74b04a01 272 case LLVMRustPassBuilderOptLevel::Os:
94222f64 273 return OptimizationLevel::Os;
74b04a01 274 case LLVMRustPassBuilderOptLevel::Oz:
94222f64 275 return OptimizationLevel::Oz;
74b04a01
XL
276 default:
277 report_fatal_error("Bad PassBuilderOptLevel.");
278 }
279}
280
f9f354fc 281enum class LLVMRustRelocModel {
7cac9316
XL
282 Static,
283 PIC,
284 DynamicNoPic,
285 ROPI,
286 RWPI,
287 ROPIRWPI,
288};
289
f9f354fc 290static Reloc::Model fromRust(LLVMRustRelocModel RustReloc) {
7cac9316 291 switch (RustReloc) {
f9f354fc 292 case LLVMRustRelocModel::Static:
7cac9316 293 return Reloc::Static;
f9f354fc 294 case LLVMRustRelocModel::PIC:
7cac9316 295 return Reloc::PIC_;
f9f354fc 296 case LLVMRustRelocModel::DynamicNoPic:
7cac9316 297 return Reloc::DynamicNoPIC;
f9f354fc 298 case LLVMRustRelocModel::ROPI:
7cac9316 299 return Reloc::ROPI;
f9f354fc 300 case LLVMRustRelocModel::RWPI:
7cac9316 301 return Reloc::RWPI;
f9f354fc 302 case LLVMRustRelocModel::ROPIRWPI:
7cac9316 303 return Reloc::ROPI_RWPI;
7cac9316 304 }
ff7c6d11 305 report_fatal_error("Bad RelocModel.");
7cac9316
XL
306}
307
a1dfa0c6 308#ifdef LLVM_RUSTLLVM
5bcae85e 309/// getLongestEntryLength - Return the length of the longest entry in the table.
416331ca
XL
310template<typename KV>
311static size_t getLongestEntryLength(ArrayRef<KV> Table) {
5bcae85e
SL
312 size_t MaxLen = 0;
313 for (auto &I : Table)
314 MaxLen = std::max(MaxLen, std::strlen(I.Key));
315 return MaxLen;
316}
317
32a655c1
SL
318extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM) {
319 const TargetMachine *Target = unwrap(TM);
320 const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo();
ea8adc8c
XL
321 const Triple::ArchType HostArch = Triple(sys::getProcessTriple()).getArch();
322 const Triple::ArchType TargetArch = Target->getTargetTriple().getArch();
416331ca 323 const ArrayRef<SubtargetSubTypeKV> CPUTable = MCInfo->getCPUTable();
32a655c1
SL
324 unsigned MaxCPULen = getLongestEntryLength(CPUTable);
325
326 printf("Available CPUs for this target:\n");
ea8adc8c
XL
327 if (HostArch == TargetArch) {
328 const StringRef HostCPU = sys::getHostCPUName();
329 printf(" %-*s - Select the CPU of the current host (currently %.*s).\n",
330 MaxCPULen, "native", (int)HostCPU.size(), HostCPU.data());
331 }
32a655c1 332 for (auto &CPU : CPUTable)
416331ca 333 printf(" %-*s\n", MaxCPULen, CPU.Key);
32a655c1 334 printf("\n");
5bcae85e
SL
335}
336
cdc7bbd5 337extern "C" size_t LLVMRustGetTargetFeaturesCount(LLVMTargetMachineRef TM) {
32a655c1
SL
338 const TargetMachine *Target = unwrap(TM);
339 const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo();
340 const ArrayRef<SubtargetFeatureKV> FeatTable = MCInfo->getFeatureTable();
cdc7bbd5
XL
341 return FeatTable.size();
342}
32a655c1 343
cdc7bbd5
XL
344extern "C" void LLVMRustGetTargetFeature(LLVMTargetMachineRef TM, size_t Index,
345 const char** Feature, const char** Desc) {
346 const TargetMachine *Target = unwrap(TM);
347 const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo();
348 const ArrayRef<SubtargetFeatureKV> FeatTable = MCInfo->getFeatureTable();
349 const SubtargetFeatureKV Feat = FeatTable[Index];
350 *Feature = Feat.Key;
351 *Desc = Feat.Desc;
5bcae85e
SL
352}
353
354#else
355
32a655c1
SL
356extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef) {
357 printf("Target CPU help is not supported by this LLVM version.\n\n");
5bcae85e
SL
358}
359
cdc7bbd5
XL
360extern "C" size_t LLVMRustGetTargetFeaturesCount(LLVMTargetMachineRef) {
361 return 0;
5bcae85e 362}
cdc7bbd5
XL
363
364extern "C" void LLVMRustGetTargetFeature(LLVMTargetMachineRef, const char**, const char**) {}
5bcae85e
SL
365#endif
366
b7449926
XL
367extern "C" const char* LLVMRustGetHostCPUName(size_t *len) {
368 StringRef Name = sys::getHostCPUName();
369 *len = Name.size();
370 return Name.data();
371}
372
32a655c1
SL
373extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
374 const char *TripleStr, const char *CPU, const char *Feature,
f9f354fc 375 const char *ABIStr, LLVMRustCodeModel RustCM, LLVMRustRelocModel RustReloc,
32a655c1 376 LLVMRustCodeGenOptLevel RustOptLevel, bool UseSoftFloat,
f9f354fc 377 bool FunctionSections,
abe05a73 378 bool DataSections,
3c0e092e 379 bool UniqueSectionNames,
abe05a73 380 bool TrapUnreachable,
b7449926 381 bool Singlethread,
0bf4aa26 382 bool AsmComments,
60c5eb7d 383 bool EmitStackSizeSection,
f9f354fc 384 bool RelaxELFRelocations,
fc512014
XL
385 bool UseInitArray,
386 const char *SplitDwarfFile) {
5bcae85e 387
32a655c1 388 auto OptLevel = fromRust(RustOptLevel);
7cac9316 389 auto RM = fromRust(RustReloc);
f9f354fc 390 auto CM = fromRust(RustCM);
5bcae85e 391
32a655c1
SL
392 std::string Error;
393 Triple Trip(Triple::normalize(TripleStr));
394 const llvm::Target *TheTarget =
395 TargetRegistry::lookupTarget(Trip.getTriple(), Error);
396 if (TheTarget == nullptr) {
397 LLVMRustSetLastError(Error.c_str());
398 return nullptr;
399 }
1a4d82fc 400
32a655c1 401 TargetOptions Options;
5bcae85e 402
32a655c1
SL
403 Options.FloatABIType = FloatABI::Default;
404 if (UseSoftFloat) {
405 Options.FloatABIType = FloatABI::Soft;
406 }
407 Options.DataSections = DataSections;
408 Options.FunctionSections = FunctionSections;
3c0e092e 409 Options.UniqueSectionNames = UniqueSectionNames;
b7449926
XL
410 Options.MCOptions.AsmVerbose = AsmComments;
411 Options.MCOptions.PreserveAsmComments = AsmComments;
60c5eb7d 412 Options.MCOptions.ABIName = ABIStr;
fc512014
XL
413 if (SplitDwarfFile) {
414 Options.MCOptions.SplitDwarfFile = SplitDwarfFile;
415 }
60c5eb7d 416 Options.RelaxELFRelocations = RelaxELFRelocations;
f9f354fc 417 Options.UseInitArray = UseInitArray;
32a655c1 418
abe05a73 419 if (TrapUnreachable) {
94b46f34 420 // Tell LLVM to codegen `unreachable` into an explicit trap instruction.
abe05a73
XL
421 // This limits the extent of possible undefined behavior in some cases, as
422 // it prevents control flow from "falling through" into whatever code
423 // happens to be laid out next in memory.
424 Options.TrapUnreachable = true;
425 }
426
427 if (Singlethread) {
428 Options.ThreadModel = ThreadModel::Single;
429 }
430
0bf4aa26
XL
431 Options.EmitStackSizeSection = EmitStackSizeSection;
432
32a655c1 433 TargetMachine *TM = TheTarget->createTargetMachine(
b7449926 434 Trip.getTriple(), CPU, Feature, Options, RM, CM, OptLevel);
32a655c1 435 return wrap(TM);
1a4d82fc
JJ
436}
437
32a655c1
SL
438extern "C" void LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) {
439 delete unwrap(TM);
1a4d82fc
JJ
440}
441
1a4d82fc
JJ
442// Unfortunately, the LLVM C API doesn't provide a way to create the
443// TargetLibraryInfo pass, so we use this method to do so.
32a655c1
SL
444extern "C" void LLVMRustAddLibraryInfo(LLVMPassManagerRef PMR, LLVMModuleRef M,
445 bool DisableSimplifyLibCalls) {
446 Triple TargetTriple(unwrap(M)->getTargetTriple());
447 TargetLibraryInfoImpl TLII(TargetTriple);
448 if (DisableSimplifyLibCalls)
449 TLII.disableAllFunctions();
450 unwrap(PMR)->add(new TargetLibraryInfoWrapperPass(TLII));
1a4d82fc
JJ
451}
452
32a655c1
SL
453extern "C" void LLVMRustSetLLVMOptions(int Argc, char **Argv) {
454 // Initializing the command-line options more than once is not allowed. So,
455 // check if they've already been initialized. (This could happen if we're
456 // being called from rustpkg, for example). If the arguments change, then
457 // that's just kinda unfortunate.
458 static bool Initialized = false;
459 if (Initialized)
460 return;
461 Initialized = true;
462 cl::ParseCommandLineOptions(Argc, Argv);
1a4d82fc
JJ
463}
464
5bcae85e 465enum class LLVMRustFileType {
32a655c1
SL
466 AssemblyFile,
467 ObjectFile,
5bcae85e
SL
468};
469
dfeec247
XL
470static CodeGenFileType fromRust(LLVMRustFileType Type) {
471 switch (Type) {
472 case LLVMRustFileType::AssemblyFile:
473 return CGFT_AssemblyFile;
474 case LLVMRustFileType::ObjectFile:
475 return CGFT_ObjectFile;
476 default:
477 report_fatal_error("Bad FileType.");
478 }
479}
5bcae85e
SL
480
481extern "C" LLVMRustResult
32a655c1 482LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR,
fc512014 483 LLVMModuleRef M, const char *Path, const char *DwoPath,
32a655c1 484 LLVMRustFileType RustFileType) {
5bcae85e 485 llvm::legacy::PassManager *PM = unwrap<llvm::legacy::PassManager>(PMR);
32a655c1 486 auto FileType = fromRust(RustFileType);
1a4d82fc
JJ
487
488 std::string ErrorInfo;
1a4d82fc 489 std::error_code EC;
17df50a5 490 raw_fd_ostream OS(Path, EC, sys::fs::OF_None);
1a4d82fc
JJ
491 if (EC)
492 ErrorInfo = EC.message();
1a4d82fc
JJ
493 if (ErrorInfo != "") {
494 LLVMRustSetLastError(ErrorInfo.c_str());
5bcae85e 495 return LLVMRustResult::Failure;
1a4d82fc 496 }
1a4d82fc 497
b7449926 498 buffer_ostream BOS(OS);
fc512014 499 if (DwoPath) {
17df50a5 500 raw_fd_ostream DOS(DwoPath, EC, sys::fs::OF_None);
fc512014
XL
501 EC.clear();
502 if (EC)
503 ErrorInfo = EC.message();
504 if (ErrorInfo != "") {
505 LLVMRustSetLastError(ErrorInfo.c_str());
506 return LLVMRustResult::Failure;
507 }
508 buffer_ostream DBOS(DOS);
509 unwrap(Target)->addPassesToEmitFile(*PM, BOS, &DBOS, FileType, false);
510 PM->run(*unwrap(M));
511 } else {
512 unwrap(Target)->addPassesToEmitFile(*PM, BOS, nullptr, FileType, false);
513 PM->run(*unwrap(M));
514 }
62682a34 515
b039eaaf 516 // Apparently `addPassesToEmitFile` adds a pointer to our on-the-stack output
62682a34
SL
517 // stream (OS), so the only real safe place to delete this is here? Don't we
518 // wish this was written in Rust?
60c5eb7d 519 LLVMDisposePassManager(PMR);
5bcae85e 520 return LLVMRustResult::Success;
1a4d82fc
JJ
521}
522
74b04a01
XL
523extern "C" typedef void (*LLVMRustSelfProfileBeforePassCallback)(void*, // LlvmSelfProfiler
524 const char*, // pass name
525 const char*); // IR name
526extern "C" typedef void (*LLVMRustSelfProfileAfterPassCallback)(void*); // LlvmSelfProfiler
527
74b04a01
XL
528std::string LLVMRustwrappedIrGetName(const llvm::Any &WrappedIr) {
529 if (any_isa<const Module *>(WrappedIr))
530 return any_cast<const Module *>(WrappedIr)->getName().str();
531 if (any_isa<const Function *>(WrappedIr))
532 return any_cast<const Function *>(WrappedIr)->getName().str();
533 if (any_isa<const Loop *>(WrappedIr))
534 return any_cast<const Loop *>(WrappedIr)->getName().str();
535 if (any_isa<const LazyCallGraph::SCC *>(WrappedIr))
536 return any_cast<const LazyCallGraph::SCC *>(WrappedIr)->getName();
537 return "<UNKNOWN>";
538}
539
540
541void LLVMSelfProfileInitializeCallbacks(
542 PassInstrumentationCallbacks& PIC, void* LlvmSelfProfiler,
543 LLVMRustSelfProfileBeforePassCallback BeforePassCallback,
544 LLVMRustSelfProfileAfterPassCallback AfterPassCallback) {
6a06907d
XL
545 PIC.registerBeforeNonSkippedPassCallback([LlvmSelfProfiler, BeforePassCallback](
546 StringRef Pass, llvm::Any Ir) {
547 std::string PassName = Pass.str();
548 std::string IrName = LLVMRustwrappedIrGetName(Ir);
549 BeforePassCallback(LlvmSelfProfiler, PassName.c_str(), IrName.c_str());
550 });
551
552 PIC.registerAfterPassCallback(
553 [LlvmSelfProfiler, AfterPassCallback](StringRef Pass, llvm::Any IR,
554 const PreservedAnalyses &Preserved) {
555 AfterPassCallback(LlvmSelfProfiler);
556 });
557
558 PIC.registerAfterPassInvalidatedCallback(
559 [LlvmSelfProfiler, AfterPassCallback](StringRef Pass, const PreservedAnalyses &Preserved) {
560 AfterPassCallback(LlvmSelfProfiler);
561 });
74b04a01
XL
562
563 PIC.registerBeforeAnalysisCallback([LlvmSelfProfiler, BeforePassCallback](
564 StringRef Pass, llvm::Any Ir) {
565 std::string PassName = Pass.str();
566 std::string IrName = LLVMRustwrappedIrGetName(Ir);
567 BeforePassCallback(LlvmSelfProfiler, PassName.c_str(), IrName.c_str());
568 });
569
570 PIC.registerAfterAnalysisCallback(
571 [LlvmSelfProfiler, AfterPassCallback](StringRef Pass, llvm::Any Ir) {
572 AfterPassCallback(LlvmSelfProfiler);
573 });
574}
74b04a01
XL
575
576enum class LLVMRustOptStage {
577 PreLinkNoLTO,
578 PreLinkThinLTO,
579 PreLinkFatLTO,
580 ThinLTO,
581 FatLTO,
582};
583
584struct LLVMRustSanitizerOptions {
f035d41b
XL
585 bool SanitizeAddress;
586 bool SanitizeAddressRecover;
74b04a01 587 bool SanitizeMemory;
f035d41b
XL
588 bool SanitizeMemoryRecover;
589 int SanitizeMemoryTrackOrigins;
74b04a01 590 bool SanitizeThread;
6a06907d
XL
591 bool SanitizeHWAddress;
592 bool SanitizeHWAddressRecover;
74b04a01
XL
593};
594
17df50a5 595extern "C" LLVMRustResult
2b03887a 596LLVMRustOptimize(
74b04a01
XL
597 LLVMModuleRef ModuleRef,
598 LLVMTargetMachineRef TMRef,
599 LLVMRustPassBuilderOptLevel OptLevelRust,
600 LLVMRustOptStage OptStage,
601 bool NoPrepopulatePasses, bool VerifyIR, bool UseThinLTOBuffers,
602 bool MergeFunctions, bool UnrollLoops, bool SLPVectorize, bool LoopVectorize,
f9f354fc 603 bool DisableSimplifyLibCalls, bool EmitLifetimeMarkers,
74b04a01
XL
604 LLVMRustSanitizerOptions *SanitizerOptions,
605 const char *PGOGenPath, const char *PGOUsePath,
f2b60f7d
FG
606 bool InstrumentCoverage, const char *InstrProfileOutput,
607 bool InstrumentGCOV,
c295e0f8 608 const char *PGOSampleUsePath, bool DebugInfoForProfiling,
74b04a01
XL
609 void* LlvmSelfProfiler,
610 LLVMRustSelfProfileBeforePassCallback BeforePassCallback,
17df50a5 611 LLVMRustSelfProfileAfterPassCallback AfterPassCallback,
a2a8927a
XL
612 const char *ExtraPasses, size_t ExtraPassesLen,
613 const char *LLVMPlugins, size_t LLVMPluginsLen) {
74b04a01
XL
614 Module *TheModule = unwrap(ModuleRef);
615 TargetMachine *TM = unwrap(TMRef);
94222f64 616 OptimizationLevel OptLevel = fromRust(OptLevelRust);
74b04a01 617
74b04a01
XL
618
619 PipelineTuningOptions PTO;
620 PTO.LoopUnrolling = UnrollLoops;
621 PTO.LoopInterleaving = UnrollLoops;
622 PTO.LoopVectorization = LoopVectorize;
623 PTO.SLPVectorization = SLPVectorize;
6a06907d 624 PTO.MergeFunctions = MergeFunctions;
6a06907d
XL
625
626 // FIXME: We may want to expose this as an option.
627 bool DebugPassManager = false;
74b04a01
XL
628
629 PassInstrumentationCallbacks PIC;
6a06907d 630 StandardInstrumentations SI(DebugPassManager);
74b04a01
XL
631 SI.registerCallbacks(PIC);
632
633 if (LlvmSelfProfiler){
634 LLVMSelfProfileInitializeCallbacks(PIC,LlvmSelfProfiler,BeforePassCallback,AfterPassCallback);
635 }
636
637 Optional<PGOOptions> PGOOpt;
638 if (PGOGenPath) {
c295e0f8
XL
639 assert(!PGOUsePath && !PGOSampleUsePath);
640 PGOOpt = PGOOptions(PGOGenPath, "", "", PGOOptions::IRInstr,
641 PGOOptions::NoCSAction, DebugInfoForProfiling);
74b04a01 642 } else if (PGOUsePath) {
c295e0f8
XL
643 assert(!PGOSampleUsePath);
644 PGOOpt = PGOOptions(PGOUsePath, "", "", PGOOptions::IRUse,
645 PGOOptions::NoCSAction, DebugInfoForProfiling);
646 } else if (PGOSampleUsePath) {
647 PGOOpt = PGOOptions(PGOSampleUsePath, "", "", PGOOptions::SampleUse,
648 PGOOptions::NoCSAction, DebugInfoForProfiling);
649 } else if (DebugInfoForProfiling) {
650 PGOOpt = PGOOptions("", "", "", PGOOptions::NoAction,
651 PGOOptions::NoCSAction, DebugInfoForProfiling);
74b04a01
XL
652 }
653
3c0e092e 654 PassBuilder PB(TM, PTO, PGOOpt, &PIC);
17df50a5
XL
655 LoopAnalysisManager LAM;
656 FunctionAnalysisManager FAM;
657 CGSCCAnalysisManager CGAM;
658 ModuleAnalysisManager MAM;
74b04a01
XL
659
660 FAM.registerPass([&] { return PB.buildDefaultAAPipeline(); });
661
662 Triple TargetTriple(TheModule->getTargetTriple());
663 std::unique_ptr<TargetLibraryInfoImpl> TLII(new TargetLibraryInfoImpl(TargetTriple));
664 if (DisableSimplifyLibCalls)
665 TLII->disableAllFunctions();
666 FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); });
667
668 PB.registerModuleAnalyses(MAM);
669 PB.registerCGSCCAnalyses(CGAM);
670 PB.registerFunctionAnalyses(FAM);
671 PB.registerLoopAnalyses(LAM);
672 PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
673
674 // We manually collect pipeline callbacks so we can apply them at O0, where the
675 // PassBuilder does not create a pipeline.
94222f64 676 std::vector<std::function<void(ModulePassManager &, OptimizationLevel)>>
6a06907d 677 PipelineStartEPCallbacks;
94222f64 678 std::vector<std::function<void(ModulePassManager &, OptimizationLevel)>>
f035d41b 679 OptimizerLastEPCallbacks;
74b04a01
XL
680
681 if (VerifyIR) {
6a06907d 682 PipelineStartEPCallbacks.push_back(
94222f64 683 [VerifyIR](ModulePassManager &MPM, OptimizationLevel Level) {
74b04a01 684 MPM.addPass(VerifierPass());
6a06907d
XL
685 }
686 );
74b04a01
XL
687 }
688
17df50a5
XL
689 if (InstrumentGCOV) {
690 PipelineStartEPCallbacks.push_back(
94222f64 691 [](ModulePassManager &MPM, OptimizationLevel Level) {
17df50a5
XL
692 MPM.addPass(GCOVProfilerPass(GCOVOptions::getDefault()));
693 }
694 );
695 }
696
697 if (InstrumentCoverage) {
698 PipelineStartEPCallbacks.push_back(
f2b60f7d 699 [InstrProfileOutput](ModulePassManager &MPM, OptimizationLevel Level) {
17df50a5 700 InstrProfOptions Options;
f2b60f7d
FG
701 if (InstrProfileOutput) {
702 Options.InstrProfileOutput = InstrProfileOutput;
703 }
17df50a5
XL
704 MPM.addPass(InstrProfiling(Options, false));
705 }
706 );
707 }
708
74b04a01
XL
709 if (SanitizerOptions) {
710 if (SanitizerOptions->SanitizeMemory) {
f2b60f7d
FG
711#if LLVM_VERSION_GE(14, 0)
712 MemorySanitizerOptions Options(
713 SanitizerOptions->SanitizeMemoryTrackOrigins,
714 SanitizerOptions->SanitizeMemoryRecover,
715 /*CompileKernel=*/false,
716 /*EagerChecks=*/true);
717#else
74b04a01
XL
718 MemorySanitizerOptions Options(
719 SanitizerOptions->SanitizeMemoryTrackOrigins,
f035d41b 720 SanitizerOptions->SanitizeMemoryRecover,
74b04a01 721 /*CompileKernel=*/false);
f2b60f7d 722#endif
f035d41b 723 OptimizerLastEPCallbacks.push_back(
94222f64 724 [Options](ModulePassManager &MPM, OptimizationLevel Level) {
f2b60f7d 725#if LLVM_VERSION_GE(14, 0) && LLVM_VERSION_LT(16, 0)
c295e0f8
XL
726 MPM.addPass(ModuleMemorySanitizerPass(Options));
727#else
f035d41b 728 MPM.addPass(MemorySanitizerPass(Options));
c295e0f8 729#endif
f2b60f7d 730#if LLVM_VERSION_LT(16, 0)
f035d41b 731 MPM.addPass(createModuleToFunctionPassAdaptor(MemorySanitizerPass(Options)));
f2b60f7d 732#endif
f035d41b
XL
733 }
734 );
74b04a01
XL
735 }
736
737 if (SanitizerOptions->SanitizeThread) {
f035d41b 738 OptimizerLastEPCallbacks.push_back(
94222f64 739 [](ModulePassManager &MPM, OptimizationLevel Level) {
c295e0f8
XL
740#if LLVM_VERSION_GE(14, 0)
741 MPM.addPass(ModuleThreadSanitizerPass());
742#else
f035d41b 743 MPM.addPass(ThreadSanitizerPass());
c295e0f8 744#endif
f035d41b
XL
745 MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass()));
746 }
747 );
74b04a01
XL
748 }
749
750 if (SanitizerOptions->SanitizeAddress) {
f035d41b 751 OptimizerLastEPCallbacks.push_back(
94222f64 752 [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
064997fb 753#if LLVM_VERSION_LT(15, 0)
f035d41b 754 MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
064997fb 755#endif
94222f64 756#if LLVM_VERSION_GE(14, 0)
3c0e092e
XL
757 AddressSanitizerOptions opts = AddressSanitizerOptions{
758 /*CompileKernel=*/false,
759 SanitizerOptions->SanitizeAddressRecover,
760 /*UseAfterScope=*/true,
761 AsanDetectStackUseAfterReturnMode::Runtime,
762 };
f2b60f7d 763#if LLVM_VERSION_LT(16, 0)
3c0e092e 764 MPM.addPass(ModuleAddressSanitizerPass(opts));
f2b60f7d
FG
765#else
766 MPM.addPass(AddressSanitizerPass(opts));
767#endif
94222f64 768#else
3c0e092e
XL
769 MPM.addPass(ModuleAddressSanitizerPass(
770 /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
f035d41b
XL
771 MPM.addPass(createModuleToFunctionPassAdaptor(AddressSanitizerPass(
772 /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover,
773 /*UseAfterScope=*/true)));
94222f64 774#endif
f035d41b
XL
775 }
776 );
6a06907d
XL
777 }
778 if (SanitizerOptions->SanitizeHWAddress) {
6a06907d 779 OptimizerLastEPCallbacks.push_back(
94222f64
XL
780 [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
781#if LLVM_VERSION_GE(14, 0)
782 HWAddressSanitizerOptions opts(
783 /*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover,
784 /*DisableOptimization=*/false);
785 MPM.addPass(HWAddressSanitizerPass(opts));
786#else
6a06907d
XL
787 MPM.addPass(HWAddressSanitizerPass(
788 /*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover));
94222f64 789#endif
6a06907d
XL
790 }
791 );
74b04a01
XL
792 }
793 }
794
a2a8927a
XL
795 if (LLVMPluginsLen) {
796 auto PluginsStr = StringRef(LLVMPlugins, LLVMPluginsLen);
797 SmallVector<StringRef> Plugins;
798 PluginsStr.split(Plugins, ',', -1, false);
799 for (auto PluginPath: Plugins) {
800 auto Plugin = PassPlugin::Load(PluginPath.str());
801 if (!Plugin) {
802 LLVMRustSetLastError(("Failed to load pass plugin" + PluginPath.str()).c_str());
803 continue;
804 }
805 Plugin->registerPassBuilderCallbacks(PB);
806 }
807 }
808
17df50a5 809 ModulePassManager MPM;
6a06907d 810 bool NeedThinLTOBufferPasses = UseThinLTOBuffers;
74b04a01 811 if (!NoPrepopulatePasses) {
c295e0f8
XL
812 // The pre-link pipelines don't support O0 and require using budilO0DefaultPipeline() instead.
813 // At the same time, the LTO pipelines do support O0 and using them is required.
814 bool IsLTO = OptStage == LLVMRustOptStage::ThinLTO || OptStage == LLVMRustOptStage::FatLTO;
815 if (OptLevel == OptimizationLevel::O0 && !IsLTO) {
74b04a01 816 for (const auto &C : PipelineStartEPCallbacks)
6a06907d
XL
817 PB.registerPipelineStartEPCallback(C);
818 for (const auto &C : OptimizerLastEPCallbacks)
819 PB.registerOptimizerLastEPCallback(C);
74b04a01 820
6a06907d
XL
821 // Pass false as we manually schedule ThinLTOBufferPasses below.
822 MPM = PB.buildO0DefaultPipeline(OptLevel, /* PreLinkLTO */ false);
74b04a01
XL
823 } else {
824 for (const auto &C : PipelineStartEPCallbacks)
825 PB.registerPipelineStartEPCallback(C);
826 if (OptStage != LLVMRustOptStage::PreLinkThinLTO) {
827 for (const auto &C : OptimizerLastEPCallbacks)
828 PB.registerOptimizerLastEPCallback(C);
829 }
830
831 switch (OptStage) {
832 case LLVMRustOptStage::PreLinkNoLTO:
833 MPM = PB.buildPerModuleDefaultPipeline(OptLevel, DebugPassManager);
834 break;
835 case LLVMRustOptStage::PreLinkThinLTO:
6a06907d
XL
836 MPM = PB.buildThinLTOPreLinkDefaultPipeline(OptLevel);
837 // The ThinLTOPreLink pipeline already includes ThinLTOBuffer passes. However, callback
838 // passes may still run afterwards. This means we need to run the buffer passes again.
839 // FIXME: In LLVM 13, the ThinLTOPreLink pipeline also runs OptimizerLastEPCallbacks
840 // before the RequiredLTOPreLinkPasses, in which case we can remove these hacks.
841 if (OptimizerLastEPCallbacks.empty())
842 NeedThinLTOBufferPasses = false;
f035d41b
XL
843 for (const auto &C : OptimizerLastEPCallbacks)
844 C(MPM, OptLevel);
74b04a01
XL
845 break;
846 case LLVMRustOptStage::PreLinkFatLTO:
6a06907d
XL
847 MPM = PB.buildLTOPreLinkDefaultPipeline(OptLevel);
848 NeedThinLTOBufferPasses = false;
74b04a01
XL
849 break;
850 case LLVMRustOptStage::ThinLTO:
851 // FIXME: Does it make sense to pass the ModuleSummaryIndex?
852 // It only seems to be needed for C++ specific optimizations.
6a06907d 853 MPM = PB.buildThinLTODefaultPipeline(OptLevel, nullptr);
74b04a01
XL
854 break;
855 case LLVMRustOptStage::FatLTO:
6a06907d 856 MPM = PB.buildLTODefaultPipeline(OptLevel, nullptr);
74b04a01
XL
857 break;
858 }
859 }
04454e1e
FG
860 } else {
861 // We're not building any of the default pipelines but we still want to
862 // add the verifier, instrumentation, etc passes if they were requested
863 for (const auto &C : PipelineStartEPCallbacks)
864 C(MPM, OptLevel);
865 for (const auto &C : OptimizerLastEPCallbacks)
866 C(MPM, OptLevel);
74b04a01
XL
867 }
868
17df50a5
XL
869 if (ExtraPassesLen) {
870 if (auto Err = PB.parsePassPipeline(MPM, StringRef(ExtraPasses, ExtraPassesLen))) {
871 std::string ErrMsg = toString(std::move(Err));
872 LLVMRustSetLastError(ErrMsg.c_str());
873 return LLVMRustResult::Failure;
874 }
875 }
876
6a06907d 877 if (NeedThinLTOBufferPasses) {
74b04a01
XL
878 MPM.addPass(CanonicalizeAliasesPass());
879 MPM.addPass(NameAnonGlobalPass());
880 }
881
882 // Upgrade all calls to old intrinsics first.
883 for (Module::iterator I = TheModule->begin(), E = TheModule->end(); I != E;)
884 UpgradeCallsToIntrinsic(&*I++); // must be post-increment, as we remove
885
886 MPM.run(*TheModule, MAM);
17df50a5 887 return LLVMRustResult::Success;
74b04a01 888}
041b39d2
XL
889
890// Callback to demangle function name
891// Parameters:
892// * name to be demangled
893// * name len
894// * output buffer
895// * output buffer len
896// Returns len of demangled string, or 0 if demangle failed.
897typedef size_t (*DemangleFn)(const char*, size_t, char*, size_t);
898
899
900namespace {
901
902class RustAssemblyAnnotationWriter : public AssemblyAnnotationWriter {
903 DemangleFn Demangle;
904 std::vector<char> Buf;
905
906public:
907 RustAssemblyAnnotationWriter(DemangleFn Demangle) : Demangle(Demangle) {}
908
909 // Return empty string if demangle failed
910 // or if name does not need to be demangled
911 StringRef CallDemangle(StringRef name) {
912 if (!Demangle) {
913 return StringRef();
914 }
915
916 if (Buf.size() < name.size() * 2) {
917 // Semangled name usually shorter than mangled,
918 // but allocate twice as much memory just in case
919 Buf.resize(name.size() * 2);
920 }
921
922 auto R = Demangle(name.data(), name.size(), Buf.data(), Buf.size());
923 if (!R) {
924 // Demangle failed.
925 return StringRef();
926 }
927
928 auto Demangled = StringRef(Buf.data(), R);
929 if (Demangled == name) {
930 // Do not print anything if demangled name is equal to mangled.
931 return StringRef();
932 }
933
934 return Demangled;
935 }
936
937 void emitFunctionAnnot(const Function *F,
938 formatted_raw_ostream &OS) override {
939 StringRef Demangled = CallDemangle(F->getName());
940 if (Demangled.empty()) {
941 return;
942 }
943
944 OS << "; " << Demangled << "\n";
945 }
946
947 void emitInstructionAnnot(const Instruction *I,
948 formatted_raw_ostream &OS) override {
949 const char *Name;
950 const Value *Value;
951 if (const CallInst *CI = dyn_cast<CallInst>(I)) {
952 Name = "call";
f035d41b 953 Value = CI->getCalledOperand();
041b39d2
XL
954 } else if (const InvokeInst* II = dyn_cast<InvokeInst>(I)) {
955 Name = "invoke";
f035d41b 956 Value = II->getCalledOperand();
041b39d2
XL
957 } else {
958 // Could demangle more operations, e. g.
959 // `store %place, @function`.
960 return;
961 }
962
963 if (!Value->hasName()) {
964 return;
965 }
966
967 StringRef Demangled = CallDemangle(Value->getName());
968 if (Demangled.empty()) {
969 return;
970 }
971
972 OS << "; " << Name << " " << Demangled << "\n";
973 }
974};
975
041b39d2
XL
976} // namespace
977
532ac7d7 978extern "C" LLVMRustResult
60c5eb7d 979LLVMRustPrintModule(LLVMModuleRef M, const char *Path, DemangleFn Demangle) {
1a4d82fc 980 std::string ErrorInfo;
1a4d82fc 981 std::error_code EC;
17df50a5 982 raw_fd_ostream OS(Path, EC, sys::fs::OF_None);
1a4d82fc
JJ
983 if (EC)
984 ErrorInfo = EC.message();
532ac7d7
XL
985 if (ErrorInfo != "") {
986 LLVMRustSetLastError(ErrorInfo.c_str());
987 return LLVMRustResult::Failure;
988 }
1a4d82fc 989
60c5eb7d 990 RustAssemblyAnnotationWriter AAW(Demangle);
1a4d82fc 991 formatted_raw_ostream FOS(OS);
60c5eb7d 992 unwrap(M)->print(FOS, &AAW);
532ac7d7
XL
993
994 return LLVMRustResult::Success;
1a4d82fc
JJ
995}
996
32a655c1
SL
997extern "C" void LLVMRustPrintPasses() {
998 LLVMInitializePasses();
999 struct MyListener : PassRegistrationListener {
1000 void passEnumerate(const PassInfo *Info) {
32a655c1
SL
1001 StringRef PassArg = Info->getPassArgument();
1002 StringRef PassName = Info->getPassName();
1003 if (!PassArg.empty()) {
1004 // These unsigned->signed casts could theoretically overflow, but
1005 // realistically never will (and even if, the result is implementation
1006 // defined rather plain UB).
1007 printf("%15.*s - %.*s\n", (int)PassArg.size(), PassArg.data(),
1008 (int)PassName.size(), PassName.data());
1009 }
32a655c1
SL
1010 }
1011 } Listener;
1a4d82fc 1012
32a655c1
SL
1013 PassRegistry *PR = PassRegistry::getPassRegistry();
1014 PR->enumerateWith(&Listener);
970d7e83
LB
1015}
1016
32a655c1
SL
1017extern "C" void LLVMRustRunRestrictionPass(LLVMModuleRef M, char **Symbols,
1018 size_t Len) {
32a655c1
SL
1019 auto PreserveFunctions = [=](const GlobalValue &GV) {
1020 for (size_t I = 0; I < Len; I++) {
1021 if (GV.getName() == Symbols[I]) {
1022 return true;
1023 }
1024 }
1025 return false;
1026 };
5bcae85e 1027
2b03887a 1028 internalizeModule(*unwrap(M), PreserveFunctions);
1a4d82fc
JJ
1029}
1030
c1a9b12d
SL
1031extern "C" void
1032LLVMRustSetDataLayoutFromTargetMachine(LLVMModuleRef Module,
1033 LLVMTargetMachineRef TMR) {
32a655c1
SL
1034 TargetMachine *Target = unwrap(TMR);
1035 unwrap(Module)->setDataLayout(Target->createDataLayout());
c1a9b12d
SL
1036}
1037
60c5eb7d
XL
1038extern "C" void LLVMRustSetModulePICLevel(LLVMModuleRef M) {
1039 unwrap(M)->setPICLevel(PICLevel::Level::BigPIC);
1040}
1041
32a655c1 1042extern "C" void LLVMRustSetModulePIELevel(LLVMModuleRef M) {
32a655c1 1043 unwrap(M)->setPIELevel(PIELevel::Level::Large);
5bcae85e 1044}
ea8adc8c 1045
6a06907d
XL
1046extern "C" void LLVMRustSetModuleCodeModel(LLVMModuleRef M,
1047 LLVMRustCodeModel Model) {
1048 auto CM = fromRust(Model);
2b03887a 1049 if (!CM)
6a06907d
XL
1050 return;
1051 unwrap(M)->setCodeModel(*CM);
1052}
1053
ea8adc8c
XL
1054// Here you'll find an implementation of ThinLTO as used by the Rust compiler
1055// right now. This ThinLTO support is only enabled on "recent ish" versions of
1056// LLVM, and otherwise it's just blanket rejected from other compilers.
1057//
1058// Most of this implementation is straight copied from LLVM. At the time of
1059// this writing it wasn't *quite* suitable to reuse more code from upstream
1060// for our purposes, but we should strive to upstream this support once it's
1061// ready to go! I figure we may want a bit of testing locally first before
1062// sending this upstream to LLVM. I hear though they're quite eager to receive
1063// feedback like this!
1064//
1065// If you're reading this code and wondering "what in the world" or you're
1066// working "good lord by LLVM upgrade is *still* failing due to these bindings"
1067// then fear not! (ok maybe fear a little). All code here is mostly based
1068// on `lib/LTO/ThinLTOCodeGenerator.cpp` in LLVM.
1069//
1070// You'll find that the general layout here roughly corresponds to the `run`
1071// method in that file as well as `ProcessThinLTOModule`. Functions are
1072// specifically commented below as well, but if you're updating this code
1073// or otherwise trying to understand it, the LLVM source will be useful in
1074// interpreting the mysteries within.
1075//
1076// Otherwise I'll apologize in advance, it probably requires a relatively
1077// significant investment on your part to "truly understand" what's going on
1078// here. Not saying I do myself, but it took me awhile staring at LLVM's source
1079// and various online resources about ThinLTO to make heads or tails of all
1080// this.
1081
ea8adc8c
XL
1082// This is a shared data structure which *must* be threadsafe to share
1083// read-only amongst threads. This also corresponds basically to the arguments
1084// of the `ProcessThinLTOModule` function in the LLVM source.
1085struct LLVMRustThinLTOData {
1086 // The combined index that is the global analysis over all modules we're
1087 // performing ThinLTO for. This is mostly managed by LLVM.
1088 ModuleSummaryIndex Index;
1089
1090 // All modules we may look at, stored as in-memory serialized versions. This
1091 // is later used when inlining to ensure we can extract any module to inline
1092 // from.
1093 StringMap<MemoryBufferRef> ModuleMap;
1094
1095 // A set that we manage of everything we *don't* want internalized. Note that
1096 // this includes all transitive references right now as well, but it may not
1097 // always!
1098 DenseSet<GlobalValue::GUID> GUIDPreservedSymbols;
1099
1100 // Not 100% sure what these are, but they impact what's internalized and
1101 // what's inlined across modules, I believe.
1102 StringMap<FunctionImporter::ImportMapTy> ImportLists;
1103 StringMap<FunctionImporter::ExportSetTy> ExportLists;
1104 StringMap<GVSummaryMapTy> ModuleToDefinedGVSummaries;
29967ef6 1105 StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
2c00a5a8 1106
9fa01778 1107 LLVMRustThinLTOData() : Index(/* HaveGVs = */ false) {}
ea8adc8c
XL
1108};
1109
1110// Just an argument to the `LLVMRustCreateThinLTOData` function below.
1111struct LLVMRustThinLTOModule {
1112 const char *identifier;
1113 const char *data;
1114 size_t len;
1115};
1116
1117// This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp`, not sure what it
1118// does.
1119static const GlobalValueSummary *
1120getFirstDefinitionForLinker(const GlobalValueSummaryList &GVSummaryList) {
1121 auto StrongDefForLinker = llvm::find_if(
1122 GVSummaryList, [](const std::unique_ptr<GlobalValueSummary> &Summary) {
1123 auto Linkage = Summary->linkage();
1124 return !GlobalValue::isAvailableExternallyLinkage(Linkage) &&
1125 !GlobalValue::isWeakForLinker(Linkage);
1126 });
1127 if (StrongDefForLinker != GVSummaryList.end())
1128 return StrongDefForLinker->get();
1129
1130 auto FirstDefForLinker = llvm::find_if(
1131 GVSummaryList, [](const std::unique_ptr<GlobalValueSummary> &Summary) {
1132 auto Linkage = Summary->linkage();
1133 return !GlobalValue::isAvailableExternallyLinkage(Linkage);
1134 });
1135 if (FirstDefForLinker == GVSummaryList.end())
1136 return nullptr;
1137 return FirstDefForLinker->get();
1138}
1139
ea8adc8c
XL
1140// The main entry point for creating the global ThinLTO analysis. The structure
1141// here is basically the same as before threads are spawned in the `run`
1142// function of `lib/LTO/ThinLTOCodeGenerator.cpp`.
1143extern "C" LLVMRustThinLTOData*
1144LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules,
1145 int num_modules,
1146 const char **preserved_symbols,
1147 int num_symbols) {
dfeec247 1148 auto Ret = std::make_unique<LLVMRustThinLTOData>();
ea8adc8c
XL
1149
1150 // Load each module's summary and merge it into one combined index
1151 for (int i = 0; i < num_modules; i++) {
1152 auto module = &modules[i];
1153 StringRef buffer(module->data, module->len);
1154 MemoryBufferRef mem_buffer(buffer, module->identifier);
1155
1156 Ret->ModuleMap[module->identifier] = mem_buffer;
1157
abe05a73
XL
1158 if (Error Err = readModuleSummaryIndex(mem_buffer, Ret->Index, i)) {
1159 LLVMRustSetLastError(toString(std::move(Err)).c_str());
1160 return nullptr;
1161 }
ea8adc8c
XL
1162 }
1163
1164 // Collect for each module the list of function it defines (GUID -> Summary)
1165 Ret->Index.collectDefinedGVSummariesPerModule(Ret->ModuleToDefinedGVSummaries);
1166
1167 // Convert the preserved symbols set from string to GUID, this is then needed
ff7c6d11 1168 // for internalization.
ea8adc8c 1169 for (int i = 0; i < num_symbols; i++) {
ff7c6d11
XL
1170 auto GUID = GlobalValue::getGUID(preserved_symbols[i]);
1171 Ret->GUIDPreservedSymbols.insert(GUID);
ea8adc8c
XL
1172 }
1173
1174 // Collect the import/export lists for all modules from the call-graph in the
1175 // combined index
1176 //
1177 // This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp`
2c00a5a8
XL
1178 auto deadIsPrevailing = [&](GlobalValue::GUID G) {
1179 return PrevailingType::Unknown;
1180 };
48663c56
XL
1181 // We don't have a complete picture in our use of ThinLTO, just our immediate
1182 // crate, so we need `ImportEnabled = false` to limit internalization.
1183 // Otherwise, we sometimes lose `static` values -- see #60184.
9fa01778 1184 computeDeadSymbolsWithConstProp(Ret->Index, Ret->GUIDPreservedSymbols,
48663c56 1185 deadIsPrevailing, /* ImportEnabled = */ false);
ea8adc8c
XL
1186 ComputeCrossModuleImport(
1187 Ret->Index,
1188 Ret->ModuleToDefinedGVSummaries,
1189 Ret->ImportLists,
1190 Ret->ExportLists
1191 );
1192
1193 // Resolve LinkOnce/Weak symbols, this has to be computed early be cause it
1194 // impacts the caching.
1195 //
ff7c6d11
XL
1196 // This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp` with some of this
1197 // being lifted from `lib/LTO/LTO.cpp` as well
ea8adc8c
XL
1198 DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
1199 for (auto &I : Ret->Index) {
abe05a73
XL
1200 if (I.second.SummaryList.size() > 1)
1201 PrevailingCopy[I.first] = getFirstDefinitionForLinker(I.second.SummaryList);
ea8adc8c
XL
1202 }
1203 auto isPrevailing = [&](GlobalValue::GUID GUID, const GlobalValueSummary *S) {
1204 const auto &Prevailing = PrevailingCopy.find(GUID);
1205 if (Prevailing == PrevailingCopy.end())
1206 return true;
1207 return Prevailing->second == S;
1208 };
1209 auto recordNewLinkage = [&](StringRef ModuleIdentifier,
1210 GlobalValue::GUID GUID,
1211 GlobalValue::LinkageTypes NewLinkage) {
29967ef6 1212 Ret->ResolvedODR[ModuleIdentifier][GUID] = NewLinkage;
ea8adc8c 1213 };
fc512014 1214
cdc7bbd5
XL
1215 // Uses FromPrevailing visibility scheme which works for many binary
1216 // formats. We probably could and should use ELF visibility scheme for many of
1217 // our targets, however.
1218 lto::Config conf;
1219 thinLTOResolvePrevailingInIndex(conf, Ret->Index, isPrevailing, recordNewLinkage,
1220 Ret->GUIDPreservedSymbols);
f2b60f7d 1221
ff7c6d11
XL
1222 // Here we calculate an `ExportedGUIDs` set for use in the `isExported`
1223 // callback below. This callback below will dictate the linkage for all
1224 // summaries in the index, and we basically just only want to ensure that dead
1225 // symbols are internalized. Otherwise everything that's already external
1226 // linkage will stay as external, and internal will stay as internal.
1227 std::set<GlobalValue::GUID> ExportedGUIDs;
1228 for (auto &List : Ret->Index) {
ff7c6d11 1229 for (auto &GVS: List.second.SummaryList) {
ff7c6d11
XL
1230 if (GlobalValue::isLocalLinkage(GVS->linkage()))
1231 continue;
1232 auto GUID = GVS->getOriginalName();
ff7c6d11 1233 if (GVS->flags().Live)
ff7c6d11
XL
1234 ExportedGUIDs.insert(GUID);
1235 }
1236 }
dfeec247
XL
1237 auto isExported = [&](StringRef ModuleIdentifier, ValueInfo VI) {
1238 const auto &ExportList = Ret->ExportLists.find(ModuleIdentifier);
1239 return (ExportList != Ret->ExportLists.end() &&
1240 ExportList->second.count(VI)) ||
1241 ExportedGUIDs.count(VI.getGUID());
1242 };
1243 thinLTOInternalizeAndPromoteInIndex(Ret->Index, isExported, isPrevailing);
ea8adc8c
XL
1244
1245 return Ret.release();
1246}
1247
1248extern "C" void
1249LLVMRustFreeThinLTOData(LLVMRustThinLTOData *Data) {
1250 delete Data;
1251}
1252
1253// Below are the various passes that happen *per module* when doing ThinLTO.
1254//
1255// In other words, these are the functions that are all run concurrently
1256// with one another, one per module. The passes here correspond to the analysis
1257// passes in `lib/LTO/ThinLTOCodeGenerator.cpp`, currently found in the
1258// `ProcessThinLTOModule` function. Here they're split up into separate steps
1259// so rustc can save off the intermediate bytecode between each step.
1260
f035d41b
XL
1261static bool
1262clearDSOLocalOnDeclarations(Module &Mod, TargetMachine &TM) {
1263 // When linking an ELF shared object, dso_local should be dropped. We
1264 // conservatively do this for -fpic.
1265 bool ClearDSOLocalOnDeclarations =
1266 TM.getTargetTriple().isOSBinFormatELF() &&
1267 TM.getRelocationModel() != Reloc::Static &&
1268 Mod.getPIELevel() == PIELevel::Default;
1269 return ClearDSOLocalOnDeclarations;
1270}
f035d41b 1271
ea8adc8c 1272extern "C" bool
f035d41b
XL
1273LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data, LLVMModuleRef M,
1274 LLVMTargetMachineRef TM) {
ea8adc8c 1275 Module &Mod = *unwrap(M);
f035d41b
XL
1276 TargetMachine &Target = *unwrap(TM);
1277
f035d41b
XL
1278 bool ClearDSOLocal = clearDSOLocalOnDeclarations(Mod, Target);
1279 bool error = renameModuleForThinLTO(Mod, Data->Index, ClearDSOLocal);
f035d41b
XL
1280
1281 if (error) {
ea8adc8c
XL
1282 LLVMRustSetLastError("renameModuleForThinLTO failed");
1283 return false;
1284 }
1285 return true;
1286}
1287
1288extern "C" bool
1289LLVMRustPrepareThinLTOResolveWeak(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
1290 Module &Mod = *unwrap(M);
1291 const auto &DefinedGlobals = Data->ModuleToDefinedGVSummaries.lookup(Mod.getModuleIdentifier());
c295e0f8
XL
1292#if LLVM_VERSION_GE(14, 0)
1293 thinLTOFinalizeInModule(Mod, DefinedGlobals, /*PropagateAttrs=*/true);
1294#else
a1dfa0c6 1295 thinLTOResolvePrevailingInModule(Mod, DefinedGlobals);
c295e0f8 1296#endif
ea8adc8c
XL
1297 return true;
1298}
1299
1300extern "C" bool
1301LLVMRustPrepareThinLTOInternalize(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
1302 Module &Mod = *unwrap(M);
1303 const auto &DefinedGlobals = Data->ModuleToDefinedGVSummaries.lookup(Mod.getModuleIdentifier());
1304 thinLTOInternalizeModule(Mod, DefinedGlobals);
1305 return true;
1306}
1307
1308extern "C" bool
f035d41b
XL
1309LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M,
1310 LLVMTargetMachineRef TM) {
ea8adc8c 1311 Module &Mod = *unwrap(M);
f035d41b 1312 TargetMachine &Target = *unwrap(TM);
8faf50e0 1313
ea8adc8c
XL
1314 const auto &ImportList = Data->ImportLists.lookup(Mod.getModuleIdentifier());
1315 auto Loader = [&](StringRef Identifier) {
1316 const auto &Memory = Data->ModuleMap.lookup(Identifier);
1317 auto &Context = Mod.getContext();
8faf50e0
XL
1318 auto MOrErr = getLazyBitcodeModule(Memory, Context, true, true);
1319
1320 if (!MOrErr)
b7449926 1321 return MOrErr;
8faf50e0
XL
1322
1323 // The rest of this closure is a workaround for
1324 // https://bugs.llvm.org/show_bug.cgi?id=38184 where during ThinLTO imports
1325 // we accidentally import wasm custom sections into different modules,
1326 // duplicating them by in the final output artifact.
1327 //
1328 // The issue is worked around here by manually removing the
1329 // `wasm.custom_sections` named metadata node from any imported module. This
1330 // we know isn't used by any optimization pass so there's no need for it to
1331 // be imported.
1332 //
1333 // Note that the metadata is currently lazily loaded, so we materialize it
1334 // here before looking up if there's metadata inside. The `FunctionImporter`
1335 // will immediately materialize metadata anyway after an import, so this
1336 // shouldn't be a perf hit.
1337 if (Error Err = (*MOrErr)->materializeMetadata()) {
1338 Expected<std::unique_ptr<Module>> Ret(std::move(Err));
b7449926 1339 return Ret;
8faf50e0
XL
1340 }
1341
1342 auto *WasmCustomSections = (*MOrErr)->getNamedMetadata("wasm.custom_sections");
1343 if (WasmCustomSections)
1344 WasmCustomSections->eraseFromParent();
1345
b7449926 1346 return MOrErr;
ea8adc8c 1347 };
f035d41b
XL
1348 bool ClearDSOLocal = clearDSOLocalOnDeclarations(Mod, Target);
1349 FunctionImporter Importer(Data->Index, Loader, ClearDSOLocal);
ea8adc8c
XL
1350 Expected<bool> Result = Importer.importFunctions(Mod, ImportList);
1351 if (!Result) {
1352 LLVMRustSetLastError(toString(Result.takeError()).c_str());
1353 return false;
1354 }
1355 return true;
1356}
1357
1358// This struct and various functions are sort of a hack right now, but the
1359// problem is that we've got in-memory LLVM modules after we generate and
1360// optimize all codegen-units for one compilation in rustc. To be compatible
1361// with the LTO support above we need to serialize the modules plus their
1362// ThinLTO summary into memory.
1363//
1364// This structure is basically an owned version of a serialize module, with
1365// a ThinLTO summary attached.
1366struct LLVMRustThinLTOBuffer {
1367 std::string data;
1368};
1369
1370extern "C" LLVMRustThinLTOBuffer*
064997fb 1371LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin) {
dfeec247 1372 auto Ret = std::make_unique<LLVMRustThinLTOBuffer>();
ea8adc8c
XL
1373 {
1374 raw_string_ostream OS(Ret->data);
1375 {
064997fb 1376 if (is_thin) {
f2b60f7d
FG
1377 PassBuilder PB;
1378 LoopAnalysisManager LAM;
1379 FunctionAnalysisManager FAM;
1380 CGSCCAnalysisManager CGAM;
1381 ModuleAnalysisManager MAM;
1382 PB.registerModuleAnalyses(MAM);
1383 PB.registerCGSCCAnalyses(CGAM);
1384 PB.registerFunctionAnalyses(FAM);
1385 PB.registerLoopAnalyses(LAM);
1386 PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
1387 ModulePassManager MPM;
1388 MPM.addPass(ThinLTOBitcodeWriterPass(OS, nullptr));
1389 MPM.run(*unwrap(M), MAM);
064997fb 1390 } else {
2b03887a 1391 WriteBitcodeToFile(*unwrap(M), OS);
064997fb 1392 }
ea8adc8c
XL
1393 }
1394 }
1395 return Ret.release();
1396}
1397
1398extern "C" void
1399LLVMRustThinLTOBufferFree(LLVMRustThinLTOBuffer *Buffer) {
1400 delete Buffer;
1401}
1402
1403extern "C" const void*
1404LLVMRustThinLTOBufferPtr(const LLVMRustThinLTOBuffer *Buffer) {
1405 return Buffer->data.data();
1406}
1407
1408extern "C" size_t
1409LLVMRustThinLTOBufferLen(const LLVMRustThinLTOBuffer *Buffer) {
1410 return Buffer->data.length();
1411}
1412
1413// This is what we used to parse upstream bitcode for actual ThinLTO
1414// processing. We'll call this once per module optimized through ThinLTO, and
1415// it'll be called concurrently on many threads.
1416extern "C" LLVMModuleRef
9fa01778
XL
1417LLVMRustParseBitcodeForLTO(LLVMContextRef Context,
1418 const char *data,
1419 size_t len,
1420 const char *identifier) {
ea8adc8c
XL
1421 StringRef Data(data, len);
1422 MemoryBufferRef Buffer(Data, identifier);
1423 unwrap(Context)->enableDebugTypeODRUniquing();
1424 Expected<std::unique_ptr<Module>> SrcOrError =
1425 parseBitcodeFile(Buffer, *unwrap(Context));
1426 if (!SrcOrError) {
1427 LLVMRustSetLastError(toString(SrcOrError.takeError()).c_str());
1428 return nullptr;
1429 }
1430 return wrap(std::move(*SrcOrError).release());
1431}
1432
f9f354fc
XL
1433// Find the bitcode section in the object file data and return it as a slice.
1434// Fail if the bitcode section is present but empty.
1435//
1436// On success, the return value is the pointer to the start of the slice and
1437// `out_len` is filled with the (non-zero) length. On failure, the return value
1438// is `nullptr` and `out_len` is set to zero.
1439extern "C" const char*
1440LLVMRustGetBitcodeSliceFromObjectData(const char *data,
1441 size_t len,
1442 size_t *out_len) {
1443 *out_len = 0;
1444
1445 StringRef Data(data, len);
1446 MemoryBufferRef Buffer(Data, ""); // The id is unused.
1447
1448 Expected<MemoryBufferRef> BitcodeOrError =
1449 object::IRObjectFile::findBitcodeInMemBuffer(Buffer);
1450 if (!BitcodeOrError) {
1451 LLVMRustSetLastError(toString(BitcodeOrError.takeError()).c_str());
1452 return nullptr;
1453 }
1454
1455 *out_len = BitcodeOrError->getBufferSize();
1456 return BitcodeOrError->getBufferStart();
1457}
1458
ff7c6d11
XL
1459// Rewrite all `DICompileUnit` pointers to the `DICompileUnit` specified. See
1460// the comment in `back/lto.rs` for why this exists.
1461extern "C" void
064997fb 1462LLVMRustThinLTOGetDICompileUnit(LLVMModuleRef Mod,
ff7c6d11
XL
1463 DICompileUnit **A,
1464 DICompileUnit **B) {
1465 Module *M = unwrap(Mod);
1466 DICompileUnit **Cur = A;
1467 DICompileUnit **Next = B;
1468 for (DICompileUnit *CU : M->debug_compile_units()) {
1469 *Cur = CU;
1470 Cur = Next;
1471 Next = nullptr;
1472 if (Cur == nullptr)
1473 break;
1474 }
1475}
1476
1477// Rewrite all `DICompileUnit` pointers to the `DICompileUnit` specified. See
1478// the comment in `back/lto.rs` for why this exists.
1479extern "C" void
064997fb 1480LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod, DICompileUnit *Unit) {
ff7c6d11
XL
1481 Module *M = unwrap(Mod);
1482
1483 // If the original source module didn't have a `DICompileUnit` then try to
1484 // merge all the existing compile units. If there aren't actually any though
1485 // then there's not much for us to do so return.
1486 if (Unit == nullptr) {
1487 for (DICompileUnit *CU : M->debug_compile_units()) {
1488 Unit = CU;
1489 break;
1490 }
1491 if (Unit == nullptr)
1492 return;
1493 }
1494
1495 // Use LLVM's built-in `DebugInfoFinder` to find a bunch of debuginfo and
f035d41b
XL
1496 // process it recursively. Note that we used to specifically iterate over
1497 // instructions to ensure we feed everything into it, but `processModule`
1498 // started doing this the same way in LLVM 7 (commit d769eb36ab2b8).
ff7c6d11
XL
1499 DebugInfoFinder Finder;
1500 Finder.processModule(*M);
ff7c6d11
XL
1501
1502 // After we've found all our debuginfo, rewrite all subprograms to point to
1503 // the same `DICompileUnit`.
1504 for (auto &F : Finder.subprograms()) {
1505 F->replaceUnit(Unit);
1506 }
1507
1508 // Erase any other references to other `DICompileUnit` instances, the verifier
1509 // will later ensure that we don't actually have any other stale references to
1510 // worry about.
1511 auto *MD = M->getNamedMetadata("llvm.dbg.cu");
1512 MD->clearOperands();
1513 MD->addOperand(Unit);
1514}
29967ef6
XL
1515
1516// Computes the LTO cache key for the provided 'ModId' in the given 'Data',
1517// storing the result in 'KeyOut'.
1518// Currently, this cache key is a SHA-1 hash of anything that could affect
1519// the result of optimizing this module (e.g. module imports, exports, liveness
1520// of access globals, etc).
1521// The precise details are determined by LLVM in `computeLTOCacheKey`, which is
1522// used during the normal linker-plugin incremental thin-LTO process.
1523extern "C" void
1524LLVMRustComputeLTOCacheKey(RustStringRef KeyOut, const char *ModId, LLVMRustThinLTOData *Data) {
1525 SmallString<40> Key;
1526 llvm::lto::Config conf;
1527 const auto &ImportList = Data->ImportLists.lookup(ModId);
1528 const auto &ExportList = Data->ExportLists.lookup(ModId);
1529 const auto &ResolvedODR = Data->ResolvedODR.lookup(ModId);
1530 const auto &DefinedGlobals = Data->ModuleToDefinedGVSummaries.lookup(ModId);
1531 std::set<GlobalValue::GUID> CfiFunctionDefs;
1532 std::set<GlobalValue::GUID> CfiFunctionDecls;
1533
1534 // Based on the 'InProcessThinBackend' constructor in LLVM
1535 for (auto &Name : Data->Index.cfiFunctionDefs())
1536 CfiFunctionDefs.insert(
1537 GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name)));
1538 for (auto &Name : Data->Index.cfiFunctionDecls())
1539 CfiFunctionDecls.insert(
1540 GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name)));
1541
1542 llvm::computeLTOCacheKey(Key, conf, Data->Index, ModId,
1543 ImportList, ExportList, ResolvedODR, DefinedGlobals, CfiFunctionDefs, CfiFunctionDecls
1544 );
1545
1546 LLVMRustStringWriteImpl(KeyOut, Key.c_str(), Key.size());
1547}