use correct LLVM intrinsic for min/max on floats#153343
use correct LLVM intrinsic for min/max on floats#153343rust-bors[bot] merged 1 commit intorust-lang:mainfrom
Conversation
|
Some changes occurred in compiler/rustc_codegen_cranelift cc @bjorn3 Some changes occurred to the CTFE / Miri interpreter cc @rust-lang/miri Some changes occurred in compiler/rustc_codegen_gcc Some changes occurred to the intrinsics. Make sure the CTFE / Miri interpreter cc @rust-lang/miri, @oli-obk, @lcnr Some changes occurred to the CTFE machinery |
| ); | ||
| // `nsz` in minimumnum/maximumnum is special: its only effect is to make signed-zero | ||
| // ordering non-deterministic. | ||
| unsafe { llvm::LLVMRustSetNoSignedZeros(call) }; |
There was a problem hiding this comment.
I have no idea if the way I wired up nsz is correct.^^
| if (auto I = dyn_cast<Instruction>(unwrap<Value>(V))) { | ||
| I->setHasNoSignedZeros(true); | ||
| } | ||
| } |
There was a problem hiding this comment.
The C bindings have a native LLVMSetFastMathFlags(), we should probably switch to that. But I guess we should do that consistently for the existing LLVMRustSetAlgebraicMath/LLVMRustSetAllowReassoc/LLVMRustSetFastMath as well, so I don't particularly mind this in the meantime.
There was a problem hiding this comment.
Yeah I don't know why we have a separate wrapper for each flag configuration here, but I figured I'd follow the existing pattern.
|
There are some odd things happening in CI Why did fcanonicalize end up with nsz? That was meant just for minimumnum. |
|
That was on the aarch64-gnu-llvm-20-1 runner. Maybe we have to fall back to minnum/maxnum for old LLVM versions? |
Ah yes, that's a good point. I believe minimumnum used to have some selection failures that were only fixed in LLVM 22. |
This comment has been minimized.
This comment has been minimized.
|
I guess that makes sense, the test fails on old LLVM where we (have to) use the wrong intrinsic. |
|
@bors try jobs=x86_64-gnu,aarch64-gnu |
This comment has been minimized.
This comment has been minimized.
rename min/maxnum intrinsics to min/maximum_number and fix their LLVM lowering try-job: x86_64-gnu try-job: aarch64-gnu
This comment has been minimized.
This comment has been minimized.
|
This is very strange, I tested the fallback implementation locally and it passes. Why does it fail on the aarch runner? And it's also a very strange return value. The inputs are |
This comment has been minimized.
This comment has been minimized.
|
now with the commit that always forces the fallback impl to be used |
This comment has been minimized.
This comment has been minimized.
rename min/maxnum intrinsics to min/maximum_number and fix their LLVM lowering try-job: x86_64-gnu try-job: aarch64-gnu try-job: x86_64-gnu-gcc
|
Seems like LLVM 20 straight-up miscompiles code like this fn minimum_num(x: f32, y: f32) -> f32 {
if x.is_nan() || y >= x {
y
} else {
// Either y < x or y is a NaN.
x
}
}
const SNAN: f32 = f32::from_bits(f32::NAN.to_bits() - 1);
fn main() {
dbg!(minimum_num(-9.0, std::hint::black_box(SNAN)));
}I tried this on an aarch64 dev desktop: with Rust 1.87, an optimized build prints How do we handle library tests that trigger miscompilations on old LLVM versions...? We could just remove the Are we anywhere close to dropping LLVM 20? :D |
This comment has been minimized.
This comment has been minimized.
|
@nikic Based on the CI results here, it looks like minimumnum/maximumnum already work well enough with LLVM 21. Is it fine to use them or should we still gate this on LLVM 22? |
|
There's a confusingly large amount of similarly named runners that don't all get run in PR CI so who knows which tests are actually covered... let's do a try run. |
This comment has been minimized.
This comment has been minimized.
use correct LLVM intrinsic for min/max on floats try-job: x86_64-gnu-llvm-21-*
This comment has been minimized.
This comment has been minimized.
|
Uh, what? Now some libtest tests are failing...? Those do involve min/max. Maybe there are miscompilations on x86 as well here (that were hopefully fixed in LLVM 22)? |
|
💔 Test for ac14465 failed: CI. Failed jobs:
|
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
|
📋 This PR cannot be approved because it currently has the following label: |
|
@bors r=nikic rollup=never |
This comment has been minimized.
This comment has been minimized.
What is this?This is an experimental post-merge analysis report that shows differences in test outcomes between the merged PR and its parent PR.Comparing 9e973d8 (parent) -> f125037 (this PR) Test differencesShow 17 test diffsStage 1
Stage 2
Additionally, 14 doctest diffs were found. These are ignored, as they are noisy. Job group index
Test dashboardRun cargo run --manifest-path src/ci/citool/Cargo.toml -- \
test-dashboard f125037ccddbeb162bce09213548314988da97a6 --output-dir test-dashboardAnd then open Job duration changes
How to interpret the job duration changes?Job durations can vary a lot, based on the actual runner instance |
|
Finished benchmarking commit (f125037): comparison URL. Overall result: ❌ regressions - no action needed@rustbot label: -perf-regression Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)Results (secondary 1.4%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (primary -2.8%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeResults (primary 0.1%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Bootstrap: 484.216s -> 479.863s (-0.90%) |
View all comments
The Rust
minnum/maxnumintrinsics are documented to return the other argument when one input is an SNaN. However, the LLVM lowering we currently choose for them does not match those semantics: we lower them tominnum/maxnum, which (since llvm/llvm-project#172012) is documented to non-deterministically return the other argument or NaN when one input is an SNaN.LLVM does have an intrinsic with the intended semantics:
minimumnum/maximumnum. Let's use that instead. We can set thenszflag since we treat signed zero ordering as non-deterministic.Also rename the intrinsics to follow the IEEE 2019 naming, since that is mostly (and in particular, as far as NaN are concerned) now what we do. Also,
minimum_numberandminimumare less easy to mix up thanminnumandminimum.r? @nikic
Cc @tgross35
Fixes #149537
Fixes #151286
(The issues are only fixed when using the latest supported LLVM, but I don't think we usually track problems specific to people compiling rustc with old versions of LLVM)