[IRGen] Update coverage mapping for version 6

The coverage format version we use is automatically
set to whatever the latest version LLVM has. This
resulting in us outputting version 6 as our
format without having made the changes necessary
to reflect the new format. Update the emission
logic to take account for [the new changes in
version 6][1] (we need to include the current
working directory as the first element of the list
of files we output). Additionally, add a
`static_assert` so we don't get caught out by
version bumps in the future. Note we can't pin our
version, as it must stay in sync with the version
Clang is using.

[1]: https://llvm.org/docs/CoverageMappingFormat.html#llvm-ir-representation
This commit is contained in:
Hamish Knight
2023-05-20 00:32:21 +01:00
parent a3848c62d5
commit b55f97250d
3 changed files with 68 additions and 19 deletions

View File

@@ -27,16 +27,24 @@
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Support/FileSystem.h"
// This selects the coverage mapping format defined when `InstrProfData.inc`
// is textually included.
#define COVMAP_V3
using namespace swift;
using namespace irgen;
using llvm::coverage::CounterMappingRegion;
using llvm::coverage::CovMapVersion;
// This affects the coverage mapping format defined when `InstrProfData.inc`
// is textually included. Note that it means 'version >= 3', not 'version == 3'.
#define COVMAP_V3
/// This assert is here to make sure we make all the necessary code generation
/// changes that are needed to support the new coverage mapping format. Note we
/// cannot pin our version, as it must remain in sync with the version Clang is
/// using.
/// Do not bump without at least filing a bug and pinging a coverage maintainer.
static_assert(CovMapVersion::CurrentVersion == CovMapVersion::Version6,
"Coverage mapping emission needs updating");
static std::string getInstrProfSection(IRGenModule &IGM,
llvm::InstrProfSectKind SK) {
return llvm::getInstrProfSectionName(SK, IGM.Triple.getObjectFormat());
@@ -77,18 +85,26 @@ void IRGenModule::emitCoverageMaps(ArrayRef<const SILCoverageMap *> Mappings) {
}
std::vector<StringRef> Files;
for (const auto &M : Mappings)
for (const auto &M : Mappings) {
if (std::find(Files.begin(), Files.end(), M->getFilename()) == Files.end())
Files.push_back(M->getFilename());
auto remapper = getOptions().CoveragePrefixMap;
}
const auto &Remapper = getOptions().CoveragePrefixMap;
llvm::SmallVector<std::string, 8> FilenameStrs;
for (StringRef Name : Files) {
llvm::SmallString<256> Path(Name);
llvm::sys::fs::make_absolute(Path);
FilenameStrs.push_back(remapper.remapPath(Path));
}
FilenameStrs.reserve(Files.size() + 1);
// First element needs to be the current working directory. Note if this
// scheme ever changes, the FileID computation below will need updating.
SmallString<256> WorkingDirectory;
llvm::sys::fs::current_path(WorkingDirectory);
FilenameStrs.emplace_back(Remapper.remapPath(WorkingDirectory));
// Following elements are the filenames present. We use their relative path,
// which llvm-cov will turn back into absolute paths using the working
// directory element.
for (auto Name : Files)
FilenameStrs.emplace_back(Remapper.remapPath(Name));
// Encode the filenames.
std::string Filenames;
@@ -112,13 +128,21 @@ void IRGenModule::emitCoverageMaps(ArrayRef<const SILCoverageMap *> Mappings) {
const uint64_t NameHash = llvm::IndexedInstrProf::ComputeHash(NameValue);
std::string FuncRecordName = "__covrec_" + llvm::utohexstr(NameHash);
unsigned FileID =
std::find(Files.begin(), Files.end(), M->getFilename()) - Files.begin();
// The file ID needs to be bumped by 1 to account for the working directory
// as the first element.
unsigned FileID = 1 +
std::find(Files.begin(), Files.end(), M->getFilename()) -
Files.begin();
assert(FileID < FilenameStrs.size());
std::vector<CounterMappingRegion> Regions;
for (const auto &MR : M->getMappedRegions())
for (const auto &MR : M->getMappedRegions()) {
// The SubFileID here is 0, because it's an index into VirtualFileMapping,
// and we only ever have a single file associated for a function.
Regions.emplace_back(CounterMappingRegion::makeRegion(
MR.Counter, /*FileID=*/0, MR.StartLine, MR.StartCol, MR.EndLine,
MR.Counter, /*SubFileID*/ 0, MR.StartLine, MR.StartCol, MR.EndLine,
MR.EndCol));
}
// Append each function's regions into the encoded buffer.
ArrayRef<unsigned> VirtualFileMapping(FileID);
llvm::coverage::CoverageMappingWriter W(VirtualFileMapping,

View File

@@ -1,15 +1,15 @@
// To make sure this test is resilient to directory changes, we create nested directories inside of the
// temporary test directory and assert those exist, or don't exist, in the emitted ir
//
// RUN: rm -rf %t
// RUN: %empty-directory(%t)
// RUN: mkdir -p %t/root/nested
// RUN: echo "func coverage() {}" > %t/root/nested/coverage_relative_path.swift
// RUN: cd %t/root
// RUN: %target-swift-frontend -profile-generate -profile-coverage-mapping -Xllvm -enable-name-compression=false -emit-ir nested/coverage_relative_path.swift | %FileCheck -check-prefix=ABSOLUTE %s
//
// ABSOLUTE: @__llvm_coverage_mapping = {{.*"\\01.*root.*nested.*coverage_relative_path\.swift}}
// ABSOLUTE: @__llvm_coverage_mapping = {{.*"\\02.*root[^/\\]*nested[/\\]*coverage_relative_path\.swift}}
// RUN: %target-swift-frontend -profile-generate -profile-coverage-mapping -Xllvm -enable-name-compression=false -coverage-prefix-map %/t/root=. -emit-ir %/t/root/nested/coverage_relative_path.swift | %FileCheck -check-prefix=RELATIVE %s
//
// RELATIVE: @__llvm_coverage_mapping = {{.*"\\01[^/]*}}.{{/|\\}}nested{{.*coverage_relative_path\.swift}}
// RELATIVE: @__llvm_coverage_mapping = {{.*"\\02.*\\01[^/]*\.[/\\]*nested[/\\]*coverage_relative_path\.swift}}

View File

@@ -0,0 +1,25 @@
// REQUIRES: profile_runtime
// REQUIRES: executable_test
// REQUIRES: OS=macosx
// This test is to make sure llvm-cov can deal with a coverage-prefix-map.
// To make sure this test is resilient to directory changes, we create nested directories inside of the
// temporary test directory and assert those exist, or don't exist, in the emitted ir
//
// RUN: %empty-directory(%t)
// RUN: mkdir -p %t/root/nested
// RUN: echo "func coverage() {}" > %t/root/nested/coverage_relative_path.swift
// RUN: cd %t/root
// RUN: %target-build-swift -profile-generate -profile-coverage-mapping -Xfrontend -coverage-prefix-map -Xfrontend %/t/root=. -Xfrontend -disable-incremental-llvm-codegen -o %t/main %/t/root/nested/coverage_relative_path.swift
// This unusual use of 'sh' allows the path of the profraw file to be
// substituted by %target-run.
// RUN: %target-codesign %t/main
// RUN: %target-run sh -c 'env LLVM_PROFILE_FILE=$1 $2' -- %t/default.profraw %t/main
// RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata
// RUN: %llvm-cov show %t/main -instr-profile=%t/default.profdata | %FileCheck %s
// CHECK: func coverage