Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions clang/lib/CodeGen/CoverageMappingGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2604,6 +2604,15 @@ void CoverageMappingModuleGen::emit() {
};
auto CovDataHeaderTy =
llvm::StructType::get(Ctx, ArrayRef(CovDataHeaderTypes));

// By default, clang instruments the code for "region" and "branch"
// coverage, and can instrument for MCDC when `-fcoverage-mcdc` is passed.
uint32_t CovInstrLevels = CoverageCapabilities::CovInstrLevel::Region |
CoverageCapabilities::CovInstrLevel::Branch;
if (CGM.getCodeGenOpts().hasProfileClangInstr() &&
CGM.getCodeGenOpts().MCDCCoverage)
CovInstrLevels |= CoverageCapabilities::CovInstrLevel::MCDC;

llvm::Constant *CovDataHeaderVals[] = {
#define COVMAP_HEADER(Type, LLVMType, Name, Init) Init,
#include "llvm/ProfileData/InstrProfData.inc"
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CoverageMapping/ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ int main(void) {
// DARWIN: [[FuncRecord1:@__covrec_[0-9A-F]+u]] = linkonce_odr hidden constant <{ i64, i32, i64, i64, [{{.*}} x i8] }> <{ {{.*}} }>, section "__LLVM_COV,__llvm_covfun", align 8
// DARWIN: [[FuncRecord2:@__covrec_[0-9A-F]+u]] = linkonce_odr hidden constant <{ i64, i32, i64, i64, [{{.*}} x i8] }> <{ {{.*}} }>, section "__LLVM_COV,__llvm_covfun", align 8
// DARWIN: [[FuncRecord3:@__covrec_[0-9A-F]+]] = linkonce_odr hidden constant <{ i64, i32, i64, i64, [{{.*}} x i8] }> <{ {{.*}} }>, section "__LLVM_COV,__llvm_covfun", align 8
// DARWIN: @__llvm_coverage_mapping = private constant { { i32, i32, i32, i32 }, [{{.*}} x i8] } { {{.*}} }, section "__LLVM_COV,__llvm_covmap", align 8
// DARWIN: @__llvm_coverage_mapping = private constant { { i32, i32, i32, i32, i32 }, [{{.*}} x i8] } { {{.*}} }, section "__LLVM_COV,__llvm_covmap", align 8

// WINDOWS: [[FuncRecord1:@__covrec_[0-9A-F]+u]] = linkonce_odr hidden constant <{ i64, i32, i64, i64, [{{.*}} x i8] }> <{ {{.*}} }>, section ".lcovfun$M", comdat, align 8
// WINDOWS: [[FuncRecord2:@__covrec_[0-9A-F]+u]] = linkonce_odr hidden constant <{ i64, i32, i64, i64, [{{.*}} x i8] }> <{ {{.*}} }>, section ".lcovfun$M", comdat, align 8
// WINDOWS: [[FuncRecord3:@__covrec_[0-9A-F]+]] = linkonce_odr hidden constant <{ i64, i32, i64, i64, [{{.*}} x i8] }> <{ {{.*}} }>, section ".lcovfun$M", comdat, align 8
// WINDOWS: @__llvm_coverage_mapping = private constant { { i32, i32, i32, i32 }, [{{.*}} x i8] } { {{.*}} }, section ".lcovmap$M", align 8
// WINDOWS: @__llvm_coverage_mapping = private constant { { i32, i32, i32, i32, i32 }, [{{.*}} x i8] } { {{.*}} }, section ".lcovmap$M", align 8

// COMMON: @llvm.used = appending global [{{.*}}] [
// COMMON-SAME: [[FuncRecord1]]
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Profile/def-assignop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ struct A {
// COVMAP: section "__llvm_covfun", comdat
// COVMAP: section "__llvm_covfun", comdat
// COVMAP: section "__llvm_covfun", comdat
// COVMAP: @__llvm_coverage_mapping = {{.*}} { { i32, i32, i32, i32 }
// COVMAP: @__llvm_coverage_mapping = {{.*}} { { i32, i32, i32, i32, i32 }
B b;
};

Expand Down
2 changes: 1 addition & 1 deletion clang/test/Profile/def-ctors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ struct Derived : public Base {
// COVMAP: section "__llvm_covfun", comdat
// COVMAP: section "__llvm_covfun", comdat
// COVMAP: section "__llvm_covfun", comdat
// COVMAP: @__llvm_coverage_mapping = {{.*}} { { i32, i32, i32, i32 }
// COVMAP: @__llvm_coverage_mapping = {{.*}} { { i32, i32, i32, i32, i32 }
};

Derived dd;
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Profile/def-dtors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ struct Derived : public Base {
// COVMAP: section "__llvm_covfun", comdat
// COVMAP: section "__llvm_covfun", comdat
// COVMAP: section "__llvm_covfun", comdat
// COVMAP: @__llvm_coverage_mapping = {{.*}} { { i32, i32, i32, i32 }
// COVMAP: @__llvm_coverage_mapping = {{.*}} { { i32, i32, i32, i32, i32 }
};

int main() {
Expand Down
4 changes: 3 additions & 1 deletion compiler-rt/include/profile/InstrProfData.inc
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,8 @@ COVMAP_HEADER(uint32_t, Int32Ty, CoverageSize, \
llvm::ConstantInt::get(Int32Ty, CoverageMappingSize))
COVMAP_HEADER(uint32_t, Int32Ty, Version, \
llvm::ConstantInt::get(Int32Ty, CovMapVersion::CurrentVersion))
COVMAP_HEADER(uint32_t, Int32Ty, CovInstrLevels, \
llvm::ConstantInt::get(Int32Ty, CovInstrLevels))
#undef COVMAP_HEADER
/* COVMAP_HEADER end. */

Expand Down Expand Up @@ -724,7 +726,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
/* Indexed profile format version (start from 1). */
#define INSTR_PROF_INDEX_VERSION 12
/* Coverage mapping format version (start from 0). */
#define INSTR_PROF_COVMAP_VERSION 6
#define INSTR_PROF_COVMAP_VERSION 7

/* Profile version is always of type uint64_t. Reserve the upper 32 bits in the
* version for other variants of profile. We set the 8th most significant bit
Expand Down
63 changes: 61 additions & 2 deletions llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -984,6 +984,52 @@ class CoverageData {
ArrayRef<MCDCRecord> getMCDCRecords() const { return MCDCRecords; }
};

/// Represents a set of available capabilities
class CoverageCapabilities {
uint32_t Capabilities;

public:
enum CovInstrLevel {
Region = (1 << 0),
Branch = (1 << 1),
MCDC = (1 << 2),
};

CoverageCapabilities(uint32_t Capabilities) : Capabilities(Capabilities){};

static CoverageCapabilities all() {
return CoverageCapabilities(Region | Branch | MCDC);
}

static CoverageCapabilities none() {
return CoverageCapabilities(0);
}

bool hasCapability(CovInstrLevel Lvl) const {
return (this->Capabilities & Lvl) != 0;
}

/// Returns true if this includes all the capabilities of Other.
bool includes(const CoverageCapabilities &Other) const {
return (this->Capabilities & Other.Capabilities) == Other.Capabilities;
}

std::string toString() const {
std::stringstream SS;
SS << std::oct << this->Capabilities;
return SS.str();
}

CoverageCapabilities& operator |= (const CoverageCapabilities &Rhs) {
this->Capabilities |= Rhs.Capabilities;
return *this;
}

CoverageCapabilities operator | (const CoverageCapabilities &Rhs) const {
return CoverageCapabilities(this->Capabilities | Rhs.Capabilities);
}
};

/// The mapping of profile information to coverage data.
///
/// This is the main interface to get coverage information, using a profile to
Expand All @@ -994,6 +1040,10 @@ class CoverageMapping {
DenseMap<size_t, SmallVector<unsigned, 0>> FilenameHash2RecordIndices;
std::vector<std::pair<std::string, uint64_t>> FuncHashMismatches;

/// Keep track of the coverage capabilities of the loaded object file,
/// which depends on the parameters used to compile it.
CoverageCapabilities AvailableInstrLevels = CoverageCapabilities::none();

std::optional<bool> SingleByteCoverage;

CoverageMapping() = default;
Expand All @@ -1011,6 +1061,7 @@ class CoverageMapping {
std::optional<std::reference_wrapper<IndexedInstrProfReader>>
&ProfileReader,
CoverageMapping &Coverage, bool &DataFound,
CoverageCapabilities RequestedCapabilities,
SmallVectorImpl<object::BuildID> *FoundBinaryIDs = nullptr);

/// Add a function record corresponding to \p Record.
Expand All @@ -1034,7 +1085,8 @@ class CoverageMapping {
LLVM_ABI static Expected<std::unique_ptr<CoverageMapping>>
load(ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
std::optional<std::reference_wrapper<IndexedInstrProfReader>>
&ProfileReader);
&ProfileReader,
CoverageCapabilities RequestCapabilities = CoverageCapabilities::none());

/// Load the coverage mapping from the given object files and profile. If
/// \p Arches is non-empty, it must specify an architecture for each object.
Expand All @@ -1044,7 +1096,8 @@ class CoverageMapping {
std::optional<StringRef> ProfileFilename, vfs::FileSystem &FS,
ArrayRef<StringRef> Arches = {}, StringRef CompilationDir = "",
const object::BuildIDFetcher *BIDFetcher = nullptr,
bool CheckBinaryIDs = false);
bool CheckBinaryIDs = false,
CoverageCapabilities RequestCapabilities = CoverageCapabilities::none());

/// The number of functions that couldn't have their profiles mapped.
///
Expand Down Expand Up @@ -1430,6 +1483,10 @@ struct CovMapHeader {
template <llvm::endianness Endian> uint32_t getVersion() const {
return support::endian::byte_swap<uint32_t, Endian>(Version);
}

template <llvm::endianness Endian> uint32_t getCovInstrLevels() const {
return support::endian::byte_swap<uint32_t, Endian>(CovInstrLevels);
}
};

LLVM_PACKED_END
Expand All @@ -1452,6 +1509,8 @@ enum CovMapVersion {
Version6 = 5,
// Branch regions extended and Decision Regions added for MC/DC.
Version7 = 6,
// Covmap header tracks the instrumentation level
Version8 = 7,
// The current version is Version7.
CurrentVersion = INSTR_PROF_COVMAP_VERSION
};
Expand Down
13 changes: 12 additions & 1 deletion llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ class CoverageMappingReader {
virtual Error readNextRecord(CoverageMappingRecord &Record) = 0;
CoverageMappingIterator begin() { return CoverageMappingIterator(this); }
CoverageMappingIterator end() { return CoverageMappingIterator(); }

/// Returns the instrumentation levels for which the code was originally
/// instrumented.
virtual CoverageCapabilities coverageCapabilities() const = 0;
};

/// Base class for the raw coverage mapping and filenames data readers.
Expand Down Expand Up @@ -188,6 +192,7 @@ class LLVM_ABI BinaryCoverageReader : public CoverageMappingReader {
std::vector<ProfileMappingRecord> MappingRecords;
std::unique_ptr<InstrProfSymtab> ProfileNames;
size_t CurrentRecord = 0;
CoverageCapabilities AvailableCapabilities;
std::vector<StringRef> FunctionsFilenames;
std::vector<CounterExpression> Expressions;
std::vector<CounterMappingRegion> MappingRegions;
Expand All @@ -205,7 +210,9 @@ class LLVM_ABI BinaryCoverageReader : public CoverageMappingReader {
BinaryCoverageReader(std::unique_ptr<InstrProfSymtab> Symtab,
FuncRecordsStorage &&FuncRecords,
CoverageMapCopyStorage &&CoverageMapCopy)
: ProfileNames(std::move(Symtab)), FuncRecords(std::move(FuncRecords)),
: ProfileNames(std::move(Symtab)),
AvailableCapabilities(CoverageCapabilities::all()),
FuncRecords(std::move(FuncRecords)),
CoverageMapCopy(std::move(CoverageMapCopy)) {}

public:
Expand All @@ -226,6 +233,10 @@ class LLVM_ABI BinaryCoverageReader : public CoverageMappingReader {
llvm::endianness Endian, StringRef CompilationDir = "");

Error readNextRecord(CoverageMappingRecord &Record) override;

CoverageCapabilities coverageCapabilities() const override {
return this->AvailableCapabilities;
};
};

/// Reader for the raw coverage filenames.
Expand Down
4 changes: 3 additions & 1 deletion llvm/include/llvm/ProfileData/InstrProfData.inc
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,8 @@ COVMAP_HEADER(uint32_t, Int32Ty, CoverageSize, \
llvm::ConstantInt::get(Int32Ty, CoverageMappingSize))
COVMAP_HEADER(uint32_t, Int32Ty, Version, \
llvm::ConstantInt::get(Int32Ty, CovMapVersion::CurrentVersion))
COVMAP_HEADER(uint32_t, Int32Ty, CovInstrLevels, \
llvm::ConstantInt::get(Int32Ty, CovInstrLevels))
#undef COVMAP_HEADER
/* COVMAP_HEADER end. */

Expand Down Expand Up @@ -724,7 +726,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
/* Indexed profile format version (start from 1). */
#define INSTR_PROF_INDEX_VERSION 12
/* Coverage mapping format version (start from 0). */
#define INSTR_PROF_COVMAP_VERSION 6
#define INSTR_PROF_COVMAP_VERSION 7

/* Profile version is always of type uint64_t. Reserve the upper 32 bits in the
* version for other variants of profile. We set the 8th most significant bit
Expand Down
23 changes: 19 additions & 4 deletions llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,7 @@ Error CoverageMapping::loadFromReaders(
Coverage.SingleByteCoverage =
!ProfileReader || ProfileReader.value().get().hasSingleByteCoverage();
for (const auto &CoverageReader : CoverageReaders) {
Coverage.AvailableInstrLevels |= CoverageReader->coverageCapabilities();
for (auto RecordOrErr : *CoverageReader) {
if (Error E = RecordOrErr.takeError())
return E;
Expand All @@ -992,7 +993,7 @@ Error CoverageMapping::loadFromReaders(
Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
std::optional<std::reference_wrapper<IndexedInstrProfReader>>
&ProfileReader) {
&ProfileReader, CoverageCapabilities RequestedCapabilities) {
auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping());
if (Error E = loadFromReaders(CoverageReaders, ProfileReader, *Coverage))
return std::move(E);
Expand All @@ -1013,6 +1014,7 @@ Error CoverageMapping::loadFromFile(
std::optional<std::reference_wrapper<IndexedInstrProfReader>>
&ProfileReader,
CoverageMapping &Coverage, bool &DataFound,
CoverageCapabilities RequestedCapabilities,
SmallVectorImpl<object::BuildID> *FoundBinaryIDs) {
auto CovMappingBufOrErr = MemoryBuffer::getFileOrSTDIN(
Filename, /*IsText=*/false, /*RequiresNullTerminator=*/false);
Expand Down Expand Up @@ -1045,14 +1047,25 @@ Error CoverageMapping::loadFromFile(
DataFound |= !Readers.empty();
if (Error E = loadFromReaders(Readers, ProfileReader, Coverage))
return createFileError(Filename, std::move(E));

// Check that the requested coverage capabilities are available.
if (!Coverage.AvailableInstrLevels.includes(RequestedCapabilities))
return createFileError(
Filename, createStringError(
"lacking coverage capabilities (requested %s, got %s)",
RequestedCapabilities.toString().c_str(),
Coverage.AvailableInstrLevels.toString().c_str()
));

return Error::success();
}

Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
ArrayRef<StringRef> ObjectFilenames,
std::optional<StringRef> ProfileFilename, vfs::FileSystem &FS,
ArrayRef<StringRef> Arches, StringRef CompilationDir,
const object::BuildIDFetcher *BIDFetcher, bool CheckBinaryIDs) {
const object::BuildIDFetcher *BIDFetcher, bool CheckBinaryIDs,
CoverageCapabilities RequestedCapabilities) {
std::unique_ptr<IndexedInstrProfReader> ProfileReader;
if (ProfileFilename) {
auto ProfileReaderOrErr =
Expand Down Expand Up @@ -1081,7 +1094,8 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
for (const auto &File : llvm::enumerate(ObjectFilenames)) {
if (Error E = loadFromFile(File.value(), GetArch(File.index()),
CompilationDir, ProfileReaderRef, *Coverage,
DataFound, &FoundBinaryIDs))
DataFound, RequestedCapabilities,
&FoundBinaryIDs))
return std::move(E);
}

Expand Down Expand Up @@ -1110,7 +1124,8 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
std::string Path = std::move(*PathOpt);
StringRef Arch = Arches.size() == 1 ? Arches.front() : StringRef();
if (Error E = loadFromFile(Path, Arch, CompilationDir, ProfileReaderRef,
*Coverage, DataFound))
*Coverage, DataFound,
RequestedCapabilities))
return std::move(E);
} else if (CheckBinaryIDs) {
return createFileError(
Expand Down
Loading