mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
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:
parent
ac7595fdb1
commit
9b0ae75ecc
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use rustc_codegen_ssa::traits::*;
|
use rustc_codegen_ssa::traits::*;
|
||||||
use rustc_hir::def_id::DefId;
|
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_middle::ty::{self, TyCtxt};
|
||||||
use rustc_session::config::{FunctionReturn, OptLevel};
|
use rustc_session::config::{FunctionReturn, OptLevel};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
@ -56,9 +56,12 @@ fn inline_attr<'ll>(cx: &CodegenCx<'ll, '_>, inline: InlineAttr) -> Option<&'ll
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn patchable_function_entry_attrs<'ll>(
|
fn patchable_function_entry_attrs<'ll>(
|
||||||
cx: &CodegenCx<'ll, '_>,
|
cx: &CodegenCx<'ll, '_>,
|
||||||
|
attr: Option<PatchableFunctionEntry>,
|
||||||
) -> SmallVec<[&'ll Attribute; 2]> {
|
) -> SmallVec<[&'ll Attribute; 2]> {
|
||||||
let mut attrs = SmallVec::new();
|
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 entry = patchable_spec.entry();
|
||||||
let prefix = patchable_spec.prefix();
|
let prefix = patchable_spec.prefix();
|
||||||
if entry > 0 {
|
if entry > 0 {
|
||||||
@ -446,7 +449,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
|
|||||||
llvm::set_alignment(llfn, align);
|
llvm::set_alignment(llfn, align);
|
||||||
}
|
}
|
||||||
to_add.extend(sanitize_attrs(cx, codegen_fn_attrs.no_sanitize));
|
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.
|
// Always annotate functions with the target-cpu they are compiled for.
|
||||||
// Without this, ThinLTO won't inline Rust functions into Clang generated
|
// Without this, ThinLTO won't inline Rust functions into Clang generated
|
||||||
|
@ -5,7 +5,9 @@ use rustc_hir as hir;
|
|||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
|
use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
|
||||||
use rustc_hir::{lang_items, weak_lang_items::WEAK_LANG_ITEMS, LangItem};
|
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::mir::mono::Linkage;
|
||||||
use rustc_middle::query::Providers;
|
use rustc_middle::query::Providers;
|
||||||
use rustc_middle::ty::{self as ty, TyCtxt};
|
use rustc_middle::ty::{self as ty, TyCtxt};
|
||||||
@ -463,6 +465,28 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||||||
None
|
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))
|
||||||
|
})
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -584,6 +584,13 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||||||
pointee, Normal, template!(Word), ErrorFollowing,
|
pointee, Normal, template!(Word), ErrorFollowing,
|
||||||
EncodeCrossCrate::No, derive_smart_pointer, experimental!(pointee)
|
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:
|
// Internal attributes: Stability, deprecation, and unsafe:
|
||||||
|
@ -565,6 +565,9 @@ declare_features! (
|
|||||||
(unstable, offset_of_slice, "CURRENT_RUSTC_VERSION", Some(126151)),
|
(unstable, offset_of_slice, "CURRENT_RUSTC_VERSION", Some(126151)),
|
||||||
/// Allows using `#[optimize(X)]`.
|
/// Allows using `#[optimize(X)]`.
|
||||||
(unstable, optimize_attribute, "1.34.0", Some(54882)),
|
(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 { ... }`
|
/// Allows postfix match `expr.match { ... }`
|
||||||
(unstable, postfix_match, "1.79.0", Some(121618)),
|
(unstable, postfix_match, "1.79.0", Some(121618)),
|
||||||
/// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args.
|
/// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args.
|
||||||
|
@ -45,6 +45,9 @@ pub struct CodegenFnAttrs {
|
|||||||
/// The `#[repr(align(...))]` attribute. Indicates the value of which the function should be
|
/// The `#[repr(align(...))]` attribute. Indicates the value of which the function should be
|
||||||
/// aligned to.
|
/// aligned to.
|
||||||
pub alignment: Option<Align>,
|
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)]
|
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||||
@ -147,6 +150,7 @@ impl CodegenFnAttrs {
|
|||||||
no_sanitize: SanitizerSet::empty(),
|
no_sanitize: SanitizerSet::empty(),
|
||||||
instruction_set: None,
|
instruction_set: None,
|
||||||
alignment: None,
|
alignment: None,
|
||||||
|
patchable_function_entry: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -768,6 +768,7 @@ symbols! {
|
|||||||
enable,
|
enable,
|
||||||
encode,
|
encode,
|
||||||
end,
|
end,
|
||||||
|
entry,
|
||||||
enumerate_method,
|
enumerate_method,
|
||||||
env,
|
env,
|
||||||
env_CFG_RELEASE: env!("CFG_RELEASE"),
|
env_CFG_RELEASE: env!("CFG_RELEASE"),
|
||||||
@ -1383,6 +1384,7 @@ symbols! {
|
|||||||
passes,
|
passes,
|
||||||
pat,
|
pat,
|
||||||
pat_param,
|
pat_param,
|
||||||
|
patchable_function_entry,
|
||||||
path,
|
path,
|
||||||
pattern_complexity,
|
pattern_complexity,
|
||||||
pattern_parentheses,
|
pattern_parentheses,
|
||||||
@ -1421,6 +1423,7 @@ symbols! {
|
|||||||
prefetch_read_instruction,
|
prefetch_read_instruction,
|
||||||
prefetch_write_data,
|
prefetch_write_data,
|
||||||
prefetch_write_instruction,
|
prefetch_write_instruction,
|
||||||
|
prefix,
|
||||||
preg,
|
preg,
|
||||||
prelude,
|
prelude,
|
||||||
prelude_import,
|
prelude_import,
|
||||||
|
@ -1,8 +1,28 @@
|
|||||||
|
#![feature(patchable_function_entry)]
|
||||||
// compile-flags: -Z patchable-function-entry=15,10
|
// compile-flags: -Z patchable-function-entry=15,10
|
||||||
|
|
||||||
#![crate_type = "lib"]
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
|
// This should have the default, as set by the compile flags
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn foo() {}
|
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: @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 #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 = { {{.*}} }
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
#[patchable_function_entry(entry(1), prefix(1))]
|
||||||
|
//~^ ERROR: the `#[patchable_function_entry]` attribute is an experimental feature
|
||||||
|
fn main() {}
|
@ -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`.
|
Loading…
Reference in New Issue
Block a user