Skip to content

Commit 8d7140c

Browse files
committed
Add instrument_fn attribute
This attribute enables or disables function instrumentation when using `-Zinstrument-xray` or `-Zinstrument-mcount`. It supports the following usage: `#[instrument_fn = "on|off"]` For XRay, "on" is equivalent to always instrument, and "off" is equivalent to never instrumenting. For mcount, "on" has no effect. "off" disables instrumentation of the function.
1 parent beae781 commit 8d7140c

16 files changed

Lines changed: 328 additions & 15 deletions

File tree

compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,47 @@ impl CombineAttributeParser for ForceTargetFeatureParser {
563563
}
564564
}
565565

566+
pub(crate) struct InstrumentFnParser;
567+
568+
impl SingleAttributeParser for InstrumentFnParser {
569+
const PATH: &[Symbol] = &[sym::instrument_fn];
570+
571+
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
572+
Allow(Target::Fn),
573+
Allow(Target::Method(MethodKind::Inherent)),
574+
Allow(Target::Method(MethodKind::Trait { body: true })),
575+
Allow(Target::Method(MethodKind::TraitImpl)),
576+
]);
577+
578+
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "on|off");
579+
580+
const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
581+
582+
fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
583+
let mut instrument = None;
584+
match args {
585+
ArgParser::NameValue(nv) => {
586+
if let Some(option) = nv.value_as_str()
587+
&& (option == sym::off || option == sym::on)
588+
{
589+
instrument = Some(option == sym::on);
590+
} else {
591+
cx.adcx()
592+
.expected_specific_argument_strings(nv.value_span, &[sym::on, sym::off]);
593+
}
594+
}
595+
ArgParser::List(l) => {
596+
cx.adcx().expected_single_argument(l.span, l.len());
597+
}
598+
ArgParser::NoArgs => {
599+
let span = cx.attr_span;
600+
cx.adcx().expected_specific_argument_strings(span, &[sym::on, sym::off]);
601+
}
602+
}
603+
Some(AttributeKind::InstrumentFn(instrument))
604+
}
605+
}
606+
566607
pub(crate) struct SanitizeParser;
567608

568609
impl SingleAttributeParser for SanitizeParser {

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ attribute_parsers!(
185185
Single<IgnoreParser>,
186186
Single<InlineParser>,
187187
Single<InstructionSetParser>,
188+
Single<InstrumentFnParser>,
188189
Single<LangParser>,
189190
Single<LinkNameParser>,
190191
Single<LinkOrdinalParser>,

compiler/rustc_codegen_llvm/src/attributes.rs

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -210,35 +210,57 @@ fn function_return_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll
210210
fn instrument_function_attr<'ll>(
211211
cx: &SimpleCx<'ll>,
212212
sess: &Session,
213+
instrument_fn: &Option<bool>,
213214
) -> SmallVec<[&'ll Attribute; 4]> {
214215
let mut attrs = SmallVec::new();
215216
if sess.opts.unstable_opts.instrument_mcount {
216217
// Similar to `clang -pg` behavior. Handled by the
217218
// `post-inline-ee-instrument` LLVM pass.
218219

219-
// The function name varies on platforms.
220-
// See test/CodeGen/mcount.c in clang.
221-
let mcount_name = match &sess.target.llvm_mcount_intrinsic {
222-
Some(llvm_mcount_intrinsic) => llvm_mcount_intrinsic.as_ref(),
223-
None => sess.target.mcount.as_ref(),
224-
};
220+
// #[instrument_fn], the default is on.
221+
let instrument_entry = instrument_fn.unwrap_or_else(|| true);
225222

226-
attrs.push(llvm::CreateAttrStringValue(
227-
cx.llcx,
228-
"instrument-function-entry-inlined",
229-
mcount_name,
230-
));
223+
if instrument_entry {
224+
// The function name varies on platforms.
225+
// See test/CodeGen/mcount.c in clang.
226+
let mcount_name = match &sess.target.llvm_mcount_intrinsic {
227+
Some(llvm_mcount_intrinsic) => llvm_mcount_intrinsic.as_ref(),
228+
None => sess.target.mcount.as_ref(),
229+
};
230+
231+
attrs.push(llvm::CreateAttrStringValue(
232+
cx.llcx,
233+
"instrument-function-entry-inlined",
234+
mcount_name,
235+
));
236+
}
231237
}
232238
if let Some(options) = &sess.opts.unstable_opts.instrument_xray {
233239
// XRay instrumentation is similar to __cyg_profile_func_{enter,exit}.
234240
// Function prologue and epilogue are instrumented with NOP sleds,
235241
// a runtime library later replaces them with detours into tracing code.
236-
if options.always {
237-
attrs.push(llvm::CreateAttrStringValue(cx.llcx, "function-instrument", "xray-always"));
242+
243+
let mut never = options.never;
244+
let mut always = options.always;
245+
246+
// Apply optional #[instrument_fn] override.
247+
match instrument_fn {
248+
Some(true) => {
249+
always = true;
250+
}
251+
Some(false) => {
252+
never = true;
253+
}
254+
None => {}
238255
}
239-
if options.never {
256+
257+
if never {
240258
attrs.push(llvm::CreateAttrStringValue(cx.llcx, "function-instrument", "xray-never"));
241259
}
260+
if always {
261+
attrs.push(llvm::CreateAttrStringValue(cx.llcx, "function-instrument", "xray-always"));
262+
}
263+
242264
if options.ignore_loops {
243265
attrs.push(llvm::CreateAttrString(cx.llcx, "xray-ignore-loops"));
244266
}
@@ -250,6 +272,7 @@ fn instrument_function_attr<'ll>(
250272
"xray-instruction-threshold",
251273
&threshold.to_string(),
252274
));
275+
253276
if options.skip_entry {
254277
attrs.push(llvm::CreateAttrString(cx.llcx, "xray-skip-entry"));
255278
}
@@ -442,7 +465,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
442465
// FIXME: none of these functions interact with source level attributes.
443466
to_add.extend(frame_pointer_type_attr(cx, sess));
444467
to_add.extend(function_return_attr(cx, sess));
445-
to_add.extend(instrument_function_attr(cx, sess));
468+
to_add.extend(instrument_function_attr(cx, sess, &codegen_fn_attrs.instrument_fn));
446469
to_add.extend(nojumptables_attr(cx, sess));
447470
to_add.extend(probestack_attr(cx, tcx));
448471
to_add.extend(stackprotector_attr(cx, sess));

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,9 @@ fn process_builtin_attrs(
293293
codegen_fn_attrs.patchable_function_entry =
294294
Some(PatchableFunctionEntry::from_prefix_and_entry(*prefix, *entry));
295295
}
296+
AttributeKind::InstrumentFn(instrument_fn) => {
297+
codegen_fn_attrs.instrument_fn = *instrument_fn;
298+
}
296299
_ => {}
297300
}
298301
}

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,13 @@ pub static BUILTIN_ATTRIBUTES: &[Symbol] = &[
208208
// - https://github.com/rust-lang/rust/issues/130494
209209
sym::pin_v2,
210210

211+
// RFC 3917
212+
// `#[instrument_fn = "on|off"]` to insert or inhibit instrumentation function
213+
// calls inside a function, usually around the prologue.
214+
gated!(
215+
instrument_fn, instrument_fn, experimental!(instrument_fn),
216+
),
217+
211218
// ==========================================================================
212219
// Internal attributes: Stability, deprecation, and unsafe:
213220
// ==========================================================================

compiler/rustc_feature/src/unstable.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,8 @@ declare_features! (
593593
(unstable, import_trait_associated_functions, "1.86.0", Some(134691)),
594594
/// Allows associated types in inherent impls.
595595
(incomplete, inherent_associated_types, "1.52.0", Some(8995)),
596+
/// Enable #[instrument_fn] on function (todo: tracking issue)
597+
(unstable, instrument_fn, "CURRENT_RUSTC_VERSION", Some(157081)),
596598
/// Allows using `pointer` and `reference` in intra-doc links
597599
(unstable, intra_doc_pointers, "1.51.0", Some(80896)),
598600
/// lahfsahf target feature on x86.

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,6 +1060,9 @@ pub enum AttributeKind {
10601060
/// Represents `#[instruction_set]`
10611061
InstructionSet(InstructionSetAttr),
10621062

1063+
/// Represents `#[instrument_fn]`
1064+
InstrumentFn(Option<bool>),
1065+
10631066
/// Represents `#[lang]`
10641067
Lang(LangItem),
10651068

compiler/rustc_hir/src/attrs/encode_cross_crate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ impl AttributeKind {
5050
Ignore { .. } => No,
5151
Inline(..) => No,
5252
InstructionSet(..) => No,
53+
InstrumentFn(..) => No,
5354
Lang(..) => Yes,
5455
Link(..) => No,
5556
LinkName { .. } => Yes, // Needed for rustdoc

compiler/rustc_middle/src/middle/codegen_fn_attrs.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ pub struct CodegenFnAttrs {
109109
pub objc_class: Option<Symbol>,
110110
/// The `#[rustc_objc_selector = "..."]` attribute.
111111
pub objc_selector: Option<Symbol>,
112+
/// The `#[instrument_fn]` attribute.
113+
pub instrument_fn: Option<bool>,
112114
}
113115

114116
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, StableHash, PartialEq, Eq)]
@@ -236,6 +238,7 @@ impl CodegenFnAttrs {
236238
patchable_function_entry: None,
237239
objc_class: None,
238240
objc_selector: None,
241+
instrument_fn: None,
239242
}
240243
}
241244

compiler/rustc_passes/src/check_attr.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
277277
AttributeKind::Fundamental => (),
278278
AttributeKind::Ignore { .. } => (),
279279
AttributeKind::InstructionSet(..) => (),
280+
AttributeKind::InstrumentFn(..) => (),
280281
AttributeKind::Lang(..) => (),
281282
AttributeKind::LinkName { .. } => (),
282283
AttributeKind::LinkOrdinal { .. } => (),

0 commit comments

Comments
 (0)