Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,46 @@ impl<S: Stage> CombineAttributeParser<S> for ForceTargetFeatureParser {
}
}

pub(crate) struct InstrumentFnParser;

impl<S: Stage> SingleAttributeParser<S> for InstrumentFnParser {
const PATH: &[Symbol] = &[sym::instrument_fn];

const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::Trait { body: true })),
Allow(Target::Method(MethodKind::TraitImpl)),
]);

const TEMPLATE: AttributeTemplate = template!(NameValueStr: "on|off");

const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;

fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let mut instrument = None;
match args {
ArgParser::NameValue(nv) => {
if let Some(option) = nv.value_as_str()
&& (option == sym::off || option == sym::on)
{
instrument = Some(option == sym::on);
} else {
cx.expected_specific_argument(nv.value_span, &[sym::on, sym::off]);
}
}
ArgParser::List(_) => {
cx.expected_single_argument(cx.attr_span);
}
ArgParser::NoArgs => {
cx.expected_specific_argument(cx.attr_span, &[sym::on, sym::off]);
}
}
Some(AttributeKind::InstrumentFn(instrument))
}
}

pub(crate) struct SanitizeParser;

impl<S: Stage> SingleAttributeParser<S> for SanitizeParser {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ attribute_parsers!(
Single<IgnoreParser>,
Single<InlineParser>,
Single<InstructionSetParser>,
Single<InstrumentFnParser>,
Single<LangParser>,
Single<LinkNameParser>,
Single<LinkOrdinalParser>,
Expand Down
140 changes: 97 additions & 43 deletions compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ use rustc_middle::middle::codegen_fn_attrs::{
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, SanitizerFnAttrs,
};
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::config::{BranchProtection, FunctionReturn, OptLevel, PAuthKey, PacRet};
use rustc_session::config::{
BranchProtection, FunctionReturn, InstrumentFunction, OptLevel, PAuthKey, PacRet,
};
use rustc_symbol_mangling::mangle_internal_symbol;
use rustc_target::spec::{Arch, FramePointer, SanitizerSet, StackProbeType, StackProtector};
use smallvec::SmallVec;
Expand Down Expand Up @@ -173,7 +175,7 @@ pub(crate) fn frame_pointer_type_attr<'ll>(
let opts = &sess.opts;
// "mcount" function relies on stack pointer.
// See <https://sourceware.org/binutils/docs/gprof/Implementation.html>.
if opts.unstable_opts.instrument_mcount {
if opts.unstable_opts.instrument_function == InstrumentFunction::Mcount {
fp.ratchet(FramePointer::Always);
}
fp.ratchet(opts.cg.force_frame_pointers);
Expand All @@ -199,52 +201,104 @@ fn function_return_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll
fn instrument_function_attr<'ll>(
cx: &SimpleCx<'ll>,
sess: &Session,
instrument_fn: &Option<bool>,
) -> SmallVec<[&'ll Attribute; 4]> {
let mut attrs = SmallVec::new();
if sess.opts.unstable_opts.instrument_mcount {
// Similar to `clang -pg` behavior. Handled by the
// `post-inline-ee-instrument` LLVM pass.

// The function name varies on platforms.
// See test/CodeGen/mcount.c in clang.
let mcount_name = match &sess.target.llvm_mcount_intrinsic {
Some(llvm_mcount_intrinsic) => llvm_mcount_intrinsic.as_ref(),
None => sess.target.mcount.as_ref(),
};
match sess.opts.unstable_opts.instrument_function {
InstrumentFunction::Fentry => {
// Similar to `clang -pg -mfentry` behavior.

attrs.push(llvm::CreateAttrStringValue(
cx.llcx,
"instrument-function-entry-inlined",
mcount_name,
));
}
if let Some(options) = &sess.opts.unstable_opts.instrument_xray {
// XRay instrumentation is similar to __cyg_profile_func_{enter,exit}.
// Function prologue and epilogue are instrumented with NOP sleds,
// a runtime library later replaces them with detours into tracing code.
if options.always {
attrs.push(llvm::CreateAttrStringValue(cx.llcx, "function-instrument", "xray-always"));
}
if options.never {
attrs.push(llvm::CreateAttrStringValue(cx.llcx, "function-instrument", "xray-never"));
}
if options.ignore_loops {
attrs.push(llvm::CreateAttrString(cx.llcx, "xray-ignore-loops"));
// #[instrument_fn], the default is on.
let instrument_entry = instrument_fn.unwrap_or_else(|| true);

if instrument_entry {
attrs.push(llvm::CreateAttrStringValue(cx.llcx, "fentry-call", "true"));

if sess.opts.unstable_opts.instrument_fentry_opts.no_call {
attrs.push(llvm::CreateAttrString(cx.llcx, "mnop-mcount"));
}
if sess.opts.unstable_opts.instrument_fentry_opts.record {
attrs.push(llvm::CreateAttrString(cx.llcx, "mrecord-mcount"));
}
}
}
// LLVM will not choose the default for us, but rather requires specific
// threshold in absence of "xray-always". Use the same default as Clang.
let threshold = options.instruction_threshold.unwrap_or(200);
attrs.push(llvm::CreateAttrStringValue(
cx.llcx,
"xray-instruction-threshold",
&threshold.to_string(),
));
if options.skip_entry {
attrs.push(llvm::CreateAttrString(cx.llcx, "xray-skip-entry"));
InstrumentFunction::Mcount => {
// Similar to `clang -pg` behavior. Handled by the
// `post-inline-ee-instrument` LLVM pass.

// #[instrument_fn], the default is on.
let instrument_entry = instrument_fn.unwrap_or_else(|| true);

if instrument_entry {
// The function name varies on platforms.
// See test/CodeGen/mcount.c in clang.
let mcount_name = match &sess.target.llvm_mcount_intrinsic {
Some(llvm_mcount_intrinsic) => llvm_mcount_intrinsic.as_ref(),
None => sess.target.mcount.as_ref(),
};

attrs.push(llvm::CreateAttrStringValue(
cx.llcx,
"instrument-function-entry-inlined",
mcount_name,
));
}
}
if options.skip_exit {
attrs.push(llvm::CreateAttrString(cx.llcx, "xray-skip-exit"));
InstrumentFunction::XRay => {
// XRay instrumentation is similar to __cyg_profile_func_{enter,exit}.
// Function prologue and epilogue are instrumented with NOP sleds,
// a runtime library later replaces them with detours into tracing code.
let options = &sess.opts.unstable_opts.instrument_xray_opts;

let mut never = options.never;
let mut always = options.always;

// Apply optional #[instrument_fn] override.
match instrument_fn {
Some(true) => {
always = true;
}
Some(false) => {
never = true;
}
None => {}
}

if never {
attrs.push(llvm::CreateAttrStringValue(
cx.llcx,
"function-instrument",
"xray-never",
));
}
if always {
attrs.push(llvm::CreateAttrStringValue(
cx.llcx,
"function-instrument",
"xray-always",
));
}

if options.ignore_loops {
attrs.push(llvm::CreateAttrString(cx.llcx, "xray-ignore-loops"));
}
// LLVM will not choose the default for us, but rather requires specific
// threshold in absence of "xray-always". Use the same default as Clang.
let threshold = options.instruction_threshold.unwrap_or(200);
attrs.push(llvm::CreateAttrStringValue(
cx.llcx,
"xray-instruction-threshold",
&threshold.to_string(),
));

if options.skip_entry {
attrs.push(llvm::CreateAttrString(cx.llcx, "xray-skip-entry"));
}
if options.skip_exit {
attrs.push(llvm::CreateAttrString(cx.llcx, "xray-skip-exit"));
}
}
InstrumentFunction::No => {}
}
attrs
}
Expand Down Expand Up @@ -397,7 +451,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
// FIXME: none of these functions interact with source level attributes.
to_add.extend(frame_pointer_type_attr(cx, sess));
to_add.extend(function_return_attr(cx, sess));
to_add.extend(instrument_function_attr(cx, sess));
to_add.extend(instrument_function_attr(cx, sess, &codegen_fn_attrs.instrument_fn));
to_add.extend(nojumptables_attr(cx, sess));
to_add.extend(probestack_attr(cx, tcx));
to_add.extend(stackprotector_attr(cx, sess));
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_codegen_ssa/src/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,9 @@ fn process_builtin_attrs(
codegen_fn_attrs.patchable_function_entry =
Some(PatchableFunctionEntry::from_prefix_and_entry(*prefix, *entry));
}
AttributeKind::InstrumentFn(instrument_fn) => {
codegen_fn_attrs.instrument_fn = *instrument_fn;
}
_ => {}
}
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
template!(List: &["set"], "https://doc.rust-lang.org/reference/attributes/codegen.html#the-instruction_set-attribute"),
ErrorPreceding, EncodeCrossCrate::No
),
gated!(
instrument_fn, Normal, template!(List: &[r#"entry = "on|off""#]), ErrorPreceding,
EncodeCrossCrate::No, instrument_fn, experimental!(instrument_fn),
),
gated!(
unsafe force_target_feature, Normal, template!(List: &[r#"enable = "name""#]),
DuplicatesOk, EncodeCrossCrate::No, effective_target_features, experimental!(force_target_feature)
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,8 @@ declare_features! (
(unstable, import_trait_associated_functions, "1.86.0", Some(134691)),
/// Allows associated types in inherent impls.
(incomplete, inherent_associated_types, "1.52.0", Some(8995)),
/// Enable #[instrument_fn] on function (todo: tracking issue)
(unstable, instrument_fn, "CURRENT_RUSTC_VERSION", Some(99999)),
/// Allows using `pointer` and `reference` in intra-doc links
(unstable, intra_doc_pointers, "1.51.0", Some(80896)),
/// lahfsahf target feature on x86.
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1070,6 +1070,9 @@ pub enum AttributeKind {
/// Represents `#[instruction_set]`
InstructionSet(InstructionSetAttr),

/// Represents `#[instrument_fn]`
InstrumentFn(Option<bool>),

/// Represents `#[lang]`
Lang(LangItem, Span),

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/attrs/encode_cross_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ impl AttributeKind {
Ignore { .. } => No,
Inline(..) => No,
InstructionSet(..) => No,
InstrumentFn(..) => No,
Lang(..) => Yes,
Link(..) => No,
LinkName { .. } => Yes, // Needed for rustdoc
Expand Down
20 changes: 12 additions & 8 deletions compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ use rustc_hir::attrs::{CollapseMacroDebuginfo, NativeLibKind};
use rustc_session::config::{
AnnotateMoves, AutoDiff, BranchProtection, CFGuard, Cfg, CoverageLevel, CoverageOptions,
DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs,
FmtDebug, FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentXRay,
LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, MirIncludeSpans, NextSolverConfig,
Offload, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes,
PatchableFunctionEntry, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath,
SymbolManglingVersion, WasiExecModel, build_configuration, build_session_options,
rustc_optgroups,
FmtDebug, FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentFunction,
InstrumentMcountOpts, InstrumentXRayOpts, LinkSelfContained, LinkerPluginLto, LocationDetail,
LtoCli, MirIncludeSpans, NextSolverConfig, Offload, Options, OutFileName, OutputType,
OutputTypes, PAuthKey, PacRet, Passes, PatchableFunctionEntry, Polonius,
ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel,
build_configuration, build_session_options, rustc_optgroups,
};
use rustc_session::lint::Level;
use rustc_session::search_paths::SearchPath;
Expand Down Expand Up @@ -811,8 +811,12 @@ fn test_unstable_options_tracking_hash() {
tracked!(inline_mir, Some(true));
tracked!(inline_mir_hint_threshold, Some(123));
tracked!(inline_mir_threshold, Some(123));
tracked!(instrument_mcount, true);
tracked!(instrument_xray, Some(InstrumentXRay::default()));
tracked!(instrument_fentry_opts, InstrumentMcountOpts { no_call: true, record: true });
tracked!(instrument_function, InstrumentFunction::Fentry);
tracked!(
instrument_xray_opts,
InstrumentXRayOpts { always: true, ..InstrumentXRayOpts::default() }
);
tracked!(link_directives, false);
tracked!(link_only, true);
tracked!(lint_llvm_ir, true);
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ pub struct CodegenFnAttrs {
pub objc_class: Option<Symbol>,
/// The `#[rustc_objc_selector = "..."]` attribute.
pub objc_selector: Option<Symbol>,
/// The `#[instrument_fn]` attribute.
pub instrument_fn: Option<bool>,
}

#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable, PartialEq, Eq)]
Expand Down Expand Up @@ -236,6 +238,7 @@ impl CodegenFnAttrs {
patchable_function_entry: None,
objc_class: None,
objc_selector: None,
instrument_fn: None,
}
}

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| AttributeKind::Fundamental
| AttributeKind::Ignore { .. }
| AttributeKind::InstructionSet(..)
| AttributeKind::InstrumentFn(..)
| AttributeKind::Lang(..)
| AttributeKind::LinkName { .. }
| AttributeKind::LinkOrdinal { .. }
Expand Down
Loading
Loading