about summary refs log tree commit diff
path: root/compiler/rustc_llvm/llvm-wrapper
diff options
context:
space:
mode:
authorThe rustc-josh-sync Cronjob Bot <github-actions@github.com>2025-09-25 04:16:26 +0000
committerThe rustc-josh-sync Cronjob Bot <github-actions@github.com>2025-09-25 04:16:26 +0000
commitff7e7319837d5029ed4f522601debc2a7bc33274 (patch)
tree42dbcb2d8c347a2e7c97c7e4361b1c361143da0b /compiler/rustc_llvm/llvm-wrapper
parent3280c210dd6e5f26595ff4857572f8feba678992 (diff)
parentd226e7aa93425ba2090f423642341a99ab047838 (diff)
downloadrust-ff7e7319837d5029ed4f522601debc2a7bc33274.tar.gz
rust-ff7e7319837d5029ed4f522601debc2a7bc33274.zip
Merge ref 'caccb4d0368b' from rust-lang/rust
Pull recent changes from https://github.com/rust-lang/rust via Josh.

Upstream ref: caccb4d0368bd918ef6668af8e13834d07040417
Filtered ref: 0f345ed05d559bbfb754f1403b16199366cda2e0
Upstream diff: https://github.com/rust-lang/rust/compare/21a19c297d4f5a03501d92ca251bd7a17073c08a...caccb4d0368bd918ef6668af8e13834d07040417

This merge was created using https://github.com/rust-lang/josh-sync.
Diffstat (limited to 'compiler/rustc_llvm/llvm-wrapper')
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp208
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp309
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp216
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp99
4 files changed, 125 insertions, 707 deletions
diff --git a/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp
deleted file mode 100644
index feac6a5649c..00000000000
--- a/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp
+++ /dev/null
@@ -1,208 +0,0 @@
-#include "LLVMWrapper.h"
-
-#include "llvm/Object/Archive.h"
-#include "llvm/Object/ArchiveWriter.h"
-#include "llvm/Support/Path.h"
-
-using namespace llvm;
-using namespace llvm::object;
-
-struct RustArchiveMember {
-  const char *Filename;
-  const char *Name;
-  Archive::Child Child;
-
-  RustArchiveMember()
-      : Filename(nullptr), Name(nullptr), Child(nullptr, nullptr, nullptr) {}
-  ~RustArchiveMember() {}
-};
-
-struct RustArchiveIterator {
-  bool First;
-  Archive::child_iterator Cur;
-  Archive::child_iterator End;
-  std::unique_ptr<Error> Err;
-
-  RustArchiveIterator(Archive::child_iterator Cur, Archive::child_iterator End,
-                      std::unique_ptr<Error> Err)
-      : First(true), Cur(Cur), End(End), Err(std::move(Err)) {}
-};
-
-enum class LLVMRustArchiveKind {
-  GNU,
-  BSD,
-  DARWIN,
-  COFF,
-  AIX_BIG,
-};
-
-static Archive::Kind fromRust(LLVMRustArchiveKind Kind) {
-  switch (Kind) {
-  case LLVMRustArchiveKind::GNU:
-    return Archive::K_GNU;
-  case LLVMRustArchiveKind::BSD:
-    return Archive::K_BSD;
-  case LLVMRustArchiveKind::DARWIN:
-    return Archive::K_DARWIN;
-  case LLVMRustArchiveKind::COFF:
-    return Archive::K_COFF;
-  case LLVMRustArchiveKind::AIX_BIG:
-    return Archive::K_AIXBIG;
-  default:
-    report_fatal_error("Bad ArchiveKind.");
-  }
-}
-
-typedef OwningBinary<Archive> *LLVMRustArchiveRef;
-typedef RustArchiveMember *LLVMRustArchiveMemberRef;
-typedef Archive::Child *LLVMRustArchiveChildRef;
-typedef Archive::Child const *LLVMRustArchiveChildConstRef;
-typedef RustArchiveIterator *LLVMRustArchiveIteratorRef;
-
-extern "C" LLVMRustArchiveRef LLVMRustOpenArchive(char *Path) {
-  ErrorOr<std::unique_ptr<MemoryBuffer>> BufOr = MemoryBuffer::getFile(
-      Path, /*IsText*/ false, /*RequiresNullTerminator=*/false);
-  if (!BufOr) {
-    LLVMRustSetLastError(BufOr.getError().message().c_str());
-    return nullptr;
-  }
-
-  Expected<std::unique_ptr<Archive>> ArchiveOr =
-      Archive::create(BufOr.get()->getMemBufferRef());
-
-  if (!ArchiveOr) {
-    LLVMRustSetLastError(toString(ArchiveOr.takeError()).c_str());
-    return nullptr;
-  }
-
-  OwningBinary<Archive> *Ret = new OwningBinary<Archive>(
-      std::move(ArchiveOr.get()), std::move(BufOr.get()));
-
-  return Ret;
-}
-
-extern "C" void LLVMRustDestroyArchive(LLVMRustArchiveRef RustArchive) {
-  delete RustArchive;
-}
-
-extern "C" LLVMRustArchiveIteratorRef
-LLVMRustArchiveIteratorNew(LLVMRustArchiveRef RustArchive) {
-  Archive *Archive = RustArchive->getBinary();
-  std::unique_ptr<Error> Err = std::make_unique<Error>(Error::success());
-  auto Cur = Archive->child_begin(*Err);
-  if (*Err) {
-    LLVMRustSetLastError(toString(std::move(*Err)).c_str());
-    return nullptr;
-  }
-  auto End = Archive->child_end();
-  return new RustArchiveIterator(Cur, End, std::move(Err));
-}
-
-extern "C" LLVMRustArchiveChildConstRef
-LLVMRustArchiveIteratorNext(LLVMRustArchiveIteratorRef RAI) {
-  if (RAI->Cur == RAI->End)
-    return nullptr;
-
-  // Advancing the iterator validates the next child, and this can
-  // uncover an error. LLVM requires that we check all Errors,
-  // so we only advance the iterator if we actually need to fetch
-  // the next child.
-  // This means we must not advance the iterator in the *first* call,
-  // but instead advance it *before* fetching the child in all later calls.
-  if (!RAI->First) {
-    ++RAI->Cur;
-    if (*RAI->Err) {
-      LLVMRustSetLastError(toString(std::move(*RAI->Err)).c_str());
-      return nullptr;
-    }
-  } else {
-    RAI->First = false;
-  }
-
-  if (RAI->Cur == RAI->End)
-    return nullptr;
-
-  const Archive::Child &Child = *RAI->Cur.operator->();
-  Archive::Child *Ret = new Archive::Child(Child);
-
-  return Ret;
-}
-
-extern "C" void LLVMRustArchiveChildFree(LLVMRustArchiveChildRef Child) {
-  delete Child;
-}
-
-extern "C" void LLVMRustArchiveIteratorFree(LLVMRustArchiveIteratorRef RAI) {
-  delete RAI;
-}
-
-extern "C" const char *
-LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef Child, size_t *Size) {
-  Expected<StringRef> NameOrErr = Child->getName();
-  if (!NameOrErr) {
-    // rustc_codegen_llvm currently doesn't use this error string, but it might
-    // be useful in the future, and in the meantime this tells LLVM that the
-    // error was not ignored and that it shouldn't abort the process.
-    LLVMRustSetLastError(toString(NameOrErr.takeError()).c_str());
-    return nullptr;
-  }
-  StringRef Name = NameOrErr.get();
-  *Size = Name.size();
-  return Name.data();
-}
-
-extern "C" LLVMRustArchiveMemberRef
-LLVMRustArchiveMemberNew(char *Filename, char *Name,
-                         LLVMRustArchiveChildRef Child) {
-  RustArchiveMember *Member = new RustArchiveMember;
-  Member->Filename = Filename;
-  Member->Name = Name;
-  if (Child)
-    Member->Child = *Child;
-  return Member;
-}
-
-extern "C" void LLVMRustArchiveMemberFree(LLVMRustArchiveMemberRef Member) {
-  delete Member;
-}
-
-extern "C" LLVMRustResult LLVMRustWriteArchive(
-    char *Dst, size_t NumMembers, const LLVMRustArchiveMemberRef *NewMembers,
-    bool WriteSymbtab, LLVMRustArchiveKind RustKind, bool isEC) {
-
-  std::vector<NewArchiveMember> Members;
-  auto Kind = fromRust(RustKind);
-
-  for (size_t I = 0; I < NumMembers; I++) {
-    auto Member = NewMembers[I];
-    assert(Member->Name);
-    if (Member->Filename) {
-      Expected<NewArchiveMember> MOrErr =
-          NewArchiveMember::getFile(Member->Filename, true);
-      if (!MOrErr) {
-        LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
-        return LLVMRustResult::Failure;
-      }
-      MOrErr->MemberName = sys::path::filename(MOrErr->MemberName);
-      Members.push_back(std::move(*MOrErr));
-    } else {
-      Expected<NewArchiveMember> MOrErr =
-          NewArchiveMember::getOldMember(Member->Child, true);
-      if (!MOrErr) {
-        LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
-        return LLVMRustResult::Failure;
-      }
-      Members.push_back(std::move(*MOrErr));
-    }
-  }
-
-  auto SymtabMode = WriteSymbtab ? SymtabWritingMode::NormalSymtab
-                                 : SymtabWritingMode::NoSymtab;
-  auto Result =
-      writeArchive(Dst, Members, SymtabMode, Kind, true, false, nullptr, isEC);
-  if (!Result)
-    return LLVMRustResult::Success;
-  LLVMRustSetLastError(toString(std::move(Result)).c_str());
-
-  return LLVMRustResult::Failure;
-}
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 8c34052770e..7518b40799b 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -79,122 +79,6 @@ extern "C" void LLVMRustTimeTraceProfilerFinish(const char *FileName) {
   timeTraceProfilerCleanup();
 }
 
-#ifdef LLVM_COMPONENT_X86
-#define SUBTARGET_X86 SUBTARGET(X86)
-#else
-#define SUBTARGET_X86
-#endif
-
-#ifdef LLVM_COMPONENT_ARM
-#define SUBTARGET_ARM SUBTARGET(ARM)
-#else
-#define SUBTARGET_ARM
-#endif
-
-#ifdef LLVM_COMPONENT_AARCH64
-#define SUBTARGET_AARCH64 SUBTARGET(AArch64)
-#else
-#define SUBTARGET_AARCH64
-#endif
-
-#ifdef LLVM_COMPONENT_AVR
-#define SUBTARGET_AVR SUBTARGET(AVR)
-#else
-#define SUBTARGET_AVR
-#endif
-
-#ifdef LLVM_COMPONENT_M68k
-#define SUBTARGET_M68K SUBTARGET(M68k)
-#else
-#define SUBTARGET_M68K
-#endif
-
-#ifdef LLVM_COMPONENT_CSKY
-#define SUBTARGET_CSKY SUBTARGET(CSKY)
-#else
-#define SUBTARGET_CSKY
-#endif
-
-#ifdef LLVM_COMPONENT_MIPS
-#define SUBTARGET_MIPS SUBTARGET(Mips)
-#else
-#define SUBTARGET_MIPS
-#endif
-
-#ifdef LLVM_COMPONENT_POWERPC
-#define SUBTARGET_PPC SUBTARGET(PPC)
-#else
-#define SUBTARGET_PPC
-#endif
-
-#ifdef LLVM_COMPONENT_SYSTEMZ
-#define SUBTARGET_SYSTEMZ SUBTARGET(SystemZ)
-#else
-#define SUBTARGET_SYSTEMZ
-#endif
-
-#ifdef LLVM_COMPONENT_MSP430
-#define SUBTARGET_MSP430 SUBTARGET(MSP430)
-#else
-#define SUBTARGET_MSP430
-#endif
-
-#ifdef LLVM_COMPONENT_RISCV
-#define SUBTARGET_RISCV SUBTARGET(RISCV)
-#else
-#define SUBTARGET_RISCV
-#endif
-
-#ifdef LLVM_COMPONENT_SPARC
-#define SUBTARGET_SPARC SUBTARGET(Sparc)
-#else
-#define SUBTARGET_SPARC
-#endif
-
-#ifdef LLVM_COMPONENT_XTENSA
-#define SUBTARGET_XTENSA SUBTARGET(XTENSA)
-#else
-#define SUBTARGET_XTENSA
-#endif
-
-#ifdef LLVM_COMPONENT_HEXAGON
-#define SUBTARGET_HEXAGON SUBTARGET(Hexagon)
-#else
-#define SUBTARGET_HEXAGON
-#endif
-
-#ifdef LLVM_COMPONENT_LOONGARCH
-#define SUBTARGET_LOONGARCH SUBTARGET(LoongArch)
-#else
-#define SUBTARGET_LOONGARCH
-#endif
-
-#define GEN_SUBTARGETS                                                         \
-  SUBTARGET_X86                                                                \
-  SUBTARGET_ARM                                                                \
-  SUBTARGET_AARCH64                                                            \
-  SUBTARGET_AVR                                                                \
-  SUBTARGET_M68K                                                               \
-  SUBTARGET_CSKY                                                               \
-  SUBTARGET_MIPS                                                               \
-  SUBTARGET_PPC                                                                \
-  SUBTARGET_SYSTEMZ                                                            \
-  SUBTARGET_MSP430                                                             \
-  SUBTARGET_SPARC                                                              \
-  SUBTARGET_HEXAGON                                                            \
-  SUBTARGET_XTENSA                                                             \
-  SUBTARGET_RISCV                                                              \
-  SUBTARGET_LOONGARCH
-
-#define SUBTARGET(x)                                                           \
-  namespace llvm {                                                             \
-  extern const SubtargetFeatureKV x##FeatureKV[];                              \
-  extern const SubtargetFeatureKV x##SubTypeKV[];                              \
-  }
-
-GEN_SUBTARGETS
-#undef SUBTARGET
-
 // This struct and various functions are sort of a hack right now, but the
 // problem is that we've got in-memory LLVM modules after we generate and
 // optimize all codegen-units for one compilation in rustc. To be compatible
@@ -340,14 +224,6 @@ static FloatABI::ABIType fromRust(LLVMRustFloatABI RustFloatAbi) {
   report_fatal_error("Bad FloatABI.");
 }
 
-/// getLongestEntryLength - Return the length of the longest entry in the table.
-template <typename KV> static size_t getLongestEntryLength(ArrayRef<KV> Table) {
-  size_t MaxLen = 0;
-  for (auto &I : Table)
-    MaxLen = std::max(MaxLen, std::strlen(I.Key));
-  return MaxLen;
-}
-
 extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM,
                                         RustStringRef OutStr) {
   ArrayRef<SubtargetSubTypeKV> CPUTable =
@@ -395,8 +271,9 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
     bool TrapUnreachable, bool Singlethread, bool VerboseAsm,
     bool EmitStackSizeSection, bool RelaxELFRelocations, bool UseInitArray,
     const char *SplitDwarfFile, const char *OutputObjFile,
-    const char *DebugInfoCompression, bool UseEmulatedTls,
-    const char *ArgsCstrBuff, size_t ArgsCstrBuffLen, bool UseWasmEH) {
+    const char *DebugInfoCompression, bool UseEmulatedTls, const char *Argv0,
+    size_t Argv0Len, const char *CommandLineArgs, size_t CommandLineArgsLen,
+    bool UseWasmEH) {
 
   auto OptLevel = fromRust(RustOptLevel);
   auto RM = fromRust(RustReloc);
@@ -467,53 +344,10 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
 
   Options.EmitStackSizeSection = EmitStackSizeSection;
 
-  if (ArgsCstrBuff != nullptr) {
-#if LLVM_VERSION_GE(20, 0)
-    size_t buffer_offset = 0;
-    assert(ArgsCstrBuff[ArgsCstrBuffLen - 1] == '\0');
-    auto Arg0 = std::string(ArgsCstrBuff);
-    buffer_offset = Arg0.size() + 1;
-
-    std::string CommandlineArgs;
-    raw_string_ostream OS(CommandlineArgs);
-    ListSeparator LS(" ");
-    for (StringRef Arg : split(StringRef(ArgsCstrBuff + buffer_offset,
-                                         ArgsCstrBuffLen - buffer_offset),
-                               '\0')) {
-      OS << LS;
-      sys::printArg(OS, Arg, /*Quote=*/true);
-    }
-    OS.flush();
-    Options.MCOptions.Argv0 = Arg0;
-    Options.MCOptions.CommandlineArgs = CommandlineArgs;
-#else
-    size_t buffer_offset = 0;
-    assert(ArgsCstrBuff[ArgsCstrBuffLen - 1] == '\0');
-
-    const size_t arg0_len = std::strlen(ArgsCstrBuff);
-    char *arg0 = new char[arg0_len + 1];
-    memcpy(arg0, ArgsCstrBuff, arg0_len);
-    arg0[arg0_len] = '\0';
-    buffer_offset += arg0_len + 1;
-
-    const size_t num_cmd_arg_strings = std::count(
-        &ArgsCstrBuff[buffer_offset], &ArgsCstrBuff[ArgsCstrBuffLen], '\0');
-
-    std::string *cmd_arg_strings = new std::string[num_cmd_arg_strings];
-    for (size_t i = 0; i < num_cmd_arg_strings; ++i) {
-      assert(buffer_offset < ArgsCstrBuffLen);
-      const size_t len = std::strlen(ArgsCstrBuff + buffer_offset);
-      cmd_arg_strings[i] = std::string(&ArgsCstrBuff[buffer_offset], len);
-      buffer_offset += len + 1;
-    }
-
-    assert(buffer_offset == ArgsCstrBuffLen);
-
-    Options.MCOptions.Argv0 = arg0;
-    Options.MCOptions.CommandLineArgs =
-        llvm::ArrayRef<std::string>(cmd_arg_strings, num_cmd_arg_strings);
-#endif
-  }
+  if (Argv0 != nullptr)
+    Options.MCOptions.Argv0 = {Argv0, Argv0Len};
+  if (CommandLineArgs != nullptr)
+    Options.MCOptions.CommandlineArgs = {CommandLineArgs, CommandLineArgsLen};
 
 #if LLVM_VERSION_GE(21, 0)
   TargetMachine *TM = TheTarget->createTargetMachine(Trip, CPU, Feature,
@@ -526,12 +360,6 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
 }
 
 extern "C" void LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) {
-#if LLVM_VERSION_LT(20, 0)
-  MCTargetOptions &MCOptions = unwrap(TM)->Options.MCOptions;
-  delete[] MCOptions.Argv0;
-  delete[] MCOptions.CommandLineArgs.data();
-#endif
-
   delete unwrap(TM);
 }
 
@@ -812,14 +640,9 @@ extern "C" LLVMRustResult LLVMRustOptimize(
   // the PassBuilder does not create a pipeline.
   std::vector<std::function<void(ModulePassManager &, OptimizationLevel)>>
       PipelineStartEPCallbacks;
-#if LLVM_VERSION_GE(20, 0)
   std::vector<std::function<void(ModulePassManager &, OptimizationLevel,
                                  ThinOrFullLTOPhase)>>
       OptimizerLastEPCallbacks;
-#else
-  std::vector<std::function<void(ModulePassManager &, OptimizationLevel)>>
-      OptimizerLastEPCallbacks;
-#endif
 
   if (!IsLinkerPluginLTO && SanitizerOptions && SanitizerOptions->SanitizeCFI &&
       !NoPrepopulatePasses) {
@@ -871,12 +694,8 @@ extern "C" LLVMRustResult LLVMRustOptimize(
           SanitizerOptions->SanitizeDataFlowABIList +
               SanitizerOptions->SanitizeDataFlowABIListLen);
       OptimizerLastEPCallbacks.push_back(
-#if LLVM_VERSION_GE(20, 0)
           [ABIListFiles](ModulePassManager &MPM, OptimizationLevel Level,
                          ThinOrFullLTOPhase phase) {
-#else
-          [ABIListFiles](ModulePassManager &MPM, OptimizationLevel Level) {
-#endif
             MPM.addPass(DataFlowSanitizerPass(ABIListFiles));
           });
     }
@@ -887,66 +706,48 @@ extern "C" LLVMRustResult LLVMRustOptimize(
           SanitizerOptions->SanitizeMemoryRecover,
           /*CompileKernel=*/false,
           /*EagerChecks=*/true);
-      OptimizerLastEPCallbacks.push_back(
-#if LLVM_VERSION_GE(20, 0)
-          [Options](ModulePassManager &MPM, OptimizationLevel Level,
-                    ThinOrFullLTOPhase phase) {
-#else
-          [Options](ModulePassManager &MPM, OptimizationLevel Level) {
-#endif
-            MPM.addPass(MemorySanitizerPass(Options));
-          });
+      OptimizerLastEPCallbacks.push_back([Options](ModulePassManager &MPM,
+                                                   OptimizationLevel Level,
+                                                   ThinOrFullLTOPhase phase) {
+        MPM.addPass(MemorySanitizerPass(Options));
+      });
     }
 
     if (SanitizerOptions->SanitizeThread) {
-      OptimizerLastEPCallbacks.push_back(
-#if LLVM_VERSION_GE(20, 0)
-          [](ModulePassManager &MPM, OptimizationLevel Level,
-             ThinOrFullLTOPhase phase) {
-#else
-          [](ModulePassManager &MPM, OptimizationLevel Level) {
-#endif
-            MPM.addPass(ModuleThreadSanitizerPass());
-            MPM.addPass(
-                createModuleToFunctionPassAdaptor(ThreadSanitizerPass()));
-          });
+      OptimizerLastEPCallbacks.push_back([](ModulePassManager &MPM,
+                                            OptimizationLevel Level,
+                                            ThinOrFullLTOPhase phase) {
+        MPM.addPass(ModuleThreadSanitizerPass());
+        MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass()));
+      });
     }
 
     if (SanitizerOptions->SanitizeAddress ||
         SanitizerOptions->SanitizeKernelAddress) {
-      OptimizerLastEPCallbacks.push_back(
-#if LLVM_VERSION_GE(20, 0)
-          [SanitizerOptions, TM](ModulePassManager &MPM,
-                                 OptimizationLevel Level,
-                                 ThinOrFullLTOPhase phase) {
-#else
-          [SanitizerOptions, TM](ModulePassManager &MPM,
-                                 OptimizationLevel Level) {
-#endif
-            auto CompileKernel = SanitizerOptions->SanitizeKernelAddress;
-            AddressSanitizerOptions opts = AddressSanitizerOptions{
-                CompileKernel,
-                SanitizerOptions->SanitizeAddressRecover ||
-                    SanitizerOptions->SanitizeKernelAddressRecover,
-                /*UseAfterScope=*/true,
-                AsanDetectStackUseAfterReturnMode::Runtime,
-            };
-            MPM.addPass(AddressSanitizerPass(
-                opts,
-                /*UseGlobalGC*/ true,
-                // UseOdrIndicator should be false on windows machines
-                // https://reviews.llvm.org/D137227
-                !TM->getTargetTriple().isOSWindows()));
-          });
+      OptimizerLastEPCallbacks.push_back([SanitizerOptions,
+                                          TM](ModulePassManager &MPM,
+                                              OptimizationLevel Level,
+                                              ThinOrFullLTOPhase phase) {
+        auto CompileKernel = SanitizerOptions->SanitizeKernelAddress;
+        AddressSanitizerOptions opts = AddressSanitizerOptions{
+            CompileKernel,
+            SanitizerOptions->SanitizeAddressRecover ||
+                SanitizerOptions->SanitizeKernelAddressRecover,
+            /*UseAfterScope=*/true,
+            AsanDetectStackUseAfterReturnMode::Runtime,
+        };
+        MPM.addPass(
+            AddressSanitizerPass(opts,
+                                 /*UseGlobalGC*/ true,
+                                 // UseOdrIndicator should be false on windows
+                                 // machines https://reviews.llvm.org/D137227
+                                 !TM->getTargetTriple().isOSWindows()));
+      });
     }
     if (SanitizerOptions->SanitizeHWAddress) {
       OptimizerLastEPCallbacks.push_back(
-#if LLVM_VERSION_GE(20, 0)
           [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level,
                              ThinOrFullLTOPhase phase) {
-#else
-          [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
-#endif
             HWAddressSanitizerOptions opts(
                 /*CompileKernel=*/false,
                 SanitizerOptions->SanitizeHWAddressRecover,
@@ -1028,11 +829,7 @@ extern "C" LLVMRustResult LLVMRustOptimize(
     for (const auto &C : PipelineStartEPCallbacks)
       C(MPM, OptLevel);
     for (const auto &C : OptimizerLastEPCallbacks)
-#if LLVM_VERSION_GE(20, 0)
       C(MPM, OptLevel, ThinOrFullLTOPhase::None);
-#else
-      C(MPM, OptLevel);
-#endif
   }
 
   if (ExtraPassesLen) {
@@ -1226,12 +1023,6 @@ extern "C" void LLVMRustPrintPasses() {
 extern "C" void LLVMRustRunRestrictionPass(LLVMModuleRef M, char **Symbols,
                                            size_t Len) {
   auto PreserveFunctions = [=](const GlobalValue &GV) {
-    // Preserve LLVM-injected, ASAN-related symbols.
-    // See also https://github.com/rust-lang/rust/issues/113404.
-    if (GV.getName() == "___asan_globals_registered") {
-      return true;
-    }
-
     // Preserve symbols exported from Rust modules.
     for (size_t I = 0; I < Len; I++) {
       if (GV.getName() == Symbols[I]) {
@@ -1315,11 +1106,7 @@ struct LLVMRustThinLTOData {
 
   // Not 100% sure what these are, but they impact what's internalized and
   // what's inlined across modules, I believe.
-#if LLVM_VERSION_GE(20, 0)
   FunctionImporter::ImportListsTy ImportLists;
-#else
-  DenseMap<StringRef, FunctionImporter::ImportMapTy> ImportLists;
-#endif
   DenseMap<StringRef, FunctionImporter::ExportSetTy> ExportLists;
   DenseMap<StringRef, GVSummaryMapTy> ModuleToDefinedGVSummaries;
   StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
@@ -1574,12 +1361,11 @@ extern "C" bool LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data,
   return true;
 }
 
-extern "C" LLVMRustThinLTOBuffer *
-LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin, bool emit_summary) {
+extern "C" LLVMRustThinLTOBuffer *LLVMRustThinLTOBufferCreate(LLVMModuleRef M,
+                                                              bool is_thin) {
   auto Ret = std::make_unique<LLVMRustThinLTOBuffer>();
   {
     auto OS = raw_string_ostream(Ret->data);
-    auto ThinLinkOS = raw_string_ostream(Ret->thin_link_data);
     {
       if (is_thin) {
         PassBuilder PB;
@@ -1593,11 +1379,7 @@ LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin, bool emit_summary) {
         PB.registerLoopAnalyses(LAM);
         PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
         ModulePassManager MPM;
-        // We only pass ThinLinkOS to be filled in if we want the summary,
-        // because otherwise LLVM does extra work and may double-emit some
-        // errors or warnings.
-        MPM.addPass(
-            ThinLTOBitcodeWriterPass(OS, emit_summary ? &ThinLinkOS : nullptr));
+        MPM.addPass(ThinLTOBitcodeWriterPass(OS, nullptr));
         MPM.run(*unwrap(M), MAM);
       } else {
         WriteBitcodeToFile(*unwrap(M), OS);
@@ -1666,13 +1448,8 @@ extern "C" void LLVMRustComputeLTOCacheKey(RustStringRef KeyOut,
   const auto &ExportList = Data->ExportLists.lookup(ModId);
   const auto &ResolvedODR = Data->ResolvedODR.lookup(ModId);
   const auto &DefinedGlobals = Data->ModuleToDefinedGVSummaries.lookup(ModId);
-#if LLVM_VERSION_GE(20, 0)
   DenseSet<GlobalValue::GUID> CfiFunctionDefs;
   DenseSet<GlobalValue::GUID> CfiFunctionDecls;
-#else
-  std::set<GlobalValue::GUID> CfiFunctionDefs;
-  std::set<GlobalValue::GUID> CfiFunctionDecls;
-#endif
 
   // Based on the 'InProcessThinBackend' constructor in LLVM
 #if LLVM_VERSION_GE(21, 0)
@@ -1691,15 +1468,9 @@ extern "C" void LLVMRustComputeLTOCacheKey(RustStringRef KeyOut,
         GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name)));
 #endif
 
-#if LLVM_VERSION_GE(20, 0)
   Key = llvm::computeLTOCacheKey(conf, Data->Index, ModId, ImportList,
                                  ExportList, ResolvedODR, DefinedGlobals,
                                  CfiFunctionDefs, CfiFunctionDecls);
-#else
-  llvm::computeLTOCacheKey(Key, conf, Data->Index, ModId, ImportList,
-                           ExportList, ResolvedODR, DefinedGlobals,
-                           CfiFunctionDefs, CfiFunctionDecls);
-#endif
 
   auto OS = RawRustStringOstream(KeyOut);
   OS << Key.str();
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 588d867bbbf..414274f24fb 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -242,7 +242,7 @@ enum class LLVMRustAttributeKind {
   MinSize = 4,
   Naked = 5,
   NoAlias = 6,
-  NoCapture = 7,
+  CapturesAddress = 7,
   NoInline = 8,
   NonNull = 9,
   NoRedZone = 10,
@@ -277,6 +277,8 @@ enum class LLVMRustAttributeKind {
   FnRetThunkExtern = 41,
   Writable = 42,
   DeadOnUnwind = 43,
+  DeadOnReturn = 44,
+  CapturesReadOnly = 45,
 };
 
 static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) {
@@ -295,12 +297,6 @@ static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) {
     return Attribute::Naked;
   case LLVMRustAttributeKind::NoAlias:
     return Attribute::NoAlias;
-  case LLVMRustAttributeKind::NoCapture:
-#if LLVM_VERSION_GE(21, 0)
-    report_fatal_error("NoCapture doesn't exist in LLVM 21");
-#else
-    return Attribute::NoCapture;
-#endif
   case LLVMRustAttributeKind::NoCfCheck:
     return Attribute::NoCfCheck;
   case LLVMRustAttributeKind::NoInline:
@@ -369,6 +365,15 @@ static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) {
     return Attribute::Writable;
   case LLVMRustAttributeKind::DeadOnUnwind:
     return Attribute::DeadOnUnwind;
+  case LLVMRustAttributeKind::DeadOnReturn:
+#if LLVM_VERSION_GE(21, 0)
+    return Attribute::DeadOnReturn;
+#else
+    report_fatal_error("DeadOnReturn attribute requires LLVM 21 or later");
+#endif
+  case LLVMRustAttributeKind::CapturesAddress:
+  case LLVMRustAttributeKind::CapturesReadOnly:
+    report_fatal_error("Should be handled separately");
   }
   report_fatal_error("bad LLVMRustAttributeKind");
 }
@@ -419,9 +424,14 @@ extern "C" void LLVMRustEraseInstFromParent(LLVMValueRef Instr) {
 extern "C" LLVMAttributeRef
 LLVMRustCreateAttrNoValue(LLVMContextRef C, LLVMRustAttributeKind RustAttr) {
 #if LLVM_VERSION_GE(21, 0)
-  // LLVM 21 replaced the NoCapture attribute with Captures(none).
-  if (RustAttr == LLVMRustAttributeKind::NoCapture) {
-    return wrap(Attribute::getWithCaptureInfo(*unwrap(C), CaptureInfo::none()));
+  if (RustAttr == LLVMRustAttributeKind::CapturesAddress) {
+    return wrap(Attribute::getWithCaptureInfo(
+        *unwrap(C), CaptureInfo(CaptureComponents::Address)));
+  }
+  if (RustAttr == LLVMRustAttributeKind::CapturesReadOnly) {
+    return wrap(Attribute::getWithCaptureInfo(
+        *unwrap(C), CaptureInfo(CaptureComponents::Address |
+                                CaptureComponents::ReadProvenance)));
   }
 #endif
   return wrap(Attribute::get(*unwrap(C), fromRust(RustAttr)));
@@ -473,6 +483,9 @@ extern "C" LLVMAttributeRef
 LLVMRustCreateRangeAttribute(LLVMContextRef C, unsigned NumBits,
                              const uint64_t LowerWords[],
                              const uint64_t UpperWords[]) {
+  // FIXME(Zalathar): There appears to be no stable guarantee that C++
+  // `AttrKind` values correspond directly to the `unsigned KindID` values
+  // accepted by LLVM-C API functions, though in practice they currently do.
   return LLVMCreateConstantRangeAttribute(C, Attribute::Range, NumBits,
                                           LowerWords, UpperWords);
 }
@@ -540,6 +553,7 @@ enum class LLVMRustMemoryEffects {
   None,
   ReadOnly,
   InaccessibleMemOnly,
+  ReadOnlyNotPure,
 };
 
 extern "C" LLVMAttributeRef
@@ -555,6 +569,10 @@ LLVMRustCreateMemoryEffectsAttr(LLVMContextRef C,
   case LLVMRustMemoryEffects::InaccessibleMemOnly:
     return wrap(Attribute::getWithMemoryEffects(
         *unwrap(C), MemoryEffects::inaccessibleMemOnly()));
+  case LLVMRustMemoryEffects::ReadOnlyNotPure:
+    return wrap(Attribute::getWithMemoryEffects(
+        *unwrap(C),
+        MemoryEffects::readOnly() | MemoryEffects::inaccessibleMemOnly()));
   default:
     report_fatal_error("bad MemoryEffects.");
   }
@@ -1013,13 +1031,6 @@ LLVMRustDIBuilderCreateFile(LLVMDIBuilderRef Builder, const char *Filename,
                                           CSInfo, oSource));
 }
 
-extern "C" LLVMMetadataRef
-LLVMRustDIBuilderCreateSubroutineType(LLVMDIBuilderRef Builder,
-                                      LLVMMetadataRef ParameterTypes) {
-  return wrap(unwrap(Builder)->createSubroutineType(
-      DITypeRefArray(unwrap<MDTuple>(ParameterTypes))));
-}
-
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction(
     LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
     size_t NameLen, const char *LinkageName, size_t LinkageNameLen,
@@ -1058,47 +1069,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMethod(
   return wrap(Sub);
 }
 
-extern "C" LLVMMetadataRef
-LLVMRustDIBuilderCreateBasicType(LLVMDIBuilderRef Builder, const char *Name,
-                                 size_t NameLen, uint64_t SizeInBits,
-                                 unsigned Encoding) {
-  return wrap(unwrap(Builder)->createBasicType(StringRef(Name, NameLen),
-                                               SizeInBits, Encoding));
-}
-
-extern "C" LLVMMetadataRef
-LLVMRustDIBuilderCreateTypedef(LLVMDIBuilderRef Builder, LLVMMetadataRef Type,
-                               const char *Name, size_t NameLen,
-                               LLVMMetadataRef File, unsigned LineNo,
-                               LLVMMetadataRef Scope) {
-  return wrap(unwrap(Builder)->createTypedef(
-      unwrap<DIType>(Type), StringRef(Name, NameLen), unwrap<DIFile>(File),
-      LineNo, unwrapDIPtr<DIScope>(Scope)));
-}
-
-extern "C" LLVMMetadataRef LLVMRustDIBuilderCreatePointerType(
-    LLVMDIBuilderRef Builder, LLVMMetadataRef PointeeTy, uint64_t SizeInBits,
-    uint32_t AlignInBits, unsigned AddressSpace, const char *Name,
-    size_t NameLen) {
-  return wrap(unwrap(Builder)->createPointerType(
-      unwrapDI<DIType>(PointeeTy), SizeInBits, AlignInBits, AddressSpace,
-      StringRef(Name, NameLen)));
-}
-
-extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStructType(
-    LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
-    size_t NameLen, LLVMMetadataRef File, unsigned LineNumber,
-    uint64_t SizeInBits, uint32_t AlignInBits, LLVMDIFlags Flags,
-    LLVMMetadataRef DerivedFrom, LLVMMetadataRef Elements, unsigned RunTimeLang,
-    LLVMMetadataRef VTableHolder, const char *UniqueId, size_t UniqueIdLen) {
-  return wrap(unwrap(Builder)->createStructType(
-      unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen),
-      unwrapDI<DIFile>(File), LineNumber, SizeInBits, AlignInBits,
-      fromRust(Flags), unwrapDI<DIType>(DerivedFrom),
-      DINodeArray(unwrapDI<MDTuple>(Elements)), RunTimeLang,
-      unwrapDI<DIType>(VTableHolder), StringRef(UniqueId, UniqueIdLen)));
-}
-
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantPart(
     LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
     size_t NameLen, LLVMMetadataRef File, unsigned LineNumber,
@@ -1113,17 +1083,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantPart(
       StringRef(UniqueId, UniqueIdLen)));
 }
 
-extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMemberType(
-    LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
-    size_t NameLen, LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits,
-    uint32_t AlignInBits, uint64_t OffsetInBits, LLVMDIFlags Flags,
-    LLVMMetadataRef Ty) {
-  return wrap(unwrap(Builder)->createMemberType(
-      unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen),
-      unwrapDI<DIFile>(File), LineNo, SizeInBits, AlignInBits, OffsetInBits,
-      fromRust(Flags), unwrapDI<DIType>(Ty)));
-}
-
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantMemberType(
     LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
     size_t NameLen, LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits,
@@ -1139,23 +1098,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantMemberType(
       fromRust(Flags), unwrapDI<DIType>(Ty)));
 }
 
-extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticMemberType(
-    LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
-    size_t NameLen, LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty,
-    LLVMDIFlags Flags, LLVMValueRef val, uint32_t AlignInBits) {
-  return wrap(unwrap(Builder)->createStaticMemberType(
-      unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen),
-      unwrapDI<DIFile>(File), LineNo, unwrapDI<DIType>(Ty), fromRust(Flags),
-      unwrap<llvm::ConstantInt>(val), llvm::dwarf::DW_TAG_member, AlignInBits));
-}
-
-extern "C" LLVMMetadataRef
-LLVMRustDIBuilderCreateQualifiedType(LLVMDIBuilderRef Builder, unsigned Tag,
-                                     LLVMMetadataRef Type) {
-  return wrap(
-      unwrap(Builder)->createQualifiedType(Tag, unwrapDI<DIType>(Type)));
-}
-
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable(
     LLVMDIBuilderRef Builder, LLVMMetadataRef Context, const char *Name,
     size_t NameLen, const char *LinkageName, size_t LinkageNameLen,
@@ -1206,15 +1148,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariable(
 }
 
 extern "C" LLVMMetadataRef
-LLVMRustDIBuilderCreateArrayType(LLVMDIBuilderRef Builder, uint64_t Size,
-                                 uint32_t AlignInBits, LLVMMetadataRef Ty,
-                                 LLVMMetadataRef Subscripts) {
-  return wrap(unwrap(Builder)->createArrayType(
-      Size, AlignInBits, unwrapDI<DIType>(Ty),
-      DINodeArray(unwrapDI<MDTuple>(Subscripts))));
-}
-
-extern "C" LLVMMetadataRef
 LLVMRustDIBuilderGetOrCreateSubrange(LLVMDIBuilderRef Builder, int64_t Lo,
                                      int64_t Count) {
   return wrap(unwrap(Builder)->getOrCreateSubrange(Lo, Count));
@@ -1262,19 +1195,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerationType(
       /* RunTimeLang */ 0, "", IsScoped));
 }
 
-extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateUnionType(
-    LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
-    size_t NameLen, LLVMMetadataRef File, unsigned LineNumber,
-    uint64_t SizeInBits, uint32_t AlignInBits, LLVMDIFlags Flags,
-    LLVMMetadataRef Elements, unsigned RunTimeLang, const char *UniqueId,
-    size_t UniqueIdLen) {
-  return wrap(unwrap(Builder)->createUnionType(
-      unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen),
-      unwrapDI<DIFile>(File), LineNumber, SizeInBits, AlignInBits,
-      fromRust(Flags), DINodeArray(unwrapDI<MDTuple>(Elements)), RunTimeLang,
-      StringRef(UniqueId, UniqueIdLen)));
-}
-
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateTemplateTypeParameter(
     LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
     size_t NameLen, LLVMMetadataRef Ty) {
@@ -1453,60 +1373,6 @@ LLVMRustGetDiagInfoKind(LLVMDiagnosticInfoRef DI) {
   return toRust((DiagnosticKind)unwrap(DI)->getKind());
 }
 
-// This is kept distinct from LLVMGetTypeKind, because when
-// a new type kind is added, the Rust-side enum must be
-// updated or UB will result.
-extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) {
-  switch (unwrap(Ty)->getTypeID()) {
-  case Type::VoidTyID:
-    return LLVMVoidTypeKind;
-  case Type::HalfTyID:
-    return LLVMHalfTypeKind;
-  case Type::FloatTyID:
-    return LLVMFloatTypeKind;
-  case Type::DoubleTyID:
-    return LLVMDoubleTypeKind;
-  case Type::X86_FP80TyID:
-    return LLVMX86_FP80TypeKind;
-  case Type::FP128TyID:
-    return LLVMFP128TypeKind;
-  case Type::PPC_FP128TyID:
-    return LLVMPPC_FP128TypeKind;
-  case Type::LabelTyID:
-    return LLVMLabelTypeKind;
-  case Type::MetadataTyID:
-    return LLVMMetadataTypeKind;
-  case Type::IntegerTyID:
-    return LLVMIntegerTypeKind;
-  case Type::FunctionTyID:
-    return LLVMFunctionTypeKind;
-  case Type::StructTyID:
-    return LLVMStructTypeKind;
-  case Type::ArrayTyID:
-    return LLVMArrayTypeKind;
-  case Type::PointerTyID:
-    return LLVMPointerTypeKind;
-  case Type::FixedVectorTyID:
-    return LLVMVectorTypeKind;
-  case Type::TokenTyID:
-    return LLVMTokenTypeKind;
-  case Type::ScalableVectorTyID:
-    return LLVMScalableVectorTypeKind;
-  case Type::BFloatTyID:
-    return LLVMBFloatTypeKind;
-  case Type::X86_AMXTyID:
-    return LLVMX86_AMXTypeKind;
-  default: {
-    std::string error;
-    auto stream = llvm::raw_string_ostream(error);
-    stream << "Rust does not support the TypeID: " << unwrap(Ty)->getTypeID()
-           << " for the type: " << *unwrap(Ty);
-    stream.flush();
-    report_fatal_error(error.c_str());
-  }
-  }
-}
-
 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SMDiagnostic, LLVMSMDiagnosticRef)
 
 extern "C" LLVMSMDiagnosticRef LLVMRustGetSMDiagnostic(LLVMDiagnosticInfoRef DI,
@@ -1986,29 +1852,3 @@ extern "C" void LLVMRustSetNoSanitizeHWAddress(LLVMValueRef Global) {
   MD.NoHWAddress = true;
   GV.setSanitizerMetadata(MD);
 }
-
-enum class LLVMRustTailCallKind {
-  None = 0,
-  Tail = 1,
-  MustTail = 2,
-  NoTail = 3
-};
-
-extern "C" void LLVMRustSetTailCallKind(LLVMValueRef Call,
-                                        LLVMRustTailCallKind Kind) {
-  CallInst *CI = unwrap<CallInst>(Call);
-  switch (Kind) {
-  case LLVMRustTailCallKind::None:
-    CI->setTailCallKind(CallInst::TCK_None);
-    break;
-  case LLVMRustTailCallKind::Tail:
-    CI->setTailCallKind(CallInst::TCK_Tail);
-    break;
-  case LLVMRustTailCallKind::MustTail:
-    CI->setTailCallKind(CallInst::TCK_MustTail);
-    break;
-  case LLVMRustTailCallKind::NoTail:
-    CI->setTailCallKind(CallInst::TCK_NoTail);
-    break;
-  }
-}
diff --git a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp
index a910e78d489..fccfff65cfc 100644
--- a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp
@@ -103,14 +103,14 @@ LLVMRustGetSymbols(char *BufPtr, size_t BufLen, void *State,
 #define TRUE_PTR (void *)1
 #define FALSE_PTR (void *)0
 
-extern "C" bool LLVMRustIs64BitSymbolicFile(char *BufPtr, size_t BufLen) {
+bool withBufferAsSymbolicFile(
+    char *BufPtr, size_t BufLen,
+    std::function<bool(object::SymbolicFile &)> Callback) {
   std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(
       StringRef(BufPtr, BufLen), StringRef("LLVMRustGetSymbolsObject"), false);
   SmallString<0> SymNameBuf;
   auto SymName = raw_svector_ostream(SymNameBuf);
 
-  // Code starting from this line is copied from s64BitSymbolicFile in
-  // ArchiveWriter.cpp.
   // In the scenario when LLVMContext is populated SymbolicFile will contain a
   // reference to it, thus SymbolicFile should be destroyed first.
   LLVMContext Context;
@@ -120,48 +120,63 @@ extern "C" bool LLVMRustIs64BitSymbolicFile(char *BufPtr, size_t BufLen) {
     return false;
   }
   std::unique_ptr<object::SymbolicFile> Obj = std::move(*ObjOrErr);
-
-  return Obj != nullptr ? Obj->is64Bit() : false;
-}
-
-extern "C" bool LLVMRustIsECObject(char *BufPtr, size_t BufLen) {
-  std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(
-      StringRef(BufPtr, BufLen), StringRef("LLVMRustGetSymbolsObject"), false);
-  SmallString<0> SymNameBuf;
-  auto SymName = raw_svector_ostream(SymNameBuf);
-
-  // In the scenario when LLVMContext is populated SymbolicFile will contain a
-  // reference to it, thus SymbolicFile should be destroyed first.
-  LLVMContext Context;
-  Expected<std::unique_ptr<object::SymbolicFile>> ObjOrErr =
-      getSymbolicFile(Buf->getMemBufferRef(), Context);
-  if (!ObjOrErr) {
-    return false;
-  }
-  std::unique_ptr<object::SymbolicFile> Obj = std::move(*ObjOrErr);
-
   if (Obj == nullptr) {
     return false;
   }
+  return Callback(*Obj);
+}
 
-  // Code starting from this line is copied from isECObject in
-  // ArchiveWriter.cpp with an extra #if to work with LLVM 17.
-  if (Obj->isCOFF())
-    return cast<llvm::object::COFFObjectFile>(&*Obj)->getMachine() !=
-           COFF::IMAGE_FILE_MACHINE_ARM64;
-
-  if (Obj->isCOFFImportFile())
-    return cast<llvm::object::COFFImportFile>(&*Obj)->getMachine() !=
-           COFF::IMAGE_FILE_MACHINE_ARM64;
-
-  if (Obj->isIR()) {
-    Expected<std::string> TripleStr =
-        getBitcodeTargetTriple(Obj->getMemoryBufferRef());
-    if (!TripleStr)
-      return false;
-    Triple T(*TripleStr);
-    return T.isWindowsArm64EC() || T.getArch() == Triple::x86_64;
-  }
+extern "C" bool LLVMRustIs64BitSymbolicFile(char *BufPtr, size_t BufLen) {
+  return withBufferAsSymbolicFile(
+      BufPtr, BufLen, [](object::SymbolicFile &Obj) { return Obj.is64Bit(); });
+}
+
+extern "C" bool LLVMRustIsECObject(char *BufPtr, size_t BufLen) {
+  return withBufferAsSymbolicFile(
+      BufPtr, BufLen, [](object::SymbolicFile &Obj) {
+        // Code starting from this line is copied from isECObject in
+        // ArchiveWriter.cpp with an extra #if to work with LLVM 17.
+        if (Obj.isCOFF())
+          return cast<llvm::object::COFFObjectFile>(&Obj)->getMachine() !=
+                 COFF::IMAGE_FILE_MACHINE_ARM64;
+
+        if (Obj.isCOFFImportFile())
+          return cast<llvm::object::COFFImportFile>(&Obj)->getMachine() !=
+                 COFF::IMAGE_FILE_MACHINE_ARM64;
+
+        if (Obj.isIR()) {
+          Expected<std::string> TripleStr =
+              getBitcodeTargetTriple(Obj.getMemoryBufferRef());
+          if (!TripleStr)
+            return false;
+          Triple T(*TripleStr);
+          return T.isWindowsArm64EC() || T.getArch() == Triple::x86_64;
+        }
+
+        return false;
+      });
+}
 
-  return false;
+extern "C" bool LLVMRustIsAnyArm64Coff(char *BufPtr, size_t BufLen) {
+  return withBufferAsSymbolicFile(
+      BufPtr, BufLen, [](object::SymbolicFile &Obj) {
+        // Code starting from this line is copied from isAnyArm64COFF in
+        // ArchiveWriter.cpp.
+        if (Obj.isCOFF())
+          return COFF::isAnyArm64(cast<COFFObjectFile>(&Obj)->getMachine());
+
+        if (Obj.isCOFFImportFile())
+          return COFF::isAnyArm64(cast<COFFImportFile>(&Obj)->getMachine());
+
+        if (Obj.isIR()) {
+          Expected<std::string> TripleStr =
+              getBitcodeTargetTriple(Obj.getMemoryBufferRef());
+          if (!TripleStr)
+            return false;
+          Triple T(*TripleStr);
+          return T.isOSWindows() && T.getArch() == Triple::aarch64;
+        }
+
+        return false;
+      });
 }