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

Add #[optimize(none)] #128657

Merged
merged 3 commits into from
Jan 25, 2025
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions compiler/rustc_attr_data_structures/src/attributes.rs
Original file line number Diff line number Diff line change
@@ -38,10 +38,20 @@ pub enum InstructionSetAttr {
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
pub enum OptimizeAttr {
None,
/// `#[optimize(none)]`
DoNotOptimize,
/// `#[optimize(speed)]`
Speed,
/// `#[optimize(size)]`
Size,
}

impl OptimizeAttr {
pub fn do_not_optimize(&self) -> bool {
matches!(self, Self::DoNotOptimize)
}
}

#[derive(Clone, Debug, Encodable, Decodable)]
pub enum DiagnosticAttribute {
// tidy-alphabetical-start
15 changes: 9 additions & 6 deletions compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
@@ -336,19 +336,22 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
OptimizeAttr::None => {
to_add.extend(default_optimisation_attrs(cx));
}
OptimizeAttr::DoNotOptimize => {
to_add.push(llvm::AttributeKind::OptimizeNone.create_attr(cx.llcx));
}
OptimizeAttr::Size => {
to_add.push(llvm::AttributeKind::MinSize.create_attr(cx.llcx));
to_add.push(llvm::AttributeKind::OptimizeForSize.create_attr(cx.llcx));
}
OptimizeAttr::Speed => {}
}

let inline =
if codegen_fn_attrs.inline == InlineAttr::None && instance.def.requires_inline(cx.tcx) {
InlineAttr::Hint
} else {
codegen_fn_attrs.inline
};
// `optnone` requires `noinline`
let inline = match (codegen_fn_attrs.inline, &codegen_fn_attrs.optimize) {
(_, OptimizeAttr::DoNotOptimize) => InlineAttr::Never,
(InlineAttr::None, _) if instance.def.requires_inline(cx.tcx) => InlineAttr::Hint,
(inline, _) => inline,
};
to_add.extend(inline_attr(cx, inline));

// The `uwtable` attribute according to LLVM is:
5 changes: 1 addition & 4 deletions compiler/rustc_codegen_ssa/src/base.rs
Original file line number Diff line number Diff line change
@@ -1053,10 +1053,7 @@ pub(crate) fn provide(providers: &mut Providers) {

let any_for_speed = defids.items().any(|id| {
let CodegenFnAttrs { optimize, .. } = tcx.codegen_fn_attrs(*id);
match optimize {
attr::OptimizeAttr::None | attr::OptimizeAttr::Size => false,
attr::OptimizeAttr::Speed => true,
}
matches!(optimize, attr::OptimizeAttr::Speed)
});

if any_for_speed {
2 changes: 2 additions & 0 deletions compiler/rustc_codegen_ssa/src/codegen_attrs.rs
Original file line number Diff line number Diff line change
@@ -592,6 +592,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
OptimizeAttr::Size
} else if list_contains_name(items, sym::speed) {
OptimizeAttr::Speed
} else if list_contains_name(items, sym::none) {
OptimizeAttr::DoNotOptimize
} else {
err(items[0].span(), "invalid argument");
OptimizeAttr::None
2 changes: 1 addition & 1 deletion compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
@@ -532,7 +532,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
),
// RFC 2412
gated!(
optimize, Normal, template!(List: "size|speed"), ErrorPreceding,
optimize, Normal, template!(List: "none|size|speed"), ErrorPreceding,
EncodeCrossCrate::No, optimize_attribute, experimental!(optimize)
),

4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
Original file line number Diff line number Diff line change
@@ -116,4 +116,8 @@ impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls {
// We may have invalidated some `cleanup` blocks so clean those up now.
super::simplify::remove_dead_blocks(body);
}

fn is_required(&self) -> bool {
true
}
}
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/add_call_guards.rs
Original file line number Diff line number Diff line change
@@ -75,4 +75,8 @@ impl<'tcx> crate::MirPass<'tcx> for AddCallGuards {

body.basic_blocks_mut().extend(new_blocks);
}

fn is_required(&self) -> bool {
true
}
}
Original file line number Diff line number Diff line change
@@ -68,6 +68,10 @@ impl<'tcx> crate::MirPass<'tcx> for AddMovesForPackedDrops {

patch.apply(body);
}

fn is_required(&self) -> bool {
true
}
}

fn add_move_for_packed_drop<'tcx>(
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/add_retag.rs
Original file line number Diff line number Diff line change
@@ -176,4 +176,8 @@ impl<'tcx> crate::MirPass<'tcx> for AddRetag {
}
}
}

fn is_required(&self) -> bool {
true
}
}
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/add_subtyping_projections.rs
Original file line number Diff line number Diff line change
@@ -61,4 +61,8 @@ impl<'tcx> crate::MirPass<'tcx> for Subtyper {
}
checker.patcher.apply(body);
}

fn is_required(&self) -> bool {
true
}
}
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/check_alignment.rs
Original file line number Diff line number Diff line change
@@ -60,6 +60,10 @@ impl<'tcx> crate::MirPass<'tcx> for CheckAlignment {
}
}
}

fn is_required(&self) -> bool {
true
}
}

struct PointerFinder<'a, 'tcx> {
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
Original file line number Diff line number Diff line change
@@ -72,4 +72,8 @@ impl<'tcx> crate::MirPass<'tcx> for CleanupPostBorrowck {
decl.user_ty = None;
}
}

fn is_required(&self) -> bool {
true
}
}
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/copy_prop.rs
Original file line number Diff line number Diff line change
@@ -56,6 +56,10 @@ impl<'tcx> crate::MirPass<'tcx> for CopyProp {
crate::simplify::remove_unused_definitions(body);
}
}

fn is_required(&self) -> bool {
false
}
}

/// `SsaLocals` computed equivalence classes between locals considering copy/move assignments.
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/coroutine.rs
Original file line number Diff line number Diff line change
@@ -1688,6 +1688,10 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform {
// Run derefer to fix Derefs that are not in the first place
deref_finder(tcx, body);
}

fn is_required(&self) -> bool {
true
}
}

/// Looks for any assignments between locals (e.g., `_4 = _5`) that will both be converted to fields
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/coverage/mod.rs
Original file line number Diff line number Diff line change
@@ -61,6 +61,10 @@ impl<'tcx> crate::MirPass<'tcx> for InstrumentCoverage {

instrument_function_for_coverage(tcx, mir_body);
}

fn is_required(&self) -> bool {
false
}
}

fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) {
2 changes: 1 addition & 1 deletion compiler/rustc_mir_transform/src/cross_crate_inline.rs
Original file line number Diff line number Diff line change
@@ -69,7 +69,7 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
// Don't do any inference if codegen optimizations are disabled and also MIR inlining is not
// enabled. This ensures that we do inference even if someone only passes -Zinline-mir,
// which is less confusing than having to also enable -Copt-level=1.
let inliner_will_run = pm::should_run_pass(tcx, &inline::Inline)
let inliner_will_run = pm::should_run_pass(tcx, &inline::Inline, pm::Optimizations::Allowed)
|| inline::ForceInline::should_run_pass_for_callee(tcx, def_id.to_def_id());
if matches!(tcx.sess.opts.optimize, OptLevel::No) && !inliner_will_run {
return false;
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/ctfe_limit.rs
Original file line number Diff line number Diff line change
@@ -36,6 +36,10 @@ impl<'tcx> crate::MirPass<'tcx> for CtfeLimit {
);
}
}

fn is_required(&self) -> bool {
true
}
}

fn has_back_edge(
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/dataflow_const_prop.rs
Original file line number Diff line number Diff line change
@@ -71,6 +71,10 @@ impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp {
let mut patch = visitor.patch;
debug_span!("patch").in_scope(|| patch.visit_body_preserves_cfg(body));
}

fn is_required(&self) -> bool {
false
}
}

// Note: Currently, places that have their reference taken cannot be tracked. Although this would
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/dead_store_elimination.rs
Original file line number Diff line number Diff line change
@@ -147,4 +147,8 @@ impl<'tcx> crate::MirPass<'tcx> for DeadStoreElimination {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
eliminate(tcx, body);
}

fn is_required(&self) -> bool {
false
}
}
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/deduplicate_blocks.rs
Original file line number Diff line number Diff line change
@@ -31,6 +31,10 @@ impl<'tcx> crate::MirPass<'tcx> for DeduplicateBlocks {
simplify_cfg(body);
}
}

fn is_required(&self) -> bool {
false
}
}

struct OptApplier<'tcx> {
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/deref_separator.rs
Original file line number Diff line number Diff line change
@@ -81,4 +81,8 @@ impl<'tcx> crate::MirPass<'tcx> for Derefer {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
deref_finder(tcx, body);
}

fn is_required(&self) -> bool {
true
}
}
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/dest_prop.rs
Original file line number Diff line number Diff line change
@@ -240,6 +240,10 @@ impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation {

trace!(round_count);
}

fn is_required(&self) -> bool {
false
}
}

#[derive(Debug, Default)]
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/dump_mir.rs
Original file line number Diff line number Diff line change
@@ -15,6 +15,10 @@ impl<'tcx> crate::MirPass<'tcx> for Marker {
}

fn run_pass(&self, _tcx: TyCtxt<'tcx>, _body: &mut Body<'tcx>) {}

fn is_required(&self) -> bool {
false
}
}

pub fn emit_mir(tcx: TyCtxt<'_>) -> io::Result<()> {
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/early_otherwise_branch.rs
Original file line number Diff line number Diff line change
@@ -227,6 +227,10 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch {
simplify_cfg(body);
}
}

fn is_required(&self) -> bool {
false
}
}

#[derive(Debug)]
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
Original file line number Diff line number Diff line change
@@ -150,4 +150,8 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateBoxDerefs {
}
}
}

fn is_required(&self) -> bool {
true
}
}
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/elaborate_drops.rs
Original file line number Diff line number Diff line change
@@ -88,6 +88,10 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateDrops {
elaborate_patch.apply(body);
deref_finder(tcx, body);
}

fn is_required(&self) -> bool {
true
}
}

/// Records unwind edges which are known to be unreachable, because they are in `drop` terminators
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/gvn.rs
Original file line number Diff line number Diff line change
@@ -163,6 +163,10 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
// statements.
StorageRemover { tcx, reused_locals: state.reused_locals }.visit_body_preserves_cfg(body);
}

fn is_required(&self) -> bool {
false
}
}

newtype_index! {
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/impossible_predicates.rs
Original file line number Diff line number Diff line change
@@ -53,4 +53,8 @@ impl<'tcx> MirPass<'tcx> for ImpossiblePredicates {
body.local_decls.raw.truncate(body.arg_count + 1);
}
}

fn is_required(&self) -> bool {
true
}
}
8 changes: 8 additions & 0 deletions compiler/rustc_mir_transform/src/inline.rs
Original file line number Diff line number Diff line change
@@ -66,6 +66,10 @@ impl<'tcx> crate::MirPass<'tcx> for Inline {
deref_finder(tcx, body);
}
}

fn is_required(&self) -> bool {
false
}
}

pub struct ForceInline;
@@ -85,6 +89,10 @@ impl<'tcx> crate::MirPass<'tcx> for ForceInline {
false
}

fn is_required(&self) -> bool {
true
}

fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let span = trace_span!("force_inline", body = %tcx.def_path_str(body.source.def_id()));
let _guard = span.enter();
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/instsimplify.rs
Original file line number Diff line number Diff line change
@@ -62,6 +62,10 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
simplify_duplicate_switch_targets(block.terminator.as_mut().unwrap());
}
}

fn is_required(&self) -> bool {
false
}
}

struct InstSimplifyContext<'a, 'tcx> {
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/jump_threading.rs
Original file line number Diff line number Diff line change
@@ -105,6 +105,10 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading {
}
OpportunitySet::new(body, opportunities).apply(body);
}

fn is_required(&self) -> bool {
false
}
}

#[derive(Debug)]
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/large_enums.rs
Original file line number Diff line number Diff line change
@@ -200,6 +200,10 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt {
});
}
}

fn is_required(&self) -> bool {
false
}
}

impl EnumSizeOpt {
33 changes: 29 additions & 4 deletions compiler/rustc_mir_transform/src/lib.rs
Original file line number Diff line number Diff line change
@@ -388,6 +388,7 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
&Lint(sanity_check::SanityCheck),
],
None,
pm::Optimizations::Allowed,
);
tcx.alloc_steal_mir(body)
}
@@ -440,6 +441,7 @@ fn mir_promoted(
&mut body,
&[&promote_pass, &simplify::SimplifyCfg::PromoteConsts, &coverage::InstrumentCoverage],
Some(MirPhase::Analysis(AnalysisPhase::Initial)),
pm::Optimizations::Allowed,
);

lint_tail_expr_drop_order::run_lint(tcx, def, &body);
@@ -473,7 +475,7 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
};

let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::Const);
pm::run_passes(tcx, &mut body, &[&ctfe_limit::CtfeLimit], None);
pm::run_passes(tcx, &mut body, &[&ctfe_limit::CtfeLimit], None, pm::Optimizations::Allowed);

body
}
@@ -493,7 +495,7 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
let is_fn_like = tcx.def_kind(def).is_fn_like();
if is_fn_like {
// Do not compute the mir call graph without said call graph actually being used.
if pm::should_run_pass(tcx, &inline::Inline)
if pm::should_run_pass(tcx, &inline::Inline, pm::Optimizations::Allowed)
|| inline::ForceInline::should_run_pass_for_callee(tcx, def.to_def_id())
{
tcx.ensure_with_value().mir_inliner_callees(ty::InstanceKind::Item(def.to_def_id()));
@@ -533,6 +535,7 @@ pub fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'
&Lint(post_drop_elaboration::CheckLiveDrops),
],
None,
pm::Optimizations::Allowed,
);
}

@@ -557,7 +560,13 @@ fn run_analysis_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
&deref_separator::Derefer,
];

pm::run_passes(tcx, body, passes, Some(MirPhase::Analysis(AnalysisPhase::PostCleanup)));
pm::run_passes(
tcx,
body,
passes,
Some(MirPhase::Analysis(AnalysisPhase::PostCleanup)),
pm::Optimizations::Allowed,
);
}

/// Returns the sequence of passes that lowers analysis to runtime MIR.
@@ -597,7 +606,13 @@ fn run_runtime_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
&simplify::SimplifyCfg::PreOptimizations,
];

pm::run_passes(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::PostCleanup)));
pm::run_passes(
tcx,
body,
passes,
Some(MirPhase::Runtime(RuntimePhase::PostCleanup)),
pm::Optimizations::Allowed,
);

// Clear this by anticipation. Optimizations and runtime MIR have no reason to look
// into this information, which is meant for borrowck diagnostics.
@@ -611,6 +626,15 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
WithMinOptLevel(1, x)
}

let def_id = body.source.def_id();
let optimizations = if tcx.def_kind(def_id).has_codegen_attrs()
&& tcx.codegen_fn_attrs(def_id).optimize.do_not_optimize()
{
pm::Optimizations::Suppressed
} else {
pm::Optimizations::Allowed
};

// The main optimizations that we do on MIR.
pm::run_passes(
tcx,
@@ -683,6 +707,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
&dump_mir::Marker("PreCodegen"),
],
Some(MirPhase::Runtime(RuntimePhase::Optimized)),
optimizations,
);
}

4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/lower_intrinsics.rs
Original file line number Diff line number Diff line change
@@ -325,4 +325,8 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
}
}
}

fn is_required(&self) -> bool {
true
}
}
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/lower_slice_len.rs
Original file line number Diff line number Diff line change
@@ -26,6 +26,10 @@ impl<'tcx> crate::MirPass<'tcx> for LowerSliceLenCalls {
lower_slice_len_call(block, slice_len_fn_item_def_id);
}
}

fn is_required(&self) -> bool {
false
}
}

fn lower_slice_len_call<'tcx>(block: &mut BasicBlockData<'tcx>, slice_len_fn_item_def_id: DefId) {
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/match_branches.rs
Original file line number Diff line number Diff line change
@@ -49,6 +49,10 @@ impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification {
simplify_cfg(body);
}
}

fn is_required(&self) -> bool {
false
}
}

trait SimplifyMatch<'tcx> {
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/mentioned_items.rs
Original file line number Diff line number Diff line change
@@ -27,6 +27,10 @@ impl<'tcx> crate::MirPass<'tcx> for MentionedItems {
visitor.visit_body(body);
body.set_mentioned_items(visitor.mentioned_items);
}

fn is_required(&self) -> bool {
true
}
}

// This visitor is carefully in sync with the one in `rustc_monomorphize::collector`. We are
Original file line number Diff line number Diff line change
@@ -36,4 +36,8 @@ impl<'tcx> crate::MirPass<'tcx> for MultipleReturnTerminators {

simplify::remove_dead_blocks(body)
}

fn is_required(&self) -> bool {
false
}
}
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/nrvo.rs
Original file line number Diff line number Diff line change
@@ -71,6 +71,10 @@ impl<'tcx> crate::MirPass<'tcx> for RenameReturnPlace {
// The return place is always mutable.
ret_decl.mutability = Mutability::Mut;
}

fn is_required(&self) -> bool {
false
}
}

/// MIR that is eligible for the NRVO must fulfill two conditions:
39 changes: 34 additions & 5 deletions compiler/rustc_mir_transform/src/pass_manager.rs
Original file line number Diff line number Diff line change
@@ -90,6 +90,11 @@ pub(super) trait MirPass<'tcx> {
fn is_mir_dump_enabled(&self) -> bool {
true
}

/// Returns `true` if this pass must be run (i.e. it is required for soundness).
/// For passes which are strictly optimizations, this should return `false`.
/// If this is `false`, `#[optimize(none)]` will disable the pass.
fn is_required(&self) -> bool;
}

/// Just like `MirPass`, except it cannot mutate `Body`, and MIR dumping is
@@ -134,6 +139,10 @@ where
fn is_mir_dump_enabled(&self) -> bool {
false
}

fn is_required(&self) -> bool {
true
}
}

pub(super) struct WithMinOptLevel<T>(pub u32, pub T);
@@ -153,6 +162,19 @@ where
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
self.1.run_pass(tcx, body)
}

fn is_required(&self) -> bool {
self.1.is_required()
}
}

/// Whether to allow non-[required] optimizations
///
/// [required]: MirPass::is_required
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(crate) enum Optimizations {
Suppressed,
Allowed,
}

/// Run the sequence of passes without validating the MIR after each pass. The MIR is still
@@ -163,7 +185,7 @@ pub(super) fn run_passes_no_validate<'tcx>(
passes: &[&dyn MirPass<'tcx>],
phase_change: Option<MirPhase>,
) {
run_passes_inner(tcx, body, passes, phase_change, false);
run_passes_inner(tcx, body, passes, phase_change, false, Optimizations::Allowed);
}

/// The optional `phase_change` is applied after executing all the passes, if present
@@ -172,11 +194,16 @@ pub(super) fn run_passes<'tcx>(
body: &mut Body<'tcx>,
passes: &[&dyn MirPass<'tcx>],
phase_change: Option<MirPhase>,
optimizations: Optimizations,
) {
run_passes_inner(tcx, body, passes, phase_change, true);
run_passes_inner(tcx, body, passes, phase_change, true, optimizations);
}

pub(super) fn should_run_pass<'tcx, P>(tcx: TyCtxt<'tcx>, pass: &P) -> bool
pub(super) fn should_run_pass<'tcx, P>(
tcx: TyCtxt<'tcx>,
pass: &P,
optimizations: Optimizations,
) -> bool
where
P: MirPass<'tcx> + ?Sized,
{
@@ -196,7 +223,8 @@ where
);
*polarity
});
overridden.unwrap_or_else(|| pass.is_enabled(tcx.sess))
let suppressed = !pass.is_required() && matches!(optimizations, Optimizations::Suppressed);
overridden.unwrap_or_else(|| !suppressed && pass.is_enabled(tcx.sess))
}

fn run_passes_inner<'tcx>(
@@ -205,6 +233,7 @@ fn run_passes_inner<'tcx>(
passes: &[&dyn MirPass<'tcx>],
phase_change: Option<MirPhase>,
validate_each: bool,
optimizations: Optimizations,
) {
let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes;
trace!(?overridden_passes);
@@ -243,7 +272,7 @@ fn run_passes_inner<'tcx>(
for pass in passes {
let name = pass.name();

if !should_run_pass(tcx, *pass) {
if !should_run_pass(tcx, *pass, optimizations) {
continue;
};

4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/post_analysis_normalize.rs
Original file line number Diff line number Diff line change
@@ -15,6 +15,10 @@ impl<'tcx> crate::MirPass<'tcx> for PostAnalysisNormalize {
let typing_env = ty::TypingEnv::post_analysis(tcx, body.source.def_id());
PostAnalysisNormalizeVisitor { tcx, typing_env }.visit_body_preserves_cfg(body);
}

fn is_required(&self) -> bool {
true
}
}

struct PostAnalysisNormalizeVisitor<'tcx> {
8 changes: 8 additions & 0 deletions compiler/rustc_mir_transform/src/prettify.rs
Original file line number Diff line number Diff line change
@@ -35,6 +35,10 @@ impl<'tcx> crate::MirPass<'tcx> for ReorderBasicBlocks {

permute(body.basic_blocks.as_mut(), &updater.map);
}

fn is_required(&self) -> bool {
false
}
}

/// Rearranges the locals into *use* order.
@@ -85,6 +89,10 @@ impl<'tcx> crate::MirPass<'tcx> for ReorderLocals {

permute(&mut body.local_decls, &updater.map);
}

fn is_required(&self) -> bool {
false
}
}

fn permute<I: rustc_index::Idx + Ord, T>(data: &mut IndexVec<I, T>, map: &IndexSlice<I, I>) {
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/promote_consts.rs
Original file line number Diff line number Diff line change
@@ -61,6 +61,10 @@ impl<'tcx> crate::MirPass<'tcx> for PromoteTemps<'tcx> {
let promoted = promote_candidates(body, tcx, temps, promotable_candidates);
self.promoted_fragments.set(promoted);
}

fn is_required(&self) -> bool {
true
}
}

/// State of a temporary during collection and promotion.
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/ref_prop.rs
Original file line number Diff line number Diff line change
@@ -81,6 +81,10 @@ impl<'tcx> crate::MirPass<'tcx> for ReferencePropagation {
debug!(def_id = ?body.source.def_id());
while propagate_ssa(tcx, body) {}
}

fn is_required(&self) -> bool {
false
}
}

fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
Original file line number Diff line number Diff line change
@@ -74,6 +74,10 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveNoopLandingPads {

debug!("removed {:?} jumps and {:?} landing pads", jumps_folded, landing_pads_removed);
}

fn is_required(&self) -> bool {
true
}
}

impl RemoveNoopLandingPads {
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/remove_place_mention.rs
Original file line number Diff line number Diff line change
@@ -20,4 +20,8 @@ impl<'tcx> crate::MirPass<'tcx> for RemovePlaceMention {
})
}
}

fn is_required(&self) -> bool {
true
}
}
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/remove_storage_markers.rs
Original file line number Diff line number Diff line change
@@ -22,4 +22,8 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveStorageMarkers {
})
}
}

fn is_required(&self) -> bool {
true
}
}
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/remove_uninit_drops.rs
Original file line number Diff line number Diff line change
@@ -62,6 +62,10 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUninitDrops {
block.terminator_mut().kind = TerminatorKind::Goto { target: *target };
}
}

fn is_required(&self) -> bool {
true
}
}

fn is_needs_drop_and_init<'tcx>(
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
Original file line number Diff line number Diff line change
@@ -38,4 +38,8 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUnneededDrops {
simplify_cfg(body);
}
}

fn is_required(&self) -> bool {
true
}
}
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/remove_zsts.rs
Original file line number Diff line number Diff line change
@@ -27,6 +27,10 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveZsts {
replacer.visit_basic_block_data(bb, data);
}
}

fn is_required(&self) -> bool {
true
}
}

struct Replacer<'a, 'tcx> {
1 change: 1 addition & 0 deletions compiler/rustc_mir_transform/src/shim.rs
Original file line number Diff line number Diff line change
@@ -119,6 +119,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body<
&add_call_guards::CriticalCallEdges,
],
Some(MirPhase::Runtime(RuntimePhase::Optimized)),
pm::Optimizations::Allowed,
);

return body;
8 changes: 8 additions & 0 deletions compiler/rustc_mir_transform/src/simplify.rs
Original file line number Diff line number Diff line change
@@ -83,6 +83,10 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyCfg {
debug!("SimplifyCfg({:?}) - simplifying {:?}", self.name(), body.source);
simplify_cfg(body);
}

fn is_required(&self) -> bool {
false
}
}

struct CfgSimplifier<'a, 'tcx> {
@@ -405,6 +409,10 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyLocals {
body.local_decls.shrink_to_fit();
}
}

fn is_required(&self) -> bool {
false
}
}

pub(super) fn remove_unused_definitions<'tcx>(body: &mut Body<'tcx>) {
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/simplify_branches.rs
Original file line number Diff line number Diff line change
@@ -60,4 +60,8 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition {
};
}
}

fn is_required(&self) -> bool {
false
}
}
Original file line number Diff line number Diff line change
@@ -140,6 +140,10 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral {
body.basic_blocks_mut()[idx].statements.insert(0, stmt);
}
}

fn is_required(&self) -> bool {
false
}
}

struct OptimizationFinder<'a, 'tcx> {
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/single_use_consts.rs
Original file line number Diff line number Diff line change
@@ -81,6 +81,10 @@ impl<'tcx> crate::MirPass<'tcx> for SingleUseConsts {
}
}
}

fn is_required(&self) -> bool {
true
}
}

#[derive(Copy, Clone, Debug)]
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/sroa.rs
Original file line number Diff line number Diff line change
@@ -48,6 +48,10 @@ impl<'tcx> crate::MirPass<'tcx> for ScalarReplacementOfAggregates {
}
}
}

fn is_required(&self) -> bool {
false
}
}

/// Identify all locals that are not eligible for SROA.
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/strip_debuginfo.rs
Original file line number Diff line number Diff line change
@@ -31,4 +31,8 @@ impl<'tcx> crate::MirPass<'tcx> for StripDebugInfo {
)
});
}

fn is_required(&self) -> bool {
true
}
}
Original file line number Diff line number Diff line change
@@ -208,4 +208,8 @@ impl<'tcx> crate::MirPass<'tcx> for UnreachableEnumBranching {

patch.apply(body);
}

fn is_required(&self) -> bool {
false
}
}
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/unreachable_prop.rs
Original file line number Diff line number Diff line change
@@ -52,6 +52,10 @@ impl crate::MirPass<'_> for UnreachablePropagation {
body.basic_blocks_mut()[bb].statements.clear();
}
}

fn is_required(&self) -> bool {
false
}
}

/// Return whether the current terminator is fully unreachable.
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/validate.rs
Original file line number Diff line number Diff line change
@@ -91,6 +91,10 @@ impl<'tcx> crate::MirPass<'tcx> for Validator {
}
}
}

fn is_required(&self) -> bool {
true
}
}

struct CfgChecker<'a, 'tcx> {
14 changes: 13 additions & 1 deletion tests/codegen/optimize-attr-1.rs
Original file line number Diff line number Diff line change
@@ -37,11 +37,23 @@ pub fn speed() -> i32 {
4 + 4
}

// CHECK-LABEL: define{{.*}}i32 @none
// CHECK-SAME: [[NONE_ATTRS:#[0-9]+]]
// SIZE-OPT: alloca
// SPEED-OPT: alloca
#[no_mangle]
#[optimize(none)]
pub fn none() -> i32 {
let arr = [0, 1, 2, 3, 4];
arr[4]
}

// NO-OPT-DAG: attributes [[SIZE_ATTRS]] = {{.*}}minsize{{.*}}optsize{{.*}}
// SPEED-OPT-DAG: attributes [[SIZE_ATTRS]] = {{.*}}minsize{{.*}}optsize{{.*}}
// SIZE-OPT-DAG: attributes [[NOTHING_ATTRS]] = {{.*}}optsize{{.*}}
// SIZE-OPT-DAG: attributes [[SIZE_ATTRS]] = {{.*}}minsize{{.*}}optsize{{.*}}
// CHECK-DAG: attributes [[NONE_ATTRS]] = {{.*}}noinline{{.*}}optnone{{.*}}

// SIZE-OPT: attributes [[SPEED_ATTRS]]
// SIZE-OPT-DAG: attributes [[SPEED_ATTRS]]
// SIZE-OPT-NOT: minsize
// SIZE-OPT-NOT: optsize
32 changes: 32 additions & 0 deletions tests/mir-opt/optimize_none.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//@ revisions: NO-OPT SPEED-OPT
//@[NO-OPT] compile-flags: -Copt-level=0
//@[SPEED-OPT] compile-flags: -Copt-level=3 -Coverflow-checks=y

#![feature(optimize_attribute)]

#[optimize(none)]
pub fn add_noopt() -> i32 {
// CHECK-LABEL: fn add_noopt(
// CHECK: AddWithOverflow(const 1_i32, const 2_i32);
// CHECK-NEXT: assert
1 + 2
}

#[optimize(none)]
pub fn const_branch() -> i32 {
// CHECK-LABEL: fn const_branch(
// CHECK: switchInt(const true) -> [0: [[FALSE:bb[0-9]+]], otherwise: [[TRUE:bb[0-9]+]]];
// CHECK-NEXT: }
// CHECK: [[FALSE]]: {
// CHECK-NEXT: _0 = const 0
// CHECK-NEXT: goto
// CHECK-NEXT: }
// CHECK: [[TRUE]]: {
// CHECK-NEXT: _0 = const 1
// CHECK-NEXT: goto
// CHECK-NEXT: }

if true { 1 } else { 0 }
}

fn main() {}
3 changes: 3 additions & 0 deletions tests/ui/feature-gates/feature-gate-optimize_attribute.rs
Original file line number Diff line number Diff line change
@@ -6,6 +6,9 @@ fn size() {}
#[optimize(speed)] //~ ERROR the `#[optimize]` attribute is an experimental feature
fn speed() {}

#[optimize(none)] //~ ERROR the `#[optimize]` attribute is an experimental feature
fn none() {}

#[optimize(banana)]
//~^ ERROR the `#[optimize]` attribute is an experimental feature
//~| ERROR E0722
14 changes: 12 additions & 2 deletions tests/ui/feature-gates/feature-gate-optimize_attribute.stderr
Original file line number Diff line number Diff line change
@@ -21,6 +21,16 @@ LL | #[optimize(speed)]
error[E0658]: the `#[optimize]` attribute is an experimental feature
--> $DIR/feature-gate-optimize_attribute.rs:9:1
|
LL | #[optimize(none)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #54882 <https://github.com/rust-lang/rust/issues/54882> for more information
= help: add `#![feature(optimize_attribute)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0658]: the `#[optimize]` attribute is an experimental feature
--> $DIR/feature-gate-optimize_attribute.rs:12:1
|
LL | #[optimize(banana)]
| ^^^^^^^^^^^^^^^^^^^
|
@@ -29,12 +39,12 @@ LL | #[optimize(banana)]
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0722]: invalid argument
--> $DIR/feature-gate-optimize_attribute.rs:9:12
--> $DIR/feature-gate-optimize_attribute.rs:12:12
|
LL | #[optimize(banana)]
| ^^^^^^

error: aborting due to 4 previous errors
error: aborting due to 5 previous errors

Some errors have detailed explanations: E0658, E0722.
For more information about an error, try `rustc --explain E0658`.