• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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