Rollup merge of #145071 - cuviper:min-llvm-20, r=nikic

Update the minimum external LLVM to 20

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

cc ```@rust-lang/wg-llvm```
r? nikic
This commit is contained in:
Stuart Cook 2025-09-17 14:56:43 +10:00 committed by GitHub
commit f104ecfba6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
47 changed files with 153 additions and 597 deletions

View file

@ -1091,16 +1091,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
ty: Ty<'tcx>,
lhs: Self::Value,
rhs: Self::Value,
) -> Option<Self::Value> {
// FIXME: See comment on the definition of `three_way_compare`.
if crate::llvm_util::get_version() < (20, 0, 0) {
return None;
}
) -> Self::Value {
let size = ty.primitive_size(self.tcx);
let name = if ty.is_signed() { "llvm.scmp" } else { "llvm.ucmp" };
Some(self.call_intrinsic(name, &[self.type_i8(), self.type_ix(size.bits())], &[lhs, rhs]))
self.call_intrinsic(name, &[self.type_i8(), self.type_ix(size.bits())], &[lhs, rhs])
}
/* Miscellaneous instructions */

View file

@ -172,35 +172,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 < (20, 0, 0) {
if sess.target.arch == "aarch64" || sess.target.arch.starts_with("arm64") {
// LLVM 20 defines three additional address spaces for alternate
// pointer kinds used in Windows.
// See https://github.com/llvm/llvm-project/pull/111879
target_data_layout =
target_data_layout.replace("-p270:32:32-p271:32:32-p272:64:64", "");
}
if sess.target.arch.starts_with("sparc") {
// LLVM 20 updates the sparc layout to correctly align 128 bit integers to 128 bit.
// See https://github.com/llvm/llvm-project/pull/106951
target_data_layout = target_data_layout.replace("-i128:128", "");
}
if sess.target.arch.starts_with("mips64") {
// LLVM 20 updates the mips64 layout to correctly align 128 bit integers to 128 bit.
// See https://github.com/llvm/llvm-project/pull/112084
target_data_layout = target_data_layout.replace("-i128:128", "");
}
if sess.target.arch.starts_with("powerpc64") {
// LLVM 20 updates the powerpc64 layout to correctly align 128 bit integers to 128 bit.
// See https://github.com/llvm/llvm-project/pull/118004
target_data_layout = target_data_layout.replace("-i128:128", "");
}
if sess.target.arch.starts_with("wasm32") || sess.target.arch.starts_with("wasm64") {
// LLVM 20 updates the wasm(32|64) layout to correctly align 128 bit integers to 128 bit.
// See https://github.com/llvm/llvm-project/pull/119204
target_data_layout = target_data_layout.replace("-i128:128", "");
}
}
if llvm_version < (21, 0, 0) {
if sess.target.arch == "nvptx64" {
// LLVM 21 updated the default layout on nvptx: https://github.com/llvm/llvm-project/pull/124961

View file

@ -246,9 +246,6 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
("aarch64", "pmuv3") => Some(LLVMFeature::new("perfmon")),
("aarch64", "paca") => Some(LLVMFeature::new("pauth")),
("aarch64", "pacg") => Some(LLVMFeature::new("pauth")),
// Before LLVM 20 those two features were packaged together as b16b16
("aarch64", "sve-b16b16") if get_version().0 < 20 => Some(LLVMFeature::new("b16b16")),
("aarch64", "sme-b16b16") if get_version().0 < 20 => Some(LLVMFeature::new("b16b16")),
("aarch64", "flagm2") => Some(LLVMFeature::new("altnzcv")),
// Rust ties fp and neon together.
("aarch64", "neon") => Some(LLVMFeature::with_dependencies(
@ -262,57 +259,17 @@ 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
("aarch64", "fpmr") => None, // only existed in 18
("arm", "fp16") => Some(LLVMFeature::new("fullfp16")),
// NVPTX targets added in LLVM 20
("nvptx64", "sm_100") if get_version().0 < 20 => None,
("nvptx64", "sm_100a") if get_version().0 < 20 => None,
("nvptx64", "sm_101") if get_version().0 < 20 => None,
("nvptx64", "sm_101a") if get_version().0 < 20 => None,
("nvptx64", "sm_120") if get_version().0 < 20 => None,
("nvptx64", "sm_120a") if get_version().0 < 20 => None,
("nvptx64", "ptx86") if get_version().0 < 20 => None,
("nvptx64", "ptx87") if get_version().0 < 20 => None,
// Filter out features that are not supported by the current LLVM version
("loongarch64", "div32" | "lam-bh" | "lamcas" | "ld-seq-sa" | "scq")
if get_version().0 < 20 =>
{
None
}
("loongarch32" | "loongarch64", "32s") if get_version().0 < 21 => None,
// Filter out features that are not supported by the current LLVM version
("riscv32" | "riscv64", "zacas" | "rva23u64" | "supm") if get_version().0 < 20 => None,
(
"s390x",
"message-security-assist-extension12"
| "concurrent-functions"
| "miscellaneous-extensions-4"
| "vector-enhancements-3"
| "vector-packed-decimal-enhancement-3",
) if get_version().0 < 20 => None,
// Enable the evex512 target feature if an avx512 target feature is enabled.
("x86", s) if s.starts_with("avx512") => Some(LLVMFeature::with_dependencies(
s,
smallvec![TargetFeatureFoldStrength::EnableOnly("evex512")],
)),
// Support for `wide-arithmetic` will first land in LLVM 20 as part of
// llvm/llvm-project#111598
("wasm32" | "wasm64", "wide-arithmetic") if get_version() < (20, 0, 0) => None,
("sparc", "leoncasa") => Some(LLVMFeature::new("hasleoncasa")),
// In LLVM 19, there is no `v8plus` feature and `v9` means "SPARC-V9 instruction available and SPARC-V8+ ABI used".
// https://github.com/llvm/llvm-project/blob/llvmorg-19.1.0/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp#L27-L28
// Before LLVM 19, there was no `v8plus` feature and `v9` means "SPARC-V9 instruction available".
// https://github.com/llvm/llvm-project/blob/llvmorg-18.1.0/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp#L26
("sparc", "v8plus") if get_version().0 == 19 => Some(LLVMFeature::new("v9")),
("powerpc", "power8-crypto") => Some(LLVMFeature::new("crypto")),
// These new `amx` variants and `movrs` were introduced in LLVM20
("x86", "amx-avx512" | "amx-fp8" | "amx-movrs" | "amx-tf32" | "amx-transpose")
if get_version().0 < 20 =>
{
None
}
("x86", "movrs") if get_version().0 < 20 => None,
("x86", "avx10.1") => Some(LLVMFeature::new("avx10.1-512")),
("x86", "avx10.2") if get_version().0 < 20 => None,
("x86", "avx10.2") if get_version().0 >= 20 => Some(LLVMFeature::new("avx10.2-512")),
("x86", "avx10.2") => Some(LLVMFeature::new("avx10.2-512")),
("x86", "apxf") => Some(LLVMFeature::with_dependencies(
"egpr",
smallvec![
@ -716,17 +673,7 @@ pub(crate) fn global_llvm_features(
};
// Features implied by an implicit or explicit `--target`.
features.extend(
sess.target
.features
.split(',')
.filter(|v| !v.is_empty())
// Drop +v8plus feature introduced in LLVM 20.
// (Hard-coded target features do not go through `to_llvm_feature` since they already
// are LLVM feature names, hence we need a special case here.)
.filter(|v| *v != "+v8plus" || get_version() >= (20, 0, 0))
.map(String::from),
);
features.extend(sess.target.features.split(',').filter(|v| !v.is_empty()).map(String::from));
if wants_wasm_eh(sess) && sess.panic_strategy() == PanicStrategy::Unwind {
features.push("+exception-handling".into());

View file

@ -901,36 +901,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}
mir::BinOp::Cmp => {
use std::cmp::Ordering;
assert!(!is_float);
if let Some(value) = bx.three_way_compare(lhs_ty, lhs, rhs) {
return value;
}
let pred = |op| base::bin_op_to_icmp_predicate(op, is_signed);
if bx.cx().tcx().sess.opts.optimize == OptLevel::No {
// FIXME: This actually generates tighter assembly, and is a classic trick
// <https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign>
// However, as of 2023-11 it optimizes worse in things like derived
// `PartialOrd`, so only use it in debug for now. Once LLVM can handle it
// better (see <https://github.com/llvm/llvm-project/issues/73417>), it'll
// be worth trying it in optimized builds as well.
let is_gt = bx.icmp(pred(mir::BinOp::Gt), lhs, rhs);
let gtext = bx.zext(is_gt, bx.type_i8());
let is_lt = bx.icmp(pred(mir::BinOp::Lt), lhs, rhs);
let ltext = bx.zext(is_lt, bx.type_i8());
bx.unchecked_ssub(gtext, ltext)
} else {
// These operations are those expected by `tests/codegen-llvm/integer-cmp.rs`,
// from <https://github.com/rust-lang/rust/pull/63767>.
let is_lt = bx.icmp(pred(mir::BinOp::Lt), lhs, rhs);
let is_ne = bx.icmp(pred(mir::BinOp::Ne), lhs, rhs);
let ge = bx.select(
is_ne,
bx.cx().const_i8(Ordering::Greater as i8),
bx.cx().const_i8(Ordering::Equal as i8),
);
bx.select(is_lt, bx.cx().const_i8(Ordering::Less as i8), ge)
}
bx.three_way_compare(lhs_ty, lhs, rhs)
}
mir::BinOp::AddWithOverflow
| mir::BinOp::SubWithOverflow

View file

@ -3,6 +3,7 @@ use std::ops::Deref;
use rustc_abi::{Align, Scalar, Size, WrappingRange};
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::mir;
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout};
use rustc_middle::ty::{AtomicOrdering, Instance, Ty};
use rustc_session::config::OptLevel;
@ -405,15 +406,41 @@ pub trait BuilderMethods<'a, 'tcx>:
fn fcmp(&mut self, op: RealPredicate, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
/// Returns `-1` if `lhs < rhs`, `0` if `lhs == rhs`, and `1` if `lhs > rhs`.
// FIXME: Move the default implementation from `codegen_scalar_binop` into this method and
// remove the `Option` return once LLVM 20 is the minimum version.
fn three_way_compare(
&mut self,
_ty: Ty<'tcx>,
_lhs: Self::Value,
_rhs: Self::Value,
) -> Option<Self::Value> {
None
ty: Ty<'tcx>,
lhs: Self::Value,
rhs: Self::Value,
) -> Self::Value {
// FIXME: This implementation was designed around LLVM's ability to optimize, but `cg_llvm`
// overrides this to just use `@llvm.scmp`/`ucmp` since LLVM 20. This default impl should be
// reevaluated with respect to the remaining backends like cg_gcc, whether they might use
// specialized implementations as well, or continue to use a generic implementation here.
use std::cmp::Ordering;
let pred = |op| crate::base::bin_op_to_icmp_predicate(op, ty.is_signed());
if self.cx().sess().opts.optimize == OptLevel::No {
// This actually generates tighter assembly, and is a classic trick:
// <https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign>.
// However, as of 2023-11 it optimized worse in LLVM in things like derived
// `PartialOrd`, so we were only using it in debug. Since LLVM now uses its own
// intrinsics, it may be be worth trying it in optimized builds for other backends.
let is_gt = self.icmp(pred(mir::BinOp::Gt), lhs, rhs);
let gtext = self.zext(is_gt, self.type_i8());
let is_lt = self.icmp(pred(mir::BinOp::Lt), lhs, rhs);
let ltext = self.zext(is_lt, self.type_i8());
self.unchecked_ssub(gtext, ltext)
} else {
// These operations were better optimized by LLVM, before `@llvm.scmp`/`ucmp` in 20.
// See <https://github.com/rust-lang/rust/pull/63767>.
let is_lt = self.icmp(pred(mir::BinOp::Lt), lhs, rhs);
let is_ne = self.icmp(pred(mir::BinOp::Ne), lhs, rhs);
let ge = self.select(
is_ne,
self.cx().const_i8(Ordering::Greater as i8),
self.cx().const_i8(Ordering::Equal as i8),
);
self.select(is_lt, self.cx().const_i8(Ordering::Less as i8), ge)
}
}
fn memcpy(

View file

@ -344,7 +344,6 @@ 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);
@ -362,33 +361,6 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
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 LLVM_VERSION_GE(21, 0)
@ -402,12 +374,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);
}
@ -688,14 +654,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) {
@ -747,12 +708,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));
});
}
@ -763,66 +720,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,
@ -904,11 +843,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) {
@ -1185,11 +1120,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;
@ -1531,13 +1462,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)
@ -1556,15 +1482,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();

View file

@ -619,11 +619,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 >= 19
&& major >= 20
{
return;
}
panic!("\n\nbad LLVM version: {version}, need >=19\n\n")
panic!("\n\nbad LLVM version: {version}, need >=20\n\n")
}
fn configure_cmake(

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-19-1` job:
For example, to run the `x86_64-gnu-llvm-20-1` job:
```
cargo run --manifest-path src/ci/citool/Cargo.toml run-local x86_64-gnu-llvm-19-1
cargo run --manifest-path src/ci/citool/Cargo.toml run-local x86_64-gnu-llvm-20-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-19-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-19-3` workflow, you can run the following script:
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:
```
DOCKER_SCRIPT=x86_64-gnu-llvm3.sh ./src/ci/docker/run.sh x86_64-gnu-llvm-19
DOCKER_SCRIPT=x86_64-gnu-llvm3.sh ./src/ci/docker/run.sh x86_64-gnu-llvm-20
```
## Local Development

View file

@ -1,4 +1,4 @@
FROM ubuntu:24.10
FROM ubuntu:25.04
ARG DEBIAN_FRONTEND=noninteractive
@ -15,8 +15,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
cmake \
sudo \
gdb \
llvm-19-tools \
llvm-19-dev \
llvm-20-tools \
llvm-20-dev \
libedit-dev \
libssl-dev \
pkg-config \
@ -43,7 +43,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-19 \
--llvm-root=/usr/lib/llvm-20 \
--enable-llvm-link-shared \
--set rust.randomize-layout=true \
--set rust.thin-lto-import-instr-limit=10

View file

@ -1,66 +0,0 @@
FROM ubuntu:24.10
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-19-tools \
llvm-19-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-19 \
--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"

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-19
- name: x86_64-gnu-llvm-20
env:
ENABLE_GCC_CODEGEN: "1"
DOCKER_SCRIPT: x86_64-gnu-llvm.sh
<<: *job-linux-4c
- name: aarch64-gnu-llvm-19-1
- name: aarch64-gnu-llvm-20-1
env:
IMAGE: aarch64-gnu-llvm-19
IMAGE: aarch64-gnu-llvm-20
DOCKER_SCRIPT: stage_2_test_set1.sh
<<: *job-aarch64-linux
- name: aarch64-gnu-llvm-19-2
- name: aarch64-gnu-llvm-20-2
env:
IMAGE: aarch64-gnu-llvm-19
IMAGE: aarch64-gnu-llvm-20
DOCKER_SCRIPT: stage_2_test_set2.sh
<<: *job-aarch64-linux
- name: x86_64-gnu-tools
@ -397,31 +397,6 @@ auto:
DOCKER_SCRIPT: x86_64-gnu-llvm3.sh
<<: *job-linux-4c
# The x86_64-gnu-llvm-19 job is split into multiple jobs to run tests in parallel.
# x86_64-gnu-llvm-19-1 skips tests that run in x86_64-gnu-llvm-19-{2,3}.
- name: x86_64-gnu-llvm-19-1
env:
RUST_BACKTRACE: 1
IMAGE: x86_64-gnu-llvm-19
DOCKER_SCRIPT: stage_2_test_set2.sh
<<: *job-linux-4c
# Skip tests that run in x86_64-gnu-llvm-19-{1,3}
- name: x86_64-gnu-llvm-19-2
env:
RUST_BACKTRACE: 1
IMAGE: x86_64-gnu-llvm-19
DOCKER_SCRIPT: x86_64-gnu-llvm2.sh
<<: *job-linux-4c
# Skip tests that run in x86_64-gnu-llvm-19-{1,2}
- name: x86_64-gnu-llvm-19-3
env:
RUST_BACKTRACE: 1
IMAGE: x86_64-gnu-llvm-19
DOCKER_SCRIPT: x86_64-gnu-llvm3.sh
<<: *job-linux-4c
- name: x86_64-gnu-nopt
<<: *job-linux-4c

View file

@ -2,9 +2,6 @@
//@ assembly-output: emit-asm
//@ compile-flags: --target riscv64imac-unknown-none-elf -Ctarget-feature=+f,+d
//@ needs-llvm-components: riscv
//@ revisions: LLVM-PRE-20 LLVM-POST-20
//@ [LLVM-PRE-20] max-llvm-major-version: 19
//@ [LLVM-POST-20] min-llvm-version: 20
#![feature(no_core, lang_items, f16)]
#![crate_type = "lib"]
@ -28,11 +25,8 @@ pub extern "C" fn read_f16(x: &f16) -> f16 {
// CHECK-LABEL: read_f32
#[no_mangle]
pub extern "C" fn read_f32(x: &f32) -> f32 {
// LLVM-PRE-20: flw fa5, 0(a0)
// LLVM-PRE-20-NEXT: fmv.x.w a0, fa5
// LLVM-PRE-20-NEXT: ret
// LLVM-POST-20: lw a0, 0(a0)
// LLVM-POST-20-NEXT: ret
// CHECK: lw a0, 0(a0)
// CHECK-NEXT: ret
*x
}

View file

@ -2,7 +2,6 @@
//@ assembly-output: emit-asm
//@ compile-flags: --crate-type=lib -Copt-level=3 -C target-cpu=x86-64-v4
//@ compile-flags: -C llvm-args=-x86-asm-syntax=intel
//@ min-llvm-version: 20
#![no_std]
#![feature(bigint_helper_methods)]

View file

@ -1,12 +1,6 @@
//@ revisions: LLVM-PRE-20-DEBUG LLVM-20-DEBUG LLVM-PRE-20-OPTIM LLVM-20-OPTIM
//@ [LLVM-PRE-20-DEBUG] compile-flags: -C opt-level=0
//@ [LLVM-PRE-20-DEBUG] max-llvm-major-version: 19
//@ [LLVM-20-DEBUG] compile-flags: -C opt-level=0
//@ [LLVM-20-DEBUG] min-llvm-version: 20
//@ [LLVM-PRE-20-OPTIM] compile-flags: -C opt-level=3
//@ [LLVM-PRE-20-OPTIM] max-llvm-major-version: 19
//@ [LLVM-20-OPTIM] compile-flags: -C opt-level=3
//@ [LLVM-20-OPTIM] min-llvm-version: 20
//@ revisions: DEBUG OPTIM
//@ [DEBUG] compile-flags: -C opt-level=0
//@ [OPTIM] compile-flags: -C opt-level=3
//@ assembly-output: emit-asm
//@ compile-flags: --crate-type=lib -C llvm-args=-x86-asm-syntax=intel
//@ only-x86_64
@ -19,61 +13,22 @@ use std::intrinsics::three_way_compare;
#[no_mangle]
// CHECK-LABEL: signed_cmp:
pub fn signed_cmp(a: i16, b: i16) -> std::cmp::Ordering {
// LLVM-PRE-20-DEBUG: cmp
// LLVM-PRE-20-DEBUG: setg
// LLVM-PRE-20-DEBUG: and
// LLVM-PRE-20-DEBUG: cmp
// LLVM-PRE-20-DEBUG: setl
// LLVM-PRE-20-DEBUG: and
// LLVM-PRE-20-DEBUG: sub
//
// LLVM-20-DEBUG: sub
// LLVM-20-DEBUG: setl
// LLVM-20-DEBUG: setg
// LLVM-20-DEBUG: sub
// LLVM-20-DEBUG: ret
// LLVM-PRE-20-OPTIM: xor
// LLVM-PRE-20-OPTIM: cmp
// LLVM-PRE-20-OPTIM: setne
// LLVM-PRE-20-OPTIM: mov
// LLVM-PRE-20-OPTIM: cmovge
// LLVM-PRE-20-OPTIM: ret
//
// LLVM-20-OPTIM: cmp
// LLVM-20-OPTIM: setl
// LLVM-20-OPTIM: setg
// LLVM-20-OPTIM: sub
// LLVM-20-OPTIM: ret
// DEBUG: sub
// OPTIM: cmp
// CHECK: setl
// CHECK: setg
// CHECK: sub
// CHECK: ret
three_way_compare(a, b)
}
#[no_mangle]
// CHECK-LABEL: unsigned_cmp:
pub fn unsigned_cmp(a: u16, b: u16) -> std::cmp::Ordering {
// LLVM-PRE-20-DEBUG: cmp
// LLVM-PRE-20-DEBUG: seta
// LLVM-PRE-20-DEBUG: and
// LLVM-PRE-20-DEBUG: cmp
// LLVM-PRE-20-DEBUG: setb
// LLVM-PRE-20-DEBUG: and
// LLVM-PRE-20-DEBUG: sub
//
// LLVM-20-DEBUG: sub
// LLVM-20-DEBUG: seta
// LLVM-20-DEBUG: sbb
// LLVM-20-DEBUG: ret
// LLVM-PRE-20-OPTIM: xor
// LLVM-PRE-20-OPTIM: cmp
// LLVM-PRE-20-OPTIM: setne
// LLVM-PRE-20-OPTIM: mov
// LLVM-PRE-20-OPTIM: cmovae
// LLVM-PRE-20-OPTIM: ret
//
// LLVM-20-OPTIM: cmp
// LLVM-20-OPTIM: seta
// LLVM-20-OPTIM: sbb
// LLVM-20-OPTIM: ret
// DEBUG: sub
// OPTIM: cmp
// CHECK: seta
// CHECK: sbb
// CHECK: ret
three_way_compare(a, b)
}

View file

@ -1,5 +1,4 @@
//@ compile-flags: -C opt-level=1
//@ min-llvm-version: 20
// The `derive(PartialOrd)` for a 2-field type doesn't override `lt`/`le`/`gt`/`ge`.
// This double-checks that the `Option<Ordering>` intermediate values used

View file

@ -1,5 +1,4 @@
//@ compile-flags: -C opt-level=1 -Z merge-functions=disabled
//@ min-llvm-version: 20
#![crate_type = "lib"]

View file

@ -1,5 +1,4 @@
//@ compile-flags: -Copt-level=0 -Cno-prepopulate-passes
//@ min-llvm-version: 19
//@ only-64bit
#![crate_type = "lib"]

View file

@ -1,5 +1,4 @@
//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled
//@ min-llvm-version: 20
//@ only-64bit
//@ revisions: LLVM20 LLVM21
//@ [LLVM21] min-llvm-version: 21

View file

@ -1,9 +1,6 @@
// This is test for more optimal Ord implementation for integers.
// See <https://github.com/rust-lang/rust/issues/63758> for more info.
//@ revisions: llvm-pre-20 llvm-20
//@ [llvm-20] min-llvm-version: 20
//@ [llvm-pre-20] max-llvm-major-version: 19
//@ compile-flags: -C opt-level=3 -Zmerge-functions=disabled
#![crate_type = "lib"]
@ -13,50 +10,29 @@ use std::cmp::Ordering;
// CHECK-LABEL: @cmp_signed
#[no_mangle]
pub fn cmp_signed(a: i64, b: i64) -> Ordering {
// llvm-20: call{{.*}} i8 @llvm.scmp.i8.i64
// llvm-pre-20: icmp slt
// llvm-pre-20: icmp ne
// llvm-pre-20: zext i1
// llvm-pre-20: select i1
// CHECK: call{{.*}} i8 @llvm.scmp.i8.i64
a.cmp(&b)
}
// CHECK-LABEL: @cmp_unsigned
#[no_mangle]
pub fn cmp_unsigned(a: u32, b: u32) -> Ordering {
// llvm-20: call{{.*}} i8 @llvm.ucmp.i8.i32
// llvm-pre-20: icmp ult
// llvm-pre-20: icmp ne
// llvm-pre-20: zext i1
// llvm-pre-20: select i1
// CHECK: call{{.*}} i8 @llvm.ucmp.i8.i32
a.cmp(&b)
}
// CHECK-LABEL: @cmp_char
#[no_mangle]
pub fn cmp_char(a: char, b: char) -> Ordering {
// llvm-20: call{{.*}} i8 @llvm.ucmp.i8.i32
// llvm-pre-20: icmp ult
// llvm-pre-20: icmp ne
// llvm-pre-20: zext i1
// llvm-pre-20: select i1
// CHECK: call{{.*}} i8 @llvm.ucmp.i8.i32
a.cmp(&b)
}
// CHECK-LABEL: @cmp_tuple
#[no_mangle]
pub fn cmp_tuple(a: (i16, u16), b: (i16, u16)) -> Ordering {
// llvm-20-DAG: call{{.*}} i8 @llvm.ucmp.i8.i16
// llvm-20-DAG: call{{.*}} i8 @llvm.scmp.i8.i16
// llvm-20: ret i8
// llvm-pre-20: icmp slt
// llvm-pre-20: icmp ne
// llvm-pre-20: zext i1
// llvm-pre-20: select i1
// llvm-pre-20: icmp ult
// llvm-pre-20: icmp ne
// llvm-pre-20: zext i1
// llvm-pre-20: select i1
// llvm-pre-20: select i1
// CHECK-DAG: call{{.*}} i8 @llvm.ucmp.i8.i16
// CHECK-DAG: call{{.*}} i8 @llvm.scmp.i8.i16
// CHECK: ret i8
a.cmp(&b)
}

View file

@ -2,7 +2,6 @@
//@ [DEBUG] compile-flags: -C opt-level=0
//@ [OPTIM] compile-flags: -C opt-level=3
//@ compile-flags: -C no-prepopulate-passes
//@ min-llvm-version: 20
#![crate_type = "lib"]
#![feature(core_intrinsics)]

View file

@ -1,5 +1,4 @@
//@ compile-flags: -Copt-level=3
//@ min-llvm-version: 20
#![crate_type = "lib"]

View file

@ -1,6 +1,5 @@
//@ compile-flags: -Copt-level=3
//@ revisions: host x86-64 x86-64-v3
//@ min-llvm-version: 20
//@[host] ignore-x86_64

View file

@ -1,5 +1,4 @@
//@ compile-flags: -Copt-level=3
//@ min-llvm-version: 20
#![crate_type = "lib"]
// Ensure that a modulo operation with an operand that is known to be

View file

@ -3,7 +3,6 @@
// use a larger value to prevent unrolling.
//@ compile-flags: -Copt-level=3
//@ min-llvm-version: 20
#![crate_type = "lib"]

View file

@ -1,5 +1,4 @@
//@ compile-flags: -Copt-level=3
//@ min-llvm-version: 20
#![crate_type = "lib"]
/// Ensure the function is properly optimized

View file

@ -1,5 +1,4 @@
//@ revisions: REGULAR LLVM21
//@ min-llvm-version: 20
//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled
//@ [LLVM21] min-llvm-version: 21
#![crate_type = "lib"]

View file

@ -1,5 +1,4 @@
//@ compile-flags: -Copt-level=3
//@ min-llvm-version: 20
#![crate_type = "lib"]
// This test verifies that LLVM 20 properly optimizes the bounds check

View file

@ -1,6 +1,5 @@
//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled
//@ only-x86_64
//@ min-llvm-version: 20
//@ ignore-std-debug-assertions (`ptr::swap_nonoverlapping` has one which blocks some optimizations)
#![crate_type = "lib"]

View file

@ -1,9 +1,6 @@
//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled
//@ edition: 2021
//@ only-x86_64
//@ revisions: NINETEEN TWENTY
//@[NINETEEN] exact-llvm-major-version: 19
//@[TWENTY] min-llvm-version: 20
#![crate_type = "lib"]
#![feature(try_blocks)]
@ -17,13 +14,9 @@ pub fn option_nop_match_32(x: Option<u32>) -> Option<u32> {
// CHECK: start:
// CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i32 %0 to i1
// NINETEEN-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i32 %0, i32 0
// NINETEEN-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } poison, i32 [[SELECT]], 0
// NINETEEN-NEXT: [[REG3:%.*]] = insertvalue { i32, i32 } [[REG2]], i32 %1, 1
// TWENTY-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i32 %1, i32 undef
// TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } poison, i32 %0, 0
// TWENTY-NEXT: [[REG3:%.*]] = insertvalue { i32, i32 } [[REG2]], i32 [[SELECT]], 1
// CHECK-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i32 %1, i32 undef
// CHECK-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } poison, i32 %0, 0
// CHECK-NEXT: [[REG3:%.*]] = insertvalue { i32, i32 } [[REG2]], i32 [[SELECT]], 1
// CHECK-NEXT: ret { i32, i32 } [[REG3]]
match x {
@ -36,8 +29,8 @@ pub fn option_nop_match_32(x: Option<u32>) -> Option<u32> {
#[no_mangle]
pub fn option_nop_traits_32(x: Option<u32>) -> Option<u32> {
// CHECK: start:
// TWENTY-NEXT: %[[IS_SOME:.+]] = trunc nuw i32 %0 to i1
// TWENTY-NEXT: select i1 %[[IS_SOME]], i32 %1, i32 undef
// CHECK-NEXT: %[[IS_SOME:.+]] = trunc nuw i32 %0 to i1
// CHECK-NEXT: select i1 %[[IS_SOME]], i32 %1, i32 undef
// CHECK-NEXT: insertvalue { i32, i32 }
// CHECK-NEXT: insertvalue { i32, i32 }
// CHECK-NEXT: ret { i32, i32 }
@ -96,13 +89,9 @@ pub fn option_nop_match_64(x: Option<u64>) -> Option<u64> {
// CHECK: start:
// CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i64 %0 to i1
// NINETEEN-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i64 %0, i64 0
// NINETEEN-NEXT: [[REG2:%.*]] = insertvalue { i64, i64 } poison, i64 [[SELECT]], 0
// NINETEEN-NEXT: [[REG3:%.*]] = insertvalue { i64, i64 } [[REG2]], i64 %1, 1
// TWENTY-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i64 %1, i64 undef
// TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i64, i64 } poison, i64 %0, 0
// TWENTY-NEXT: [[REG3:%.*]] = insertvalue { i64, i64 } [[REG2]], i64 [[SELECT]], 1
// CHECK-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i64 %1, i64 undef
// CHECK-NEXT: [[REG2:%.*]] = insertvalue { i64, i64 } poison, i64 %0, 0
// CHECK-NEXT: [[REG3:%.*]] = insertvalue { i64, i64 } [[REG2]], i64 [[SELECT]], 1
// CHECK-NEXT: ret { i64, i64 } [[REG3]]
match x {
@ -115,8 +104,8 @@ pub fn option_nop_match_64(x: Option<u64>) -> Option<u64> {
#[no_mangle]
pub fn option_nop_traits_64(x: Option<u64>) -> Option<u64> {
// CHECK: start:
// TWENTY-NEXT: %[[TRUNC:[0-9]+]] = trunc nuw i64 %0 to i1
// TWENTY-NEXT: %[[SEL:\.[0-9]+]] = select i1 %[[TRUNC]], i64 %1, i64 undef
// CHECK-NEXT: %[[TRUNC:[0-9]+]] = trunc nuw i64 %0 to i1
// CHECK-NEXT: %[[SEL:\.[0-9]+]] = select i1 %[[TRUNC]], i64 %1, i64 undef
// CHECK-NEXT: insertvalue { i64, i64 }
// CHECK-NEXT: insertvalue { i64, i64 }
// CHECK-NEXT: ret { i64, i64 }

View file

@ -1,5 +1,4 @@
//@ compile-flags: -Copt-level=0 -Cno-prepopulate-passes
//@ min-llvm-version: 19
//@ only-64bit
#![crate_type = "lib"]

View file

@ -1,42 +0,0 @@
//@ add-core-stubs
//@ revisions: sparc sparcv8plus sparc_cpu_v9 sparc_feature_v8plus sparc_cpu_v9_feature_v8plus
//@[sparc] compile-flags: --target sparc-unknown-none-elf
//@[sparc] needs-llvm-components: sparc
//@[sparcv8plus] compile-flags: --target sparc-unknown-linux-gnu
//@[sparcv8plus] needs-llvm-components: sparc
//@[sparc_cpu_v9] compile-flags: --target sparc-unknown-none-elf -C target-cpu=v9
//@[sparc_cpu_v9] needs-llvm-components: sparc
//@[sparc_feature_v8plus] compile-flags: --target sparc-unknown-none-elf -C target-feature=+v8plus
//@[sparc_feature_v8plus] needs-llvm-components: sparc
//@[sparc_cpu_v9_feature_v8plus] compile-flags: --target sparc-unknown-none-elf -C target-cpu=v9 -C target-feature=+v8plus
//@[sparc_cpu_v9_feature_v8plus] needs-llvm-components: sparc
//@ exact-llvm-major-version: 19
#![crate_type = "rlib"]
#![feature(no_core, rustc_attrs, lang_items)]
#![no_core]
extern crate minicore;
use minicore::*;
#[rustc_builtin_macro]
macro_rules! compile_error {
() => {};
}
#[cfg(all(not(target_feature = "v8plus"), not(target_feature = "v9")))]
compile_error!("-v8plus,-v9");
//[sparc]~^ ERROR -v8plus,-v9
// FIXME: sparc_cpu_v9 should be in "-v8plus,+v9" group (fixed in LLVM 20)
#[cfg(all(target_feature = "v8plus", target_feature = "v9"))]
compile_error!("+v8plus,+v9");
//[sparcv8plus,sparc_cpu_v9_feature_v8plus,sparc_cpu_v9]~^ ERROR +v8plus,+v9
// FIXME: should be rejected
#[cfg(all(target_feature = "v8plus", not(target_feature = "v9")))]
compile_error!("+v8plus,-v9 (FIXME)");
//[sparc_feature_v8plus]~^ ERROR +v8plus,-v9 (FIXME)
#[cfg(all(not(target_feature = "v8plus"), target_feature = "v9"))]
compile_error!("-v8plus,+v9");

View file

@ -1,8 +0,0 @@
error: -v8plus,-v9
--> $DIR/sparcv8plus-llvm19.rs:28:1
|
LL | compile_error!("-v8plus,-v9");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View file

@ -1,8 +0,0 @@
error: +v8plus,+v9
--> $DIR/sparcv8plus-llvm19.rs:33:1
|
LL | compile_error!("+v8plus,+v9");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View file

@ -1,8 +0,0 @@
error: +v8plus,+v9
--> $DIR/sparcv8plus-llvm19.rs:33:1
|
LL | compile_error!("+v8plus,+v9");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View file

@ -1,8 +0,0 @@
error: +v8plus,-v9 (FIXME)
--> $DIR/sparcv8plus-llvm19.rs:38:1
|
LL | compile_error!("+v8plus,-v9 (FIXME)");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View file

@ -1,8 +0,0 @@
error: +v8plus,+v9
--> $DIR/sparcv8plus-llvm19.rs:33:1
|
LL | compile_error!("+v8plus,+v9");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View file

@ -10,7 +10,6 @@
//@[sparc_feature_v8plus] needs-llvm-components: sparc
//@[sparc_cpu_v9_feature_v8plus] compile-flags: --target sparc-unknown-none-elf -C target-cpu=v9 -C target-feature=+v8plus
//@[sparc_cpu_v9_feature_v8plus] needs-llvm-components: sparc
//@ min-llvm-version: 20
#![crate_type = "rlib"]
#![feature(no_core, rustc_attrs, lang_items)]

View file

@ -1,5 +1,5 @@
error: -v8plus,-v9
--> $DIR/sparcv8plus.rs:28:1
--> $DIR/sparcv8plus.rs:27:1
|
LL | compile_error!("-v8plus,-v9");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -1,5 +1,5 @@
error: -v8plus,+v9
--> $DIR/sparcv8plus.rs:41:1
--> $DIR/sparcv8plus.rs:40:1
|
LL | compile_error!("-v8plus,+v9");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -1,5 +1,5 @@
error: +v8plus,+v9
--> $DIR/sparcv8plus.rs:32:1
--> $DIR/sparcv8plus.rs:31:1
|
LL | compile_error!("+v8plus,+v9");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -1,5 +1,5 @@
error: +v8plus,-v9 (FIXME)
--> $DIR/sparcv8plus.rs:37:1
--> $DIR/sparcv8plus.rs:36:1
|
LL | compile_error!("+v8plus,-v9 (FIXME)");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -1,5 +1,5 @@
error: +v8plus,+v9
--> $DIR/sparcv8plus.rs:32:1
--> $DIR/sparcv8plus.rs:31:1
|
LL | compile_error!("+v8plus,+v9");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -1,35 +1,35 @@
error: invalid register `$r0`: constant zero cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:27:18
--> $DIR/bad-reg.rs:26:18
|
LL | asm!("", out("$r0") _);
| ^^^^^^^^^^^^
error: invalid register `$tp`: reserved for TLS
--> $DIR/bad-reg.rs:29:18
--> $DIR/bad-reg.rs:28:18
|
LL | asm!("", out("$tp") _);
| ^^^^^^^^^^^^
error: invalid register `$sp`: the stack pointer cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:31:18
--> $DIR/bad-reg.rs:30:18
|
LL | asm!("", out("$sp") _);
| ^^^^^^^^^^^^
error: invalid register `$r21`: reserved by the ABI
--> $DIR/bad-reg.rs:33:18
--> $DIR/bad-reg.rs:32:18
|
LL | asm!("", out("$r21") _);
| ^^^^^^^^^^^^^
error: invalid register `$fp`: the frame pointer cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:35:18
--> $DIR/bad-reg.rs:34:18
|
LL | asm!("", out("$fp") _);
| ^^^^^^^^^^^^
error: invalid register `$r31`: $r31 is used internally by LLVM and cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:37:18
--> $DIR/bad-reg.rs:36:18
|
LL | asm!("", out("$r31") _);
| ^^^^^^^^^^^^^

View file

@ -1,59 +1,59 @@
error: invalid register `$r0`: constant zero cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:27:18
--> $DIR/bad-reg.rs:26:18
|
LL | asm!("", out("$r0") _);
| ^^^^^^^^^^^^
error: invalid register `$tp`: reserved for TLS
--> $DIR/bad-reg.rs:29:18
--> $DIR/bad-reg.rs:28:18
|
LL | asm!("", out("$tp") _);
| ^^^^^^^^^^^^
error: invalid register `$sp`: the stack pointer cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:31:18
--> $DIR/bad-reg.rs:30:18
|
LL | asm!("", out("$sp") _);
| ^^^^^^^^^^^^
error: invalid register `$r21`: reserved by the ABI
--> $DIR/bad-reg.rs:33:18
--> $DIR/bad-reg.rs:32:18
|
LL | asm!("", out("$r21") _);
| ^^^^^^^^^^^^^
error: invalid register `$fp`: the frame pointer cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:35:18
--> $DIR/bad-reg.rs:34:18
|
LL | asm!("", out("$fp") _);
| ^^^^^^^^^^^^
error: invalid register `$r31`: $r31 is used internally by LLVM and cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:37:18
--> $DIR/bad-reg.rs:36:18
|
LL | asm!("", out("$r31") _);
| ^^^^^^^^^^^^^
error: register class `freg` requires at least one of the following target features: d, f
--> $DIR/bad-reg.rs:41:26
--> $DIR/bad-reg.rs:40:26
|
LL | asm!("/* {} */", in(freg) f);
| ^^^^^^^^^^
error: register class `freg` requires at least one of the following target features: d, f
--> $DIR/bad-reg.rs:43:26
--> $DIR/bad-reg.rs:42:26
|
LL | asm!("/* {} */", out(freg) _);
| ^^^^^^^^^^^
error: register class `freg` requires at least one of the following target features: d, f
--> $DIR/bad-reg.rs:45:26
--> $DIR/bad-reg.rs:44:26
|
LL | asm!("/* {} */", in(freg) d);
| ^^^^^^^^^^
error: register class `freg` requires at least one of the following target features: d, f
--> $DIR/bad-reg.rs:47:26
--> $DIR/bad-reg.rs:46:26
|
LL | asm!("/* {} */", out(freg) d);
| ^^^^^^^^^^^

View file

@ -1,35 +1,35 @@
error: invalid register `$r0`: constant zero cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:27:18
--> $DIR/bad-reg.rs:26:18
|
LL | asm!("", out("$r0") _);
| ^^^^^^^^^^^^
error: invalid register `$tp`: reserved for TLS
--> $DIR/bad-reg.rs:29:18
--> $DIR/bad-reg.rs:28:18
|
LL | asm!("", out("$tp") _);
| ^^^^^^^^^^^^
error: invalid register `$sp`: the stack pointer cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:31:18
--> $DIR/bad-reg.rs:30:18
|
LL | asm!("", out("$sp") _);
| ^^^^^^^^^^^^
error: invalid register `$r21`: reserved by the ABI
--> $DIR/bad-reg.rs:33:18
--> $DIR/bad-reg.rs:32:18
|
LL | asm!("", out("$r21") _);
| ^^^^^^^^^^^^^
error: invalid register `$fp`: the frame pointer cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:35:18
--> $DIR/bad-reg.rs:34:18
|
LL | asm!("", out("$fp") _);
| ^^^^^^^^^^^^
error: invalid register `$r31`: $r31 is used internally by LLVM and cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:37:18
--> $DIR/bad-reg.rs:36:18
|
LL | asm!("", out("$r31") _);
| ^^^^^^^^^^^^^

View file

@ -1,59 +1,59 @@
error: invalid register `$r0`: constant zero cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:27:18
--> $DIR/bad-reg.rs:26:18
|
LL | asm!("", out("$r0") _);
| ^^^^^^^^^^^^
error: invalid register `$tp`: reserved for TLS
--> $DIR/bad-reg.rs:29:18
--> $DIR/bad-reg.rs:28:18
|
LL | asm!("", out("$tp") _);
| ^^^^^^^^^^^^
error: invalid register `$sp`: the stack pointer cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:31:18
--> $DIR/bad-reg.rs:30:18
|
LL | asm!("", out("$sp") _);
| ^^^^^^^^^^^^
error: invalid register `$r21`: reserved by the ABI
--> $DIR/bad-reg.rs:33:18
--> $DIR/bad-reg.rs:32:18
|
LL | asm!("", out("$r21") _);
| ^^^^^^^^^^^^^
error: invalid register `$fp`: the frame pointer cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:35:18
--> $DIR/bad-reg.rs:34:18
|
LL | asm!("", out("$fp") _);
| ^^^^^^^^^^^^
error: invalid register `$r31`: $r31 is used internally by LLVM and cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:37:18
--> $DIR/bad-reg.rs:36:18
|
LL | asm!("", out("$r31") _);
| ^^^^^^^^^^^^^
error: register class `freg` requires at least one of the following target features: d, f
--> $DIR/bad-reg.rs:41:26
--> $DIR/bad-reg.rs:40:26
|
LL | asm!("/* {} */", in(freg) f);
| ^^^^^^^^^^
error: register class `freg` requires at least one of the following target features: d, f
--> $DIR/bad-reg.rs:43:26
--> $DIR/bad-reg.rs:42:26
|
LL | asm!("/* {} */", out(freg) _);
| ^^^^^^^^^^^
error: register class `freg` requires at least one of the following target features: d, f
--> $DIR/bad-reg.rs:45:26
--> $DIR/bad-reg.rs:44:26
|
LL | asm!("/* {} */", in(freg) d);
| ^^^^^^^^^^
error: register class `freg` requires at least one of the following target features: d, f
--> $DIR/bad-reg.rs:47:26
--> $DIR/bad-reg.rs:46:26
|
LL | asm!("/* {} */", out(freg) d);
| ^^^^^^^^^^^

View file

@ -1,7 +1,6 @@
//@ add-core-stubs
//@ needs-asm-support
//@ revisions: loongarch32_ilp32d loongarch32_ilp32s loongarch64_lp64d loongarch64_lp64s
//@ min-llvm-version: 20
//@[loongarch32_ilp32d] compile-flags: --target loongarch32-unknown-none
//@[loongarch32_ilp32d] needs-llvm-components: loongarch
//@[loongarch32_ilp32s] compile-flags: --target loongarch32-unknown-none-softfloat