From 1d8c381c014f202eeae59994b9b664841e91cb72 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Mon, 23 Nov 2020 12:56:07 -0800 Subject: [PATCH 1/8] Upgrades the coverage map to Version 4 Changes the coverage map injected into binaries compiled with `-Zinstrument-coverage` to LLVM Coverage Mapping Format, Version 4 (from Version 3). Note, binaries compiled with this version will require LLVM tools from at least LLVM Version 11. --- .../src/coverageinfo/mapgen.rs | 201 +++++++++--------- .../src/coverageinfo/mod.rs | 54 ++++- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 8 +- compiler/rustc_codegen_llvm/src/llvm/mod.rs | 12 ++ .../llvm-wrapper/CoverageMappingWrapper.cpp | 47 ++-- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 2 +- .../coverage-llvmir-base/Makefile | 6 + .../filecheck.testprog.txt | 5 +- 8 files changed, 203 insertions(+), 132 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 41827a91ba4be..a6372a77a70ad 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -4,7 +4,7 @@ use crate::llvm; use llvm::coverageinfo::CounterMappingRegion; use rustc_codegen_ssa::coverageinfo::map::{Counter, CounterExpression}; -use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods}; +use rustc_codegen_ssa::traits::ConstMethods; use rustc_data_structures::fx::FxIndexSet; use rustc_llvm::RustString; use rustc_middle::mir::coverage::CodeRegion; @@ -38,46 +38,50 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { let mut mapgen = CoverageMapGenerator::new(); // Encode coverage mappings and generate function records - let mut function_records = Vec::<&'ll llvm::Value>::new(); - let coverage_mappings_buffer = llvm::build_byte_buffer(|coverage_mappings_buffer| { - for (instance, function_coverage) in function_coverage_map.into_iter() { - debug!("Generate coverage map for: {:?}", instance); - - let mangled_function_name = cx.tcx.symbol_name(instance).to_string(); - let function_source_hash = function_coverage.source_hash(); - let (expressions, counter_regions) = - function_coverage.get_expressions_and_counter_regions(); - - let old_len = coverage_mappings_buffer.len(); - mapgen.write_coverage_mappings(expressions, counter_regions, coverage_mappings_buffer); - let mapping_data_size = coverage_mappings_buffer.len() - old_len; - debug_assert!( - mapping_data_size > 0, - "Every `FunctionCoverage` should have at least one counter" - ); - - let function_record = mapgen.make_function_record( - cx, - mangled_function_name, - function_source_hash, - mapping_data_size, - ); - function_records.push(function_record); - } - }); + let mut function_data = Vec::new(); + for (instance, function_coverage) in function_coverage_map.into_iter() { + debug!("Generate coverage map for: {:?}", instance); + + let mangled_function_name = cx.tcx.symbol_name(instance).to_string(); + let function_source_hash = function_coverage.source_hash(); + let (expressions, counter_regions) = + function_coverage.get_expressions_and_counter_regions(); + + let coverage_mapping_buffer = llvm::build_byte_buffer(|coverage_mapping_buffer| { + mapgen.write_coverage_mapping(expressions, counter_regions, coverage_mapping_buffer); + }); + debug_assert!( + coverage_mapping_buffer.len() > 0, + "Every `FunctionCoverage` should have at least one counter" + ); + + function_data.push((mangled_function_name, function_source_hash, coverage_mapping_buffer)); + } // Encode all filenames referenced by counters/expressions in this module let filenames_buffer = llvm::build_byte_buffer(|filenames_buffer| { coverageinfo::write_filenames_section_to_buffer(&mapgen.filenames, filenames_buffer); }); + let filenames_size = filenames_buffer.len(); + let filenames_val = cx.const_bytes(&filenames_buffer[..]); + let filenames_ref = coverageinfo::hash_bytes(filenames_buffer); + // Generate the LLVM IR representation of the coverage map and store it in a well-known global - mapgen.save_generated_coverage_map( - cx, - function_records, - filenames_buffer, - coverage_mappings_buffer, - ); + let cov_data_val = mapgen.generate_coverage_map(cx, filenames_size, filenames_val); + + for (mangled_function_name, function_source_hash, coverage_mapping_buffer) in function_data { + save_function_record( + cx, + mangled_function_name, + function_source_hash, + filenames_ref, + coverage_mapping_buffer, + ); + } + + // Save the coverage data value to LLVM IR + coverageinfo::save_cov_data_to_mod(cx, cov_data_val); } struct CoverageMapGenerator { @@ -92,12 +96,12 @@ impl CoverageMapGenerator { /// Using the `expressions` and `counter_regions` collected for the current function, generate /// the `mapping_regions` and `virtual_file_mapping`, and capture any new filenames. Then use /// LLVM APIs to encode the `virtual_file_mapping`, `expressions`, and `mapping_regions` into - /// the given `coverage_mappings` byte buffer, compliant with the LLVM Coverage Mapping format. - fn write_coverage_mappings( + /// the given `coverage_mapping` byte buffer, compliant with the LLVM Coverage Mapping format. + fn write_coverage_mapping( &mut self, expressions: Vec, counter_regions: impl Iterator, - coverage_mappings_buffer: &RustString, + coverage_mapping_buffer: &RustString, ) { let mut counter_regions = counter_regions.collect::>(); if counter_regions.is_empty() { @@ -145,89 +149,78 @@ impl CoverageMapGenerator { virtual_file_mapping, expressions, mapping_regions, - coverage_mappings_buffer, + coverage_mapping_buffer, ); } - /// Generate and return the function record `Value` - fn make_function_record( - &mut self, - cx: &CodegenCx<'ll, 'tcx>, - mangled_function_name: String, - function_source_hash: u64, - mapping_data_size: usize, - ) -> &'ll llvm::Value { - let name_ref = coverageinfo::compute_hash(&mangled_function_name); - let name_ref_val = cx.const_u64(name_ref); - let mapping_data_size_val = cx.const_u32(mapping_data_size as u32); - let func_hash_val = cx.const_u64(function_source_hash); - cx.const_struct( - &[name_ref_val, mapping_data_size_val, func_hash_val], - /*packed=*/ true, - ) - } - - /// Combine the filenames and coverage mappings buffers, construct coverage map header and the - /// array of function records, and combine everything into the complete coverage map. Save the - /// coverage map data into the LLVM IR as a static global using a specific, well-known section - /// and name. - fn save_generated_coverage_map( + /// Construct coverage map header and the array of function records, and combine them into the + /// coverage map. Save the coverage map data into the LLVM IR as a static global using a + /// specific, well-known section and name. + fn generate_coverage_map( self, cx: &CodegenCx<'ll, 'tcx>, - function_records: Vec<&'ll llvm::Value>, - filenames_buffer: Vec, - mut coverage_mappings_buffer: Vec, - ) { - // Concatenate the encoded filenames and encoded coverage mappings, and add additional zero - // bytes as-needed to ensure 8-byte alignment. - let mut coverage_size = coverage_mappings_buffer.len(); - let filenames_size = filenames_buffer.len(); - let remaining_bytes = - (filenames_size + coverage_size) % coverageinfo::COVMAP_VAR_ALIGN_BYTES; - if remaining_bytes > 0 { - let pad = coverageinfo::COVMAP_VAR_ALIGN_BYTES - remaining_bytes; - coverage_mappings_buffer.append(&mut [0].repeat(pad)); - coverage_size += pad; - } - let filenames_and_coverage_mappings = [filenames_buffer, coverage_mappings_buffer].concat(); - let filenames_and_coverage_mappings_val = - cx.const_bytes(&filenames_and_coverage_mappings[..]); - + filenames_size: usize, + filenames_val: &'ll llvm::Value, + ) -> &'ll llvm::Value { debug!( - "cov map: n_records = {}, filenames_size = {}, coverage_size = {}, 0-based version = {}", - function_records.len(), + "cov map: filenames_size = {}, 0-based version = {}", filenames_size, - coverage_size, coverageinfo::mapping_version() ); - // Create the coverage data header - let n_records_val = cx.const_u32(function_records.len() as u32); + // Create the coverage data header (Note, fields 0 and 2 are now always zero, + // as of `llvm::coverage::CovMapVersion::Version4`. + let zero_was_n_records_val = cx.const_u32(0); let filenames_size_val = cx.const_u32(filenames_size as u32); - let coverage_size_val = cx.const_u32(coverage_size as u32); + let zero_was_coverage_size_val = cx.const_u32(0 as u32); let version_val = cx.const_u32(coverageinfo::mapping_version()); let cov_data_header_val = cx.const_struct( - &[n_records_val, filenames_size_val, coverage_size_val, version_val], + &[zero_was_n_records_val, filenames_size_val, zero_was_coverage_size_val, version_val], /*packed=*/ false, ); - // Create the function records array - let name_ref_from_u64 = cx.type_i64(); - let mapping_data_size_from_u32 = cx.type_i32(); - let func_hash_from_u64 = cx.type_i64(); - let function_record_ty = cx.type_struct( - &[name_ref_from_u64, mapping_data_size_from_u32, func_hash_from_u64], - /*packed=*/ true, - ); - let function_records_val = cx.const_array(function_record_ty, &function_records[..]); - // Create the complete LLVM coverage data value to add to the LLVM IR - let cov_data_val = cx.const_struct( - &[cov_data_header_val, function_records_val, filenames_and_coverage_mappings_val], - /*packed=*/ false, - ); - - // Save the coverage data value to LLVM IR - coverageinfo::save_map_to_mod(cx, cov_data_val); + cx.const_struct(&[cov_data_header_val, filenames_val], /*packed=*/ false) } } + +/// Construct a function record and combine it with the function's coverage mapping data. +/// Save the function record into the LLVM IR as a static global using a +/// specific, well-known section and name. +fn save_function_record( + cx: &CodegenCx<'ll, 'tcx>, + mangled_function_name: String, + function_source_hash: u64, + filenames_ref: u64, + coverage_mapping_buffer: Vec, +) { + // Concatenate the encoded coverage mappings + let coverage_mapping_size = coverage_mapping_buffer.len(); + let coverage_mapping_val = cx.const_bytes(&coverage_mapping_buffer[..]); + + let func_name_hash = coverageinfo::hash_str(&mangled_function_name); + let func_name_hash_val = cx.const_u64(func_name_hash); + let coverage_mapping_size_val = cx.const_u32(coverage_mapping_size as u32); + let func_hash_val = cx.const_u64(function_source_hash); + let filenames_ref_val = cx.const_u64(filenames_ref); + let func_record_val = cx.const_struct( + &[ + func_name_hash_val, + coverage_mapping_size_val, + func_hash_val, + filenames_ref_val, + coverage_mapping_val, + ], + /*packed=*/ true, + ); + + // At the present time, the coverage map for Rust assumes every instrumented function `is_used`. + // Note that Clang marks functions as "unused" in `CodeGenPGO::emitEmptyCounterMapping`. (See: + // https://github.com/rust-lang/llvm-project/blob/de02a75e398415bad4df27b4547c25b896c8bf3b/clang%2Flib%2FCodeGen%2FCodeGenPGO.cpp#L877-L878 + // for example.) + // + // It's not yet clear if or how this may be applied to Rust in the future, but the `is_used` + // argument is available and handled similarly. + let is_used = true; + coverageinfo::save_func_record_to_mod(cx, func_name_hash, func_record_val, is_used); +} diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index e21e03822ebb3..e777f363eb084 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -23,7 +23,7 @@ use tracing::debug; pub mod mapgen; -const COVMAP_VAR_ALIGN_BYTES: usize = 8; +const VAR_ALIGN_BYTES: usize = 8; /// A context object for maintaining all state needed by the coverageinfo module. pub struct CrateCoverageContext<'tcx> { @@ -177,17 +177,20 @@ pub(crate) fn write_mapping_to_buffer( ); } } +pub(crate) fn hash_str(strval: &str) -> u64 { + let strval = CString::new(strval).expect("null error converting hashable str to C string"); + unsafe { llvm::LLVMRustCoverageHashCString(strval.as_ptr()) } +} -pub(crate) fn compute_hash(name: &str) -> u64 { - let name = CString::new(name).expect("null error converting hashable name to C string"); - unsafe { llvm::LLVMRustCoverageComputeHash(name.as_ptr()) } +pub(crate) fn hash_bytes(bytes: Vec) -> u64 { + unsafe { llvm::LLVMRustCoverageHashByteArray(bytes.as_ptr().cast(), bytes.len()) } } pub(crate) fn mapping_version() -> u32 { unsafe { llvm::LLVMRustCoverageMappingVersion() } } -pub(crate) fn save_map_to_mod<'ll, 'tcx>( +pub(crate) fn save_cov_data_to_mod<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, cov_data_val: &'ll llvm::Value, ) { @@ -198,7 +201,7 @@ pub(crate) fn save_map_to_mod<'ll, 'tcx>( debug!("covmap var name: {:?}", covmap_var_name); let covmap_section_name = llvm::build_string(|s| unsafe { - llvm::LLVMRustCoverageWriteSectionNameToString(cx.llmod, s); + llvm::LLVMRustCoverageWriteMapSectionNameToString(cx.llmod, s); }) .expect("Rust Coverage section name failed UTF-8 conversion"); debug!("covmap section name: {:?}", covmap_section_name); @@ -206,8 +209,43 @@ pub(crate) fn save_map_to_mod<'ll, 'tcx>( let llglobal = llvm::add_global(cx.llmod, cx.val_ty(cov_data_val), &covmap_var_name); llvm::set_initializer(llglobal, cov_data_val); llvm::set_global_constant(llglobal, true); - llvm::set_linkage(llglobal, llvm::Linkage::InternalLinkage); + llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); llvm::set_section(llglobal, &covmap_section_name); - llvm::set_alignment(llglobal, COVMAP_VAR_ALIGN_BYTES); + llvm::set_alignment(llglobal, VAR_ALIGN_BYTES); + cx.add_used_global(llglobal); +} + +pub(crate) fn save_func_record_to_mod<'ll, 'tcx>( + cx: &CodegenCx<'ll, 'tcx>, + func_name_hash: u64, + func_record_val: &'ll llvm::Value, + is_used: bool, +) { + // Assign a name to the function record. This is used to merge duplicates. + // + // In LLVM, a "translation unit" (effectively, a `Crate` in Rust) can describe functions that + // are included-but-not-used. If (or when) Rust generates functions that are + // included-but-not-used, note that a dummy description for a function included-but-not-used + // in a Crate can be replaced by full description provided by a different Crate. The two kinds + // of descriptions play distinct roles in LLVM IR; therefore, assign them different names (by + // appending "u" to the end of the function record var name, to prevent `linkonce_odr` merging. + let func_record_var_name = + format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" }); + debug!("function record var name: {:?}", func_record_var_name); + + let func_record_section_name = llvm::build_string(|s| unsafe { + llvm::LLVMRustCoverageWriteFuncSectionNameToString(cx.llmod, s); + }) + .expect("Rust Coverage function record section name failed UTF-8 conversion"); + debug!("function record section name: {:?}", func_record_section_name); + + let llglobal = llvm::add_global(cx.llmod, cx.val_ty(func_record_val), &func_record_var_name); + llvm::set_initializer(llglobal, func_record_val); + llvm::set_global_constant(llglobal, true); + llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage); + llvm::set_visibility(llglobal, llvm::Visibility::Hidden); + llvm::set_section(llglobal, &func_record_section_name); + llvm::set_alignment(llglobal, VAR_ALIGN_BYTES); + llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name); cx.add_used_global(llglobal); } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 8b15c8b0eb607..69a37dba0f1e6 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1791,10 +1791,14 @@ extern "C" { pub fn LLVMRustCoverageCreatePGOFuncNameVar(F: &'a Value, FuncName: *const c_char) -> &'a Value; - pub fn LLVMRustCoverageComputeHash(Name: *const c_char) -> u64; + pub fn LLVMRustCoverageHashCString(StrVal: *const c_char) -> u64; + pub fn LLVMRustCoverageHashByteArray(Bytes: *const c_char, NumBytes: size_t) -> u64; #[allow(improper_ctypes)] - pub fn LLVMRustCoverageWriteSectionNameToString(M: &Module, Str: &RustString); + pub fn LLVMRustCoverageWriteMapSectionNameToString(M: &Module, Str: &RustString); + + #[allow(improper_ctypes)] + pub fn LLVMRustCoverageWriteFuncSectionNameToString(M: &Module, Str: &RustString); #[allow(improper_ctypes)] pub fn LLVMRustCoverageWriteMappingVarNameToString(Str: &RustString); diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 53a404ee01944..fc40065a9664e 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -220,12 +220,24 @@ pub fn set_linkage(llglobal: &Value, linkage: Linkage) { } } +pub fn set_visibility(llglobal: &Value, visibility: Visibility) { + unsafe { + LLVMRustSetVisibility(llglobal, visibility); + } +} + pub fn set_alignment(llglobal: &Value, bytes: usize) { unsafe { ffi::LLVMSetAlignment(llglobal, bytes as c_uint); } } +pub fn set_comdat(llmod: &Module, llglobal: &Value, name: &str) { + unsafe { + LLVMRustSetComdat(llmod, llglobal, name.as_ptr().cast(), name.len()); + } +} + /// Safe wrapper around `LLVMGetParam`, because segfaults are no fun. pub fn get_param(llfn: &Value, index: c_uint) -> &Value { unsafe { diff --git a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp index 2b1143a4ecff5..6700482f2b7bd 100644 --- a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp @@ -3,7 +3,6 @@ #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h" #include "llvm/ProfileData/InstrProf.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/Support/LEB128.h" #include @@ -13,15 +12,14 @@ extern "C" void LLVMRustCoverageWriteFilenamesSectionToBuffer( const char* const Filenames[], size_t FilenamesLen, RustStringRef BufferOut) { - // LLVM 11's CoverageFilenamesSectionWriter uses its new `Version4` format, - // so we're manually writing the `Version3` format ourselves. - RawRustStringOstream OS(BufferOut); - encodeULEB128(FilenamesLen, OS); + SmallVector FilenameRefs; for (size_t i = 0; i < FilenamesLen; i++) { - StringRef Filename(Filenames[i]); - encodeULEB128(Filename.size(), OS); - OS << Filename; + FilenameRefs.push_back(StringRef(Filenames[i])); } + auto FilenamesWriter = coverage::CoverageFilenamesSectionWriter( + makeArrayRef(FilenameRefs)); + RawRustStringOstream OS(BufferOut); + FilenamesWriter.write(OS); } extern "C" void LLVMRustCoverageWriteMappingToBuffer( @@ -45,20 +43,37 @@ extern "C" LLVMValueRef LLVMRustCoverageCreatePGOFuncNameVar(LLVMValueRef F, con return wrap(createPGOFuncNameVar(*cast(unwrap(F)), FuncNameRef)); } -extern "C" uint64_t LLVMRustCoverageComputeHash(const char *Name) { - StringRef NameRef(Name); - return IndexedInstrProf::ComputeHash(NameRef); +extern "C" uint64_t LLVMRustCoverageHashCString(const char *StrVal) { + StringRef StrRef(StrVal); + return IndexedInstrProf::ComputeHash(StrRef); +} + +extern "C" uint64_t LLVMRustCoverageHashByteArray( + const char *Bytes, + unsigned NumBytes) { + StringRef StrRef(Bytes, NumBytes); + return IndexedInstrProf::ComputeHash(StrRef); } -extern "C" void LLVMRustCoverageWriteSectionNameToString(LLVMModuleRef M, - RustStringRef Str) { +static void WriteSectionNameToString(LLVMModuleRef M, + InstrProfSectKind SK, + RustStringRef Str) { Triple TargetTriple(unwrap(M)->getTargetTriple()); - auto name = getInstrProfSectionName(IPSK_covmap, - TargetTriple.getObjectFormat()); + auto name = getInstrProfSectionName(SK, TargetTriple.getObjectFormat()); RawRustStringOstream OS(Str); OS << name; } +extern "C" void LLVMRustCoverageWriteMapSectionNameToString(LLVMModuleRef M, + RustStringRef Str) { + WriteSectionNameToString(M, IPSK_covmap, Str); +} + +extern "C" void LLVMRustCoverageWriteFuncSectionNameToString(LLVMModuleRef M, + RustStringRef Str) { + WriteSectionNameToString(M, IPSK_covfun, Str); +} + extern "C" void LLVMRustCoverageWriteMappingVarNameToString(RustStringRef Str) { auto name = getCoverageMappingVarName(); RawRustStringOstream OS(Str); @@ -66,5 +81,5 @@ extern "C" void LLVMRustCoverageWriteMappingVarNameToString(RustStringRef Str) { } extern "C" uint32_t LLVMRustCoverageMappingVersion() { - return coverage::CovMapVersion::Version3; + return coverage::CovMapVersion::Version4; } diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 9b0c176b69203..e17f933932e6a 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1462,7 +1462,7 @@ extern "C" void LLVMRustSetComdat(LLVMModuleRef M, LLVMValueRef V, const char *Name, size_t NameLen) { Triple TargetTriple(unwrap(M)->getTargetTriple()); GlobalObject *GV = unwrap(V); - if (!TargetTriple.isOSBinFormatMachO()) { + if (TargetTriple.supportsCOMDAT()) { StringRef NameRef(Name, NameLen); GV->setComdat(unwrap(M)->getOrInsertComdat(NameRef)); } diff --git a/src/test/run-make-fulldeps/coverage-llvmir-base/Makefile b/src/test/run-make-fulldeps/coverage-llvmir-base/Makefile index e84642922d934..b1368bdb79365 100644 --- a/src/test/run-make-fulldeps/coverage-llvmir-base/Makefile +++ b/src/test/run-make-fulldeps/coverage-llvmir-base/Makefile @@ -12,10 +12,12 @@ ifeq ($(UNAME),Darwin) INSTR_PROF_DATA_SUFFIX=,regular,live_support DATA_SECTION_PREFIX=__DATA, LLVM_COV_SECTION_PREFIX=__LLVM_COV, + COMDAT_IF_SUPPORTED= else INSTR_PROF_DATA_SUFFIX= DATA_SECTION_PREFIX= LLVM_COV_SECTION_PREFIX= + COMDAT_IF_SUPPORTED=, comdat endif ifeq ($(LINK_DEAD_CODE),yes) @@ -29,24 +31,28 @@ ifdef IS_WINDOWS -check-prefixes=CHECK,WINDOWS \ -DPRIVATE_GLOBAL='internal global' \ -DDEFINE_INTERNAL='$(DEFINE_INTERNAL)' \ + -DCOMDAT_IF_SUPPORTED='$(COMDAT_IF_SUPPORTED)' \ -DINSTR_PROF_DATA='.lprfd$$M' \ -DINSTR_PROF_NAME='.lprfn$$M' \ -DINSTR_PROF_CNTS='.lprfc$$M' \ -DINSTR_PROF_VALS='.lprfv$$M' \ -DINSTR_PROF_VNODES='.lprfnd$$M' \ -DINSTR_PROF_COVMAP='.lcovmap$$M' \ + -DINSTR_PROF_COVFUN='.lcovfun$$M' \ -DINSTR_PROF_ORDERFILE='.lorderfile$$M' else LLVM_FILECHECK_OPTIONS=\ -check-prefixes=CHECK \ -DPRIVATE_GLOBAL='private global' \ -DDEFINE_INTERNAL='$(DEFINE_INTERNAL)' \ + -DCOMDAT_IF_SUPPORTED='$(COMDAT_IF_SUPPORTED)' \ -DINSTR_PROF_DATA='$(DATA_SECTION_PREFIX)__llvm_prf_data$(INSTR_PROF_DATA_SUFFIX)' \ -DINSTR_PROF_NAME='$(DATA_SECTION_PREFIX)__llvm_prf_names' \ -DINSTR_PROF_CNTS='$(DATA_SECTION_PREFIX)__llvm_prf_cnts' \ -DINSTR_PROF_VALS='$(DATA_SECTION_PREFIX)__llvm_prf_vals' \ -DINSTR_PROF_VNODES='$(DATA_SECTION_PREFIX)__llvm_prf_vnds' \ -DINSTR_PROF_COVMAP='$(LLVM_COV_SECTION_PREFIX)__llvm_covmap' \ + -DINSTR_PROF_COVFUN='$(LLVM_COV_SECTION_PREFIX)__llvm_covfun' \ -DINSTR_PROF_ORDERFILE='$(DATA_SECTION_PREFIX)__llvm_orderfile' endif diff --git a/src/test/run-make-fulldeps/coverage-llvmir-base/filecheck.testprog.txt b/src/test/run-make-fulldeps/coverage-llvmir-base/filecheck.testprog.txt index bd2a2475d9e10..a312ec48e8498 100644 --- a/src/test/run-make-fulldeps/coverage-llvmir-base/filecheck.testprog.txt +++ b/src/test/run-make-fulldeps/coverage-llvmir-base/filecheck.testprog.txt @@ -3,7 +3,10 @@ WINDOWS: $__llvm_profile_runtime_user = comdat any -CHECK: @__llvm_coverage_mapping = internal constant +CHECK: @__covrec_{{[A-F0-9]+}}u = linkonce_odr hidden constant +CHECK-SAME: section "[[INSTR_PROF_COVFUN]]"[[COMDAT_IF_SUPPORTED]], align 8 + +CHECK: @__llvm_coverage_mapping = private constant CHECK-SAME: section "[[INSTR_PROF_COVMAP]]", align 8 WINDOWS: @__llvm_profile_runtime = external global i32 From 5d5dc4c9d86499854a50a54a8dab73c180f7cbbc Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Mon, 23 Nov 2020 19:11:56 -0800 Subject: [PATCH 2/8] Updated links to LLVM 11 docs and types --- compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs | 6 +++--- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 6 +++--- compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs | 8 ++++---- compiler/rustc_middle/src/mir/coverage.rs | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index a6372a77a70ad..e4a9ac7a5e866 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -15,9 +15,9 @@ use tracing::debug; /// Generates and exports the Coverage Map. /// -/// This Coverage Map complies with Coverage Mapping Format version 3 (zero-based encoded as 2), -/// as defined at [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format) -/// and published in Rust's current (July 2020) fork of LLVM. This version is supported by the +/// This Coverage Map complies with Coverage Mapping Format version 4 (zero-based encoded as 3), +/// as defined at [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format) +/// and published in Rust's current (November 2020) fork of LLVM. This version is supported by the /// LLVM coverage tools (`llvm-profdata` and `llvm-cov`) bundled with Rust's fork of LLVM. /// /// Consequently, Rust's bundled version of Clang also generates Coverage Maps compliant with diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 69a37dba0f1e6..41482d18946ad 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -642,7 +642,7 @@ pub type InlineAsmDiagHandler = unsafe extern "C" fn(&SMDiagnostic, *const c_voi pub mod coverageinfo { use super::coverage_map; - /// Aligns with [llvm::coverage::CounterMappingRegion::RegionKind](https://github.com/rust-lang/llvm-project/blob/rustc/10.0-2020-05-05/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L205-L221) + /// Aligns with [llvm::coverage::CounterMappingRegion::RegionKind](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L206-L222) #[derive(Copy, Clone, Debug)] #[repr(C)] pub enum RegionKind { @@ -665,13 +665,13 @@ pub mod coverageinfo { /// This struct provides LLVM's representation of a "CoverageMappingRegion", encoded into the /// coverage map, in accordance with the - /// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format). + /// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format). /// The struct composes fields representing the `Counter` type and value(s) (injected counter /// ID, or expression type and operands), the source file (an indirect index into a "filenames /// array", encoded separately), and source location (start and end positions of the represented /// code region). /// - /// Aligns with [llvm::coverage::CounterMappingRegion](https://github.com/rust-lang/llvm-project/blob/rustc/10.0-2020-05-05/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L223-L226) + /// Aligns with [llvm::coverage::CounterMappingRegion](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L224-L227) /// Important: The Rust struct layout (order and types of fields) must match its C++ /// counterpart. #[derive(Copy, Clone, Debug)] diff --git a/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs index bcac2c90fdc20..af6c476292bd1 100644 --- a/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs +++ b/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs @@ -1,6 +1,6 @@ use rustc_middle::mir::coverage::{CounterValueReference, MappedExpressionIndex}; -/// Aligns with [llvm::coverage::Counter::CounterKind](https://github.com/rust-lang/llvm-project/blob/rustc/10.0-2020-05-05/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L91) +/// Aligns with [llvm::coverage::Counter::CounterKind](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L206-L222) #[derive(Copy, Clone, Debug)] #[repr(C)] pub enum CounterKind { @@ -17,7 +17,7 @@ pub enum CounterKind { /// `instrprof.increment()`) /// * For `CounterKind::Expression`, `id` is the index into the coverage map's array of /// counter expressions. -/// Aligns with [llvm::coverage::Counter](https://github.com/rust-lang/llvm-project/blob/rustc/10.0-2020-05-05/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L98-L99) +/// Aligns with [llvm::coverage::Counter](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L99-L100) /// Important: The Rust struct layout (order and types of fields) must match its C++ counterpart. #[derive(Copy, Clone, Debug)] #[repr(C)] @@ -41,7 +41,7 @@ impl Counter { } } -/// Aligns with [llvm::coverage::CounterExpression::ExprKind](https://github.com/rust-lang/llvm-project/blob/rustc/10.0-2020-05-05/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L146) +/// Aligns with [llvm::coverage::CounterExpression::ExprKind](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L147) #[derive(Copy, Clone, Debug)] #[repr(C)] pub enum ExprKind { @@ -49,7 +49,7 @@ pub enum ExprKind { Add = 1, } -/// Aligns with [llvm::coverage::CounterExpression](https://github.com/rust-lang/llvm-project/blob/rustc/10.0-2020-05-05/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L147-L148) +/// Aligns with [llvm::coverage::CounterExpression](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L148-L149) /// Important: The Rust struct layout (order and types of fields) must match its C++ /// counterpart. #[derive(Copy, Clone, Debug)] diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index 6b46d7c497d3e..72050013854dd 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -21,9 +21,9 @@ rustc_index::newtype_index! { impl ExpressionOperandId { /// An expression operand for a "zero counter", as described in the following references: /// - /// * - /// * - /// * + /// * https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#counter + /// * https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#tag + /// * https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#counter-expressions /// /// This operand can be used to count two or more separate code regions with a single counter, /// if they run sequentially with no branches, by injecting the `Counter` in a `BasicBlock` for From 51268d2735ed59b4f6b6351fd75edd0f4cf19c9f Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Tue, 24 Nov 2020 11:50:24 -0800 Subject: [PATCH 3/8] Check for LLVM 11+ when using `-Z instrument-coverage` * `rustc` should now compile under LLVM 9 or 10 * Compiler generates an error if `-Z instrument-coverage` is specified but LLVM version is less than 11 * Coverage tests that require `-Z instrument-coverage` and run codegen should be skipped if LLVM version is less than 11 --- compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs | 4 ++-- .../rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp | 8 ++++++++ .../run-make-fulldeps/coverage-llvmir-base/Makefile | 10 +++++++++- .../run-make-fulldeps/coverage-reports-base/Makefile | 10 +++++++++- .../run-make-fulldeps/coverage-spanview-base/Makefile | 5 +++++ src/test/run-make-fulldeps/coverage/coverage_tools.mk | 7 +++++++ 6 files changed, 40 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index e4a9ac7a5e866..d3de960fbec84 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -39,7 +39,7 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { // Encode coverage mappings and generate function records let mut function_data = Vec::new(); - for (instance, function_coverage) in function_coverage_map.into_iter() { + for (instance, function_coverage) in function_coverage_map { debug!("Generate coverage map for: {:?}", instance); let mangled_function_name = cx.tcx.symbol_name(instance).to_string(); @@ -172,7 +172,7 @@ impl CoverageMapGenerator { // as of `llvm::coverage::CovMapVersion::Version4`. let zero_was_n_records_val = cx.const_u32(0); let filenames_size_val = cx.const_u32(filenames_size as u32); - let zero_was_coverage_size_val = cx.const_u32(0 as u32); + let zero_was_coverage_size_val = cx.const_u32(0); let version_val = cx.const_u32(coverageinfo::mapping_version()); let cov_data_header_val = cx.const_struct( &[zero_was_n_records_val, filenames_size_val, zero_was_coverage_size_val, version_val], diff --git a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp index 6700482f2b7bd..2b76cd5849d3e 100644 --- a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp @@ -71,7 +71,11 @@ extern "C" void LLVMRustCoverageWriteMapSectionNameToString(LLVMModuleRef M, extern "C" void LLVMRustCoverageWriteFuncSectionNameToString(LLVMModuleRef M, RustStringRef Str) { +#if LLVM_VERSION_GE(11, 0) WriteSectionNameToString(M, IPSK_covfun, Str); +#else + report_fatal_error("rustc option `-Z instrument-coverage` requires LLVM 11 or higher."); +#endif } extern "C" void LLVMRustCoverageWriteMappingVarNameToString(RustStringRef Str) { @@ -81,5 +85,9 @@ extern "C" void LLVMRustCoverageWriteMappingVarNameToString(RustStringRef Str) { } extern "C" uint32_t LLVMRustCoverageMappingVersion() { +#if LLVM_VERSION_GE(11, 0) return coverage::CovMapVersion::Version4; +#else + report_fatal_error("rustc option `-Z instrument-coverage` requires LLVM 11 or higher."); +#endif } diff --git a/src/test/run-make-fulldeps/coverage-llvmir-base/Makefile b/src/test/run-make-fulldeps/coverage-llvmir-base/Makefile index b1368bdb79365..2b803b95053ae 100644 --- a/src/test/run-make-fulldeps/coverage-llvmir-base/Makefile +++ b/src/test/run-make-fulldeps/coverage-llvmir-base/Makefile @@ -56,7 +56,14 @@ else -DINSTR_PROF_ORDERFILE='$(DATA_SECTION_PREFIX)__llvm_orderfile' endif +ifeq ($(LLVM_VERSION_11_PLUS),false) +all: test_llvm_ir +else +$(info Rust option `-Z instrument-coverage` requires LLVM 11 or higher. Test skipped.) all: +endif + +test_llvm_ir: # Compile the test program with non-experimental coverage instrumentation, and generate LLVM IR # # Note: `-Clink-dead-code=no` disables the option, needed because the option is automatically @@ -68,4 +75,5 @@ all: -Clink-dead-code=$(LINK_DEAD_CODE) \ --emit=llvm-ir - cat "$(TMPDIR)"/testprog.ll | "$(LLVM_FILECHECK)" $(BASEDIR)/filecheck.testprog.txt $(LLVM_FILECHECK_OPTIONS) + cat "$(TMPDIR)"/testprog.ll | \ + "$(LLVM_FILECHECK)" $(BASEDIR)/filecheck.testprog.txt $(LLVM_FILECHECK_OPTIONS) diff --git a/src/test/run-make-fulldeps/coverage-reports-base/Makefile b/src/test/run-make-fulldeps/coverage-reports-base/Makefile index 1e2aa056e4008..2dac8fc2225bf 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/Makefile +++ b/src/test/run-make-fulldeps/coverage-reports-base/Makefile @@ -18,7 +18,10 @@ SOURCEDIR=../coverage # `llvm/release_debuginfo`. Note that some CI builds disable debug assertions (by setting # `NO_LLVM_ASSERTIONS=1`), so it is not OK to fail the test, but `bless`ed test results cannot be # generated without debug assertions. -LLVM_COV_DEBUG := $(shell "$(LLVM_BIN_DIR)"/llvm-cov show --debug 2>&1 | grep -q "Unknown command line argument '--debug'"; echo $$?) +LLVM_COV_DEBUG := $(shell \ + "$(LLVM_BIN_DIR)"/llvm-cov show --debug 2>&1 | \ + grep -q "Unknown command line argument '--debug'"; \ + echo $$?) ifeq ($(LLVM_COV_DEBUG), 1) DEBUG_FLAG=--debug endif @@ -30,7 +33,12 @@ ifdef RUSTC_BLESS_TEST DEBUG_FLAG=--debug endif +ifeq ($(LLVM_VERSION_11_PLUS),true) all: $(patsubst $(SOURCEDIR)/%.rs,%,$(wildcard $(SOURCEDIR)/*.rs)) +else +$(info Rust option `-Z instrument-coverage` requires LLVM 11 or higher. Test skipped.) +all: +endif # Ensure there are no `expected` results for tests that may have been removed or renamed .PHONY: clear_expected_if_blessed diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/Makefile b/src/test/run-make-fulldeps/coverage-spanview-base/Makefile index 03ef04776a03b..9f9440340e0ed 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-base/Makefile +++ b/src/test/run-make-fulldeps/coverage-spanview-base/Makefile @@ -24,7 +24,12 @@ For revisions in Pull Requests (PR): endef export SPANVIEW_HEADER +ifeq ($(LLVM_VERSION_11_PLUS),true) all: $(patsubst $(SOURCEDIR)/%.rs,%,$(wildcard $(SOURCEDIR)/*.rs)) +else +$(info Rust option `-Z instrument-coverage` requires LLVM 11 or higher. Test skipped.) +all: +endif # Ensure there are no `expected` results for tests that may have been removed or renamed .PHONY: clear_expected_if_blessed diff --git a/src/test/run-make-fulldeps/coverage/coverage_tools.mk b/src/test/run-make-fulldeps/coverage/coverage_tools.mk index 17f7696a8cf1d..99a2e0ba9523e 100644 --- a/src/test/run-make-fulldeps/coverage/coverage_tools.mk +++ b/src/test/run-make-fulldeps/coverage/coverage_tools.mk @@ -38,6 +38,13 @@ endif UNAME = $(shell uname) +# Rust option `-Z instrument-coverage` uses LLVM Coverage Mapping Format version 4, +# which requires LLVM 11 or greater. +LLVM_VERSION_11_PLUS := $(shell \ + LLVM_VERSION=$$("$(LLVM_BIN_DIR)"/llvm-config --version) && \ + LLVM_VERSION_MAJOR=$${LLVM_VERSION/.*/} && \ + [ $$LLVM_VERSION_MAJOR -ge 11 ] && echo true || echo false) + # FIXME(richkadel): Can any of the features tested by `run-make-fulldeps/coverage-*` tests be tested # just as completely by more focused unit tests of the code logic itself, to reduce the number of # test result files generated and maintained, and to help identify specific test failures and root From b5fef37d23f4e4471caea5508ab18da20522e51f Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Tue, 24 Nov 2020 18:34:10 -0800 Subject: [PATCH 4/8] Apply suggestions from code review Co-authored-by: Wesley Wiser --- compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs | 2 +- src/test/run-make-fulldeps/coverage-llvmir-base/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index d3de960fbec84..51baa2aafb7d8 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -169,7 +169,7 @@ impl CoverageMapGenerator { ); // Create the coverage data header (Note, fields 0 and 2 are now always zero, - // as of `llvm::coverage::CovMapVersion::Version4`. + // as of `llvm::coverage::CovMapVersion::Version4`.) let zero_was_n_records_val = cx.const_u32(0); let filenames_size_val = cx.const_u32(filenames_size as u32); let zero_was_coverage_size_val = cx.const_u32(0); diff --git a/src/test/run-make-fulldeps/coverage-llvmir-base/Makefile b/src/test/run-make-fulldeps/coverage-llvmir-base/Makefile index 2b803b95053ae..219ba15ad116d 100644 --- a/src/test/run-make-fulldeps/coverage-llvmir-base/Makefile +++ b/src/test/run-make-fulldeps/coverage-llvmir-base/Makefile @@ -56,7 +56,7 @@ else -DINSTR_PROF_ORDERFILE='$(DATA_SECTION_PREFIX)__llvm_orderfile' endif -ifeq ($(LLVM_VERSION_11_PLUS),false) +ifeq ($(LLVM_VERSION_11_PLUS),true) all: test_llvm_ir else $(info Rust option `-Z instrument-coverage` requires LLVM 11 or higher. Test skipped.) From b4668ecb7317fe821844d89d27a718e50c930215 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Wed, 25 Nov 2020 09:45:33 -0800 Subject: [PATCH 5/8] Improved version check --- .../src/coverageinfo/mapgen.rs | 16 +++++++++------- .../llvm-wrapper/CoverageMappingWrapper.cpp | 5 ++--- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 51baa2aafb7d8..ff65726c83793 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -26,6 +26,11 @@ use tracing::debug; /// undocumented details in Clang's implementation (that may or may not be important) were also /// replicated for Rust's Coverage Map. pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { + // Ensure LLVM supports Coverage Map Version 4 (encoded as a zero-based value: 3). + // If not, the LLVM Version must be less than 11. + let version = coverageinfo::mapping_version(); + assert_eq!(version, 3, "rustc option `-Z instrument-coverage` requires LLVM 11 or higher."); + let function_coverage_map = match cx.coverage_context() { Some(ctx) => ctx.take_function_coverage_map(), None => return, @@ -68,7 +73,7 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { let filenames_ref = coverageinfo::hash_bytes(filenames_buffer); // Generate the LLVM IR representation of the coverage map and store it in a well-known global - let cov_data_val = mapgen.generate_coverage_map(cx, filenames_size, filenames_val); + let cov_data_val = mapgen.generate_coverage_map(cx, version, filenames_size, filenames_val); for (mangled_function_name, function_source_hash, coverage_mapping_buffer) in function_data { save_function_record( @@ -159,21 +164,18 @@ impl CoverageMapGenerator { fn generate_coverage_map( self, cx: &CodegenCx<'ll, 'tcx>, + version: u32, filenames_size: usize, filenames_val: &'ll llvm::Value, ) -> &'ll llvm::Value { - debug!( - "cov map: filenames_size = {}, 0-based version = {}", - filenames_size, - coverageinfo::mapping_version() - ); + debug!("cov map: filenames_size = {}, 0-based version = {}", filenames_size, version); // Create the coverage data header (Note, fields 0 and 2 are now always zero, // as of `llvm::coverage::CovMapVersion::Version4`.) let zero_was_n_records_val = cx.const_u32(0); let filenames_size_val = cx.const_u32(filenames_size as u32); let zero_was_coverage_size_val = cx.const_u32(0); - let version_val = cx.const_u32(coverageinfo::mapping_version()); + let version_val = cx.const_u32(version); let cov_data_header_val = cx.const_struct( &[zero_was_n_records_val, filenames_size_val, zero_was_coverage_size_val, version_val], /*packed=*/ false, diff --git a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp index 2b76cd5849d3e..25badc3f4e17b 100644 --- a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp @@ -73,8 +73,7 @@ extern "C" void LLVMRustCoverageWriteFuncSectionNameToString(LLVMModuleRef M, RustStringRef Str) { #if LLVM_VERSION_GE(11, 0) WriteSectionNameToString(M, IPSK_covfun, Str); -#else - report_fatal_error("rustc option `-Z instrument-coverage` requires LLVM 11 or higher."); +// else do nothing; the `Version` check will abort codegen on the Rust side #endif } @@ -88,6 +87,6 @@ extern "C" uint32_t LLVMRustCoverageMappingVersion() { #if LLVM_VERSION_GE(11, 0) return coverage::CovMapVersion::Version4; #else - report_fatal_error("rustc option `-Z instrument-coverage` requires LLVM 11 or higher."); + return coverage::CovMapVersion::Version3; #endif } From b1df6c0e63ae1b5f42a1039e03ce77a491780147 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Wed, 25 Nov 2020 11:38:09 -0800 Subject: [PATCH 6/8] replace assert with condition and `fatal` error --- compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index ff65726c83793..87eada5d55706 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -29,7 +29,9 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { // Ensure LLVM supports Coverage Map Version 4 (encoded as a zero-based value: 3). // If not, the LLVM Version must be less than 11. let version = coverageinfo::mapping_version(); - assert_eq!(version, 3, "rustc option `-Z instrument-coverage` requires LLVM 11 or higher."); + if version != 3 { + cx.tcx.sess.fatal("rustc option `-Z instrument-coverage` requires LLVM 11 or higher."); + }``` let function_coverage_map = match cx.coverage_context() { Some(ctx) => ctx.take_function_coverage_map(), From d334f589c4d98dbc9736af033f68bd2c35cd8a79 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Wed, 25 Nov 2020 11:41:23 -0800 Subject: [PATCH 7/8] Update compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs --- compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 87eada5d55706..85aaa7e8893bf 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -31,7 +31,7 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { let version = coverageinfo::mapping_version(); if version != 3 { cx.tcx.sess.fatal("rustc option `-Z instrument-coverage` requires LLVM 11 or higher."); - }``` + } let function_coverage_map = match cx.coverage_context() { Some(ctx) => ctx.take_function_coverage_map(), From fdbc121620704ab50bd427ff1a2bb3282ffac745 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Wed, 25 Nov 2020 13:30:33 -0800 Subject: [PATCH 8/8] fix URLs in doc comment The angle brackets were confusing my IDE and I thought they were unnecessary. I was wrong. --- compiler/rustc_middle/src/mir/coverage.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index 72050013854dd..8a6bf9dff7b6f 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -21,9 +21,9 @@ rustc_index::newtype_index! { impl ExpressionOperandId { /// An expression operand for a "zero counter", as described in the following references: /// - /// * https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#counter - /// * https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#tag - /// * https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#counter-expressions + /// * + /// * + /// * /// /// This operand can be used to count two or more separate code regions with a single counter, /// if they run sequentially with no branches, by injecting the `Counter` in a `BasicBlock` for