Closed CAD97 closed 5 months ago
https://github.com/rust-lang/rust/pull/122975 may help, can you try again once that lands?
That does look likely to be relevant, at least to the open-coded version; that the version using <Vec<_> as Deref>::deref
isn't inlining likely means that it still won't and thus won't be able to see UbChecks
transition from unknown to constant via inlining.
On the other hand, it somewhat feels like assert_unsafe_precondition!
should be checking cfg!(ub_checks)
"one level" up (e.g. from core::slice
into alloc::vec
) instead of "all the way" up (i.e. out of the sysroot crates); perhaps, in analogy to how overflow checks are handled, it's wanting for a per-function #[rustc_inherit_ub_checks]
instead of a crate-wide configuration? (Although even then, unsafe fn
should probably default to inheriting UB checks configuration.)
WG-prioritization assigning priority (Zulip discussion).
@rustbot label -I-prioritize +P-medium
I am not sure that PR fixes this. The replacement of the NullOp would occur after inlining, so we need the function to be a good inlining candidate in the first place in order to have its UbCheck removed. Resolving that was why I wrote https://github.com/rust-lang/rust/pull/121767, to remove the huge penalty from the call.
We could also special-case the check calls, they already have a special inliner attribute so what's a bit more magic 🙃
I tried this out with my reworked costs in #123179, but it still doesn't inline by default -- it needs the threshold to be raised to -Z inline-mir-hint-threshold=110
to get inlined with those new costs.
Seems like it's right on the edge. On nightly (2024-03-27) it took -Z inline-mir-hint-threshold=105
to inline https://rust.godbolt.org/z/7bK7n4d66, so it's only one instruction away.
It was so close to the threshold that a touch of simplification in libcore got it inlining again for you.
PR up: #123190
...instead of that previous one, changed to a new more holistic PR that also fixes this #123840
Code
I tried this code: [playground]
I expected to see this happen: in release mode with default MIR optimization, both
closed
andopen
would generate equivalent optimized MIR — an inlined conversion from&Vec<u8>
to&[u8]
(deconstruct theVec
into ptr and len then build the&[_]
).Instead, this happened: On 1.77.0, the inlining happens as expected. On 1.78.0-beta.3 (2024-03-27 4147533e05ee20c4fcc4),
<Vec<u8> as Deref>::deref
(vec_deref
foropen
) is called outline. Impactfully, the call is additionally not known to never unwind (-> [return: …, unwind continue]
in MIR), which likely impedes optimization around the call.
```rust fn vec_deref(_1: &Vecvec_deref
MIR on stable
```rust fn vec_deref(_1: &Vecvec_deref
MIR on betaOn stable,
vec_deref
's optimized MIR is a single straightline basic block. On beta, it contains aswitchInt
onUbCheck(LanguageUb)
guarding a conditional call tostd::slice::from_raw_parts::precondition_check
, resulting in four basic blocks including an MIR call operation. AIUI both of these metrics (block/call count) directly contribute to the MIR inlining heuristics.stable
```rust pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. unsafe { assert_unsafe_precondition!( "slice::from_raw_parts requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`", [T](data: *const T, len: usize) => is_aligned_and_not_null(data) && is_valid_allocation_size::slice::from_raw_parts
beta
```rust pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. unsafe { assert_unsafe_precondition!( check_language_ub, "slice::from_raw_parts requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`", ( data: *mut () = data as *mut (), size: usize = size_of::slice::from_raw_parts
Version it worked on
It most recently worked on: Rust Stable 1.77.0
Version with regression
It isn't working on: Rust Beta 1.78.0-beta.3 (2024-03-27 4147533e05ee20c4fcc4)
Meta
Found on irlo while looking at inlining behavior of
ToString
.@rustbot modify labels: +regression-from-stable-to-beta
(didn't do
-regression-untriaged
since I didn't try to narrow it any further than playground stable/beta, but don't know the convention here)cc @saethlin (IIRC you've been working on
assert_unsafe_precondition!
s and otherprecondition_check
s)