Skip to content

Commit e59dc8e

Browse files
committed
Refactor -Zinstrument-mcount, -Zinstrument-fentry, -Zinstrument-xray
Convert these into `-Zinstrument-function={none|fentry|xray}`. `-Zinstrument-xray` is split into `-Zinstrument-function=xray` and `-Zinstrument-xray-opts=...`. Also, rename `-Zinstrument-mcount-opts` to `-Zinstrument-fentry-opts` to reflect it is only usable with fentry. In theory, it could work with both (as it does on gcc), in practice the llvm support is limited to s390x/fentry as of llvm 22.
1 parent 85e4b04 commit e59dc8e

27 files changed

Lines changed: 232 additions & 178 deletions

compiler/rustc_codegen_llvm/src/attributes.rs

Lines changed: 88 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ use rustc_middle::middle::codegen_fn_attrs::{
66
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, SanitizerFnAttrs,
77
};
88
use rustc_middle::ty::{self, TyCtxt};
9-
use rustc_session::config::{BranchProtection, FunctionReturn, OptLevel, PAuthKey, PacRet};
9+
use rustc_session::config::{
10+
BranchProtection, FunctionReturn, InstrumentFunction, OptLevel, PAuthKey, PacRet,
11+
};
1012
use rustc_symbol_mangling::mangle_internal_symbol;
1113
use rustc_target::spec::{Arch, FramePointer, SanitizerSet, StackProbeType, StackProtector};
1214
use smallvec::SmallVec;
@@ -173,7 +175,7 @@ pub(crate) fn frame_pointer_type_attr<'ll>(
173175
let opts = &sess.opts;
174176
// "mcount" function relies on stack pointer.
175177
// See <https://sourceware.org/binutils/docs/gprof/Implementation.html>.
176-
if opts.unstable_opts.instrument_mcount {
178+
if opts.unstable_opts.instrument_function == InstrumentFunction::Mcount {
177179
fp.ratchet(FramePointer::Always);
178180
}
179181
fp.ratchet(opts.cg.force_frame_pointers);
@@ -202,83 +204,101 @@ fn instrument_function_attr<'ll>(
202204
instrument_fn: &Option<bool>,
203205
) -> SmallVec<[&'ll Attribute; 4]> {
204206
let mut attrs = SmallVec::new();
205-
if sess.opts.unstable_opts.instrument_mcount || sess.opts.unstable_opts.instrument_fentry {
206-
// Similar to `clang -pg` behavior. Handled by the
207-
// `post-inline-ee-instrument` LLVM pass.
208-
209-
// #[instrument_fn], the default is on.
210-
let instrument_entry = instrument_fn.unwrap_or_else(|| true);
211-
212-
if instrument_entry && sess.opts.unstable_opts.instrument_mcount {
213-
// The function name varies on platforms.
214-
// See test/CodeGen/mcount.c in clang.
215-
let mcount_name = match &sess.target.llvm_mcount_intrinsic {
216-
Some(llvm_mcount_intrinsic) => llvm_mcount_intrinsic.as_ref(),
217-
None => sess.target.mcount.as_ref(),
218-
};
207+
match sess.opts.unstable_opts.instrument_function {
208+
InstrumentFunction::Fentry => {
209+
// Similar to `clang -pg -mfentry` behavior.
219210

220-
attrs.push(llvm::CreateAttrStringValue(
221-
cx.llcx,
222-
"instrument-function-entry-inlined",
223-
mcount_name,
224-
));
225-
}
211+
// #[instrument_fn], the default is on.
212+
let instrument_entry = instrument_fn.unwrap_or_else(|| true);
226213

227-
if instrument_entry && sess.opts.unstable_opts.instrument_fentry {
228-
attrs.push(llvm::CreateAttrStringValue(cx.llcx, "fentry-call", "true"));
229-
}
214+
if instrument_entry {
215+
attrs.push(llvm::CreateAttrStringValue(cx.llcx, "fentry-call", "true"));
230216

231-
if sess.opts.unstable_opts.instrument_mcount_opts.no_call {
232-
attrs.push(llvm::CreateAttrString(cx.llcx, "mnop-mcount"));
217+
if sess.opts.unstable_opts.instrument_fentry_opts.no_call {
218+
attrs.push(llvm::CreateAttrString(cx.llcx, "mnop-mcount"));
219+
}
220+
if sess.opts.unstable_opts.instrument_fentry_opts.record {
221+
attrs.push(llvm::CreateAttrString(cx.llcx, "mrecord-mcount"));
222+
}
223+
}
233224
}
234-
if sess.opts.unstable_opts.instrument_mcount_opts.record {
235-
attrs.push(llvm::CreateAttrString(cx.llcx, "mrecord-mcount"));
225+
InstrumentFunction::Mcount => {
226+
// Similar to `clang -pg` behavior. Handled by the
227+
// `post-inline-ee-instrument` LLVM pass.
228+
229+
// #[instrument_fn], the default is on.
230+
let instrument_entry = instrument_fn.unwrap_or_else(|| true);
231+
232+
if instrument_entry {
233+
// The function name varies on platforms.
234+
// See test/CodeGen/mcount.c in clang.
235+
let mcount_name = match &sess.target.llvm_mcount_intrinsic {
236+
Some(llvm_mcount_intrinsic) => llvm_mcount_intrinsic.as_ref(),
237+
None => sess.target.mcount.as_ref(),
238+
};
239+
240+
attrs.push(llvm::CreateAttrStringValue(
241+
cx.llcx,
242+
"instrument-function-entry-inlined",
243+
mcount_name,
244+
));
245+
}
236246
}
237-
}
238-
if let Some(options) = &sess.opts.unstable_opts.instrument_xray {
239-
// XRay instrumentation is similar to __cyg_profile_func_{enter,exit}.
240-
// Function prologue and epilogue are instrumented with NOP sleds,
241-
// a runtime library later replaces them with detours into tracing code.
242-
243-
let mut never = options.never;
244-
let mut always = options.always;
247+
InstrumentFunction::XRay => {
248+
// XRay instrumentation is similar to __cyg_profile_func_{enter,exit}.
249+
// Function prologue and epilogue are instrumented with NOP sleds,
250+
// a runtime library later replaces them with detours into tracing code.
251+
let options = &sess.opts.unstable_opts.instrument_xray_opts;
252+
253+
let mut never = options.never;
254+
let mut always = options.always;
255+
256+
// Apply optional #[instrument_fn] override.
257+
match instrument_fn {
258+
Some(true) => {
259+
always = true;
260+
}
261+
Some(false) => {
262+
never = true;
263+
}
264+
None => {}
265+
}
245266

246-
// Apply optional #[instrument_fn] override.
247-
match instrument_fn {
248-
Some(true) => {
249-
always = true;
267+
if never {
268+
attrs.push(llvm::CreateAttrStringValue(
269+
cx.llcx,
270+
"function-instrument",
271+
"xray-never",
272+
));
250273
}
251-
Some(false) => {
252-
never = true;
274+
if always {
275+
attrs.push(llvm::CreateAttrStringValue(
276+
cx.llcx,
277+
"function-instrument",
278+
"xray-always",
279+
));
253280
}
254-
None => {}
255-
}
256281

257-
if never {
258-
attrs.push(llvm::CreateAttrStringValue(cx.llcx, "function-instrument", "xray-never"));
259-
}
260-
if always {
261-
attrs.push(llvm::CreateAttrStringValue(cx.llcx, "function-instrument", "xray-always"));
262-
}
263-
264-
if options.ignore_loops {
265-
attrs.push(llvm::CreateAttrString(cx.llcx, "xray-ignore-loops"));
266-
}
267-
// LLVM will not choose the default for us, but rather requires specific
268-
// threshold in absence of "xray-always". Use the same default as Clang.
269-
let threshold = options.instruction_threshold.unwrap_or(200);
270-
attrs.push(llvm::CreateAttrStringValue(
271-
cx.llcx,
272-
"xray-instruction-threshold",
273-
&threshold.to_string(),
274-
));
282+
if options.ignore_loops {
283+
attrs.push(llvm::CreateAttrString(cx.llcx, "xray-ignore-loops"));
284+
}
285+
// LLVM will not choose the default for us, but rather requires specific
286+
// threshold in absence of "xray-always". Use the same default as Clang.
287+
let threshold = options.instruction_threshold.unwrap_or(200);
288+
attrs.push(llvm::CreateAttrStringValue(
289+
cx.llcx,
290+
"xray-instruction-threshold",
291+
&threshold.to_string(),
292+
));
275293

276-
if options.skip_entry {
277-
attrs.push(llvm::CreateAttrString(cx.llcx, "xray-skip-entry"));
278-
}
279-
if options.skip_exit {
280-
attrs.push(llvm::CreateAttrString(cx.llcx, "xray-skip-exit"));
294+
if options.skip_entry {
295+
attrs.push(llvm::CreateAttrString(cx.llcx, "xray-skip-entry"));
296+
}
297+
if options.skip_exit {
298+
attrs.push(llvm::CreateAttrString(cx.llcx, "xray-skip-exit"));
299+
}
281300
}
301+
InstrumentFunction::No => {}
282302
}
283303
attrs
284304
}

compiler/rustc_interface/src/tests.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ use rustc_hir::attrs::{CollapseMacroDebuginfo, NativeLibKind};
1212
use rustc_session::config::{
1313
AnnotateMoves, AutoDiff, BranchProtection, CFGuard, Cfg, CoverageLevel, CoverageOptions,
1414
DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs,
15-
FmtDebug, FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentXRay,
16-
LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, MirIncludeSpans, NextSolverConfig,
17-
Offload, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes,
18-
PatchableFunctionEntry, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath,
19-
SymbolManglingVersion, WasiExecModel, build_configuration, build_session_options,
20-
rustc_optgroups,
15+
FmtDebug, FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentFunction,
16+
InstrumentMcountOpts, InstrumentXRayOpts, LinkSelfContained, LinkerPluginLto, LocationDetail,
17+
LtoCli, MirIncludeSpans, NextSolverConfig, Offload, Options, OutFileName, OutputType,
18+
OutputTypes, PAuthKey, PacRet, Passes, PatchableFunctionEntry, Polonius,
19+
ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel,
20+
build_configuration, build_session_options, rustc_optgroups,
2121
};
2222
use rustc_session::lint::Level;
2323
use rustc_session::search_paths::SearchPath;
@@ -811,8 +811,12 @@ fn test_unstable_options_tracking_hash() {
811811
tracked!(inline_mir, Some(true));
812812
tracked!(inline_mir_hint_threshold, Some(123));
813813
tracked!(inline_mir_threshold, Some(123));
814-
tracked!(instrument_mcount, true);
815-
tracked!(instrument_xray, Some(InstrumentXRay::default()));
814+
tracked!(instrument_fentry_opts, InstrumentMcountOpts { no_call: true, record: true });
815+
tracked!(instrument_function, InstrumentFunction::Fentry);
816+
tracked!(
817+
instrument_xray_opts,
818+
InstrumentXRayOpts { always: true, ..InstrumentXRayOpts::default() }
819+
);
816820
tracked!(link_directives, false);
817821
tracked!(link_only, true);
818822
tracked!(lint_llvm_ir, true);

compiler/rustc_session/src/config.rs

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,19 @@ pub enum InstrumentCoverage {
150150
Yes,
151151
}
152152

153+
/// The different settings that the `-Z instrument-function` flag can have.
154+
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
155+
pub enum InstrumentFunction {
156+
/// No instrumentation requested, or `-Z instrument-function=none`
157+
No,
158+
/// `-Z instrument-function=fentry`
159+
Fentry,
160+
/// `-Z instrument-function=mcount`
161+
Mcount,
162+
/// `-Z instrument-function=xray`
163+
XRay,
164+
}
165+
153166
/// Individual flag values controlled by `-Zcoverage-options`.
154167
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
155168
pub struct CoverageOptions {
@@ -255,22 +268,22 @@ pub struct InstrumentMcountOpts {
255268
pub record: bool,
256269
}
257270

258-
/// Settings for `-Z instrument-xray` flag.
271+
/// Settings for `-Z instrument-xray-opts` flag.
259272
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
260-
pub struct InstrumentXRay {
261-
/// `-Z instrument-xray=always`, force instrumentation
273+
pub struct InstrumentXRayOpts {
274+
/// `-Z instrument-xray-opts=always`, force instrumentation
262275
pub always: bool,
263-
/// `-Z instrument-xray=never`, disable instrumentation
276+
/// `-Z instrument-xray-opts=never`, disable instrumentation
264277
pub never: bool,
265-
/// `-Z instrument-xray=ignore-loops`, ignore presence of loops,
278+
/// `-Z instrument-xray-opts=ignore-loops`, ignore presence of loops,
266279
/// instrument functions based only on instruction count
267280
pub ignore_loops: bool,
268-
/// `-Z instrument-xray=instruction-threshold=N`, explicitly set instruction threshold
281+
/// `-Z instrument-xray-opts=instruction-threshold=N`, explicitly set instruction threshold
269282
/// for instrumentation, or `None` to use compiler's default
270283
pub instruction_threshold: Option<usize>,
271-
/// `-Z instrument-xray=skip-entry`, do not instrument function entry
284+
/// `-Z instrument-xray-opts=skip-entry`, do not instrument function entry
272285
pub skip_entry: bool,
273-
/// `-Z instrument-xray=skip-exit`, do not instrument function exit
286+
/// `-Z instrument-xray-opts=skip-exit`, do not instrument function exit
274287
pub skip_exit: bool,
275288
}
276289

@@ -3083,11 +3096,11 @@ pub(crate) mod dep_tracking {
30833096
use super::{
30843097
AnnotateMoves, AutoDiff, BranchProtection, CFGuard, CFProtection, CoverageOptions,
30853098
CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, FmtDebug, FunctionReturn,
3086-
InliningThreshold, InstrumentCoverage, InstrumentMcountOpts, InstrumentXRay,
3087-
LinkerPluginLto, LocationDetail, LtoCli, MirStripDebugInfo, NextSolverConfig, Offload,
3088-
OptLevel, OutFileName, OutputType, OutputTypes, PatchableFunctionEntry, Polonius,
3089-
ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath,
3090-
SymbolManglingVersion, WasiExecModel,
3099+
InliningThreshold, InstrumentCoverage, InstrumentFunction, InstrumentMcountOpts,
3100+
InstrumentXRayOpts, LinkerPluginLto, LocationDetail, LtoCli, MirStripDebugInfo,
3101+
NextSolverConfig, Offload, OptLevel, OutFileName, OutputType, OutputTypes,
3102+
PatchableFunctionEntry, Polonius, ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind,
3103+
SwitchWithOptPath, SymbolManglingVersion, WasiExecModel,
30913104
};
30923105
use crate::lint;
30933106
use crate::utils::NativeLib;
@@ -3148,9 +3161,10 @@ pub(crate) mod dep_tracking {
31483161
CodeModel,
31493162
TlsModel,
31503163
InstrumentCoverage,
3164+
InstrumentFunction,
31513165
CoverageOptions,
31523166
InstrumentMcountOpts,
3153-
InstrumentXRay,
3167+
InstrumentXRayOpts,
31543168
CrateType,
31553169
MergeFunctions,
31563170
OnBrokenPipe,

0 commit comments

Comments
 (0)