-
Notifications
You must be signed in to change notification settings - Fork 13k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of #134082 - davidtwco:forced-inlining, r=saethlin
mir_transform: implement `#[rustc_force_inline]` Adds `#[rustc_force_inline]` which is similar to always inlining but reports an error if the inlining was not possible. - `#[rustc_force_inline]` can only be applied to free functions to guarantee that the MIR inliner will be able to resolve calls. - `rustc_mir_transform::inline::Inline` is refactored into two passes (`Inline` and `ForceInline`), sharing the vast majority of the implementation. - `rustc_mir_transform::inline::ForceInline` can't be disabled so annotated items are always inlined. - `rustc_mir_transform::inline::ForceInline` runs regardless of optimisation level. - `#[rustc_force_inline]` won't inline unless target features match, as with normal inlining. - MIR validation will ICE if a `#[rustc_force_inline]` isn't inlined, to guarantee that it will never be codegened independently. As a further guarantee, monomorphisation collection will always decide that `#[rustc_force_inline]` functions cannot be codegened locally. - Like other intrinsics, `#[rustc_force_inline]` annotated functions cannot be cast to function pointers. - As with other rustc attrs, this cannot be used by users, just within the compiler and standard library. - This is only implemented within rustc, so should avoid any limitations of LLVM's inlining. It is intended that this attribute be used with intrinsics that must be inlined for security reasons. For example, pointer authentication intrinsics would allow Rust users to make use of pointer authentication instructions, but if these intrinsic functions were in the binary then they could be used as gadgets with ROP attacks, defeating the point of introducing them. We don't have any intrinsics like this today, but I expect to upstream some once a force inlining mechanism such as this is available. cc #131687 rust-lang/rfcs#3711 - this approach should resolve the concerns from these previous attempts r? `@saethlin`
- Loading branch information
Showing
63 changed files
with
2,402 additions
and
661 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
use rustc_attr_parsing::InlineAttr; | ||
use rustc_hir::def_id::DefId; | ||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; | ||
use rustc_middle::mir::{Body, TerminatorKind}; | ||
use rustc_middle::ty; | ||
use rustc_middle::ty::TyCtxt; | ||
use rustc_span::sym; | ||
|
||
/// Check that a body annotated with `#[rustc_force_inline]` will not fail to inline based on its | ||
/// definition alone (irrespective of any specific caller). | ||
pub(crate) fn check_force_inline<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { | ||
let def_id = body.source.def_id(); | ||
if !tcx.hir().body_owner_kind(def_id).is_fn_or_closure() || !def_id.is_local() { | ||
return; | ||
} | ||
let InlineAttr::Force { attr_span, .. } = tcx.codegen_fn_attrs(def_id).inline else { | ||
return; | ||
}; | ||
|
||
if let Err(reason) = | ||
is_inline_valid_on_fn(tcx, def_id).and_then(|_| is_inline_valid_on_body(tcx, body)) | ||
{ | ||
tcx.dcx().emit_err(crate::errors::InvalidForceInline { | ||
attr_span, | ||
callee_span: tcx.def_span(def_id), | ||
callee: tcx.def_path_str(def_id), | ||
reason, | ||
}); | ||
} | ||
} | ||
|
||
pub fn is_inline_valid_on_fn<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Result<(), &'static str> { | ||
let codegen_attrs = tcx.codegen_fn_attrs(def_id); | ||
if tcx.has_attr(def_id, sym::rustc_no_mir_inline) { | ||
return Err("#[rustc_no_mir_inline]"); | ||
} | ||
|
||
// FIXME(#127234): Coverage instrumentation currently doesn't handle inlined | ||
// MIR correctly when Modified Condition/Decision Coverage is enabled. | ||
if tcx.sess.instrument_coverage_mcdc() { | ||
return Err("incompatible with MC/DC coverage"); | ||
} | ||
|
||
let ty = tcx.type_of(def_id); | ||
if match ty.instantiate_identity().kind() { | ||
ty::FnDef(..) => tcx.fn_sig(def_id).instantiate_identity().c_variadic(), | ||
ty::Closure(_, args) => args.as_closure().sig().c_variadic(), | ||
_ => false, | ||
} { | ||
return Err("C variadic"); | ||
} | ||
|
||
if codegen_attrs.flags.contains(CodegenFnAttrFlags::COLD) { | ||
return Err("cold"); | ||
} | ||
|
||
// Intrinsic fallback bodies are automatically made cross-crate inlineable, | ||
// but at this stage we don't know whether codegen knows the intrinsic, | ||
// so just conservatively don't inline it. This also ensures that we do not | ||
// accidentally inline the body of an intrinsic that *must* be overridden. | ||
if tcx.has_attr(def_id, sym::rustc_intrinsic) { | ||
return Err("callee is an intrinsic"); | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
pub fn is_inline_valid_on_body<'tcx>( | ||
_: TyCtxt<'tcx>, | ||
body: &Body<'tcx>, | ||
) -> Result<(), &'static str> { | ||
if body | ||
.basic_blocks | ||
.iter() | ||
.any(|bb| matches!(bb.terminator().kind, TerminatorKind::TailCall { .. })) | ||
{ | ||
return Err("can't inline functions with tail calls"); | ||
} | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.