Skip to content

Commit

Permalink
Auto merge of rust-lang#128657 - clubby789:optimize-none, r=<try>
Browse files Browse the repository at this point in the history
Add `#[optimize(none)]`

cc rust-lang#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.
  • Loading branch information
bors committed Aug 10, 2024
2 parents 7347f8e + 4408092 commit 334c324
Show file tree
Hide file tree
Showing 32 changed files with 235 additions and 88 deletions.
11 changes: 10 additions & 1 deletion compiler/rustc_attr/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,22 @@ pub enum InstructionSetAttr {
ArmT32,
}

#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic, PartialEq, Eq)]
pub enum OptimizeAttr {
/// `#[optimize(none)]`. This implies `#[inline(never)]`, required by LLVM
None,
/// `#[optimize(speed)]`
Speed,
/// `#[optimize(size)]`
Size,
}

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

/// Represents the following attributes:
///
/// - `#[stable]`
Expand Down
23 changes: 14 additions & 9 deletions compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,22 +337,27 @@ pub fn llfn_attrs_from_instance<'ll, 'tcx>(
let mut to_add = SmallVec::<[_; 16]>::new();

match codegen_fn_attrs.optimize {
OptimizeAttr::None => {
None => {
to_add.extend(default_optimisation_attrs(cx));
}
OptimizeAttr::Size => {
Some(OptimizeAttr::None) => {
to_add.push(llvm::AttributeKind::OptimizeNone.create_attr(cx.llcx));
}
Some(OptimizeAttr::Size) => {
to_add.push(llvm::AttributeKind::MinSize.create_attr(cx.llcx));
to_add.push(llvm::AttributeKind::OptimizeForSize.create_attr(cx.llcx));
}
OptimizeAttr::Speed => {}
Some(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 = if codegen_fn_attrs.optimize == Some(OptimizeAttr::None) {
InlineAttr::Never
} else if codegen_fn_attrs.inline == InlineAttr::None && instance.def.requires_inline(cx.tcx) {
InlineAttr::Hint
} else {
codegen_fn_attrs.inline
};
to_add.extend(inline_attr(cx, inline));

// The `uwtable` attribute according to LLVM is:
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_ssa/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1024,8 +1024,8 @@ pub 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,
None | Some(attr::OptimizeAttr::None | attr::OptimizeAttr::Size) => false,
Some(attr::OptimizeAttr::Speed) => true,
}
});

Expand Down
12 changes: 7 additions & 5 deletions compiler/rustc_codegen_ssa/src/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
}
});

codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| {
codegen_fn_attrs.optimize = attrs.iter().fold(None, |ia, attr| {
if !attr.has_name(sym::optimize) {
return ia;
}
Expand All @@ -573,14 +573,16 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
inline_span = Some(attr.span);
if items.len() != 1 {
err(attr.span, "expected one argument");
OptimizeAttr::None
None
} else if list_contains_name(items, sym::size) {
OptimizeAttr::Size
Some(OptimizeAttr::Size)
} else if list_contains_name(items, sym::speed) {
OptimizeAttr::Speed
Some(OptimizeAttr::Speed)
} else if list_contains_name(items, sym::none) {
Some(OptimizeAttr::None)
} else {
err(items[0].span(), "invalid argument");
OptimizeAttr::None
None
}
}
Some(MetaItemKind::NameValue(_)) => ia,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
),

Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ pub struct CodegenFnAttrs {
pub flags: CodegenFnAttrFlags,
/// Parsed representation of the `#[inline]` attribute
pub inline: InlineAttr,
/// Parsed representation of the `#[optimize]` attribute
pub optimize: OptimizeAttr,
/// Parsed representation of the `#[optimize]` attribute if present
pub optimize: Option<OptimizeAttr>,
/// The `#[export_name = "..."]` attribute, indicating a custom symbol a
/// function should be exported under
pub export_name: Option<Symbol>,
Expand Down Expand Up @@ -146,7 +146,7 @@ impl CodegenFnAttrs {
CodegenFnAttrs {
flags: CodegenFnAttrFlags::empty(),
inline: InlineAttr::None,
optimize: OptimizeAttr::None,
optimize: None,
export_name: None,
link_name: None,
link_ordinal: None,
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ pub trait MirPass<'tcx> {
to_profiler_name(self.name())
}

fn min_mir_opt_level(&self) -> usize {
0
}

/// Returns `true` if this pass is enabled with the current combination of compiler flags.
fn is_enabled(&self, _sess: &Session) -> bool {
true
Expand Down Expand Up @@ -443,6 +447,8 @@ pub struct Body<'tcx> {
/// If `-Cinstrument-coverage` is not active, or if an individual function
/// is not eligible for coverage, then this should always be `None`.
pub function_coverage_info: Option<Box<coverage::FunctionCoverageInfo>>,
// /// Whether optimization is disabled by `#[optimize(none)]`
// pub optimization_disabled: bool,
}

impl<'tcx> Body<'tcx> {
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/copy_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ use crate::ssa::SsaLocals;
pub struct CopyProp;

impl<'tcx> MirPass<'tcx> for CopyProp {
fn min_mir_opt_level(&self) -> usize {
1
}

fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 1
}
Expand Down
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
Expand Up @@ -28,6 +28,10 @@ const PLACE_LIMIT: usize = 100;
pub struct DataflowConstProp;

impl<'tcx> MirPass<'tcx> for DataflowConstProp {
fn min_mir_opt_level(&self) -> usize {
3
}

fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 3
}
Expand Down
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
Expand Up @@ -140,6 +140,10 @@ impl<'tcx> MirPass<'tcx> for DeadStoreElimination {
}
}

fn min_mir_opt_level(&self) -> usize {
2
}

fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 2
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/deduplicate_blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ use super::simplify::simplify_cfg;
pub struct DeduplicateBlocks;

impl<'tcx> MirPass<'tcx> for DeduplicateBlocks {
fn min_mir_opt_level(&self) -> usize {
4
}

fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 4
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/dest_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ use crate::MirPass;
pub struct DestinationPropagation;

impl<'tcx> MirPass<'tcx> for DestinationPropagation {
fn min_mir_opt_level(&self) -> usize {
3
}

fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
// For now, only run at MIR opt level 3. Two things need to be changed before this can be
// turned on by default:
Expand Down
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
Expand Up @@ -92,6 +92,10 @@ use super::simplify::simplify_cfg;
pub struct EarlyOtherwiseBranch;

impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
fn min_mir_opt_level(&self) -> usize {
2
}

fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 2
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/gvn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ use crate::ssa::{AssignedValue, SsaLocals};
pub struct GVN;

impl<'tcx> MirPass<'tcx> for GVN {
fn min_mir_opt_level(&self) -> usize {
2
}

fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 2
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/instsimplify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ impl<'tcx> MirPass<'tcx> for InstSimplify {
self.name()
}

fn min_mir_opt_level(&self) -> usize {
1
}

fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() > 0
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/jump_threading.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ const MAX_COST: usize = 100;
const MAX_PLACES: usize = 100;

impl<'tcx> MirPass<'tcx> for JumpThreading {
fn min_mir_opt_level(&self) -> usize {
2
}

fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 2
}
Expand Down
136 changes: 71 additions & 65 deletions compiler/rustc_mir_transform/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -558,72 +558,78 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
WithMinOptLevel(1, x)
}

let passes: [&dyn MirPass<'tcx>; 40] = [
// Add some UB checks before any UB gets optimized away.
&check_alignment::CheckAlignment as &dyn MirPass<'_>,
// Before inlining: trim down MIR with passes to reduce inlining work.

// Has to be done before inlining, otherwise actual call will be almost always inlined.
// Also simple, so can just do first
&lower_slice_len::LowerSliceLenCalls,
// Perform instsimplify before inline to eliminate some trivial calls (like clone shims).
&instsimplify::InstSimplify::BeforeInline,
// Perform inlining, which may add a lot of code.
&inline::Inline,
// Code from other crates may have storage markers, so this needs to happen after inlining.
&remove_storage_markers::RemoveStorageMarkers,
// Inlining and instantiation may introduce ZST and useless drops.
&remove_zsts::RemoveZsts,
&remove_unneeded_drops::RemoveUnneededDrops,
// Type instantiation may create uninhabited enums.
// Also eliminates some unreachable branches based on variants of enums.
&unreachable_enum_branching::UnreachableEnumBranching,
&unreachable_prop::UnreachablePropagation,
&o1(simplify::SimplifyCfg::AfterUnreachableEnumBranching),
// Inlining may have introduced a lot of redundant code and a large move pattern.
// Now, we need to shrink the generated MIR.
&ref_prop::ReferencePropagation,
&sroa::ScalarReplacementOfAggregates,
&match_branches::MatchBranchSimplification,
// inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
&multiple_return_terminators::MultipleReturnTerminators,
// After simplifycfg, it allows us to discover new opportunities for peephole optimizations.
&instsimplify::InstSimplify::AfterSimplifyCfg,
&simplify::SimplifyLocals::BeforeConstProp,
&dead_store_elimination::DeadStoreElimination::Initial,
&gvn::GVN,
&simplify::SimplifyLocals::AfterGVN,
&dataflow_const_prop::DataflowConstProp,
&single_use_consts::SingleUseConsts,
&o1(simplify_branches::SimplifyConstCondition::AfterConstProp),
&jump_threading::JumpThreading,
&early_otherwise_branch::EarlyOtherwiseBranch,
&simplify_comparison_integral::SimplifyComparisonIntegral,
&dest_prop::DestinationPropagation,
&o1(simplify_branches::SimplifyConstCondition::Final),
&o1(remove_noop_landing_pads::RemoveNoopLandingPads),
&o1(simplify::SimplifyCfg::Final),
&copy_prop::CopyProp,
&dead_store_elimination::DeadStoreElimination::Final,
&nrvo::RenameReturnPlace,
&simplify::SimplifyLocals::Final,
&multiple_return_terminators::MultipleReturnTerminators,
&deduplicate_blocks::DeduplicateBlocks,
&large_enums::EnumSizeOpt { discrepancy: 128 },
// Some cleanup necessary at least for LLVM and potentially other codegen backends.
&add_call_guards::CriticalCallEdges,
// Cleanup for human readability, off by default.
&prettify::ReorderBasicBlocks,
&prettify::ReorderLocals,
// Dump the end result for testing and debugging purposes.
&dump_mir::Marker("PreCodegen"),
];

let mut passes = passes.to_vec();
let def_id = body.source.def_id();
if tcx.def_kind(def_id).has_codegen_attrs()
&& let Some(ref attrs) = tcx.codegen_fn_attrs(def_id).optimize
&& attrs.do_not_optimize()
{
passes.retain(|pass| pass.min_mir_opt_level() <= 1);
}

// The main optimizations that we do on MIR.
pm::run_passes(
tcx,
body,
&[
// Add some UB checks before any UB gets optimized away.
&check_alignment::CheckAlignment,
// Before inlining: trim down MIR with passes to reduce inlining work.

// Has to be done before inlining, otherwise actual call will be almost always inlined.
// Also simple, so can just do first
&lower_slice_len::LowerSliceLenCalls,
// Perform instsimplify before inline to eliminate some trivial calls (like clone shims).
&instsimplify::InstSimplify::BeforeInline,
// Perform inlining, which may add a lot of code.
&inline::Inline,
// Code from other crates may have storage markers, so this needs to happen after inlining.
&remove_storage_markers::RemoveStorageMarkers,
// Inlining and instantiation may introduce ZST and useless drops.
&remove_zsts::RemoveZsts,
&remove_unneeded_drops::RemoveUnneededDrops,
// Type instantiation may create uninhabited enums.
// Also eliminates some unreachable branches based on variants of enums.
&unreachable_enum_branching::UnreachableEnumBranching,
&unreachable_prop::UnreachablePropagation,
&o1(simplify::SimplifyCfg::AfterUnreachableEnumBranching),
// Inlining may have introduced a lot of redundant code and a large move pattern.
// Now, we need to shrink the generated MIR.
&ref_prop::ReferencePropagation,
&sroa::ScalarReplacementOfAggregates,
&match_branches::MatchBranchSimplification,
// inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
&multiple_return_terminators::MultipleReturnTerminators,
// After simplifycfg, it allows us to discover new opportunities for peephole optimizations.
&instsimplify::InstSimplify::AfterSimplifyCfg,
&simplify::SimplifyLocals::BeforeConstProp,
&dead_store_elimination::DeadStoreElimination::Initial,
&gvn::GVN,
&simplify::SimplifyLocals::AfterGVN,
&dataflow_const_prop::DataflowConstProp,
&single_use_consts::SingleUseConsts,
&o1(simplify_branches::SimplifyConstCondition::AfterConstProp),
&jump_threading::JumpThreading,
&early_otherwise_branch::EarlyOtherwiseBranch,
&simplify_comparison_integral::SimplifyComparisonIntegral,
&dest_prop::DestinationPropagation,
&o1(simplify_branches::SimplifyConstCondition::Final),
&o1(remove_noop_landing_pads::RemoveNoopLandingPads),
&o1(simplify::SimplifyCfg::Final),
&copy_prop::CopyProp,
&dead_store_elimination::DeadStoreElimination::Final,
&nrvo::RenameReturnPlace,
&simplify::SimplifyLocals::Final,
&multiple_return_terminators::MultipleReturnTerminators,
&deduplicate_blocks::DeduplicateBlocks,
&large_enums::EnumSizeOpt { discrepancy: 128 },
// Some cleanup necessary at least for LLVM and potentially other codegen backends.
&add_call_guards::CriticalCallEdges,
// Cleanup for human readability, off by default.
&prettify::ReorderBasicBlocks,
&prettify::ReorderLocals,
// Dump the end result for testing and debugging purposes.
&dump_mir::Marker("PreCodegen"),
],
Some(MirPhase::Runtime(RuntimePhase::Optimized)),
);
pm::run_passes(tcx, body, &passes, Some(MirPhase::Runtime(RuntimePhase::Optimized)));
}

/// Optimize the MIR and prepare it for codegen.
Expand Down
Loading

0 comments on commit 334c324

Please sign in to comment.