Skip to content

Commit 8c64d48

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 cced03b commit 8c64d48

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
@@ -550,6 +550,47 @@ impl CombineAttributeParser for ForceTargetFeatureParser {
550550
}
551551
}
552552

553+
pub(crate) struct InstrumentFnParser;
554+
555+
impl SingleAttributeParser for InstrumentFnParser {
556+
const PATH: &[Symbol] = &[sym::instrument_fn];
557+
558+
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
559+
Allow(Target::Fn),
560+
Allow(Target::Method(MethodKind::Inherent)),
561+
Allow(Target::Method(MethodKind::Trait { body: true })),
562+
Allow(Target::Method(MethodKind::TraitImpl)),
563+
]);
564+
565+
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "on|off");
566+
567+
const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
568+
569+
fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
570+
let mut instrument = None;
571+
match args {
572+
ArgParser::NameValue(nv) => {
573+
if let Some(option) = nv.value_as_str()
574+
&& (option == sym::off || option == sym::on)
575+
{
576+
instrument = Some(option == sym::on);
577+
} else {
578+
cx.adcx()
579+
.expected_specific_argument_strings(nv.value_span, &[sym::on, sym::off]);
580+
}
581+
}
582+
ArgParser::List(l) => {
583+
cx.adcx().expected_single_argument(l.span, l.len());
584+
}
585+
ArgParser::NoArgs => {
586+
let span = cx.attr_span;
587+
cx.adcx().expected_specific_argument_strings(span, &[sym::on, sym::off]);
588+
}
589+
}
590+
Some(AttributeKind::InstrumentFn(instrument))
591+
}
592+
}
593+
553594
pub(crate) struct SanitizeParser;
554595

555596
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
@@ -180,6 +180,7 @@ attribute_parsers!(
180180
Single<IgnoreParser>,
181181
Single<InlineParser>,
182182
Single<InstructionSetParser>,
183+
Single<InstrumentFnParser>,
183184
Single<LangParser>,
184185
Single<LinkNameParser>,
185186
Single<LinkOrdinalParser>,

compiler/rustc_codegen_llvm/src/attributes.rs

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -205,35 +205,57 @@ fn function_return_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll
205205
fn instrument_function_attr<'ll>(
206206
cx: &SimpleCx<'ll>,
207207
sess: &Session,
208+
instrument_fn: &Option<bool>,
208209
) -> SmallVec<[&'ll Attribute; 4]> {
209210
let mut attrs = SmallVec::new();
210211
if sess.opts.unstable_opts.instrument_mcount {
211212
// Similar to `clang -pg` behavior. Handled by the
212213
// `post-inline-ee-instrument` LLVM pass.
213214

214-
// The function name varies on platforms.
215-
// See test/CodeGen/mcount.c in clang.
216-
let mcount_name = match &sess.target.llvm_mcount_intrinsic {
217-
Some(llvm_mcount_intrinsic) => llvm_mcount_intrinsic.as_ref(),
218-
None => sess.target.mcount.as_ref(),
219-
};
215+
// #[instrument_fn], the default is on.
216+
let instrument_entry = instrument_fn.unwrap_or_else(|| true);
220217

221-
attrs.push(llvm::CreateAttrStringValue(
222-
cx.llcx,
223-
"instrument-function-entry-inlined",
224-
mcount_name,
225-
));
218+
if instrument_entry {
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+
};
225+
226+
attrs.push(llvm::CreateAttrStringValue(
227+
cx.llcx,
228+
"instrument-function-entry-inlined",
229+
mcount_name,
230+
));
231+
}
226232
}
227233
if let Some(options) = &sess.opts.unstable_opts.instrument_xray {
228234
// XRay instrumentation is similar to __cyg_profile_func_{enter,exit}.
229235
// Function prologue and epilogue are instrumented with NOP sleds,
230236
// a runtime library later replaces them with detours into tracing code.
231-
if options.always {
232-
attrs.push(llvm::CreateAttrStringValue(cx.llcx, "function-instrument", "xray-always"));
237+
238+
let mut never = options.never;
239+
let mut always = options.always;
240+
241+
// Apply optional #[instrument_fn] override.
242+
match instrument_fn {
243+
Some(true) => {
244+
always = true;
245+
}
246+
Some(false) => {
247+
never = true;
248+
}
249+
None => {}
233250
}
234-
if options.never {
251+
252+
if never {
235253
attrs.push(llvm::CreateAttrStringValue(cx.llcx, "function-instrument", "xray-never"));
236254
}
255+
if always {
256+
attrs.push(llvm::CreateAttrStringValue(cx.llcx, "function-instrument", "xray-always"));
257+
}
258+
237259
if options.ignore_loops {
238260
attrs.push(llvm::CreateAttrString(cx.llcx, "xray-ignore-loops"));
239261
}
@@ -245,6 +267,7 @@ fn instrument_function_attr<'ll>(
245267
"xray-instruction-threshold",
246268
&threshold.to_string(),
247269
));
270+
248271
if options.skip_entry {
249272
attrs.push(llvm::CreateAttrString(cx.llcx, "xray-skip-entry"));
250273
}
@@ -437,7 +460,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
437460
// FIXME: none of these functions interact with source level attributes.
438461
to_add.extend(frame_pointer_type_attr(cx, sess));
439462
to_add.extend(function_return_attr(cx, sess));
440-
to_add.extend(instrument_function_attr(cx, sess));
463+
to_add.extend(instrument_function_attr(cx, sess, &codegen_fn_attrs.instrument_fn));
441464
to_add.extend(nojumptables_attr(cx, sess));
442465
to_add.extend(probestack_attr(cx, tcx));
443466
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
@@ -401,6 +401,13 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
401401
// - https://github.com/rust-lang/rust/issues/130494
402402
gated!(pin_v2, pin_ergonomics, experimental!(pin_v2)),
403403

404+
// RFC 3917
405+
// `#[instrument_fn = "on|off"]` to insert or inhibit instrumentation function
406+
// calls inside a function, usually around the prologue.
407+
gated!(
408+
instrument_fn, instrument_fn, experimental!(instrument_fn),
409+
),
410+
404411
// ==========================================================================
405412
// Internal attributes: Stability, deprecation, and unsafe:
406413
// ==========================================================================

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
@@ -279,6 +279,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
279279
AttributeKind::Fundamental => (),
280280
AttributeKind::Ignore { .. } => (),
281281
AttributeKind::InstructionSet(..) => (),
282+
AttributeKind::InstrumentFn(..) => (),
282283
AttributeKind::Lang(..) => (),
283284
AttributeKind::LinkName { .. } => (),
284285
AttributeKind::LinkOrdinal { .. } => (),

0 commit comments

Comments
 (0)