Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[goal] modifying private method in another crate's impl should not require users of public methods to recompile #37333

Closed
nikomatsakis opened this issue Oct 21, 2016 · 17 comments
Labels
A-incr-comp Area: Incremental compilation C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. P-medium Medium priority T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@nikomatsakis
Copy link
Contributor

This is an extension of #37121 but to support modification of a private method in another crate. This is currently complicated by the fact that when we write metadata, we make one metadata node per item. So any changes to the item at all are confounded together. IOW, we can't tell the difference between adding an inherent impl or method to a struct and changing the types of its fields. This results in really poor re-use.

@nikomatsakis
Copy link
Contributor Author

cc @michaelwoerister

@nikomatsakis
Copy link
Contributor Author

As far as priorities, I would put this goal somewhat secondary -- it's very important, but we should focus first on #37121 and of course correctness goals. IOW we can have a widely used version that doesn't handle this yet, since most people work primarily at a leaf crate when building. But we should link this goal perhaps to some issues that pertain to specific impl changes for fixing it.

@nikomatsakis nikomatsakis added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. A-incr-comp Area: Incremental compilation labels Oct 21, 2016
@nikomatsakis
Copy link
Contributor Author

triage: P-medium

@rust-highfive rust-highfive added the P-medium Medium priority label Oct 21, 2016
nikomatsakis added a commit to nikomatsakis/rust that referenced this issue Oct 21, 2016
Currently doesn't work that well at all in terms of getting reuse
afterwards, see rust-lang#37333. =)
@nagisa
Copy link
Member

nagisa commented Oct 22, 2016

The private callees might have been inlined through the public method.

@KalitaAlexey
Copy link
Contributor

@nagisa Good note. Is there any way to determine whether some private item was inlined? We must investigate this case.

@michaelwoerister
Copy link
Member

Inlining should mostly be handled by splitting interfaces from bodies for Metadata dep-nodes, like we also plan to do for HIR dep-nodes.

  1. If the public extern method is neither generic nor marked with #[inline] then we should not need to care what got inlined into it.
  2. If the public extern method is generic or marked with #[inline], we must track what goes into its body. If inlining happens at the MIR level, this should already be covered by the current tracking system. At LLVM level it's more difficult. I could imagine that we give the Rust compiler a heuristic that decides which functions are very unlikely to be inlined and then mark those functions with #[inline(never)] at the LLVM level --- and add dependency edges to all other callees because we can't guarantee that they haven't been inlined.

@hanna-kruppe
Copy link
Contributor

hanna-kruppe commented Oct 23, 2016

Just because a function (in the same LLVM module) is noinline doesn't mean LLVM won't peek at its implementation. For example, consider this playground example:

#[inline(never)]
pub fn five() -> i32 {
    5
}

pub fn caller() -> i32 {
    five() + 1
}

The LLVM IR for five is noinline (in debug and in release), but in release mode, caller gets optimized to ret i32 6. It also adds various attributes to caller that can only be justified by analyzing or inlining five (e.g., nounwind).

@michaelwoerister
Copy link
Member

@rkruppe Wow! That's a pretty blatant violation of what the documentation says about the attribute. Thanks for the info!

Oh well, we can still fall back to the brute force method of preventing inlining by moving those functions into their own compilation unit.

@nagisa
Copy link
Member

nagisa commented Oct 23, 2016

Wow! That's a pretty blatant violation of what the documentation says about the attribute. Thanks for the info!

This optimisation happens because of global (cross-function) constant propagation and not inlining, so no violations here. The way I see it, this goal cannot be achieved without instrumenting LLVM appropriately.

As an aside, LLVM has quite a few module-wide optimisations (inlining and global constprop being two examples), all of which would have to be instrumented somehow. Separate compilation units sound quite inefficient to me at the first consideration.

@eddyb
Copy link
Member

eddyb commented Oct 23, 2016

Separate compilation units might work with ThinLTO, if we get the granularity just right.

@michaelwoerister
Copy link
Member

Separate compilation units sound quite inefficient to me at the first consideration.

They are probably not ideal from a compile-time point of view.

One consequence of instrumenting LLVM would be that we have to push some of the dependency tracking past the LLVM passes. Probably not that big a deal.

A short-term solution would be to add dependency edges to everything that is transitively called within the same compilation unit (i.e. the worst case result that LLVM instrumentation data could yield).

@michaelwoerister
Copy link
Member

Oh wait, all of this might be a red herring: We are never re-using LLVM IR from an external crate. And regenerating the IR for locally inlined instances will necessarily create dependency edges to the MIR in metadata, so we should be fine.

@nikomatsakis
Copy link
Contributor Author

Just because a function (in the same LLVM module) is noinline doesn't mean LLVM won't peek at its implementation.

Right, this is one of the reasons we don't attempt to second guess LLVM's inlining, instead relying on just not giving it access to data, and assuming it uses whatever we give it, no matter what we say....

Oh wait, all of this might be a red herring

...and yes, I'm not sure how all of this is relevant. =)

Certainly if the function is #[inline] and we regenerate its IR, that is one thing...but that wasn't the case I was worried about, really. (And even then, we should be able to limit the effect of its propagation in many cases.)

@Mark-Simulacrum Mark-Simulacrum added the C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. label Jul 26, 2017
@Aaron1011
Copy link
Member

I'd like to work on this - is there a good place that I should start?

@michaelwoerister
Copy link
Member

This probably already works. So I suggest:

  1. See if there's a test case for it already in src/test/incremental.
  2. If not, add one.

michalt added a commit to michalt/rust that referenced this issue Jan 1, 2020
The test checks that we reuse the CGU of a crate when the implementation
details of an `extern crate` have changed.

Signed-off-by: Michal Terepeta <michal.terepeta@gmail.com>
Centril added a commit to Centril/rust that referenced this issue Jan 3, 2020
…sakis

Add a test for rust-lang#37333

The test checks that we reuse the CGU of a crate when the implementation
details of an `extern crate` have changed.

Signed-off-by: Michal Terepeta <michal.terepeta@gmail.com>
Centril added a commit to Centril/rust that referenced this issue Jan 4, 2020
…sakis

Add a test for rust-lang#37333

The test checks that we reuse the CGU of a crate when the implementation
details of an `extern crate` have changed.

Signed-off-by: Michal Terepeta <michal.terepeta@gmail.com>
bors added a commit that referenced this issue Jan 4, 2020
Rollup of 8 pull requests

Successful merges:

 - #66913 (Suggest calling method when first argument is `self`)
 - #67531 (no longer promote non-pattern const functions)
 - #67773 (Add a test for #37333)
 - #67786 (Nix reexports from `rustc_span` in `syntax`)
 - #67789 (Cleanup linkchecker whitelist)
 - #67810 (Implement uncommon_codepoints lint.)
 - #67835 (tweak wording of mismatched delimiter errors)
 - #67845 (Also remove const-hack for abs)

Failed merges:

r? @ghost
@michalt
Copy link
Contributor

michalt commented Jan 8, 2020

With the test added, I think this can be closed now. :)

@michaelwoerister
Copy link
Member

Yes, the test looks good. Thanks, @michalt!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-incr-comp Area: Incremental compilation C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. P-medium Medium priority T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

10 participants