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