Auto merge of #153684 - cuviper:min-llvm-21, r=nikic

Update the minimum external LLVM to 21

With this change, we'll have stable support for LLVM 21 and 22.
For reference, the previous increase to LLVM 20 was rust-lang/rust#145071.

cc @rust-lang/wg-llvm
r? nikic
This commit is contained in:
bors
2026-03-13 10:36:35 +00:00
38 changed files with 68 additions and 339 deletions
+11 -16
View File
@@ -23,7 +23,6 @@
use crate::builder::Builder;
use crate::context::CodegenCx;
use crate::llvm::{self, Attribute, AttributePlace, Type, Value};
use crate::llvm_util;
use crate::type_of::LayoutLlvmExt;
trait ArgAttributesExt {
@@ -46,6 +45,12 @@ fn apply_attrs_to_callsite(
(ArgAttribute::NoUndef, llvm::AttributeKind::NoUndef),
];
const CAPTURES_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 3] = [
(ArgAttribute::CapturesNone, llvm::AttributeKind::CapturesNone),
(ArgAttribute::CapturesAddress, llvm::AttributeKind::CapturesAddress),
(ArgAttribute::CapturesReadOnly, llvm::AttributeKind::CapturesReadOnly),
];
fn get_attrs<'ll>(this: &ArgAttributes, cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'ll Attribute; 8]> {
let mut regular = this.regular;
@@ -82,18 +87,10 @@ fn apply_attrs_to_callsite(
attrs.push(llattr.create_attr(cx.llcx));
}
}
// captures(...) is only available since LLVM 21.
if (21, 0, 0) <= llvm_util::get_version() {
const CAPTURES_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 3] = [
(ArgAttribute::CapturesNone, llvm::AttributeKind::CapturesNone),
(ArgAttribute::CapturesAddress, llvm::AttributeKind::CapturesAddress),
(ArgAttribute::CapturesReadOnly, llvm::AttributeKind::CapturesReadOnly),
];
for (attr, llattr) in CAPTURES_ATTRIBUTES {
if regular.contains(attr) {
attrs.push(llattr.create_attr(cx.llcx));
break;
}
for (attr, llattr) in CAPTURES_ATTRIBUTES {
if regular.contains(attr) {
attrs.push(llattr.create_attr(cx.llcx));
break;
}
}
} else if cx.tcx.sess.sanitizers().contains(SanitizerSet::MEMORY) {
@@ -508,9 +505,7 @@ fn apply_attrs_llfn(
}
PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => {
let i = apply(attrs);
if cx.sess().opts.optimize != config::OptLevel::No
&& llvm_util::get_version() >= (21, 0, 0)
{
if cx.sess().opts.optimize != config::OptLevel::No {
attributes::apply_to_llfn(
llfn,
llvm::AttributePlace::Argument(i),
@@ -506,15 +506,11 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
to_add.push(llvm::CreateAllocKindAttr(cx.llcx, AllocKindFlags::Free));
// applies to argument place instead of function place
let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx);
let attrs: &[_] = if llvm_util::get_version() >= (21, 0, 0) {
// "Does not capture provenance" means "if the function call stashes the pointer somewhere,
// accessing that pointer after the function returns is UB". That is definitely the case here since
// freeing will destroy the provenance.
let captures_addr = AttributeKind::CapturesAddress.create_attr(cx.llcx);
&[allocated_pointer, captures_addr]
} else {
&[allocated_pointer]
};
// "Does not capture provenance" means "if the function call stashes the pointer somewhere,
// accessing that pointer after the function returns is UB". That is definitely the case here since
// freeing will destroy the provenance.
let captures_addr = AttributeKind::CapturesAddress.create_attr(cx.llcx);
let attrs = &[allocated_pointer, captures_addr];
attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), attrs);
}
if let Some(align) = codegen_fn_attrs.alignment {
@@ -190,17 +190,6 @@ pub(crate) unsafe fn create_module<'ll>(
let mut target_data_layout = sess.target.data_layout.to_string();
let llvm_version = llvm_util::get_version();
if llvm_version < (21, 0, 0) {
if sess.target.arch == Arch::Nvptx64 {
// LLVM 21 updated the default layout on nvptx: https://github.com/llvm/llvm-project/pull/124961
target_data_layout = target_data_layout.replace("e-p6:32:32-i64", "e-i64");
}
if sess.target.arch == Arch::AmdGpu {
// LLVM 21 adds the address width for address space 8.
// See https://github.com/llvm/llvm-project/pull/139419
target_data_layout = target_data_layout.replace("p8:128:128:128:48", "p8:128:128")
}
}
if llvm_version < (22, 0, 0) {
if sess.target.arch == Arch::Avr {
// LLVM 22.0 updated the default layout on avr: https://github.com/llvm/llvm-project/pull/153010
@@ -342,11 +331,6 @@ pub(crate) unsafe fn create_module<'ll>(
// Add "kcfi-arity" module flag if KCFI arity indicator is enabled. (See
// https://github.com/llvm/llvm-project/pull/117121.)
if sess.is_sanitizer_kcfi_arity_enabled() {
// KCFI arity indicator requires LLVM 21.0.0 or later.
if llvm_version < (21, 0, 0) {
tcx.dcx().emit_err(crate::errors::SanitizerKcfiArityRequiresLLVM2100);
}
llvm::add_module_flag_u32(
llmod,
llvm::ModuleFlagMergeBehavior::Override,
@@ -204,7 +204,3 @@ pub(crate) struct MismatchedDataLayout<'a> {
pub(crate) struct FixedX18InvalidArch<'a> {
pub arch: &'a str,
}
#[derive(Diagnostic)]
#[diag("`-Zsanitizer-kcfi-arity` requires LLVM 21.0.0 or later")]
pub(crate) struct SanitizerKcfiArityRequiresLLVM2100;
@@ -254,10 +254,6 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
},
// Filter out features that are not supported by the current LLVM version
Arch::LoongArch32 | Arch::LoongArch64 => match s {
"32s" if major < 21 => None,
s => Some(LLVMFeature::new(s)),
},
Arch::PowerPC | Arch::PowerPC64 => match s {
"power8-crypto" => Some(LLVMFeature::new("crypto")),
s => Some(LLVMFeature::new(s)),
@@ -372,23 +368,12 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) {
let (major, _, _) = version;
cfg.has_reliable_f16 = match (target_arch, target_os) {
// LLVM crash without neon <https://github.com/llvm/llvm-project/issues/129394> (fixed in LLVM 20.1.1)
(Arch::AArch64, _)
if !cfg.target_features.iter().any(|f| f.as_str() == "neon")
&& version < (20, 1, 1) =>
{
false
}
// Unsupported <https://github.com/llvm/llvm-project/issues/94434> (fixed in llvm22)
(Arch::Arm64EC, _) if major < 22 => false,
// Selection failure <https://github.com/llvm/llvm-project/issues/50374> (fixed in llvm21)
(Arch::S390x, _) if major < 21 => false,
// MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054>
(Arch::X86_64, Os::Windows) if *target_env == Env::Gnu && *target_abi != Abi::Llvm => false,
// Infinite recursion <https://github.com/llvm/llvm-project/issues/97981>
(Arch::CSky, _) if major < 22 => false, // (fixed in llvm22)
(Arch::Hexagon, _) if major < 21 => false, // (fixed in llvm21)
(Arch::LoongArch32 | Arch::LoongArch64, _) if major < 21 => false, // (fixed in llvm21)
(Arch::PowerPC | Arch::PowerPC64, _) if major < 22 => false, // (fixed in llvm22)
(Arch::Sparc | Arch::Sparc64, _) if major < 22 => false, // (fixed in llvm22)
(Arch::Wasm32 | Arch::Wasm64, _) if major < 22 => false, // (fixed in llvm22)
@@ -403,8 +388,6 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) {
(Arch::AmdGpu, _) => false,
// Unsupported <https://github.com/llvm/llvm-project/issues/94434>
(Arch::Arm64EC, _) => false,
// Selection bug <https://github.com/llvm/llvm-project/issues/96432> (fixed in LLVM 20.1.0)
(Arch::Mips64 | Arch::Mips64r6, _) if version < (20, 1, 0) => false,
// Selection bug <https://github.com/llvm/llvm-project/issues/95471>. This issue is closed
// but basic math still does not work.
(Arch::Nvptx64, _) => false,
@@ -413,9 +396,6 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) {
(Arch::PowerPC | Arch::PowerPC64, _) => false,
// ABI unsupported <https://github.com/llvm/llvm-project/issues/41838>
(Arch::Sparc, _) => false,
// Stack alignment bug <https://github.com/llvm/llvm-project/issues/77401>. NB: tests may
// not fail if our compiler-builtins is linked. (fixed in llvm21)
(Arch::X86, _) if major < 21 => false,
// MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054>
(Arch::X86_64, Os::Windows) if *target_env == Env::Gnu && *target_abi != Abi::Llvm => false,
// There are no known problems on other platforms, so the only requirement is that symbols
@@ -301,12 +301,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
std::string Error;
auto Trip = Triple(Triple::normalize(TripleStr));
const llvm::Target *TheTarget =
#if LLVM_VERSION_GE(21, 0)
TargetRegistry::lookupTarget(Trip, Error);
#else
TargetRegistry::lookupTarget(Trip.getTriple(), Error);
#endif
const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Trip, Error);
if (TheTarget == nullptr) {
LLVMRustSetLastError(Error.c_str());
return nullptr;
@@ -367,13 +362,8 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
Options.EmitStackSizeSection = EmitStackSizeSection;
#if LLVM_VERSION_GE(21, 0)
TargetMachine *TM = TheTarget->createTargetMachine(Trip, CPU, Feature,
Options, RM, CM, OptLevel);
#else
TargetMachine *TM = TheTarget->createTargetMachine(
Trip.getTriple(), CPU, Feature, Options, RM, CM, OptLevel);
#endif
if (LargeDataThreshold != 0) {
TM->setLargeDataThreshold(LargeDataThreshold);
@@ -701,12 +691,8 @@ extern "C" LLVMRustResult LLVMRustOptimize(
if (LintIR) {
PipelineStartEPCallbacks.push_back([](ModulePassManager &MPM,
OptimizationLevel Level) {
#if LLVM_VERSION_GE(21, 0)
MPM.addPass(
createModuleToFunctionPassAdaptor(LintPass(/*AbortOnError=*/true)));
#else
MPM.addPass(createModuleToFunctionPassAdaptor(LintPass()));
#endif
});
}
@@ -1210,12 +1196,8 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, size_t num_modules,
// Convert the preserved symbols set from string to GUID, this is then needed
// for internalization.
for (size_t i = 0; i < num_symbols; i++) {
#if LLVM_VERSION_GE(21, 0)
auto GUID =
GlobalValue::getGUIDAssumingExternalLinkage(preserved_symbols[i]);
#else
auto GUID = GlobalValue::getGUID(preserved_symbols[i]);
#endif
Ret->GUIDPreservedSymbols.insert(GUID);
}
@@ -1474,21 +1456,12 @@ extern "C" void LLVMRustComputeLTOCacheKey(RustStringRef KeyOut,
DenseSet<GlobalValue::GUID> CfiFunctionDecls;
// Based on the 'InProcessThinBackend' constructor in LLVM
#if LLVM_VERSION_GE(21, 0)
for (auto &Name : Data->Index.cfiFunctionDefs().symbols())
CfiFunctionDefs.insert(GlobalValue::getGUIDAssumingExternalLinkage(
GlobalValue::dropLLVMManglingEscape(Name)));
for (auto &Name : Data->Index.cfiFunctionDecls().symbols())
CfiFunctionDecls.insert(GlobalValue::getGUIDAssumingExternalLinkage(
GlobalValue::dropLLVMManglingEscape(Name)));
#else
for (auto &Name : Data->Index.cfiFunctionDefs())
CfiFunctionDefs.insert(
GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name)));
for (auto &Name : Data->Index.cfiFunctionDecls())
CfiFunctionDecls.insert(
GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name)));
#endif
Key = llvm::computeLTOCacheKey(conf, Data->Index, ModId, ImportList,
ExportList, ResolvedODR, DefinedGlobals,
@@ -137,11 +137,7 @@ extern "C" void LLVMRustSetLastError(const char *Err) {
extern "C" void LLVMRustSetNormalizedTarget(LLVMModuleRef M,
const char *Target) {
#if LLVM_VERSION_GE(21, 0)
unwrap(M)->setTargetTriple(Triple(Triple::normalize(Target)));
#else
unwrap(M)->setTargetTriple(Triple::normalize(Target));
#endif
}
extern "C" void LLVMRustPrintPassTimings(RustStringRef OutBuf) {
@@ -452,11 +448,7 @@ static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) {
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:
case LLVMRustAttributeKind::CapturesNone:
@@ -514,7 +506,6 @@ extern "C" void LLVMRustEraseInstFromParent(LLVMValueRef Instr) {
extern "C" LLVMAttributeRef
LLVMRustCreateAttrNoValue(LLVMContextRef C, LLVMRustAttributeKind RustAttr) {
#if LLVM_VERSION_GE(21, 0)
if (RustAttr == LLVMRustAttributeKind::CapturesNone) {
return wrap(Attribute::getWithCaptureInfo(*unwrap(C), CaptureInfo::none()));
}
@@ -527,7 +518,6 @@ LLVMRustCreateAttrNoValue(LLVMContextRef C, LLVMRustAttributeKind RustAttr) {
*unwrap(C), CaptureInfo(CaptureComponents::Address |
CaptureComponents::ReadProvenance)));
}
#endif
#if LLVM_VERSION_GE(23, 0)
if (RustAttr == LLVMRustAttributeKind::DeadOnReturn) {
return wrap(Attribute::getWithDeadOnReturnInfo(*unwrap(C),
+2 -2
View File
@@ -631,11 +631,11 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) {
let version = get_llvm_version(builder, llvm_config);
let mut parts = version.split('.').take(2).filter_map(|s| s.parse::<u32>().ok());
if let (Some(major), Some(_minor)) = (parts.next(), parts.next())
&& major >= 20
&& major >= 21
{
return;
}
panic!("\n\nbad LLVM version: {version}, need >=20\n\n")
panic!("\n\nbad LLVM version: {version}, need >=21\n\n")
}
fn configure_cmake(
+4 -4
View File
@@ -14,9 +14,9 @@ To run a specific CI job locally, you can use the `citool` Rust crate:
cargo run --manifest-path src/ci/citool/Cargo.toml run-local <job-name>
```
For example, to run the `x86_64-gnu-llvm-20-1` job:
For example, to run the `x86_64-gnu-llvm-21-1` job:
```
cargo run --manifest-path src/ci/citool/Cargo.toml run-local x86_64-gnu-llvm-20-1
cargo run --manifest-path src/ci/citool/Cargo.toml run-local x86_64-gnu-llvm-21-1
```
The job will output artifacts in an `obj/<image-name>` dir at the root of a repository. Note
@@ -27,10 +27,10 @@ Docker image executed in the given CI job.
while locally, to the `obj/<image-name>` directory. This is primarily to prevent
strange linker errors when using multiple Docker images.
For some Linux workflows (for example `x86_64-gnu-llvm-20-N`), the process is more involved. You will need to see which script is executed for the given workflow inside the [`jobs.yml`](../github-actions/jobs.yml) file and pass it through the `DOCKER_SCRIPT` environment variable. For example, to reproduce the `x86_64-gnu-llvm-20-3` workflow, you can run the following script:
For some Linux workflows (for example `x86_64-gnu-llvm-21-N`), the process is more involved. You will need to see which script is executed for the given workflow inside the [`jobs.yml`](../github-actions/jobs.yml) file and pass it through the `DOCKER_SCRIPT` environment variable. For example, to reproduce the `x86_64-gnu-llvm-21-3` workflow, you can run the following script:
```
DOCKER_SCRIPT=x86_64-gnu-llvm3.sh ./src/ci/docker/run.sh x86_64-gnu-llvm-20
DOCKER_SCRIPT=x86_64-gnu-llvm3.sh ./src/ci/docker/run.sh x86_64-gnu-llvm-21
```
## Local Development
@@ -15,8 +15,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
cmake \
sudo \
gdb \
llvm-20-tools \
llvm-20-dev \
llvm-21-tools \
llvm-21-dev \
libedit-dev \
libssl-dev \
pkg-config \
@@ -42,7 +42,7 @@ ENV EXTERNAL_LLVM="1"
# Using llvm-link-shared due to libffi issues -- see #34486
ENV RUST_CONFIGURE_ARGS="--build=aarch64-unknown-linux-gnu \
--llvm-root=/usr/lib/llvm-20 \
--llvm-root=/usr/lib/llvm-21 \
--enable-llvm-link-shared \
--set rust.randomize-layout=true \
--set rust.thin-lto-import-instr-limit=10"
@@ -1,66 +0,0 @@
FROM ubuntu:25.04
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
bzip2 \
g++ \
gcc-multilib \
make \
ninja-build \
file \
curl \
ca-certificates \
python3 \
git \
cmake \
sudo \
gdb \
llvm-20-tools \
llvm-20-dev \
libedit-dev \
libssl-dev \
pkg-config \
zlib1g-dev \
xz-utils \
nodejs \
mingw-w64 \
# libgccjit dependencies
flex \
libmpfr-dev \
libgmp-dev \
libmpc3 \
libmpc-dev \
&& rm -rf /var/lib/apt/lists/*
# Install powershell (universal package) so we can test x.ps1 on Linux
# FIXME: need a "universal" version that supports libicu74, but for now it still works to ignore that dep.
RUN curl -sL "https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/powershell_7.3.1-1.deb_amd64.deb" > powershell.deb && \
dpkg --ignore-depends=libicu72 -i powershell.deb && \
rm -f powershell.deb
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
# We are disabling CI LLVM since this builder is intentionally using a host
# LLVM, rather than the typical src/llvm-project LLVM.
ENV NO_DOWNLOAD_CI_LLVM 1
ENV EXTERNAL_LLVM 1
# Using llvm-link-shared due to libffi issues -- see #34486
ENV RUST_CONFIGURE_ARGS \
--build=x86_64-unknown-linux-gnu \
--llvm-root=/usr/lib/llvm-20 \
--enable-llvm-link-shared \
--set rust.randomize-layout=true \
--set rust.thin-lto-import-instr-limit=10
COPY scripts/shared.sh /scripts/
COPY scripts/x86_64-gnu-llvm.sh /scripts/
COPY scripts/x86_64-gnu-llvm2.sh /scripts/
COPY scripts/x86_64-gnu-llvm3.sh /scripts/
COPY scripts/stage_2_test_set1.sh /scripts/
COPY scripts/stage_2_test_set2.sh /scripts/
ENV SCRIPT "Must specify DOCKER_SCRIPT for this image"
+5 -30
View File
@@ -122,19 +122,19 @@ pr:
# tidy. This speeds up the PR CI job by ~1 minute.
SKIP_SUBMODULES: src/gcc
<<: *job-linux-4c
- name: x86_64-gnu-llvm-20
- name: x86_64-gnu-llvm-21
env:
ENABLE_GCC_CODEGEN: "1"
DOCKER_SCRIPT: x86_64-gnu-llvm.sh
<<: *job-linux-4c
- name: aarch64-gnu-llvm-20-1
- name: aarch64-gnu-llvm-21-1
env:
IMAGE: aarch64-gnu-llvm-20
IMAGE: aarch64-gnu-llvm-21
DOCKER_SCRIPT: stage_2_test_set1.sh
<<: *job-aarch64-linux
- name: aarch64-gnu-llvm-20-2
- name: aarch64-gnu-llvm-21-2
env:
IMAGE: aarch64-gnu-llvm-20
IMAGE: aarch64-gnu-llvm-21
DOCKER_SCRIPT: stage_2_test_set2.sh
<<: *job-aarch64-linux
- name: x86_64-gnu-tools
@@ -381,31 +381,6 @@ auto:
- name: x86_64-gnu-distcheck
<<: *job-linux-4c
# The x86_64-gnu-llvm-20 job is split into multiple jobs to run tests in parallel.
# x86_64-gnu-llvm-20-1 skips tests that run in x86_64-gnu-llvm-20-{2,3}.
- name: x86_64-gnu-llvm-20-1
env:
RUST_BACKTRACE: 1
IMAGE: x86_64-gnu-llvm-20
DOCKER_SCRIPT: stage_2_test_set2.sh
<<: *job-linux-4c
# Skip tests that run in x86_64-gnu-llvm-20-{1,3}
- name: x86_64-gnu-llvm-20-2
env:
RUST_BACKTRACE: 1
IMAGE: x86_64-gnu-llvm-20
DOCKER_SCRIPT: x86_64-gnu-llvm2.sh
<<: *job-linux-4c
# Skip tests that run in x86_64-gnu-llvm-20-{1,2}
- name: x86_64-gnu-llvm-20-3
env:
RUST_BACKTRACE: 1
IMAGE: x86_64-gnu-llvm-20
DOCKER_SCRIPT: x86_64-gnu-llvm3.sh
<<: *job-linux-4c
# The x86_64-gnu-llvm-21 job is split into multiple jobs to run tests in parallel.
# x86_64-gnu-llvm-21-1 skips tests that run in x86_64-gnu-llvm-21-{2,3}.
- name: x86_64-gnu-llvm-21-1
@@ -5,7 +5,6 @@
//@ assembly-output: emit-asm
//@ needs-llvm-components: aarch64
//@ compile-flags: --target aarch64-unknown-linux-gnu
//@ [GCS] min-llvm-version: 21
//@ [GCS] ignore-apple (XCode version needs updating)
//@ [GCS] compile-flags: -Z branch-protection=gcs
//@ [PACRET] compile-flags: -Z branch-protection=pac-ret,leaf
-1
View File
@@ -6,7 +6,6 @@
//@[s390x_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-feature=+vector
//@[s390x_vector] needs-llvm-components: systemz
//@ compile-flags: -Zmerge-functions=disabled
//@ min-llvm-version: 21
#![feature(no_core, repr_simd, f16, f128)]
#![cfg_attr(s390x_vector, feature(asm_experimental_reg))]
+1 -5
View File
@@ -1,9 +1,6 @@
//@ assembly-output: ptx-linker
//@ compile-flags: --crate-type cdylib
//@ only-nvptx64
//@ revisions: LLVM20 LLVM21
//@ [LLVM21] min-llvm-version: 21
//@ [LLVM20] max-llvm-major-version: 20
#![feature(abi_ptx)]
#![no_std]
@@ -18,8 +15,7 @@
#[no_mangle]
pub unsafe extern "ptx-kernel" fn top_kernel(a: *const u32, b: *mut u32) {
// CHECK: call.uni (retval0),
// LLVM20-NEXT: [[IMPL_FN]]
// LLVM21-SAME: [[IMPL_FN]]
// CHECK-SAME: [[IMPL_FN]]
*b = deep::private::MyStruct::new(*a).square();
}
@@ -5,7 +5,6 @@
//@ assembly-output: emit-asm
//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu -Cllvm-args=-x86-asm-syntax=intel -Ctarget-feature=-crt-static -Cpanic=abort -Zsanitizer=kcfi -Zsanitizer-kcfi-arity -Copt-level=0
//@ [x86_64] needs-llvm-components: x86
//@ min-llvm-version: 21.0.0
#![crate_type = "lib"]
#![feature(no_core)]
@@ -37,8 +37,7 @@ pub extern "C" fn second_f64(_: f64, x: f64) -> f64 {
}
// CHECK-LABEL: second_f128
// FIXME(llvm21): this can be just %rdx instead of the regex once we don't test on LLVM 20
// CHECK: movaps {{(%xmm1|\(%rdx\))}}, %xmm0
// CHECK: movaps (%rdx), %xmm0
// CHECK-NEXT: retq
#[no_mangle]
pub extern "C" fn second_f128(_: f128, x: f128) -> f128 {
@@ -1,6 +1,5 @@
//@ needs-unwind
//@ compile-flags: -Copt-level=3
//@ min-llvm-version: 21
#![crate_type = "lib"]
#![feature(c_variadic)]
-1
View File
@@ -1,6 +1,5 @@
//@ needs-unwind
//@ compile-flags: -C no-prepopulate-passes -Copt-level=0
//@ min-llvm-version: 21
#![crate_type = "lib"]
#![feature(c_variadic)]
-1
View File
@@ -1,5 +1,4 @@
//@ compile-flags: -C opt-level=3
//@ min-llvm-version: 21
#![crate_type = "lib"]
#![allow(unused_assignments, unused_variables)]
+8 -16
View File
@@ -1,8 +1,5 @@
//@ compile-flags: -Copt-level=3 -Cno-prepopulate-passes
//@ compile-flags: -Cpanic=abort -Csymbol-mangling-version=v0
//@ revisions: LLVM21 LLVM20
//@ [LLVM21] min-llvm-version: 21
//@ [LLVM20] max-llvm-major-version: 20
#![feature(custom_mir, core_intrinsics, unboxed_closures)]
#![crate_type = "lib"]
extern crate core;
@@ -37,15 +34,13 @@ pub fn mutate(mut b: Big) {
black_box(&b);
}
// LLVM21-LABEL: @deref_mut({{.*}}readonly {{.*}}captures(none) {{.*}}%c)
// LLVM20-LABEL: @deref_mut({{.*}}readonly {{.*}}%c)
// CHECK-LABEL: @deref_mut({{.*}}readonly {{.*}}captures(none) {{.*}}%c)
#[unsafe(no_mangle)]
pub fn deref_mut(c: (BigCell, &mut usize)) {
*c.1 = 42;
}
// LLVM21-LABEL: @call_copy_arg(ptr {{.*}}readonly {{.*}}captures(none){{.*}})
// LLVM20-LABEL: @call_copy_arg(ptr {{.*}}readonly {{.*}})
// CHECK-LABEL: @call_copy_arg(ptr {{.*}}readonly {{.*}}captures(none){{.*}})
#[unsafe(no_mangle)]
#[custom_mir(dialect = "runtime", phase = "optimized")]
pub fn call_copy_arg(a: Big) {
@@ -61,7 +56,7 @@ pub fn call_copy_arg(a: Big) {
// CHECK-LABEL: @call_move_arg(
// CHECK-NOT: readonly
// LLVM21-SAME: captures(address)
// CHECK-SAME: captures(address)
// CHECK-SAME: )
#[unsafe(no_mangle)]
#[custom_mir(dialect = "runtime", phase = "optimized")]
@@ -84,8 +79,7 @@ fn shared_borrow<T>(a: T) {
//
// CHECK-LABEL: ; deduced_param_attrs::shared_borrow::<deduced_param_attrs::Big>
// CHECK-NEXT: ;
// LLVM21-NEXT: (ptr {{.*}}readonly {{.*}}captures(address) {{.*}}%a)
// LLVM20-NEXT: (ptr {{.*}}readonly {{.*}}%a)
// CHECK-NEXT: (ptr {{.*}}readonly {{.*}}captures(address) {{.*}}%a)
pub static A0: fn(Big) = shared_borrow;
// !Freeze parameter can be mutated through a shared borrow.
@@ -113,16 +107,14 @@ fn consume<T>(_: T) {}
//
// CHECK-LABEL: ; deduced_param_attrs::consume::<deduced_param_attrs::BigCell>
// CHECK-NEXT: ;
// LLVM21-NEXT: (ptr {{.*}}readonly {{.*}}captures(none) {{.*}})
// LLVM20-NEXT: (ptr {{.*}}readonly {{.*}})
// CHECK-NEXT: (ptr {{.*}}readonly {{.*}}captures(none) {{.*}})
pub static B0: fn(BigCell) = consume;
// The parameter needs to be dropped.
//
// CHECK-LABEL: ; deduced_param_attrs::consume::<deduced_param_attrs::BigDrop>
// CHECK-NEXT: ;
// LLVM21-NEXT: (ptr {{.*}}captures(address) {{.*}})
// LLVM20-NEXT: (ptr {{.*}})
// CHECK-NEXT: (ptr {{.*}}captures(address) {{.*}})
pub static B1: fn(BigDrop) = consume;
fn consume_parts<T>(t: (T, T)) {
@@ -160,13 +152,13 @@ pub fn manually_drop_field(a: fn() -> BigDrop, mut b: ManuallyDrop<BigDrop>) {
loop {}
}
// LLVM21-LABEL: @not_captured_return_place(ptr{{.*}} captures(none) {{.*}}%_0)
// CHECK-LABEL: @not_captured_return_place(ptr{{.*}} captures(none) {{.*}}%_0)
#[unsafe(no_mangle)]
pub fn not_captured_return_place() -> [u8; 80] {
[0u8; 80]
}
// LLVM21-LABEL: @captured_return_place(ptr{{.*}} captures(address) {{.*}}%_0)
// CHECK-LABEL: @captured_return_place(ptr{{.*}} captures(address) {{.*}}%_0)
#[unsafe(no_mangle)]
pub fn captured_return_place() -> [u8; 80] {
black_box([0u8; 80])
+11 -33
View File
@@ -1,8 +1,5 @@
//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled
//@ only-64bit
//@ revisions: LLVM20 LLVM21
//@ [LLVM21] min-llvm-version: 21
//@ [LLVM20] max-llvm-major-version: 20
// The `derive(PartialEq)` on enums with field-less variants compares discriminants,
// so make sure we emit that in some reasonable way.
@@ -92,21 +89,16 @@ pub fn mid_bool_eq_discr(a: Mid<bool>, b: Mid<bool>) -> bool {
// CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %a, 3
// CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]])
// LLVM20: %[[A_REL_DISCR:.+]] = add nsw i8 %a, -2
// CHECK: %[[A_IS_NICHE:.+]] = icmp samesign ugt i8 %a, 1
// LLVM20: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1
// CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %b, 3
// CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]])
// LLVM20: %[[B_REL_DISCR:.+]] = add nsw i8 %b, -2
// CHECK: %[[B_IS_NICHE:.+]] = icmp samesign ugt i8 %b, 1
// LLVM20: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1
// LLVM21: %[[A_MOD_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %a, i8 3
// LLVM21: %[[B_MOD_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %b, i8 3
// CHECK: %[[A_MOD_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %a, i8 3
// CHECK: %[[B_MOD_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %b, i8 3
// LLVM20: %[[R:.+]] = icmp eq i8 %[[A_DISCR]], %[[B_DISCR]]
// LLVM21: %[[R:.+]] = icmp eq i8 %[[A_MOD_DISCR]], %[[B_MOD_DISCR]]
// CHECK: %[[R:.+]] = icmp eq i8 %[[A_MOD_DISCR]], %[[B_MOD_DISCR]]
// CHECK: ret i1 %[[R]]
discriminant_value(&a) == discriminant_value(&b)
}
@@ -117,21 +109,16 @@ pub fn mid_ord_eq_discr(a: Mid<Ordering>, b: Mid<Ordering>) -> bool {
// CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %a, 3
// CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]])
// LLVM20: %[[A_REL_DISCR:.+]] = add nsw i8 %a, -2
// CHECK: %[[A_IS_NICHE:.+]] = icmp sgt i8 %a, 1
// LLVM20: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1
// CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %b, 3
// CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]])
// LLVM20: %[[B_REL_DISCR:.+]] = add nsw i8 %b, -2
// CHECK: %[[B_IS_NICHE:.+]] = icmp sgt i8 %b, 1
// LLVM20: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1
// LLVM21: %[[A_MOD_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %a, i8 3
// LLVM21: %[[B_MOD_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %b, i8 3
// CHECK: %[[A_MOD_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %a, i8 3
// CHECK: %[[B_MOD_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %b, i8 3
// LLVM20: %[[R:.+]] = icmp eq i8 %[[A_DISCR]], %[[B_DISCR]]
// LLVM21: %[[R:.+]] = icmp eq i8 %[[A_MOD_DISCR]], %[[B_MOD_DISCR]]
// CHECK: %[[R:.+]] = icmp eq i8 %[[A_MOD_DISCR]], %[[B_MOD_DISCR]]
// CHECK: ret i1 %[[R]]
discriminant_value(&a) == discriminant_value(&b)
}
@@ -150,18 +137,14 @@ pub fn mid_ac_eq_discr(a: Mid<AC>, b: Mid<AC>) -> bool {
// CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %a, -127
// CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]])
// LLVM20: %[[A_REL_DISCR:.+]] = xor i8 %a, -128
// CHECK: %[[A_IS_NICHE:.+]] = icmp slt i8 %a, 0
// LLVM20: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1
// CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %b, -127
// CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]])
// LLVM20: %[[B_REL_DISCR:.+]] = xor i8 %b, -128
// CHECK: %[[B_IS_NICHE:.+]] = icmp slt i8 %b, 0
// LLVM20: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1
// LLVM21: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %a, i8 -127
// LLVM21: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %b, i8 -127
// CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %a, i8 -127
// CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %b, i8 -127
// CHECK: %[[R:.+]] = icmp eq i8 %[[A_DISCR]], %[[B_DISCR]]
// CHECK: ret i1 %[[R]]
@@ -177,22 +160,17 @@ pub fn mid_giant_eq_discr(a: Mid<Giant>, b: Mid<Giant>) -> bool {
// CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i128 %a, 6
// CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]])
// CHECK: %[[A_TRUNC:.+]] = trunc nuw nsw i128 %a to i64
// LLVM20: %[[A_REL_DISCR:.+]] = add nsw i64 %[[A_TRUNC]], -5
// CHECK: %[[A_IS_NICHE:.+]] = icmp samesign ugt i128 %a, 4
// LLVM20: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i64 %[[A_REL_DISCR]], i64 1
// CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i128 %b, 6
// CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]])
// CHECK: %[[B_TRUNC:.+]] = trunc nuw nsw i128 %b to i64
// LLVM20: %[[B_REL_DISCR:.+]] = add nsw i64 %[[B_TRUNC]], -5
// CHECK: %[[B_IS_NICHE:.+]] = icmp samesign ugt i128 %b, 4
// LLVM20: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i64 %[[B_REL_DISCR]], i64 1
// LLVM21: %[[A_MODIFIED_TAG:.+]] = select i1 %[[A_IS_NICHE]], i64 %[[A_TRUNC]], i64 6
// LLVM21: %[[B_MODIFIED_TAG:.+]] = select i1 %[[B_IS_NICHE]], i64 %[[B_TRUNC]], i64 6
// LLVM21: %[[R:.+]] = icmp eq i64 %[[A_MODIFIED_TAG]], %[[B_MODIFIED_TAG]]
// CHECK: %[[A_MODIFIED_TAG:.+]] = select i1 %[[A_IS_NICHE]], i64 %[[A_TRUNC]], i64 6
// CHECK: %[[B_MODIFIED_TAG:.+]] = select i1 %[[B_IS_NICHE]], i64 %[[B_TRUNC]], i64 6
// CHECK: %[[R:.+]] = icmp eq i64 %[[A_MODIFIED_TAG]], %[[B_MODIFIED_TAG]]
// LLVM20: %[[R:.+]] = icmp eq i64 %[[A_DISCR]], %[[B_DISCR]]
// CHECK: ret i1 %[[R]]
discriminant_value(&a) == discriminant_value(&b)
}
@@ -11,7 +11,6 @@
// at the time still sometimes fails, so only verify it for the power-of-two size
// - https://github.com/llvm/llvm-project/issues/134735
//@[x86-64-v3] only-x86_64
//@[x86-64-v3] min-llvm-version: 21
//@[x86-64-v3] compile-flags: -Ctarget-cpu=x86-64-v3
#![crate_type = "lib"]
@@ -1,4 +1,3 @@
//@ min-llvm-version: 21
//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled
//! Tests that matching + eq on `Option<FieldlessEnum>` produces a simple compare with no branching
@@ -1,7 +1,6 @@
//! This test checks that removing trailing zeroes from a `NonZero`,
//! then creating a new `NonZero` from the result does not panic.
//@ min-llvm-version: 21
//@ compile-flags: -O -Zmerge-functions=disabled
#![crate_type = "lib"]
@@ -2,7 +2,6 @@
// index doesn't generate another bounds check.
//@ compile-flags: -Copt-level=3
//@ min-llvm-version: 21
#![crate_type = "lib"]
@@ -1,6 +1,5 @@
//@ compile-flags: -O -Zmerge-functions=disabled
//@ needs-deterministic-layouts
//@ min-llvm-version: 21
//@ ignore-std-debug-assertions (causes different value naming)
#![crate_type = "lib"]
+4 -6
View File
@@ -1,6 +1,4 @@
//@ revisions: REGULAR LLVM21
//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled
//@ [LLVM21] min-llvm-version: 21
#![crate_type = "lib"]
extern crate core;
@@ -76,11 +74,11 @@ pub fn niche_eq(l: Option<EnumWithNiche>, r: Option<EnumWithNiche>) -> bool {
l == r
}
// LLVM21-LABEL: @bool_eq
// CHECK-LABEL: @bool_eq
#[no_mangle]
pub fn bool_eq(l: Option<bool>, r: Option<bool>) -> bool {
// LLVM21: start:
// LLVM21-NEXT: icmp eq i8
// LLVM21-NEXT: ret i1
// CHECK: start:
// CHECK-NEXT: icmp eq i8
// CHECK-NEXT: ret i1
l == r
}
@@ -1,5 +1,4 @@
//@ compile-flags: -C opt-level=3 -Z mir-opt-level=0
//@ min-llvm-version: 21
#![crate_type = "lib"]
@@ -5,7 +5,6 @@
//@ [riscv32gc] needs-llvm-components: riscv
//@ [riscv64gc] compile-flags: --target riscv64gc-unknown-linux-gnu
//@ [riscv64gc] needs-llvm-components: riscv
//@ min-llvm-version: 21
#![feature(link_llvm_intrinsics)]
#![feature(no_core, lang_items)]
@@ -5,7 +5,6 @@
//@ [x86_64] compile-flags: --target x86_64-unknown-none
//@ [x86_64] needs-llvm-components: x86
//@ compile-flags: -Ctarget-feature=-crt-static -Cpanic=abort -Zsanitizer=kcfi -Zsanitizer-kcfi-arity
//@ min-llvm-version: 21.0.0
#![feature(no_core, lang_items)]
#![crate_type = "lib"]
@@ -1,5 +1,4 @@
//@ compile-flags: -Copt-level=3
//@ min-llvm-version: 21
#![crate_type = "lib"]
-1
View File
@@ -1,5 +1,4 @@
//@ compile-flags: -Copt-level=3
//@ min-llvm-version: 21
#![crate_type = "lib"]
+9 -12
View File
@@ -1,6 +1,4 @@
//@ revisions: normal llvm21
//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled
//@ [llvm21] min-llvm-version: 21
//@ only-x86_64
#![crate_type = "lib"]
@@ -178,21 +176,20 @@ pub fn vec_option_i32(n: usize) -> Vec<Option<i32>> {
vec![None; n]
}
// LLVM21-LABEL: @vec_array
#[cfg(llvm21)]
// CHECK-LABEL: @vec_array
#[no_mangle]
pub fn vec_array(n: usize) -> Vec<[u32; 1_000_000]> {
// LLVM21-NOT: call {{.*}}alloc::vec::from_elem
// LLVM21-NOT: call {{.*}}reserve
// LLVM21-NOT: call {{.*}}__rust_alloc(
// CHECK-NOT: call {{.*}}alloc::vec::from_elem
// CHECK-NOT: call {{.*}}reserve
// CHECK-NOT: call {{.*}}__rust_alloc(
// LLVM21: call {{.*}}__rust_alloc_zeroed(
// CHECK: call {{.*}}__rust_alloc_zeroed(
// LLVM21-NOT: call {{.*}}alloc::vec::from_elem
// LLVM21-NOT: call {{.*}}reserve
// LLVM21-NOT: call {{.*}}__rust_alloc(
// CHECK-NOT: call {{.*}}alloc::vec::from_elem
// CHECK-NOT: call {{.*}}reserve
// CHECK-NOT: call {{.*}}__rust_alloc(
// LLVM21: ret void
// CHECK: ret void
vec![[0; 1_000_000]; 3]
}
+1 -7
View File
@@ -17,7 +17,6 @@ pub enum I128Enum {
I128D = i128::MAX.to_le(),
}
#[cfg(not(old_llvm))]
#[repr(u128)]
pub enum U128VariantEnum {
VariantU128A(u8) = 0_u128.to_le(),
@@ -26,7 +25,6 @@ pub enum U128VariantEnum {
VariantU128D = u128::MAX.to_le(),
}
#[cfg(not(old_llvm))]
#[repr(i128)]
pub enum I128VariantEnum {
VariantI128A(u8) = 0_i128.to_le(),
@@ -37,13 +35,9 @@ pub enum I128VariantEnum {
pub fn f(_: U128Enum, _: I128Enum) {}
#[cfg(not(old_llvm))]
pub fn g(_: U128VariantEnum, _: I128VariantEnum) {}
fn main() {
f(U128Enum::U128A, I128Enum::I128A);
#[cfg(not(old_llvm))]
{
g(U128VariantEnum::VariantU128A(1), I128VariantEnum::VariantI128A(2));
}
g(U128VariantEnum::VariantU128A(1), I128VariantEnum::VariantI128A(2));
}
+2 -19
View File
@@ -13,25 +13,8 @@
use run_make_support::{gimli, object, rfs, rustc};
fn main() {
// Before LLVM 20, 128-bit enums with variants didn't emit debuginfo correctly.
// This check can be removed once Rust no longer supports LLVM 18 and 19.
let llvm_version = rustc()
.verbose()
.arg("--version")
.run()
.stdout_utf8()
.lines()
.filter_map(|line| line.strip_prefix("LLVM version: "))
.map(|version| version.split(".").next().unwrap().parse::<u32>().unwrap())
.next()
.unwrap();
let is_old_llvm = llvm_version < 20;
let output = PathBuf::from("repr128");
let mut rustc = rustc();
if is_old_llvm {
rustc.cfg("old_llvm");
}
rustc.input("main.rs").output(&output).arg("-Cdebuginfo=2").run();
// Mach-O uses packed debug info
let dsym_location = output
@@ -88,7 +71,7 @@ fn main() {
while let Some((_, entry)) = cursor.next_dfs().unwrap() {
match entry.tag() {
gimli::constants::DW_TAG_variant if !is_old_llvm => {
gimli::constants::DW_TAG_variant => {
let Some(value) = entry.attr(gimli::constants::DW_AT_discr_value).unwrap()
else {
// `std` enums might have variants without `DW_AT_discr_value`.
@@ -143,7 +126,7 @@ fn main() {
if !enumerators_to_find.is_empty() {
panic!("Didn't find debug enumerator entries for {enumerators_to_find:?}");
}
if !is_old_llvm && !variants_to_find.is_empty() {
if !variants_to_find.is_empty() {
panic!("Didn't find debug variant entries for {variants_to_find:?}");
}
}
@@ -1,11 +0,0 @@
// Verifies that `-Zsanitizer-kcfi-arity` requires LLVM 21.0.0 or later.
//
//@ needs-sanitizer-kcfi
//@ compile-flags: -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Cpanic=abort -Zsanitizer=kcfi -Zsanitizer-kcfi-arity
//@ build-fail
//@ max-llvm-major-version: 20
//~? ERROR `-Zsanitizer-kcfi-arity` requires LLVM 21.0.0 or later
#![feature(no_core)]
#![no_core]
#![no_main]
@@ -1,4 +0,0 @@
error: `-Zsanitizer-kcfi-arity` requires LLVM 21.0.0 or later
error: aborting due to 1 previous error