Stabilize optimize attribute#157273
Conversation
|
rust-analyzer is developed in its own repository. If possible, consider making this change to rust-lang/rust-analyzer instead. cc @rust-lang/rust-analyzer |
|
r? @JohnTitor rustbot has assigned @JohnTitor. Use Why was this reviewer chosen?The reviewer was selected based on:
|
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
deb33c2 to
1de7123
Compare
This comment has been minimized.
This comment has been minimized.
1de7123 to
56db805
Compare
|
Given the interactions here, I expect this will need a lang+compiler FCP @rustbot label +I-lang-nominated +I-compiler-nominated See some recent discussion about this feature on Zulip #t-lang > status of #[optimize] attribute |
This comment has been minimized.
This comment has been minimized.
|
Marking as S-blocked given the current status. |
56db805 to
680ec3c
Compare
|
These commits modify Please ensure that if you've changed the output:
|
|
With my For example, can applying or removing this attribute on an item influence the contexts in which that item may be used without compile errors or other changes that would be considered public-API-breaking? |
I don't believe this is possible - the attribute should only influence how the compiler optimizes functions, and compiler optimizations should not have any visible effects. |
There was a problem hiding this comment.
Discussion: hm, I wonder if this attribute deserves an entry in the rustc book (a bit like lint levels), because while sure there's the Reference PR, but this is more like a compiler knob?
optimize attribute
Yes, this PR will stabilize the following: #![feature(optimize_attribute)]
fn main() {
f(
#[optimize(size)] || { },
);
}
fn f(_: impl Fn()) {}Note the absence of |
…mejrs,wesleywiser Ensure that optimize attributes on closures are inherited by the shim. Tracking issue: rust-lang#54882 Stabilization PR: rust-lang#157273
|
I think it's weird for this attribute not to apply to nested functions, and I finally put my finger on why. Optimization is a knob you usually set at the level of an entire compilation unit, and in fact, even an entire project. This attribute is great as a way of making that knob more fine-grained. But that implies it should work on modules. In other words, it would be surprising if there was a discontinuity here:
If we accept that In contrast, there is no equivalent of |
…mejrs,wesleywiser Ensure that optimize attributes on closures are inherited by the shim. Tracking issue: rust-lang#54882 Stabilization PR: rust-lang#157273
…mejrs,wesleywiser Ensure that optimize attributes on closures are inherited by the shim. Tracking issue: rust-lang#54882 Stabilization PR: rust-lang#157273
…mejrs,wesleywiser Ensure that optimize attributes on closures are inherited by the shim. Tracking issue: rust-lang#54882 Stabilization PR: rust-lang#157273
The intended semantics would be that:
Is that correct? If so, I can make a PR for that once #157802 is merged. This naturally extends to allowing the optimize attribute on modules, but we can leave that to a future extension IMO. |
I've wanted
Would you feel the same way if we had attributes to control loop unrolling or vectorization (i.e., some of the underlying things controlled by an While I understand the UX intuition that you mention (i.e., that some knobs feel more like compilation-unit ones), when adding attributes to control those, it seems better to me, as a language matter, for our codegen attributes to apply to items in a consistent way rather than having them differ based on those intuitions (which may vary between people). If we want to support automatic application to nested items, I'd suggest we do that (later) as an orthogonal axis in a syntactically distinct way. As one comparable, that's what GCC does: // Compile compilation unit with `-O2`.
static int helper(int x) { return x * 7 + 3; }
__attribute__((optimize("O0")))
int with_attribute(int x) {
int attr_nested(int y) { return helper(y) + 1; } // Still `-O2`.
return attr_nested(x);
}
#pragma GCC push_options
#pragma GCC optimize ("O0")
int in_region(int x) {
int region_nested(int y) { return helper(y) + 2; } // This is `-O0`.
return region_nested(x);
}
#pragma GCC pop_options |
|
@rfcbot reviewed |
|
This seems fine to me, but one thing did surprise me:
Looking at the code I see that |
I don't personally know, perhaps @nagisa would? (as - I believe - the person to implement that part) |
|
There isn't a way to tell LLVM that you want to optimize a single function for speed; or at least there wasn't. My memory is that I had planned to implement this as setting EDIT: though now with the improvements on LLVM side that Nikita mentioned maybe we can do tell LLVM that we want speed pretty much unconditionally and then mark all the functions not otherwise annotated with an |
Whatever ends up happening, a comment on that empty match arm would be helpful. |
|
We shouldn't stabilize @rfcbot concern optimize-speed-does-nothing |
Agreed. @nikic, is there a way to get My two cents: it'd be nice to stabilize |
|
tl;dr |
|
See rust/compiler/rustc_codegen_ssa/src/base.rs Lines 1101 to 1118 in 8e15021 |
Sure, I can see the case for
I think all of those could make sense on a per-module basis.
To expand on this, the idea of an #[apply(optimize(size))]
mod foo;I think to carry its weight, we would have to see that this helps for a lot of attributes where the "default" should not be to apply to sub-items.
That situation strikes me as something that "developed over time" versus being "designed", and I think we could be heading in a similar direction here. To summarize: Under the current semantics we may be heading toward a world where you have both |
|
The unknown for me is how we get there from here, but if we agree on the goal I think we can come up with something together. |
|
You're correct that what I'm flagging most here is the inconsistency that would result from treating the Is that the right thing to do, overall? Interesting question. I'm not sure. I do see the appeal. At the same time, I see challenges. Do we need some kind of reset to default across the entire family? And what about macros that might want to apply something to an item the macro expansion introduces but then reset the (user-written) items nested within it to the current in-scope default? And how do we define nested items exactly? If a codegen attribute is applied to a trait with default bodies and a conflicting attribute is applied to an impl instantiating those default bodies, which one wins? (It'd have to be def-site, right? But is that what people would expect here?) We error when combining Will we end up needing a way to express "apply this codegen attribute to exactly one item"? And I'm given to understand that there may be implementation challenges with nested application in terms of limiting the ability to consider each item in isolation, affecting incremental builds and opportunities for parallel processing. (And these challenges would apply equally, I'd imagine, to any kind of There are, as well, the migration challenges you mention. Probably there are good answers to these questions and challenges. I'd need to think more about them. (Thanks to @petrochenkov for useful discussion; all errors and worries remain mine.) |
|
I think the assignee here should be one who involves in the discussion so r? tmandry |
|
@rfcbot resolve optimize-speed-does-nothing See #157273 (comment). |
|
@rfcbot concern should-apply-to-closures I think this attribute should apply to closures. Not doing so would make sense if we viewed closures as standalone anonymous function objects, but I think it is better to view them as callable extensions of the current function. In this view, code inside a closure is "part of" the enclosing function. My proposal is different from how
|
|
Besides the concern I just filed about closures, I've reviewed the other aspects of this feature and come to the conclusion that I'm happy to ship it as-is. Thanks to @veluca93 for picking up this work and writing the stabilization report. @rfcbot reviewed PurposeI understand the purpose of this attribute to be setting the optimization goal for a function body. This is framed around intent rather than mechanics. It does not offer fine-grained control over backend-specific optimization levels. (The implementation offers limited control by letting compiler flags influence that.) One can imagine adding more fine-grained control later. At the language level this would be useful to application-specific code. But this feature is already useful for libraries. Library authors tend to know the performance-sensitive areas of their code better than users, and when paired with information about the intended use case this can be enough to override the globally configured optimization goal of the program or crate. This applies most of all to Applicability to inner itemsOn the question I brought up of whether I would have preferred to see the question handled in the RFC, so those implications could have been handled at the design stage. But given that we are at this stage, and because this is relatively difficult to change now and relatively easy to change later, I would rather stick with a version we can ship now than keep exploring the design space. I think there should be some affordance for applying |
View all comments
This commit stabilizes the
#[optimize]attribute, which allows for more fine-grained control of optimization levels.Stabilization report
Summary
Tracking issue: #54882
Reference PRs: rust-lang/reference#2278
cc @rust-lang/lang @rust-lang/lang-advisors @rust-lang/t-compiler
What is stabilized
What isn't stabilized
We might want to allow specifying a per-function optimization level (i.e.
#[optimize(level = 3)]). To my understanding, backend support for this is not quite there yet (and this - or other - extensions have consequently not been implemented yet).Applying the attribute on a module level is also not implemented yet.
Design
Reference
RFC history
Answers to unresolved question
Not yet.
Not yet.
Post-RFC changes
The
optimize(none)variant was added. The variants above were discussed here: #54882 (comment)Key points
#[optimize(none)]implies#[inline(never)]to be effective (#[optimize(none)] should imply #[inline(never)] #136329)#[optimize]is applied to an incompatible item #128458Nightly uses
The standard library itself uses this attribute in a few places
Implementation
Major part
rust/compiler/rustc_codegen_llvm/src/attributes.rs
Line 416 in c0bb140
#[optimize]is applied to an incompatible item #128458optimize(none): Add#[optimize(none)]#128657#[optimize(none)]implies#[inline(never)]#136358 (includes disabling MIR opts)Coverage
Tool changes
Trivial changes to rust-analyzer to support the new attribute as an inert attribute: rust-lang/rust-analyzer#22511
Type system, opsem
Breaks the AM?
As far as the AM is concerned, this attribute doesn't exist.
Acknowledgments
Most of the work was not done by me, I'm just writing the stabilization report :-)
@nagisa did the initial implementation, @clubby789 implemented optimize(none) and fixed the attribute being allowed in too many places.
Note
Concerns (0 active)
are-we-happy-wiht-capability-and-scope-of-this-attributeresolved in this commentmeaning-of-optimize-sizeresolved in this commentexplicitly-decide-on-effect-on-nested-functionsresolved in this commentManaged by
@rustbot—see help for details.