Support #[patchable_function_entries]

See [RFC](https://github.com/maurer/rust-rfcs/blob/patchable-function-entry/text/0000-patchable-function-entry.md) (yet to be numbered)

TODO before submission:
* Needs an RFC
* Improve error reporting for malformed attributes
This commit is contained in:
Matthew Maurer 2023-12-12 13:37:04 -08:00 committed by Florian Schmiderer
parent ac7595fdb1
commit 9b0ae75ecc
9 changed files with 83 additions and 4 deletions

View File

@ -2,7 +2,7 @@
use rustc_codegen_ssa::traits::*;
use rustc_hir::def_id::DefId;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, PatchableFunctionEntry};
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::config::{FunctionReturn, OptLevel};
use rustc_span::symbol::sym;
@ -56,9 +56,12 @@ fn inline_attr<'ll>(cx: &CodegenCx<'ll, '_>, inline: InlineAttr) -> Option<&'ll
#[inline]
fn patchable_function_entry_attrs<'ll>(
cx: &CodegenCx<'ll, '_>,
attr: Option<PatchableFunctionEntry>,
) -> SmallVec<[&'ll Attribute; 2]> {
let mut attrs = SmallVec::new();
let patchable_spec = cx.tcx.sess.opts.unstable_opts.patchable_function_entry;
let patchable_spec = attr.unwrap_or_else(|| {
PatchableFunctionEntry::from_config(cx.tcx.sess.opts.unstable_opts.patchable_function_entry)
});
let entry = patchable_spec.entry();
let prefix = patchable_spec.prefix();
if entry > 0 {
@ -446,7 +449,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
llvm::set_alignment(llfn, align);
}
to_add.extend(sanitize_attrs(cx, codegen_fn_attrs.no_sanitize));
to_add.extend(patchable_function_entry_attrs(cx));
to_add.extend(patchable_function_entry_attrs(cx, codegen_fn_attrs.patchable_function_entry));
// Always annotate functions with the target-cpu they are compiled for.
// Without this, ThinLTO won't inline Rust functions into Clang generated

View File

@ -5,7 +5,9 @@
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
use rustc_hir::{lang_items, weak_lang_items::WEAK_LANG_ITEMS, LangItem};
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::middle::codegen_fn_attrs::{
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry,
};
use rustc_middle::mir::mono::Linkage;
use rustc_middle::query::Providers;
use rustc_middle::ty::{self as ty, TyCtxt};
@ -463,6 +465,28 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
None
};
}
sym::patchable_function_entry => {
codegen_fn_attrs.patchable_function_entry = attr.meta_item_list().and_then(|l| {
let mut prefix = 0;
let mut entry = 0;
for item in l {
if let Some((sym, lit)) = item.name_value_literal() {
let val = match lit.kind {
// FIXME emit error if too many nops requested
rustc_ast::LitKind::Int(i, _) => i as u8,
_ => continue,
};
match sym {
sym::prefix => prefix = val,
sym::entry => entry = val,
// FIXME possibly emit error here?
_ => continue,
}
}
}
Some(PatchableFunctionEntry::from_prefix_and_entry(prefix, entry))
})
}
_ => {}
}
}

View File

@ -584,6 +584,13 @@ pub struct BuiltinAttribute {
pointee, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::No, derive_smart_pointer, experimental!(pointee)
),
// FIXME RFC
// `#[patchable_function_entry(prefix(n), entry(n))]`
gated!(
patchable_function_entry, Normal, template!(List: "prefix(n), entry(n)"), ErrorPreceding,
experimental!(patchable_function_entry)
),
// ==========================================================================
// Internal attributes: Stability, deprecation, and unsafe:

View File

@ -565,6 +565,9 @@ pub fn internal(&self, feature: Symbol) -> bool {
(unstable, offset_of_slice, "CURRENT_RUSTC_VERSION", Some(126151)),
/// Allows using `#[optimize(X)]`.
(unstable, optimize_attribute, "1.34.0", Some(54882)),
/// Allows specifying nop padding on functions for dynamic patching.
// FIXME this needs an RFC #
(unstable, patchable_function_entry, "CURRENT_RUSTC_VERSION", Some(9999)),
/// Allows postfix match `expr.match { ... }`
(unstable, postfix_match, "1.79.0", Some(121618)),
/// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args.

View File

@ -45,6 +45,9 @@ pub struct CodegenFnAttrs {
/// The `#[repr(align(...))]` attribute. Indicates the value of which the function should be
/// aligned to.
pub alignment: Option<Align>,
/// The `#[patchable_function_entry(...)]` attribute. Indicates how many nops should be around
/// the function entry.
pub patchable_function_entry: Option<PatchableFunctionEntry>,
}
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
@ -147,6 +150,7 @@ pub const fn new() -> CodegenFnAttrs {
no_sanitize: SanitizerSet::empty(),
instruction_set: None,
alignment: None,
patchable_function_entry: None,
}
}

View File

@ -768,6 +768,7 @@
enable,
encode,
end,
entry,
enumerate_method,
env,
env_CFG_RELEASE: env!("CFG_RELEASE"),
@ -1383,6 +1384,7 @@
passes,
pat,
pat_param,
patchable_function_entry,
path,
pattern_complexity,
pattern_parentheses,
@ -1421,6 +1423,7 @@
prefetch_read_instruction,
prefetch_write_data,
prefetch_write_instruction,
prefix,
preg,
prelude,
prelude_import,

View File

@ -1,8 +1,28 @@
#![feature(patchable_function_entry)]
// compile-flags: -Z patchable-function-entry=15,10
#![crate_type = "lib"]
// This should have the default, as set by the compile flags
#[no_mangle]
pub fn foo() {}
// The attribute should override the compile flags
#[no_mangle]
#[patchable_function_entry(prefix(1), entry(2))]
pub fn bar() {}
// If we override an attribute to 0 or unset, the attribute should go away
#[no_mangle]
#[patchable_function_entry(entry(0))]
pub fn baz() {}
// CHECK: @foo() unnamed_addr #0
// CHECK: @bar() unnamed_addr #1
// CHECK: @baz() unnamed_addr #2
// CHECK: attributes #0 = { {{.*}}"patchable-function-entry"="5"{{.*}}"patchable-function-prefix"="10" {{.*}} }
// CHECK: attributes #1 = { {{.*}}"patchable-function-entry"="2"{{.*}}"patchable-function-prefix"="1" {{.*}} }
// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-entry{{.*}} }
// CHECK-NOT: attributes #2 = { {{.*}}patchable-function-prefix{{.*}} }
// CHECK: attributes #2 = { {{.*}} }

View File

@ -0,0 +1,3 @@
#[patchable_function_entry(entry(1), prefix(1))]
//~^ ERROR: the `#[patchable_function_entry]` attribute is an experimental feature
fn main() {}

View File

@ -0,0 +1,12 @@
error[E0658]: the `#[patchable_function_entry]` attribute is an experimental feature
--> $DIR/feature-gate-patchable-function-entry.rs:1:1
|
LL | #[patchable_function_entry(entry(1), prefix(1))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #9999 <https://github.com/rust-lang/rust/issues/9999> for more information
= help: add `#![feature(patchable_function_entry)]` to the crate attributes to enable
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0658`.