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_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
|
||||
|
@ -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))
|
||||
})
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -585,6 +585,13 @@ pub struct BuiltinAttribute {
|
||||
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:
|
||||
// ==========================================================================
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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 = { {{.*}} }
|
||||
|
@ -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