tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Zprofile.patch (18288B)


      1 This reverts
      2 https://github.com/rust-lang/rust/commit/659e20fa7524f8fd217476daf5ecbbe366b2ae61
      3 and
      4 https://github.com/rust-lang/rust/pull/131829
      5 
      6 to restore support for -Zprofile (gcov-style coverage) that was removed from
      7 rustc 1.84.0
      8 
      9 diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
     10 index c548f467583..61bac4fbdab 100644
     11 --- a/compiler/rustc_codegen_llvm/src/attributes.rs
     12 +++ b/compiler/rustc_codegen_llvm/src/attributes.rs
     13 @@ -250,6 +250,11 @@ fn probestack_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
     14         return None;
     15     }
     16 
     17 +    // probestack doesn't play nice either with gcov profiling.
     18 +    if cx.sess().opts.unstable_opts.profile {
     19 +        return None;
     20 +    }
     21 +
     22     let attr_value = match cx.sess().target.stack_probes {
     23         StackProbeType::None => return None,
     24         // Request LLVM to generate the probes inline. If the given LLVM version does not support
     25 diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
     26 index 85a06f457eb..aa199a8fb26 100644
     27 --- a/compiler/rustc_codegen_llvm/src/back/write.rs
     28 +++ b/compiler/rustc_codegen_llvm/src/back/write.rs
     29 @@ -693,6 +693,7 @@ pub(crate) unsafe fn llvm_optimize(
     30             pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
     31             config.instrument_coverage,
     32             instr_profile_output_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
     33 +            config.instrument_gcov,
     34             pgo_sample_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
     35             config.debug_info_for_profiling,
     36             llvm_selfprofiler,
     37 diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
     38 index 0e9dbfba658..af3e145f016 100644
     39 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
     40 +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
     41 @@ -9,6 +9,7 @@
     42 use rustc_abi::{Align, Size};
     43 use rustc_codegen_ssa::debuginfo::type_names::{VTableNameKind, cpp_like_debuginfo};
     44 use rustc_codegen_ssa::traits::*;
     45 +use rustc_fs_util::path_to_c_string;
     46 use rustc_hir::def::{CtorKind, DefKind};
     47 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
     48 use rustc_middle::bug;
     49 @@ -968,8 +969,33 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>(
     50             debug_name_table_kind,
     51         );
     52 
     53 +        if tcx.sess.opts.unstable_opts.profile {
     54 +            let default_gcda_path = &output_filenames.with_extension("gcda");
     55 +            let gcda_path =
     56 +                tcx.sess.opts.unstable_opts.profile_emit.as_ref().unwrap_or(default_gcda_path);
     57 +
     58 +            let gcov_cu_info = [
     59 +                path_to_mdstring(debug_context.llcontext, &output_filenames.with_extension("gcno")),
     60 +                path_to_mdstring(debug_context.llcontext, gcda_path),
     61 +                unit_metadata,
     62 +            ];
     63 +            let gcov_metadata = llvm::LLVMMDNodeInContext2(
     64 +                debug_context.llcontext,
     65 +                gcov_cu_info.as_ptr(),
     66 +                gcov_cu_info.len(),
     67 +            );
     68 +            let val = llvm::LLVMMetadataAsValue(debug_context.llcontext, gcov_metadata);
     69 +
     70 +            llvm::LLVMAddNamedMetadataOperand(debug_context.llmod, c"llvm.gcov".as_ptr(), val);
     71 +        }
     72 +
     73         return unit_metadata;
     74     };
     75 +
     76 +    fn path_to_mdstring<'ll>(llcx: &'ll llvm::Context, path: &Path) -> &'ll llvm::Metadata {
     77 +        let path_str = path_to_c_string(path);
     78 +        unsafe { llvm::LLVMMDStringInContext2(llcx, path_str.as_ptr(), path_str.as_bytes().len()) }
     79 +    }
     80 }
     81 
     82 /// Creates a `DW_TAG_member` entry inside the DIE represented by the given `type_di_node`.
     83 diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
     84 index 6cbf2dbf7d3..2aa628efae5 100644
     85 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
     86 +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
     87 @@ -61,6 +61,7 @@
     88 
     89 /// A context object for maintaining all state needed by the debuginfo module.
     90 pub(crate) struct CodegenUnitDebugContext<'ll, 'tcx> {
     91 +    llcontext: &'ll llvm::Context,
     92     llmod: &'ll llvm::Module,
     93     builder: DIBuilderBox<'ll>,
     94     created_files: RefCell<UnordMap<Option<(StableSourceFileId, SourceFileHash)>, &'ll DIFile>>,
     95 @@ -76,7 +77,9 @@ pub(crate) fn new(llmod: &'ll llvm::Module) -> Self {
     96         debug!("CodegenUnitDebugContext::new");
     97         let builder = DIBuilderBox::new(llmod);
     98         // DIBuilder inherits context from the module, so we'd better use the same one
     99 +        let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) };
    100         CodegenUnitDebugContext {
    101 +            llcontext,
    102             llmod,
    103             builder,
    104             created_files: Default::default(),
    105 diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
    106 index 2443194ff48..e380af246a4 100644
    107 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
    108 +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
    109 @@ -1019,6 +1019,7 @@ pub(crate) fn LLVMModuleCreateWithNameInContext(
    110         ModuleID: *const c_char,
    111         C: &Context,
    112     ) -> &Module;
    113 +    pub(crate) fn LLVMGetModuleContext(M: &Module) -> &Context;
    114     pub(crate) safe fn LLVMCloneModule(M: &Module) -> &Module;
    115 
    116     /// Data layout. See Module::getDataLayout.
    117 @@ -2488,6 +2489,7 @@ pub(crate) fn LLVMRustOptimize<'a>(
    118         PGOUsePath: *const c_char,
    119         InstrumentCoverage: bool,
    120         InstrProfileOutput: *const c_char,
    121 +        InstrumentGCOV: bool,
    122         PGOSampleUsePath: *const c_char,
    123         DebugInfoForProfiling: bool,
    124         llvm_selfprofiler: *mut c_void,
    125 diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
    126 index aa29afb7f5b..1fee2e45ebf 100644
    127 --- a/compiler/rustc_codegen_ssa/src/back/write.rs
    128 +++ b/compiler/rustc_codegen_ssa/src/back/write.rs
    129 @@ -87,6 +87,7 @@ pub struct ModuleConfig {
    130     pub pgo_sample_use: Option<PathBuf>,
    131     pub debug_info_for_profiling: bool,
    132     pub instrument_coverage: bool,
    133 +    pub instrument_gcov: bool,
    134 
    135     pub sanitizer: SanitizerSet,
    136     pub sanitizer_recover: SanitizerSet,
    137 @@ -121,7 +122,12 @@ pub struct ModuleConfig {
    138 }
    139 
    140 impl ModuleConfig {
    141 -    fn new(kind: ModuleKind, tcx: TyCtxt<'_>, no_builtins: bool) -> ModuleConfig {
    142 +    fn new(
    143 +        kind: ModuleKind,
    144 +        tcx: TyCtxt<'_>,
    145 +        no_builtins: bool,
    146 +        is_compiler_builtins: bool,
    147 +    ) -> ModuleConfig {
    148         // If it's a regular module, use `$regular`, otherwise use `$other`.
    149         // `$regular` and `$other` are evaluated lazily.
    150         macro_rules! if_regular {
    151 @@ -181,6 +187,13 @@ macro_rules! if_regular {
    152             pgo_sample_use: if_regular!(sess.opts.unstable_opts.profile_sample_use.clone(), None),
    153             debug_info_for_profiling: sess.opts.unstable_opts.debug_info_for_profiling,
    154             instrument_coverage: if_regular!(sess.instrument_coverage(), false),
    155 +            instrument_gcov: if_regular!(
    156 +                // compiler_builtins overrides the codegen-units settings,
    157 +                // which is incompatible with -Zprofile which requires that
    158 +                // only a single codegen unit is used per crate.
    159 +                sess.opts.unstable_opts.profile && !is_compiler_builtins,
    160 +                false
    161 +            ),
    162 
    163             sanitizer: if_regular!(sess.opts.unstable_opts.sanitizer, SanitizerSet::empty()),
    164             sanitizer_dataflow_abilist: if_regular!(
    165 @@ -460,11 +473,14 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>(
    166 
    167     let crate_attrs = tcx.hir_attrs(rustc_hir::CRATE_HIR_ID);
    168     let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins);
    169 +    let is_compiler_builtins = attr::contains_name(crate_attrs, sym::compiler_builtins);
    170 
    171     let crate_info = CrateInfo::new(tcx, target_cpu);
    172 
    173 -    let regular_config = ModuleConfig::new(ModuleKind::Regular, tcx, no_builtins);
    174 -    let allocator_config = ModuleConfig::new(ModuleKind::Allocator, tcx, no_builtins);
    175 +    let regular_config =
    176 +        ModuleConfig::new(ModuleKind::Regular, tcx, no_builtins, is_compiler_builtins);
    177 +    let allocator_config =
    178 +        ModuleConfig::new(ModuleKind::Allocator, tcx, no_builtins, is_compiler_builtins);
    179 
    180     let (shared_emitter, shared_emitter_main) = SharedEmitter::new();
    181     let (codegen_worker_send, codegen_worker_receive) = channel();
    182 diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
    183 index 8771bb44050..f82a4d6ce19 100644
    184 --- a/compiler/rustc_interface/src/tests.rs
    185 +++ b/compiler/rustc_interface/src/tests.rs
    186 @@ -848,6 +848,8 @@ macro_rules! tracked {
    187     tracked!(plt, Some(true));
    188     tracked!(polonius, Polonius::Legacy);
    189     tracked!(precise_enum_drop_elaboration, false);
    190 +    tracked!(profile, true);
    191 +    tracked!(profile_emit, Some(PathBuf::from("abc")));
    192     tracked!(profile_sample_use, Some(PathBuf::from("abc")));
    193     tracked!(profiler_runtime, "abc".to_string());
    194     tracked!(reg_struct_return, true);
    195 diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
    196 index 8c34052770e..d807abfa9b5 100644
    197 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
    198 +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
    199 @@ -35,6 +35,7 @@
    200 #include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h"
    201 #include "llvm/Transforms/Instrumentation/AddressSanitizer.h"
    202 #include "llvm/Transforms/Instrumentation/DataFlowSanitizer.h"
    203 +#include "llvm/Transforms/Instrumentation/GCOVProfiler.h"
    204 #include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
    205 #include "llvm/Transforms/Instrumentation/InstrProfiling.h"
    206 #include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
    207 @@ -720,8 +721,9 @@ extern "C" LLVMRustResult LLVMRustOptimize(
    208     bool PrintAfterEnzyme, bool PrintPasses,
    209     LLVMRustSanitizerOptions *SanitizerOptions, const char *PGOGenPath,
    210     const char *PGOUsePath, bool InstrumentCoverage,
    211 -    const char *InstrProfileOutput, const char *PGOSampleUsePath,
    212 -    bool DebugInfoForProfiling, void *LlvmSelfProfiler,
    213 +    const char *InstrProfileOutput, bool InstrumentGCOV,
    214 +    const char *PGOSampleUsePath, bool DebugInfoForProfiling,
    215 +    void *LlvmSelfProfiler,
    216     LLVMRustSelfProfileBeforePassCallback BeforePassCallback,
    217     LLVMRustSelfProfileAfterPassCallback AfterPassCallback,
    218     const char *ExtraPasses, size_t ExtraPassesLen, const char *LLVMPlugins,
    219 @@ -850,6 +852,13 @@ extern "C" LLVMRustResult LLVMRustOptimize(
    220     });
    221   }
    222 
    223 +  if (InstrumentGCOV) {
    224 +    PipelineStartEPCallbacks.push_back(
    225 +        [](ModulePassManager &MPM, OptimizationLevel Level) {
    226 +          MPM.addPass(GCOVProfilerPass(GCOVOptions::getDefault()));
    227 +        });
    228 +  }
    229 +
    230   if (InstrumentCoverage) {
    231     PipelineStartEPCallbacks.push_back(
    232         [InstrProfileOutput](ModulePassManager &MPM, OptimizationLevel Level) {
    233 diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
    234 index 6bfb3769f24..14700bea72b 100644
    235 --- a/compiler/rustc_metadata/src/creader.rs
    236 +++ b/compiler/rustc_metadata/src/creader.rs
    237 @@ -1039,7 +1039,7 @@ fn inject_panic_runtime(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) {
    238 
    239     fn inject_profiler_runtime(&mut self, tcx: TyCtxt<'_>) {
    240         let needs_profiler_runtime =
    241 -            tcx.sess.instrument_coverage() || tcx.sess.opts.cg.profile_generate.enabled();
    242 +            tcx.sess.instrument_coverage() || tcx.sess.opts.unstable_opts.profile || tcx.sess.opts.cg.profile_generate.enabled();
    243         if !needs_profiler_runtime || tcx.sess.opts.unstable_opts.no_profiler_runtime {
    244             return;
    245         }
    246 diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
    247 index 8f624e0fb2f..9d6e376c16f 100644
    248 --- a/compiler/rustc_session/src/config.rs
    249 +++ b/compiler/rustc_session/src/config.rs
    250 @@ -2606,7 +2606,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
    251     let output_types = parse_output_types(early_dcx, &unstable_opts, matches);
    252 
    253     let mut cg = CodegenOptions::build(early_dcx, matches, &mut target_modifiers);
    254 -    let (disable_local_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
    255 +    let (disable_local_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
    256         early_dcx,
    257         &output_types,
    258         matches,
    259 @@ -2625,6 +2625,18 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
    260 
    261     let assert_incr_state = parse_assert_incr_state(early_dcx, &unstable_opts.assert_incr_state);
    262 
    263 +    if unstable_opts.profile && incremental.is_some() {
    264 +        early_dcx.early_fatal("can't instrument with gcov profiling when compiling incrementally");
    265 +    }
    266 +    if unstable_opts.profile {
    267 +        match codegen_units {
    268 +            Some(1) => {}
    269 +            None => codegen_units = Some(1),
    270 +            Some(_) => early_dcx
    271 +                .early_fatal("can't instrument with gcov profiling with multiple codegen units"),
    272 +        }
    273 +    }
    274 +
    275     if cg.profile_generate.enabled() && cg.profile_use.is_some() {
    276         early_dcx.early_fatal("options `-C profile-generate` and `-C profile-use` are exclusive");
    277     }
    278 diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
    279 index 44b35e8921e..235e04fa5b0 100644
    280 --- a/compiler/rustc_session/src/options.rs
    281 +++ b/compiler/rustc_session/src/options.rs
    282 @@ -2471,8 +2471,13 @@ pub(crate) fn parse_align(slot: &mut Option<Align>, v: Option<&str>) -> bool {
    283     proc_macro_execution_strategy: ProcMacroExecutionStrategy = (ProcMacroExecutionStrategy::SameThread,
    284         parse_proc_macro_execution_strategy, [UNTRACKED],
    285         "how to run proc-macro code (default: same-thread)"),
    286 +    profile: bool = (false, parse_bool, [TRACKED],
    287 +        "insert profiling code (default: no)"),
    288     profile_closures: bool = (false, parse_no_value, [UNTRACKED],
    289         "profile size of closures"),
    290 +    profile_emit: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
    291 +        "file path to emit profiling data at runtime when using 'profile' \
    292 +        (default based on relative source path)"),
    293     profile_sample_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
    294         "use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)"),
    295     profiler_runtime: String = (String::from("profiler_builtins"), parse_string, [TRACKED],
    296 diff --git a/src/doc/rustc/src/instrument-coverage.md b/src/doc/rustc/src/instrument-coverage.md
    297 index 57679f82f48..0f88bec2c71 100644
    298 --- a/src/doc/rustc/src/instrument-coverage.md
    299 +++ b/src/doc/rustc/src/instrument-coverage.md
    300 @@ -2,8 +2,12 @@
    301 
    302 ## Introduction
    303 
    304 -This document describes how to enable and use LLVM instrumentation-based coverage,
    305 -via the `-C instrument-coverage` compiler flag.
    306 +The Rust compiler includes two code coverage implementations:
    307 +
    308 +-   A GCC-compatible, gcov-based coverage implementation, enabled with `-Z profile`, which derives coverage data based on DebugInfo.
    309 +-   A source-based code coverage implementation, enabled with `-C instrument-coverage`, which uses LLVM's native, efficient coverage instrumentation to generate very precise coverage data.
    310 +
    311 +This document describes how to enable and use the LLVM instrumentation-based coverage, via the `-C instrument-coverage` compiler flag.
    312 
    313 ## How it works
    314 
    315 diff --git a/src/doc/unstable-book/src/compiler-flags/profile.md b/src/doc/unstable-book/src/compiler-flags/profile.md
    316 new file mode 100644
    317 index 00000000000..71303bfaff2
    318 --- /dev/null
    319 +++ b/src/doc/unstable-book/src/compiler-flags/profile.md
    320 @@ -0,0 +1,27 @@
    321 +# `profile`
    322 +
    323 +The tracking issue for this feature is: [#42524](https://github.com/rust-lang/rust/issues/42524).
    324 +
    325 +------------------------
    326 +
    327 +This feature allows the generation of code coverage reports.
    328 +
    329 +Set the `-Zprofile` compiler flag in order to enable gcov profiling.
    330 +
    331 +For example:
    332 +```Bash
    333 +cargo new testgcov --bin
    334 +cd testgcov
    335 +export RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort"
    336 +export CARGO_INCREMENTAL=0
    337 +cargo build
    338 +cargo run
    339 +```
    340 +
    341 +Once you've built and run your program, files with the `gcno` (after build) and `gcda` (after execution) extensions will be created.
    342 +You can parse them with [llvm-cov gcov](https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-gcov) or [grcov](https://github.com/mozilla/grcov).
    343 +
    344 +Please note that `RUSTFLAGS` by default applies to everything that cargo builds and runs during a build!
    345 +When the `--target` flag is explicitly passed to cargo, the `RUSTFLAGS` no longer apply to build scripts and procedural macros.
    346 +For more fine-grained control consider passing a `RUSTC_WRAPPER` program to cargo that only adds the profiling flags to
    347 +rustc for the specific crates you want to profile.
    348 diff --git a/tests/run-make/profile/rmake.rs b/tests/run-make/profile/rmake.rs
    349 new file mode 100644
    350 index 00000000000..58a1b53c040
    351 --- /dev/null
    352 +++ b/tests/run-make/profile/rmake.rs
    353 @@ -0,0 +1,21 @@
    354 +// This test revolves around the rustc flag -Z profile, which should
    355 +// generate a .gcno file (initial profiling information) as well
    356 +// as a .gcda file (branch counters). The path where these are emitted
    357 +// should also be configurable with -Z profile-emit. This test checks
    358 +// that the files are produced, and then that the latter flag is respected.
    359 +// See https://github.com/rust-lang/rust/pull/42433
    360 +
    361 +//@ ignore-cross-compile
    362 +//@ needs-profiler-runtime
    363 +
    364 +use run_make_support::{path, run, rustc};
    365 +
    366 +fn main() {
    367 +    rustc().arg("-g").arg("-Zprofile").input("test.rs").run();
    368 +    run("test");
    369 +    assert!(path("test.gcno").exists(), "no .gcno file");
    370 +    assert!(path("test.gcda").exists(), "no .gcda file");
    371 +    rustc().arg("-g").arg("-Zprofile").arg("-Zprofile-emit=abc/abc.gcda").input("test.rs").run();
    372 +    run("test");
    373 +    assert!(path("abc/abc.gcda").exists(), "gcda file not emitted to defined path");
    374 +}
    375 diff --git a/tests/run-make/profile/test.rs b/tests/run-make/profile/test.rs
    376 new file mode 100644
    377 index 00000000000..f328e4d9d04
    378 --- /dev/null
    379 +++ b/tests/run-make/profile/test.rs
    380 @@ -0,0 +1 @@
    381 +fn main() {}