Skip to content

Commit 334c324

Browse files
committed
Auto merge of #128657 - clubby789:optimize-none, r=<try>
Add `#[optimize(none)]` cc #54882 This extends the `optimize` attribute to add `none`, which corresponds to the LLVM `OptimizeNone` attribute. Not sure if an MCP is required for this, happy to file one if so.
2 parents 7347f8e + 4408092 commit 334c324

32 files changed

+235
-88
lines changed

compiler/rustc_attr/src/builtin.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,22 @@ pub enum InstructionSetAttr {
5353
ArmT32,
5454
}
5555

56-
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
56+
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic, PartialEq, Eq)]
5757
pub enum OptimizeAttr {
58+
/// `#[optimize(none)]`. This implies `#[inline(never)]`, required by LLVM
5859
None,
60+
/// `#[optimize(speed)]`
5961
Speed,
62+
/// `#[optimize(size)]`
6063
Size,
6164
}
6265

66+
impl OptimizeAttr {
67+
pub fn do_not_optimize(&self) -> bool {
68+
matches!(*self, OptimizeAttr::None)
69+
}
70+
}
71+
6372
/// Represents the following attributes:
6473
///
6574
/// - `#[stable]`

compiler/rustc_codegen_llvm/src/attributes.rs

+14-9
Original file line numberDiff line numberDiff line change
@@ -337,22 +337,27 @@ pub fn llfn_attrs_from_instance<'ll, 'tcx>(
337337
let mut to_add = SmallVec::<[_; 16]>::new();
338338

339339
match codegen_fn_attrs.optimize {
340-
OptimizeAttr::None => {
340+
None => {
341341
to_add.extend(default_optimisation_attrs(cx));
342342
}
343-
OptimizeAttr::Size => {
343+
Some(OptimizeAttr::None) => {
344+
to_add.push(llvm::AttributeKind::OptimizeNone.create_attr(cx.llcx));
345+
}
346+
Some(OptimizeAttr::Size) => {
344347
to_add.push(llvm::AttributeKind::MinSize.create_attr(cx.llcx));
345348
to_add.push(llvm::AttributeKind::OptimizeForSize.create_attr(cx.llcx));
346349
}
347-
OptimizeAttr::Speed => {}
350+
Some(OptimizeAttr::Speed) => {}
348351
}
349352

350-
let inline =
351-
if codegen_fn_attrs.inline == InlineAttr::None && instance.def.requires_inline(cx.tcx) {
352-
InlineAttr::Hint
353-
} else {
354-
codegen_fn_attrs.inline
355-
};
353+
// `optnone` requires `noinline`
354+
let inline = if codegen_fn_attrs.optimize == Some(OptimizeAttr::None) {
355+
InlineAttr::Never
356+
} else if codegen_fn_attrs.inline == InlineAttr::None && instance.def.requires_inline(cx.tcx) {
357+
InlineAttr::Hint
358+
} else {
359+
codegen_fn_attrs.inline
360+
};
356361
to_add.extend(inline_attr(cx, inline));
357362

358363
// The `uwtable` attribute according to LLVM is:

compiler/rustc_codegen_ssa/src/base.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1024,8 +1024,8 @@ pub fn provide(providers: &mut Providers) {
10241024
let any_for_speed = defids.items().any(|id| {
10251025
let CodegenFnAttrs { optimize, .. } = tcx.codegen_fn_attrs(*id);
10261026
match optimize {
1027-
attr::OptimizeAttr::None | attr::OptimizeAttr::Size => false,
1028-
attr::OptimizeAttr::Speed => true,
1027+
None | Some(attr::OptimizeAttr::None | attr::OptimizeAttr::Size) => false,
1028+
Some(attr::OptimizeAttr::Speed) => true,
10291029
}
10301030
});
10311031

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
559559
}
560560
});
561561

562-
codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| {
562+
codegen_fn_attrs.optimize = attrs.iter().fold(None, |ia, attr| {
563563
if !attr.has_name(sym::optimize) {
564564
return ia;
565565
}
@@ -573,14 +573,16 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
573573
inline_span = Some(attr.span);
574574
if items.len() != 1 {
575575
err(attr.span, "expected one argument");
576-
OptimizeAttr::None
576+
None
577577
} else if list_contains_name(items, sym::size) {
578-
OptimizeAttr::Size
578+
Some(OptimizeAttr::Size)
579579
} else if list_contains_name(items, sym::speed) {
580-
OptimizeAttr::Speed
580+
Some(OptimizeAttr::Speed)
581+
} else if list_contains_name(items, sym::none) {
582+
Some(OptimizeAttr::None)
581583
} else {
582584
err(items[0].span(), "invalid argument");
583-
OptimizeAttr::None
585+
None
584586
}
585587
}
586588
Some(MetaItemKind::NameValue(_)) => ia,

compiler/rustc_feature/src/builtin_attrs.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
532532
),
533533
// RFC 2412
534534
gated!(
535-
optimize, Normal, template!(List: "size|speed"), ErrorPreceding,
535+
optimize, Normal, template!(List: "none|size|speed"), ErrorPreceding,
536536
EncodeCrossCrate::No, optimize_attribute, experimental!(optimize)
537537
),
538538

compiler/rustc_middle/src/middle/codegen_fn_attrs.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ pub struct CodegenFnAttrs {
1111
pub flags: CodegenFnAttrFlags,
1212
/// Parsed representation of the `#[inline]` attribute
1313
pub inline: InlineAttr,
14-
/// Parsed representation of the `#[optimize]` attribute
15-
pub optimize: OptimizeAttr,
14+
/// Parsed representation of the `#[optimize]` attribute if present
15+
pub optimize: Option<OptimizeAttr>,
1616
/// The `#[export_name = "..."]` attribute, indicating a custom symbol a
1717
/// function should be exported under
1818
pub export_name: Option<Symbol>,
@@ -146,7 +146,7 @@ impl CodegenFnAttrs {
146146
CodegenFnAttrs {
147147
flags: CodegenFnAttrFlags::empty(),
148148
inline: InlineAttr::None,
149-
optimize: OptimizeAttr::None,
149+
optimize: None,
150150
export_name: None,
151151
link_name: None,
152152
link_ordinal: None,

compiler/rustc_middle/src/mir/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,10 @@ pub trait MirPass<'tcx> {
153153
to_profiler_name(self.name())
154154
}
155155

156+
fn min_mir_opt_level(&self) -> usize {
157+
0
158+
}
159+
156160
/// Returns `true` if this pass is enabled with the current combination of compiler flags.
157161
fn is_enabled(&self, _sess: &Session) -> bool {
158162
true
@@ -443,6 +447,8 @@ pub struct Body<'tcx> {
443447
/// If `-Cinstrument-coverage` is not active, or if an individual function
444448
/// is not eligible for coverage, then this should always be `None`.
445449
pub function_coverage_info: Option<Box<coverage::FunctionCoverageInfo>>,
450+
// /// Whether optimization is disabled by `#[optimize(none)]`
451+
// pub optimization_disabled: bool,
446452
}
447453

448454
impl<'tcx> Body<'tcx> {

compiler/rustc_mir_transform/src/copy_prop.rs

+4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ use crate::ssa::SsaLocals;
1919
pub struct CopyProp;
2020

2121
impl<'tcx> MirPass<'tcx> for CopyProp {
22+
fn min_mir_opt_level(&self) -> usize {
23+
1
24+
}
25+
2226
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
2327
sess.mir_opt_level() >= 1
2428
}

compiler/rustc_mir_transform/src/dataflow_const_prop.rs

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ const PLACE_LIMIT: usize = 100;
2828
pub struct DataflowConstProp;
2929

3030
impl<'tcx> MirPass<'tcx> for DataflowConstProp {
31+
fn min_mir_opt_level(&self) -> usize {
32+
3
33+
}
34+
3135
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
3236
sess.mir_opt_level() >= 3
3337
}

compiler/rustc_mir_transform/src/dead_store_elimination.rs

+4
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,10 @@ impl<'tcx> MirPass<'tcx> for DeadStoreElimination {
140140
}
141141
}
142142

143+
fn min_mir_opt_level(&self) -> usize {
144+
2
145+
}
146+
143147
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
144148
sess.mir_opt_level() >= 2
145149
}

compiler/rustc_mir_transform/src/deduplicate_blocks.rs

+4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ use super::simplify::simplify_cfg;
1515
pub struct DeduplicateBlocks;
1616

1717
impl<'tcx> MirPass<'tcx> for DeduplicateBlocks {
18+
fn min_mir_opt_level(&self) -> usize {
19+
4
20+
}
21+
1822
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
1923
sess.mir_opt_level() >= 4
2024
}

compiler/rustc_mir_transform/src/dest_prop.rs

+4
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,10 @@ use crate::MirPass;
150150
pub struct DestinationPropagation;
151151

152152
impl<'tcx> MirPass<'tcx> for DestinationPropagation {
153+
fn min_mir_opt_level(&self) -> usize {
154+
3
155+
}
156+
153157
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
154158
// For now, only run at MIR opt level 3. Two things need to be changed before this can be
155159
// turned on by default:

compiler/rustc_mir_transform/src/early_otherwise_branch.rs

+4
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ use super::simplify::simplify_cfg;
9292
pub struct EarlyOtherwiseBranch;
9393

9494
impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
95+
fn min_mir_opt_level(&self) -> usize {
96+
2
97+
}
98+
9599
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
96100
sess.mir_opt_level() >= 2
97101
}

compiler/rustc_mir_transform/src/gvn.rs

+4
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ use crate::ssa::{AssignedValue, SsaLocals};
111111
pub struct GVN;
112112

113113
impl<'tcx> MirPass<'tcx> for GVN {
114+
fn min_mir_opt_level(&self) -> usize {
115+
2
116+
}
117+
114118
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
115119
sess.mir_opt_level() >= 2
116120
}

compiler/rustc_mir_transform/src/instsimplify.rs

+4
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ impl<'tcx> MirPass<'tcx> for InstSimplify {
3232
self.name()
3333
}
3434

35+
fn min_mir_opt_level(&self) -> usize {
36+
1
37+
}
38+
3539
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
3640
sess.mir_opt_level() > 0
3741
}

compiler/rustc_mir_transform/src/jump_threading.rs

+4
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ const MAX_COST: usize = 100;
6161
const MAX_PLACES: usize = 100;
6262

6363
impl<'tcx> MirPass<'tcx> for JumpThreading {
64+
fn min_mir_opt_level(&self) -> usize {
65+
2
66+
}
67+
6468
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
6569
sess.mir_opt_level() >= 2
6670
}

compiler/rustc_mir_transform/src/lib.rs

+71-65
Original file line numberDiff line numberDiff line change
@@ -558,72 +558,78 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
558558
WithMinOptLevel(1, x)
559559
}
560560

561+
let passes: [&dyn MirPass<'tcx>; 40] = [
562+
// Add some UB checks before any UB gets optimized away.
563+
&check_alignment::CheckAlignment as &dyn MirPass<'_>,
564+
// Before inlining: trim down MIR with passes to reduce inlining work.
565+
566+
// Has to be done before inlining, otherwise actual call will be almost always inlined.
567+
// Also simple, so can just do first
568+
&lower_slice_len::LowerSliceLenCalls,
569+
// Perform instsimplify before inline to eliminate some trivial calls (like clone shims).
570+
&instsimplify::InstSimplify::BeforeInline,
571+
// Perform inlining, which may add a lot of code.
572+
&inline::Inline,
573+
// Code from other crates may have storage markers, so this needs to happen after inlining.
574+
&remove_storage_markers::RemoveStorageMarkers,
575+
// Inlining and instantiation may introduce ZST and useless drops.
576+
&remove_zsts::RemoveZsts,
577+
&remove_unneeded_drops::RemoveUnneededDrops,
578+
// Type instantiation may create uninhabited enums.
579+
// Also eliminates some unreachable branches based on variants of enums.
580+
&unreachable_enum_branching::UnreachableEnumBranching,
581+
&unreachable_prop::UnreachablePropagation,
582+
&o1(simplify::SimplifyCfg::AfterUnreachableEnumBranching),
583+
// Inlining may have introduced a lot of redundant code and a large move pattern.
584+
// Now, we need to shrink the generated MIR.
585+
&ref_prop::ReferencePropagation,
586+
&sroa::ScalarReplacementOfAggregates,
587+
&match_branches::MatchBranchSimplification,
588+
// inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
589+
&multiple_return_terminators::MultipleReturnTerminators,
590+
// After simplifycfg, it allows us to discover new opportunities for peephole optimizations.
591+
&instsimplify::InstSimplify::AfterSimplifyCfg,
592+
&simplify::SimplifyLocals::BeforeConstProp,
593+
&dead_store_elimination::DeadStoreElimination::Initial,
594+
&gvn::GVN,
595+
&simplify::SimplifyLocals::AfterGVN,
596+
&dataflow_const_prop::DataflowConstProp,
597+
&single_use_consts::SingleUseConsts,
598+
&o1(simplify_branches::SimplifyConstCondition::AfterConstProp),
599+
&jump_threading::JumpThreading,
600+
&early_otherwise_branch::EarlyOtherwiseBranch,
601+
&simplify_comparison_integral::SimplifyComparisonIntegral,
602+
&dest_prop::DestinationPropagation,
603+
&o1(simplify_branches::SimplifyConstCondition::Final),
604+
&o1(remove_noop_landing_pads::RemoveNoopLandingPads),
605+
&o1(simplify::SimplifyCfg::Final),
606+
&copy_prop::CopyProp,
607+
&dead_store_elimination::DeadStoreElimination::Final,
608+
&nrvo::RenameReturnPlace,
609+
&simplify::SimplifyLocals::Final,
610+
&multiple_return_terminators::MultipleReturnTerminators,
611+
&deduplicate_blocks::DeduplicateBlocks,
612+
&large_enums::EnumSizeOpt { discrepancy: 128 },
613+
// Some cleanup necessary at least for LLVM and potentially other codegen backends.
614+
&add_call_guards::CriticalCallEdges,
615+
// Cleanup for human readability, off by default.
616+
&prettify::ReorderBasicBlocks,
617+
&prettify::ReorderLocals,
618+
// Dump the end result for testing and debugging purposes.
619+
&dump_mir::Marker("PreCodegen"),
620+
];
621+
622+
let mut passes = passes.to_vec();
623+
let def_id = body.source.def_id();
624+
if tcx.def_kind(def_id).has_codegen_attrs()
625+
&& let Some(ref attrs) = tcx.codegen_fn_attrs(def_id).optimize
626+
&& attrs.do_not_optimize()
627+
{
628+
passes.retain(|pass| pass.min_mir_opt_level() <= 1);
629+
}
630+
561631
// The main optimizations that we do on MIR.
562-
pm::run_passes(
563-
tcx,
564-
body,
565-
&[
566-
// Add some UB checks before any UB gets optimized away.
567-
&check_alignment::CheckAlignment,
568-
// Before inlining: trim down MIR with passes to reduce inlining work.
569-
570-
// Has to be done before inlining, otherwise actual call will be almost always inlined.
571-
// Also simple, so can just do first
572-
&lower_slice_len::LowerSliceLenCalls,
573-
// Perform instsimplify before inline to eliminate some trivial calls (like clone shims).
574-
&instsimplify::InstSimplify::BeforeInline,
575-
// Perform inlining, which may add a lot of code.
576-
&inline::Inline,
577-
// Code from other crates may have storage markers, so this needs to happen after inlining.
578-
&remove_storage_markers::RemoveStorageMarkers,
579-
// Inlining and instantiation may introduce ZST and useless drops.
580-
&remove_zsts::RemoveZsts,
581-
&remove_unneeded_drops::RemoveUnneededDrops,
582-
// Type instantiation may create uninhabited enums.
583-
// Also eliminates some unreachable branches based on variants of enums.
584-
&unreachable_enum_branching::UnreachableEnumBranching,
585-
&unreachable_prop::UnreachablePropagation,
586-
&o1(simplify::SimplifyCfg::AfterUnreachableEnumBranching),
587-
// Inlining may have introduced a lot of redundant code and a large move pattern.
588-
// Now, we need to shrink the generated MIR.
589-
&ref_prop::ReferencePropagation,
590-
&sroa::ScalarReplacementOfAggregates,
591-
&match_branches::MatchBranchSimplification,
592-
// inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
593-
&multiple_return_terminators::MultipleReturnTerminators,
594-
// After simplifycfg, it allows us to discover new opportunities for peephole optimizations.
595-
&instsimplify::InstSimplify::AfterSimplifyCfg,
596-
&simplify::SimplifyLocals::BeforeConstProp,
597-
&dead_store_elimination::DeadStoreElimination::Initial,
598-
&gvn::GVN,
599-
&simplify::SimplifyLocals::AfterGVN,
600-
&dataflow_const_prop::DataflowConstProp,
601-
&single_use_consts::SingleUseConsts,
602-
&o1(simplify_branches::SimplifyConstCondition::AfterConstProp),
603-
&jump_threading::JumpThreading,
604-
&early_otherwise_branch::EarlyOtherwiseBranch,
605-
&simplify_comparison_integral::SimplifyComparisonIntegral,
606-
&dest_prop::DestinationPropagation,
607-
&o1(simplify_branches::SimplifyConstCondition::Final),
608-
&o1(remove_noop_landing_pads::RemoveNoopLandingPads),
609-
&o1(simplify::SimplifyCfg::Final),
610-
&copy_prop::CopyProp,
611-
&dead_store_elimination::DeadStoreElimination::Final,
612-
&nrvo::RenameReturnPlace,
613-
&simplify::SimplifyLocals::Final,
614-
&multiple_return_terminators::MultipleReturnTerminators,
615-
&deduplicate_blocks::DeduplicateBlocks,
616-
&large_enums::EnumSizeOpt { discrepancy: 128 },
617-
// Some cleanup necessary at least for LLVM and potentially other codegen backends.
618-
&add_call_guards::CriticalCallEdges,
619-
// Cleanup for human readability, off by default.
620-
&prettify::ReorderBasicBlocks,
621-
&prettify::ReorderLocals,
622-
// Dump the end result for testing and debugging purposes.
623-
&dump_mir::Marker("PreCodegen"),
624-
],
625-
Some(MirPhase::Runtime(RuntimePhase::Optimized)),
626-
);
632+
pm::run_passes(tcx, body, &passes, Some(MirPhase::Runtime(RuntimePhase::Optimized)));
627633
}
628634

629635
/// Optimize the MIR and prepare it for codegen.

0 commit comments

Comments
 (0)