about summary refs log tree commit diff
path: root/compiler/rustc_llvm
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_llvm')
-rw-r--r--compiler/rustc_llvm/Cargo.toml10
-rw-r--r--compiler/rustc_llvm/build.rs17
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp208
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp65
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp54
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp109
6 files changed, 99 insertions, 364 deletions
diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml
index 061562b2ec5..cd352ce3d0f 100644
--- a/compiler/rustc_llvm/Cargo.toml
+++ b/compiler/rustc_llvm/Cargo.toml
@@ -10,7 +10,13 @@ libc = "0.2.73"
 
 [build-dependencies]
 # tidy-alphabetical-start
-# Pinned so `cargo update` bumps don't cause breakage. Please also update the
-# pinned `cc` in `rustc_codegen_ssa` if you update `cc` here.
+# `cc` updates often break things, so we pin it here. Cargo enforces "max 1 semver-compat version
+# per crate", so if you change this, you need to also change it in `rustc_codegen_ssa`.
 cc = "=1.2.16"
 # tidy-alphabetical-end
+
+[features]
+# tidy-alphabetical-start
+# Used by ./x.py check --compile-time-deps to skip building C++ code
+check_only = []
+# tidy-alphabetical-end
diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs
index 9a6549379d3..d01f79dcade 100644
--- a/compiler/rustc_llvm/build.rs
+++ b/compiler/rustc_llvm/build.rs
@@ -106,6 +106,10 @@ fn output(cmd: &mut Command) -> String {
 }
 
 fn main() {
+    if cfg!(feature = "check_only") {
+        return;
+    }
+
     for component in REQUIRED_COMPONENTS.iter().chain(OPTIONAL_COMPONENTS.iter()) {
         println!("cargo:rustc-check-cfg=cfg(llvm_component,values(\"{component}\"))");
     }
@@ -167,6 +171,16 @@ fn main() {
     let cxxflags = output(&mut cmd);
     let mut cfg = cc::Build::new();
     cfg.warnings(false);
+
+    // Prevent critical warnings when we're compiling from rust-lang/rust CI,
+    // except on MSVC, as the compiler throws warnings that are only reported
+    // for this platform. See https://github.com/rust-lang/rust/pull/145031#issuecomment-3162677202
+    // FIXME(llvm22): It looks like the specific problem code has been removed
+    // in https://github.com/llvm/llvm-project/commit/e8fc808bf8e78a3c80d1f8e293a92677b92366dd,
+    // retry msvc once we bump our LLVM version.
+    if std::env::var_os("CI").is_some() && !target.contains("msvc") {
+        cfg.warnings_into_errors(true);
+    }
     for flag in cxxflags.split_whitespace() {
         // Ignore flags like `-m64` when we're doing a cross build
         if is_crossed && flag.starts_with("-m") {
@@ -212,7 +226,6 @@ fn main() {
     rerun_if_changed_anything_in_dir(Path::new("llvm-wrapper"));
     cfg.file("llvm-wrapper/PassWrapper.cpp")
         .file("llvm-wrapper/RustWrapper.cpp")
-        .file("llvm-wrapper/ArchiveWrapper.cpp")
         .file("llvm-wrapper/CoverageMappingWrapper.cpp")
         .file("llvm-wrapper/SymbolWrapper.cpp")
         .file("llvm-wrapper/Linker.cpp")
@@ -241,7 +254,7 @@ fn main() {
         println!("cargo:rustc-link-lib=kstat");
     }
 
-    if (target.starts_with("arm") && !target.contains("freebsd")) && !target.contains("ohos")
+    if (target.starts_with("arm") && !target.contains("freebsd") && !target.contains("ohos"))
         || target.starts_with("mips-")
         || target.starts_with("mipsel-")
         || target.starts_with("powerpc-")
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/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
index 4695de8ea09..22e7c7a160f 100644
--- a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
@@ -37,28 +37,6 @@ static coverage::Counter fromRust(LLVMRustCounter Counter) {
   report_fatal_error("Bad LLVMRustCounterKind!");
 }
 
-struct LLVMRustMCDCDecisionParameters {
-  uint32_t BitmapIdx;
-  uint16_t NumConditions;
-};
-
-struct LLVMRustMCDCBranchParameters {
-  int16_t ConditionID;
-  int16_t ConditionIDs[2];
-};
-
-static coverage::mcdc::BranchParameters
-fromRust(LLVMRustMCDCBranchParameters Params) {
-  return coverage::mcdc::BranchParameters(
-      Params.ConditionID, {Params.ConditionIDs[0], Params.ConditionIDs[1]});
-}
-
-static coverage::mcdc::DecisionParameters
-fromRust(LLVMRustMCDCDecisionParameters Params) {
-  return coverage::mcdc::DecisionParameters(Params.BitmapIdx,
-                                            Params.NumConditions);
-}
-
 // Must match the layout of
 // `rustc_codegen_llvm::coverageinfo::ffi::CoverageSpan`.
 struct LLVMRustCoverageSpan {
@@ -90,22 +68,6 @@ struct LLVMRustCoverageBranchRegion {
   LLVMRustCounter FalseCount;
 };
 
-// Must match the layout of
-// `rustc_codegen_llvm::coverageinfo::ffi::MCDCBranchRegion`.
-struct LLVMRustCoverageMCDCBranchRegion {
-  LLVMRustCoverageSpan Span;
-  LLVMRustCounter TrueCount;
-  LLVMRustCounter FalseCount;
-  LLVMRustMCDCBranchParameters MCDCBranchParams;
-};
-
-// Must match the layout of
-// `rustc_codegen_llvm::coverageinfo::ffi::MCDCDecisionRegion`.
-struct LLVMRustCoverageMCDCDecisionRegion {
-  LLVMRustCoverageSpan Span;
-  LLVMRustMCDCDecisionParameters MCDCDecisionParams;
-};
-
 // FFI equivalent of enum `llvm::coverage::CounterExpression::ExprKind`
 // https://github.com/rust-lang/llvm-project/blob/ea6fa9c2/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L154
 enum class LLVMRustCounterExprKind {
@@ -159,10 +121,7 @@ extern "C" void LLVMRustCoverageWriteFunctionMappingsToBuffer(
     const LLVMRustCoverageExpansionRegion *ExpansionRegions,
     size_t NumExpansionRegions,
     const LLVMRustCoverageBranchRegion *BranchRegions, size_t NumBranchRegions,
-    const LLVMRustCoverageMCDCBranchRegion *MCDCBranchRegions,
-    size_t NumMCDCBranchRegions,
-    const LLVMRustCoverageMCDCDecisionRegion *MCDCDecisionRegions,
-    size_t NumMCDCDecisionRegions, RustStringRef BufferOut) {
+    RustStringRef BufferOut) {
   // Convert from FFI representation to LLVM representation.
 
   // Expressions:
@@ -176,8 +135,8 @@ extern "C" void LLVMRustCoverageWriteFunctionMappingsToBuffer(
   }
 
   std::vector<coverage::CounterMappingRegion> MappingRegions;
-  MappingRegions.reserve(NumCodeRegions + NumBranchRegions +
-                         NumMCDCBranchRegions + NumMCDCDecisionRegions);
+  MappingRegions.reserve(NumCodeRegions + NumExpansionRegions +
+                         NumBranchRegions);
 
   // Code regions:
   for (const auto &Region : ArrayRef(CodeRegions, NumCodeRegions)) {
@@ -201,24 +160,6 @@ extern "C" void LLVMRustCoverageWriteFunctionMappingsToBuffer(
         Region.Span.LineEnd, Region.Span.ColumnEnd));
   }
 
-  // MC/DC branch regions:
-  for (const auto &Region : ArrayRef(MCDCBranchRegions, NumMCDCBranchRegions)) {
-    MappingRegions.push_back(coverage::CounterMappingRegion::makeBranchRegion(
-        fromRust(Region.TrueCount), fromRust(Region.FalseCount),
-        Region.Span.FileID, Region.Span.LineStart, Region.Span.ColumnStart,
-        Region.Span.LineEnd, Region.Span.ColumnEnd,
-        fromRust(Region.MCDCBranchParams)));
-  }
-
-  // MC/DC decision regions:
-  for (const auto &Region :
-       ArrayRef(MCDCDecisionRegions, NumMCDCDecisionRegions)) {
-    MappingRegions.push_back(coverage::CounterMappingRegion::makeDecisionRegion(
-        fromRust(Region.MCDCDecisionParams), Region.Span.FileID,
-        Region.Span.LineStart, Region.Span.ColumnStart, Region.Span.LineEnd,
-        Region.Span.ColumnEnd));
-  }
-
   // Write the converted expressions and mappings to a byte buffer.
   auto CoverageMappingWriter = coverage::CoverageMappingWriter(
       ArrayRef<unsigned>(VirtualFileMappingIDs, NumVirtualFileMappingIDs),
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index d4a05fbbbc5..8c34052770e 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -396,7 +396,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
     bool EmitStackSizeSection, bool RelaxELFRelocations, bool UseInitArray,
     const char *SplitDwarfFile, const char *OutputObjFile,
     const char *DebugInfoCompression, bool UseEmulatedTls,
-    const char *ArgsCstrBuff, size_t ArgsCstrBuffLen) {
+    const char *ArgsCstrBuff, size_t ArgsCstrBuffLen, bool UseWasmEH) {
 
   auto OptLevel = fromRust(RustOptLevel);
   auto RM = fromRust(RustReloc);
@@ -462,6 +462,9 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
     Options.ThreadModel = ThreadModel::Single;
   }
 
+  if (UseWasmEH)
+    Options.ExceptionModel = ExceptionHandling::Wasm;
+
   Options.EmitStackSizeSection = EmitStackSizeSection;
 
   if (ArgsCstrBuff != nullptr) {
@@ -700,6 +703,10 @@ struct LLVMRustSanitizerOptions {
 #ifdef ENZYME
 extern "C" void registerEnzymeAndPassPipeline(llvm::PassBuilder &PB,
                                               /* augmentPassBuilder */ bool);
+
+extern "C" {
+extern llvm::cl::opt<std::string> EnzymeFunctionToAnalyze;
+}
 #endif
 
 extern "C" LLVMRustResult LLVMRustOptimize(
@@ -1069,6 +1076,15 @@ extern "C" LLVMRustResult LLVMRustOptimize(
       return LLVMRustResult::Failure;
     }
 
+    // Check if PrintTAFn was used and add type analysis pass if needed
+    if (!EnzymeFunctionToAnalyze.empty()) {
+      if (auto Err = PB.parsePassPipeline(MPM, "print-type-analysis")) {
+        std::string ErrMsg = toString(std::move(Err));
+        LLVMRustSetLastError(ErrMsg.c_str());
+        return LLVMRustResult::Failure;
+      }
+    }
+
     if (PrintAfterEnzyme) {
       // Handle the Rust flag `-Zautodiff=PrintModAfter`.
       std::string Banner = "Module after EnzymeNewPM";
@@ -1275,7 +1291,7 @@ extern "C" void LLVMRustSetModuleCodeModel(LLVMModuleRef M,
 //
 // Otherwise I'll apologize in advance, it probably requires a relatively
 // significant investment on your part to "truly understand" what's going on
-// here. Not saying I do myself, but it took me awhile staring at LLVM's source
+// here. Not saying I do myself, but it took me a while staring at LLVM's source
 // and various online resources about ThinLTO to make heads or tails of all
 // this.
 
@@ -1634,40 +1650,6 @@ extern "C" LLVMModuleRef LLVMRustParseBitcodeForLTO(LLVMContextRef Context,
   return wrap(std::move(*SrcOrError).release());
 }
 
-// Find a section of an object file by name. Fail if the section is missing or
-// empty.
-extern "C" const char *LLVMRustGetSliceFromObjectDataByName(const char *data,
-                                                            size_t len,
-                                                            const char *name,
-                                                            size_t name_len,
-                                                            size_t *out_len) {
-  *out_len = 0;
-  auto Name = StringRef(name, name_len);
-  auto Data = StringRef(data, len);
-  auto Buffer = MemoryBufferRef(Data, ""); // The id is unused.
-  file_magic Type = identify_magic(Buffer.getBuffer());
-  Expected<std::unique_ptr<object::ObjectFile>> ObjFileOrError =
-      object::ObjectFile::createObjectFile(Buffer, Type);
-  if (!ObjFileOrError) {
-    LLVMRustSetLastError(toString(ObjFileOrError.takeError()).c_str());
-    return nullptr;
-  }
-  for (const object::SectionRef &Sec : (*ObjFileOrError)->sections()) {
-    Expected<StringRef> SecName = Sec.getName();
-    if (SecName && *SecName == Name) {
-      Expected<StringRef> SectionOrError = Sec.getContents();
-      if (!SectionOrError) {
-        LLVMRustSetLastError(toString(SectionOrError.takeError()).c_str());
-        return nullptr;
-      }
-      *out_len = SectionOrError->size();
-      return SectionOrError->data();
-    }
-  }
-  LLVMRustSetLastError("could not find requested section");
-  return nullptr;
-}
-
 // Computes the LTO cache key for the provided 'ModId' in the given 'Data',
 // storing the result in 'KeyOut'.
 // Currently, this cache key is a SHA-1 hash of anything that could affect
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 90aa9188c83..cce40da354d 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -277,6 +277,8 @@ enum class LLVMRustAttributeKind {
   FnRetThunkExtern = 41,
   Writable = 42,
   DeadOnUnwind = 43,
+  DeadOnReturn = 44,
+  CapturesReadOnly = 45,
 };
 
 static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) {
@@ -369,6 +371,14 @@ 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::CapturesReadOnly:
+    report_fatal_error("Should be handled separately");
   }
   report_fatal_error("bad LLVMRustAttributeKind");
 }
@@ -423,6 +433,11 @@ LLVMRustCreateAttrNoValue(LLVMContextRef C, LLVMRustAttributeKind RustAttr) {
   if (RustAttr == LLVMRustAttributeKind::NoCapture) {
     return wrap(Attribute::getWithCaptureInfo(*unwrap(C), CaptureInfo::none()));
   }
+  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 +488,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);
 }
@@ -1453,60 +1471,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,
@@ -1591,12 +1555,49 @@ extern "C" LLVMValueRef LLVMRustBuildMemSet(LLVMBuilderRef B, LLVMValueRef Dst,
                                       MaybeAlign(DstAlign), IsVolatile));
 }
 
+extern "C" void LLVMRustPositionBuilderPastAllocas(LLVMBuilderRef B,
+                                                   LLVMValueRef Fn) {
+  Function *F = unwrap<Function>(Fn);
+  unwrap(B)->SetInsertPointPastAllocas(F);
+}
 extern "C" void LLVMRustPositionBuilderAtStart(LLVMBuilderRef B,
                                                LLVMBasicBlockRef BB) {
   auto Point = unwrap(BB)->getFirstInsertionPt();
   unwrap(B)->SetInsertPoint(unwrap(BB), Point);
 }
 
+extern "C" void LLVMRustPositionBefore(LLVMBuilderRef B, LLVMValueRef Instr) {
+  if (auto I = dyn_cast<Instruction>(unwrap<Value>(Instr))) {
+    unwrap(B)->SetInsertPoint(I);
+  }
+}
+
+extern "C" void LLVMRustPositionAfter(LLVMBuilderRef B, LLVMValueRef Instr) {
+  if (auto I = dyn_cast<Instruction>(unwrap<Value>(Instr))) {
+    auto J = I->getNextNode();
+    unwrap(B)->SetInsertPoint(J);
+  }
+}
+
+extern "C" LLVMValueRef
+LLVMRustGetFunctionCall(LLVMValueRef Fn, const char *Name, size_t NameLen) {
+  auto targetName = StringRef(Name, NameLen);
+  Function *F = unwrap<Function>(Fn);
+  for (auto &BB : *F) {
+    for (auto &I : BB) {
+      if (auto *callInst = llvm::dyn_cast<llvm::CallBase>(&I)) {
+        const llvm::Function *calledFunc = callInst->getCalledFunction();
+        if (calledFunc && calledFunc->getName() == targetName) {
+          // Found a call to the target function
+          return wrap(callInst);
+        }
+      }
+    }
+  }
+
+  return nullptr;
+}
+
 extern "C" bool LLVMRustConstIntGetZExtValue(LLVMValueRef CV, uint64_t *value) {
   auto C = unwrap<llvm::ConstantInt>(CV);
   if (C->getBitWidth() > 64)