From 1d8c381c014f202eeae59994b9b664841e91cb72 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Mon, 23 Nov 2020 12:56:07 -0800 Subject: 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. --- .../llvm-wrapper/CoverageMappingWrapper.cpp | 47 ++++++++++++++-------- 1 file changed, 31 insertions(+), 16 deletions(-) (limited to 'compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp') diff --git a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp index 2b1143a4ecf..6700482f2b7 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; } -- cgit 1.4.1-3-g733a5 From 51268d2735ed59b4f6b6351fd75edd0f4cf19c9f Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Tue, 24 Nov 2020 11:50:24 -0800 Subject: 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 ++-- compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp | 8 ++++++++ src/test/run-make-fulldeps/coverage-llvmir-base/Makefile | 10 +++++++++- src/test/run-make-fulldeps/coverage-reports-base/Makefile | 10 +++++++++- src/test/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(-) (limited to 'compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp') diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index e4a9ac7a5e8..d3de960fbec 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 6700482f2b7..2b76cd5849d 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 b1368bdb793..2b803b95053 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 1e2aa056e40..2dac8fc2225 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 03ef04776a0..9f9440340e0 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 17f7696a8cf..99a2e0ba952 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 -- cgit 1.4.1-3-g733a5 From b4668ecb7317fe821844d89d27a718e50c930215 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Wed, 25 Nov 2020 09:45:33 -0800 Subject: Improved version check --- compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs | 16 +++++++++------- .../rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp | 5 ++--- 2 files changed, 11 insertions(+), 10 deletions(-) (limited to 'compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp') diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 51baa2aafb7..ff65726c837 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 2b76cd5849d..25badc3f4e1 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 } -- cgit 1.4.1-3-g733a5