3028 Commits

Author SHA1 Message Date
Jacob Pratt
1ae00ba888 Rollup merge of #147858 - yotamofek:pr/mir/coroutine-layout-opt, r=cjgillot
Micro-optimization attempt in coroutine layout computation

In `compute_layout`, there were a bunch of collections (`IndexVec`s) that were being created by `push`ing in a loop, instead of a, hopefully, more performant usage of iterator combinators. [Second commit](6f682c2774) is just a small cleanup.

I'd love a perf run to see if this shows up in benchmarks.
2025-10-30 02:43:42 -04:00
Jacob Pratt
f1a0dfd145 Rollup merge of #138217 - theemathas:cow_is_owned_borrowed_associated, r=dtolnay
Turn `Cow::is_borrowed,is_owned` into associated functions.

This is done because `Cow` implements `Deref`. Therefore, to avoid conflicts with an inner type having a method of the same name, we use an associated method, like `Box::into_raw`.

Tracking issue: #65143
2025-10-30 02:43:41 -04:00
Matthias Krüger
9489751d80 Rollup merge of #148131 - tmiasko:deduce-spread-arg, r=wesleywiser
Skip parameter attribute deduction for MIR with `spread_arg`

When a MIR argument is spread at ABI level, deduced attributes are potentially misapplied, since a spread argument can correspond to zero or more arguments at ABI level.

Disable deduction for MIR using spread argument for the time being.
2025-10-29 08:07:50 +01:00
Tomasz Miąsko
e9252a42f5 Skip parameter attribute deduction for MIR with spread_arg
When a MIR argument is spread at ABI level, deduced attributes are
potentially misapplied, since a spread argument can correspond to zero
or more arguments at ABI level.

Disable deduction for MIR using spread argument for the time being.
2025-10-28 23:07:04 +01:00
Ben Kimock
9cbfbb164e Accept trivial consts based on trivial consts 2025-10-27 13:36:57 -04:00
bors
4b53279854 Auto merge of #148040 - saethlin:trivial-consts, r=oli-obk
Add a fast path for lowering trivial consts

The objective of this PR is to improve compilation performance for crates that define a lot of trivial consts. This is a flamegraph of a build of a library crate that is just 100,000 trivial consts, taken from a nightly compiler:
<img width="842" height="280" alt="2025-10-25-164005_842x280_scrot" src="https://github.com/user-attachments/assets/e5400aaf-03bd-4461-b905-054aa82ca60f" />
My objective is to target all of the cycles in `eval_to_const_value_raw` that are not part of `mir_built`, because if you look at the `mir_built` for a trivial const, we already have the value available.

In this PR, the definition of a trivial const is this:
```rust
const A: usize = 0;
```
Specifically, we look for if the `mir_built` body is a single basic block containing one assign statement and a return terminator, where the assign statement assigns an `Operand::Constant(Const::Val)`. The MIR dumps for these look like:
```
const A: usize = {
    let mut _0: usize;

    bb0: {
        _0 = const 0_usize;
        return;
    }
}
```

The implementation is built around a new query, `trivial_const(LocalDefId) -> Option<(ConstValue, Ty)>` which returns the contents of the `Const::Val` in the `mir_built` if the `LocalDefId` is a trivial const.

Then I added _debug_ assertions to the beginning of `mir_for_ctfe` and `mir_promoted` to prevent trying to get the body of a trivial const, because that would defeat the optimization here. But these are deliberately _debug_ assertions because the consequence of failing the assertion is that compilation is slow, not corrupt. If we made these hard assertions, I'm sure there are obscure scenarios people will run into where the compiler would ICE instead of continuing on compilation, just a bit slower. I'd like to know about those, but I do not think serving up an ICE is worth it.

With the assertions in place, I just added logic around all the places they were hit, to skip over trying to analyze the bodies of trivial consts.

In the future, I'd like to see this work extended by:
* Pushing detection of trivial consts before MIR building
* Including DefKind::Static and DefKind::InlineConst
* Including consts like `_1 = const 0_usize; _0 = &_1`, which would make a lot of promoteds into trivial consts
* Handling less-trivial consts like `const A: usize = B`, which have `Operand::Constant(Const::Unevaluated)`
2025-10-27 11:02:41 +00:00
Ben Kimock
a63035f9bf Explain that the current impl is only silly, not recursive 2025-10-26 22:13:12 -04:00
Ben Kimock
6ba56d227f Move trivial_const to a separate module with a doc comment 2025-10-26 22:09:33 -04:00
Ben Kimock
775da711c6 Add a fast path for lowering trivial consts 2025-10-25 16:59:53 -04:00
Tomasz Miąsko
2a03a948b9 Deduce captures(none) for a return place and parameters
Extend attribute deduction to determine whether parameters using
indirect pass mode might have their address captured. Similarly to
the deduction of `readonly` attribute this information facilitates
memcpy optimizations.
2025-10-25 22:53:52 +02:00
Camille Gillot
ed85b96bb5 Insert assignment after Retag. 2025-10-24 02:41:51 +00:00
Camille Gillot
a15ef42488 Only load pin field once. 2025-10-24 02:41:50 +00:00
Camille Gillot
5dfbf67f94 Replace NullOp::SizeOf and NullOp::AlignOf by lang items. 2025-10-23 00:38:28 +00:00
bors
f5e2df741b Auto merge of #147687 - cjgillot:noshallow-init-box, r=nnethercote
Forbid ShallowInitBox after box deref elaboration.

MIR currently contains a `ShallowInitBox` rvalue. Its principal usage is to allow for in-place initialization of boxes. Having it is necessary for drop elaboration to be correct with that in-place initialization.

As part of analysis->runtime MIR lowering, we canonicalize deref of boxes to use the stored raw pointer. But we did not perform the same change to the construction of the box.

This PR replaces `ShallowInitBox` by the pointer manipulation it represents.

Alternatives:
- fully remove `ShallowInitBox` and implement `Box` in-place initialization differently;
- remove the `ElaborateBoxDeref` pass and keep dereferencing `Box` in runtime MIR.
2025-10-22 09:53:50 +00:00
Camille Gillot
0156eaf0d1 Introduce indexvec macro. 2025-10-22 00:52:52 +00:00
Camille Gillot
51275e82c9 Elaborate ShallowInitBox too. 2025-10-22 00:52:52 +00:00
Oli Scherer
375899c940 Allow unsizing pattern types with pointer base 2025-10-21 11:22:51 +00:00
bors
63dcdf7ca8 Auto merge of #147867 - cjgillot:invalidate-cleanup, r=tmiasko
Stop invalidating CFG caches in CleanupPostBorrowck.

r? `@ghost`
2025-10-21 01:17:03 +00:00
Camille Gillot
6abc50b394 Stop invalidating in CleanupPostBorrowck. 2025-10-20 21:34:46 +00:00
Yotam Ofek
a67c615506 Reduce rightward drift in locals_live_across_suspend_points 2025-10-19 22:46:27 +03:00
Yotam Ofek
f0c98c2caa Allocate vec capacity upfront in coroutine layout computation 2025-10-19 22:46:27 +03:00
Matthias Krüger
362c9e23dd Rollup merge of #147873 - RalfJung:deduce_param_attrs, r=tmiasko
comments for deduce_param_attrs

Cc `@saethlin` since IIRC you experimented with codegen doing post-mono MIR ops? That seems to be in conflict with this pass.
Cc `@tmiasko`

r? `@scottmcm`
2025-10-19 14:04:55 +02:00
Matthias Krüger
3f1d4fbb53 Rollup merge of #147868 - cjgillot:patch-local, r=saethlin
MirPatch: Simplify new_local.

Small simplification.
2025-10-19 14:04:55 +02:00
Matthias Krüger
3bfd71290e Rollup merge of #147575 - beepster4096:movesubpath, r=oli-obk
Refactor move analysis subpath representation

Follow up to rust-lang/rust#147055

This PR does two things:
1. Document/validate move analysis's assumptions about `Subslice` projections
2. Decouple move paths from `ProjectionElem`, using a new enum `MoveSubPath` instead
    - This would be needed eventually when `ProjectionElem::Deref` is removed

I wanted to do even more abstraction, making `MovePathLookup::find` return an iterator to remove the special handling of subslices in borrowck, but that regressed diagnostics and just wasn't worth the complexity.
2025-10-19 14:04:53 +02:00
Ralf Jung
82f6c60fe7 comments for deduce_param_attrs 2025-10-19 10:12:43 +02:00
Camille Gillot
a1e42f96f6 Simplify new_local. 2025-10-19 02:22:18 +00:00
bors
0c0f27afd4 Auto merge of #147695 - cjgillot:deduce-param-freeze, r=tmiasko
deduced_param_attrs: check Freeze on monomorphic types.

`deduced_param_attrs` currently checks `Freeze` bound on polymorphic MIR. This pessimizes the deduction, as generic types are not `Freeze` by default.

This moves the check to the ABI adjustment.
2025-10-18 12:37:45 +00:00
bors
c8a31b780d Auto merge of #147654 - dianqk:simplify-const-condition, r=cjgillot
Simplify trivial constants in SimplifyConstCondition

After `InstSimplify-after-simplifycfg` with `-Zub_checks=false`, there are many of the following patterns.

```
_13 = const false;
assume(copy _13);
_12 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable];
```

Simplifying them to unreachable early should make CFG simpler.
2025-10-18 09:29:51 +00:00
Matthias Krüger
a5d38ede1d Rollup merge of #145724 - folkertdev:track-caller-drop-no-mangle, r=fee1-dead
the `#[track_caller]` shim should not inherit `#[no_mangle]`

fixes https://github.com/rust-lang/rust/issues/143162

builds on https://github.com/rust-lang/rust/pull/143293 which introduced a mechanism to strip attributes from shims.

cc `@Jules-Bertholet` `@workingjubilee` `@bjorn3`

---

Summary:

This PR fixes an interaction between `#[track_caller]`, `#[no_mangle]`, and casting to a function pointer.

A function annotated with `#[track_caller]` internally has a hidden extra argument for the panic location. The `#[track_caller]` attribute is only allowed on `extern "Rust"` functions. When a function is annotated with both `#[no_mangle]` and `#[track_caller]`, the exported symbol has the signature that includes the extra panic location argument. This works on stable rust today:

```rust
extern "Rust" {
    #[track_caller]
    fn rust_track_caller_ffi_test_tracked() -> &'static Location<'static>;
}

mod provides {
    use std::panic::Location;
    #[track_caller] // UB if we did not have this!
    #[no_mangle]
    fn rust_track_caller_ffi_test_tracked() -> &'static Location<'static> {
        Location::caller()
    }
}
```

When a `#[track_caller]` function is converted to a function pointer, a shim is added to drop the additional argument. So this is a valid program:

```rust
#[track_caller]
fn foo() {}

fn main() {
    let f = foo as fn();
    f();
}
```

The issue arises when `foo` is additionally annotated with `#[no_mangle]`, the generated shim currently inherits this attribute, also exporting a symbol named `foo`, but one without the hidden panic location argument. The linker rightfully complains about a duplicate symbol.

The solution of this PR is to have the generated shim drop the `#[no_mangle]` attribute.
2025-10-18 08:08:36 +02:00
Camille Gillot
0b02102dc0 Attempt to compress representation. 2025-10-17 21:20:50 +00:00
Camille Gillot
73264f21e9 Restrict drop to empty projections. 2025-10-17 21:00:12 +00:00
Camille Gillot
97f88f5603 Generalize the non-freeze and needs_drop handling. 2025-10-17 16:28:37 +00:00
Cameron Steffen
e60e9f0826 Split impl_(opt_)trait_ref 2025-10-17 08:36:34 -05:00
Matthias Krüger
334b3af42c Rollup merge of #144438 - dawidl022:contracts/guarded-lowering, r=oli-obk
Guard HIR lowered contracts with `contract_checks`

Refactor contract HIR lowering to ensure no contract code is executed when contract-checks are disabled.

The call to `contract_checks` is moved to inside the lowered fn body, and contract closures are built conditionally, ensuring no side-effects present in contracts occur when those are disabled. This partially addresses rust-lang/rust#139548, i.e. the bad behavior no longer happens with contract checks disabled (`-Zcontract-checks=no`).

The change is made in preparation for adding contract variable declarations - variables declared before the `requires` assertion, and accessible from both `requires` and `ensures`, but not in the function body (PR rust-lang/rust#144444). As those declarations may also have side-effects, it's good to guard them with `contract_checks` - the new lowering approach allows for this to be done easily.

Contracts tracking issue: rust-lang/rust#128044

**Known limiatations**:

- It is still possible to early return from the *function* from within a contract, e.g.

  ```rust
  #[ensures({if x > 0 { return 0 }; |_| true})]
  fn foo(x: u32) -> i32 {
      42
  }
  ```

  When `foo` is called with an argument greater than 0, instead of `42`, `0` will be returned.

  As this is not a regression, it is not addressed in this PR. However, it may be worth revisiting later down the line, as users may expect a form of early return from *contract specifications*, and so returning from the entire *function* could cause confusion.

- ~Contracts are still not optimised out when disabled. Currently, even when contracts are disabled, the code generated causes existing optimisations to fail, meaning even disabled contracts could impact runtime performance. This issue is blocking rust-lang/rust#136578, and has not been addressed in this PR, i.e. the `mir-opt` and `codegen` tests that fail in rust-lang/rust#136578 still fail with these new HIR lowering changes.~ Contracts should now be optimised out when disabled, however some regressions tests still need to be added to be sure that is indeed the case.
2025-10-16 19:35:22 +02:00
dianqk
afff0502a6 GVN: Preserve derefs at terminators that cannot write to memory 2025-10-16 23:03:05 +08:00
dianqk
a673575b24 mir-opt: Simplify trivial constants in SimplifyConstCondition 2025-10-16 21:30:06 +08:00
Camille Gillot
fb38d75ca5 Simplify implementation. 2025-10-15 21:47:10 +00:00
Camille Gillot
031929c369 deduced_param_attrs: check Freeze on monomorphic types. 2025-10-15 21:21:05 +00:00
Stuart Cook
4fc3a05e54 Rollup merge of #147607 - dianqk:gvn-deref-loop, r=cjgillot
GVN: Invalidate derefs at loop headers

Fix a miscompiled case I found when re-reviewing rust-lang/rust#132527.

r? cjgillot
r? oli-obk
2025-10-14 16:31:02 +11:00
dianqk
2048b9c027 GVN: Invalidate derefs at loop headers 2025-10-14 08:09:32 +08:00
Matthias Krüger
6dd08cbd45 Rollup merge of #147533 - cjgillot:coro-late-renumber, r=davidtwco
Renumber return local after state transform

The current implementation of `StateTransform` renames `_0` before analyzing liveness. This is inconsistent, as a `return` terminator hardcodes a read of `_0`.

This PR proposes to perform such rename *after* analyzing the body, in fact after the whole transform. The implementation is not much more complicated.
2025-10-13 16:54:13 +02:00
bors
ff6dc928c5 Auto merge of #142390 - cjgillot:mir-liveness, r=davidtwco
Perform unused assignment and unused variables lints on MIR.

Rebase of https://github.com/rust-lang/rust/pull/101500

Fixes https://github.com/rust-lang/rust/issues/51003.

The first commit moves detection of uninhabited types from the current liveness pass to MIR building.

In order to keep the same level of diagnostics, I had to instrument MIR a little more:
- keep for which original local a guard local is created;
- store in the `VarBindingForm` the list of introducer places and whether this was a shorthand pattern.

I am not very proud of the handling of self-assignments. The proposed scheme is in two parts: first detect probable self-assignments, by pattern matching on MIR, and second treat them specially during dataflow analysis. I welcome ideas.

Please review carefully the changes in tests. There are many small changes to behaviour, and I'm not sure all of them are desirable.
2025-10-12 13:00:04 +00:00
beepster4096
3e94dd7f6a document unstated condition of Subslice and validate more 2025-10-11 22:51:39 -07:00
beepster4096
8f430d68f7 sort visit_projection_elem by definition order 2025-10-11 22:49:34 -07:00
bors
3be68033b6 Auto merge of #145513 - beepster4096:erasedereftemps, r=saethlin,cjgillot
Validate CopyForDeref and DerefTemps better and remove them from runtime MIR

(split from my WIP rust-lang/rust#145344)

This PR:
- Removes `Rvalue::CopyForDeref` and `LocalInfo::DerefTemp` from runtime MIR
    - Using a new mir pass `EraseDerefTemps`
    - `CopyForDeref(x)` is turned into `Use(Copy(x))`
    - `DerefTemp` is turned into `Boring`
        - Not sure if this part is actually necessary, it made more sense in rust-lang/rust#145344 with `DerefTemp` storing actual data that I wanted to keep from having to be kept in sync with the rest of the body in runtime MIR
- Checks in validation that `CopyForDeref` and `DerefTemp` are only used together
- Removes special handling for `CopyForDeref` from many places
- Removes `CopyForDeref` from `custom_mir` reverting rust-lang/rust#111587
    - In runtime MIR simple copies can be used instead
    - In post cleanup analysis MIR it was already wrong to use due to the lack of support for creating `DerefTemp` locals
    - Possibly this should be its own PR?
 - Adds an argument to `deref_finder` to avoid creating new `DerefTemp`s and `CopyForDeref` in runtime MIR.
     - Ideally we would just avoid making intermediate derefs instead of fixing it at the end of a pass / during shim building
 - Removes some usages of `deref_finder` that I found out don't actually do anything

r? oli-obk
2025-10-12 02:34:20 +00:00
Camille Gillot
b198bf8060 Rebase fallout. 2025-10-11 20:56:10 +00:00
Camille Gillot
c653430714 Suggest unit struct and constants. 2025-10-11 20:50:21 +00:00
Camille GILLOT
ca0379d6cd Diagnose liveness on MIR. 2025-10-11 20:50:21 +00:00
beepster4096
033474bacf remove some deref_finder uses
elaborate drops and inline don't seem to actually need it
2025-10-10 20:30:19 -07:00
Dawid Lachowicz
2a5dac7682 Remove no longer used contract_checks intrinsic
The contract_checks compiler flag is now used to determine
if runtime contract checks should be enabled, as opposed
to the compiler intrinsic as previously.
2025-10-11 00:16:44 +01:00