Change:
<!-- Thank you for filing a bug report! Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug. --While working on I noticed that some optimizations regressed after a rebase. The following should be a reduction. I tried this code: I expected to see this happen (beta): Instead, this happened (nightly): <!-- If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. --:
I was able to "fix" the nightly codegen to be identical to beta by adding to Probably some inlining change in llvm 18 ? :thinking:
cc
WG-prioritization assigning priority (). label -I-prioritize +P-medium
Odd, changing to fixes it. But is supposed to have strictly more UB, i.e. let LLVM optimize more.
I think the the direct cause here is a correctness fix in LLVM 18 which ends up stripping more poison flags during certain loop transformations, and ends up (likely unnecessarily) dropping here. The reason why offsetfrom helps is that it allows making use of the flag earlier by transforming a into . This transform requires that the exact operation be sdiv or ashr -- presumably because GEP offsets are signed. But this is not actually required (). It works just as well with unsigned exact division. I'll see about fixing that.
Upstream patch:
Now this is just rude. Apparently LoopIdiomRecognize strips the flags -- without actually performing any transform. I think LIR does some speculative expansion and then drops instructions again, but this doesn't recover flag changes.
Upstream issue for LIR:
Looks like my reduction was insufficient. The example on godbolt does optimize now but the original code that I was working on still fails with the but optimizes properly with . I'll extract the IR from a codegen test.
unoptimized IR, using subptr: <details<summaryoptimized IR, using subptr, fails to eliminate loop</summary</details<details<summaryoptimized IR, using offset_from, eliminates the loop</summary</details
Can you please provide a Rust test case or unoptimized IR?
The text file above should contain unoptimized IR.
Oh sorry, totally missed the first line...
This optimizes with LLVM 19, presumably due to the fix for But this is too risky to backport.
Not sure how to confirm whether this is really fixed now or not.
I'll dedust my branch and check it locally.
triage: original repro indeed fixed, any news on that local check?
is working again.

Discussion:
} } <del> fn install_llvm_file(builder: &Builder<'_>, source: &Path, destination: &Path) { </del> <ins> fn install_llvm_file( builder: &Builder<'_>, source: &Path, destination: &Path, install_symlink: bool, ) { </ins> if builder.config.dry_run() { return; } <del> builder.install(source, destination, 0o644); </del> <ins> if source.is_symlink() { // If we have a symlink like libLLVM-18.so -> libLLVM.so.18.1, install the target of the // symlink, which is what will actually get loaded at runtime. builder.install(&t!(fs::canonicalize(source)), destination, 0o644); if install_symlink { // If requested, also install the symlink. This is used by download-ci-llvm. let full_dest = destination.join(source.file_name().unwrap()); builder.copy(&source, &full_dest); } } else { builder.install(&source, destination, 0o644); } </ins> } /// Maybe add LLVM object files to the given destination lib-dir. Allows either static or dynamic linking. /// /// Returns whether the files were actually copied. <del> fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir: &Path) -> bool { </del> <ins> fn maybe_install_llvm( builder: &Builder<'_>, target: TargetSelection, dst_libdir: &Path, install_symlink: bool, ) -> bool { </ins> // If the LLVM was externally provided, then we don't currently copy // artifacts into the sysroot. This is not necessarily the right // choice (in particular, it will require the LLVM dylib to be in

} else { PathBuf::from(file) }; <del> install_llvm_file(builder, &file, dst_libdir); </del> <ins> install_llvm_file(builder, &file, dst_libdir, install_symlink); </ins> } !builder.config.dry_run() } else {

// dynamically linked; it is already included into librustc_llvm // statically. if builder.llvm_link_shared() { <del> maybe_install_llvm(builder, target, &dst_libdir); </del> <ins> maybe_install_llvm(builder, target, &dst_libdir, false); </ins> } }

let mut tarball = Tarball::new(builder, "rust-dev", &target.triple); tarball.set_overlay(OverlayKind::LLVM); <ins> // LLVM requires a shared object symlink to exist on some platforms. tarball.permit_symlinks(true); </ins> builder.ensure(crate::core::build_steps::llvm::Llvm { target });

// of `rustc-dev` to support the inherited `-lLLVM` when using the // compiler libraries. let dst_libdir = tarball.image_dir().join("lib"); <del> maybe_install_llvm(builder, target, &dst_libdir); </del> <ins> maybe_install_llvm(builder, target, &dst_libdir, true); </ins> let link_type = if builder.llvm_link_shared() { "dynamic" } else { "static" }; t!(std::fs::write(tarball.image_dir().join("link-type.txt"), link_type), dst_libdir);

let out_dir = builder.llvm_out(target); let mut llvm_config_ret_dir = builder.llvm_out(builder.config.build); <del> if (!builder.config.build.is_msvc() || builder.ninja()) && !builder.config.llvm_from_ci { llvm_config_ret_dir.push("build"); } </del> llvm_config_ret_dir.push("bin"); let build_llvm_config = llvm_config_ret_dir.join(exe("llvm-config", builder.config.build)); let llvm_cmake_dir = out_dir.join("lib/cmake/llvm");

<del> Subproject commit 9ea7f739f257b049a65deeb1f2455bb2ea021cfa </del> <ins> Subproject commit 7973f3560287d750500718314a0fd4025bd8ac0e </ins>

})?; let libdir = env.build_artifacts().join("stage2").join("lib"); <del> let llvm_lib = io::find_file_in_dir(&libdir, "libLLVM", ".so")?; </del> <ins> // The actual name will be something like libLLVM.so.18.1-rust-dev. let llvm_lib = io::find_file_in_dir(&libdir, "libLLVM.so", "")?; </ins> log::info!("Optimizing {llvm_lib} with BOLT");