Reland "[InstrProf][compiler-rt] Enable MC/DC Support in LLVM Source-based Code Coverage (1/3)"

Part 1 of 3. This includes the LLVM back-end processing and profile
reading/writing components. compiler-rt changes are included.

Differential Revision: https://reviews.llvm.org/D138846
This commit is contained in:
Alan Phipps 2023-09-21 13:07:31 -05:00
parent dc8c2a7794
commit f95b2f1acf
52 changed files with 1441 additions and 174 deletions

View File

@ -1400,7 +1400,7 @@ void Darwin::addProfileRTLibs(const ArgList &Args,
addExportedSymbol(CmdArgs, "_reset_fn_list");
}
// Align __llvm_prf_{cnts,data} sections to the maximum expected page
// Align __llvm_prf_{cnts,bits,data} sections to the maximum expected page
// alignment. This allows profile counters to be mmap()'d to disk. Note that
// it's not enough to just page-align __llvm_prf_cnts: the following section
// must also be page-aligned so that its data is not clobbered by mmap().
@ -1410,7 +1410,7 @@ void Darwin::addProfileRTLibs(const ArgList &Args,
// extra alignment also allows the same binary to be used with/without sync
// enabled.
if (!ForGCOV) {
for (auto IPSK : {llvm::IPSK_cnts, llvm::IPSK_data}) {
for (auto IPSK : {llvm::IPSK_cnts, llvm::IPSK_bitmap, llvm::IPSK_data}) {
addSectalignToPage(
Args, CmdArgs, "__DATA",
llvm::getInstrProfSectionName(IPSK, llvm::Triple::MachO,

View File

@ -336,7 +336,7 @@
// RUN: FileCheck -check-prefix=PROFILE_SECTALIGN %s < %t.log
// RUN: %clang -target arm64-apple-ios12 -fprofile-instr-generate -### %t.o 2> %t.log
// RUN: FileCheck -check-prefix=PROFILE_SECTALIGN %s < %t.log
// PROFILE_SECTALIGN: "-sectalign" "__DATA" "__llvm_prf_cnts" "0x4000" "-sectalign" "__DATA" "__llvm_prf_data" "0x4000"
// PROFILE_SECTALIGN: "-sectalign" "__DATA" "__llvm_prf_cnts" "0x4000" "-sectalign" "__DATA" "__llvm_prf_bits" "0x4000" "-sectalign" "__DATA" "__llvm_prf_data" "0x4000"
// RUN: %clang -target x86_64-apple-darwin12 -fprofile-instr-generate --coverage -### %t.o 2> %t.log
// RUN: FileCheck -check-prefix=NO_PROFILE_EXPORT %s < %t.log

View File

@ -76,6 +76,7 @@ INSTR_PROF_DATA(const uint64_t, llvm::Type::getInt64Ty(Ctx), FuncHash, \
ConstantInt::get(llvm::Type::getInt64Ty(Ctx), \
Inc->getHash()->getZExtValue()))
INSTR_PROF_DATA(const IntPtrT, IntPtrTy, CounterPtr, RelativeCounterPtr)
INSTR_PROF_DATA(const IntPtrT, IntPtrTy, BitmapPtr, RelativeBitmapPtr)
/* This is used to map function pointers for the indirect call targets to
* function name hashes during the conversion from raw to merged profile
* data.
@ -87,7 +88,9 @@ INSTR_PROF_DATA(IntPtrT, llvm::Type::getInt8PtrTy(Ctx), Values, \
INSTR_PROF_DATA(const uint32_t, llvm::Type::getInt32Ty(Ctx), NumCounters, \
ConstantInt::get(llvm::Type::getInt32Ty(Ctx), NumCounters))
INSTR_PROF_DATA(const uint16_t, Int16ArrayTy, NumValueSites[IPVK_Last+1], \
ConstantArray::get(Int16ArrayTy, Int16ArrayVals))
ConstantArray::get(Int16ArrayTy, Int16ArrayVals)) \
INSTR_PROF_DATA(const uint32_t, llvm::Type::getInt32Ty(Ctx), NumBitmapBytes, \
ConstantInt::get(llvm::Type::getInt32Ty(Ctx), NumBitmapBytes))
#undef INSTR_PROF_DATA
/* INSTR_PROF_DATA end. */
@ -132,9 +135,13 @@ INSTR_PROF_RAW_HEADER(uint64_t, NumData, NumData)
INSTR_PROF_RAW_HEADER(uint64_t, PaddingBytesBeforeCounters, PaddingBytesBeforeCounters)
INSTR_PROF_RAW_HEADER(uint64_t, NumCounters, NumCounters)
INSTR_PROF_RAW_HEADER(uint64_t, PaddingBytesAfterCounters, PaddingBytesAfterCounters)
INSTR_PROF_RAW_HEADER(uint64_t, NumBitmapBytes, NumBitmapBytes)
INSTR_PROF_RAW_HEADER(uint64_t, PaddingBytesAfterBitmapBytes, PaddingBytesAfterBitmapBytes)
INSTR_PROF_RAW_HEADER(uint64_t, NamesSize, NamesSize)
INSTR_PROF_RAW_HEADER(uint64_t, CountersDelta,
(uintptr_t)CountersBegin - (uintptr_t)DataBegin)
INSTR_PROF_RAW_HEADER(uint64_t, BitmapDelta,
(uintptr_t)BitmapBegin - (uintptr_t)DataBegin)
INSTR_PROF_RAW_HEADER(uint64_t, NamesDelta, (uintptr_t)NamesBegin)
INSTR_PROF_RAW_HEADER(uint64_t, ValueKindLast, IPVK_Last)
#undef INSTR_PROF_RAW_HEADER
@ -267,6 +274,9 @@ INSTR_PROF_SECT_ENTRY(IPSK_data, \
INSTR_PROF_SECT_ENTRY(IPSK_cnts, \
INSTR_PROF_QUOTE(INSTR_PROF_CNTS_COMMON), \
INSTR_PROF_CNTS_COFF, "__DATA,")
INSTR_PROF_SECT_ENTRY(IPSK_bitmap, \
INSTR_PROF_QUOTE(INSTR_PROF_BITS_COMMON), \
INSTR_PROF_BITS_COFF, "__DATA,")
INSTR_PROF_SECT_ENTRY(IPSK_name, \
INSTR_PROF_QUOTE(INSTR_PROF_NAME_COMMON), \
INSTR_PROF_NAME_COFF, "__DATA,")
@ -645,11 +655,11 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
(uint64_t)'f' << 16 | (uint64_t)'R' << 8 | (uint64_t)129
/* Raw profile format version (start from 1). */
#define INSTR_PROF_RAW_VERSION 8
#define INSTR_PROF_RAW_VERSION 9
/* Indexed profile format version (start from 1). */
#define INSTR_PROF_INDEX_VERSION 10
#define INSTR_PROF_INDEX_VERSION 11
/* Coverage mapping format version (start from 0). */
#define INSTR_PROF_COVMAP_VERSION 5
#define INSTR_PROF_COVMAP_VERSION 6
/* 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
@ -686,6 +696,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_DATA_COMMON __llvm_prf_data
#define INSTR_PROF_NAME_COMMON __llvm_prf_names
#define INSTR_PROF_CNTS_COMMON __llvm_prf_cnts
#define INSTR_PROF_BITS_COMMON __llvm_prf_bits
#define INSTR_PROF_VALS_COMMON __llvm_prf_vals
#define INSTR_PROF_VNODES_COMMON __llvm_prf_vnds
#define INSTR_PROF_COVMAP_COMMON __llvm_covmap
@ -697,6 +708,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_DATA_COFF ".lprfd$M"
#define INSTR_PROF_NAME_COFF ".lprfn$M"
#define INSTR_PROF_CNTS_COFF ".lprfc$M"
#define INSTR_PROF_BITS_COFF ".lprfb$M"
#define INSTR_PROF_VALS_COFF ".lprfv$M"
#define INSTR_PROF_VNODES_COFF ".lprfnd$M"
#define INSTR_PROF_COVMAP_COFF ".lcovmap$M"
@ -708,6 +720,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_DATA_SECT_NAME INSTR_PROF_DATA_COFF
#define INSTR_PROF_NAME_SECT_NAME INSTR_PROF_NAME_COFF
#define INSTR_PROF_CNTS_SECT_NAME INSTR_PROF_CNTS_COFF
#define INSTR_PROF_BITS_SECT_NAME INSTR_PROF_BITS_COFF
/* Array of pointers. Each pointer points to a list
* of value nodes associated with one value site.
*/
@ -722,6 +735,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_DATA_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_DATA_COMMON)
#define INSTR_PROF_NAME_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_NAME_COMMON)
#define INSTR_PROF_CNTS_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_CNTS_COMMON)
#define INSTR_PROF_BITS_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_BITS_COMMON)
/* Array of pointers. Each pointer points to a list
* of value nodes associated with one value site.
*/

View File

@ -60,6 +60,10 @@ COMPILER_RT_VISIBILITY void __llvm_profile_reset_counters(void) {
(__llvm_profile_get_version() & VARIANT_MASK_BYTE_COVERAGE) ? 0xFF : 0;
memset(I, ResetValue, E - I);
I = __llvm_profile_begin_bitmap();
E = __llvm_profile_end_bitmap();
memset(I, 0x0, E - I);
const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
const __llvm_profile_data *DI;

View File

@ -88,6 +88,8 @@ const char *__llvm_profile_begin_names(void);
const char *__llvm_profile_end_names(void);
char *__llvm_profile_begin_counters(void);
char *__llvm_profile_end_counters(void);
char *__llvm_profile_begin_bitmap(void);
char *__llvm_profile_end_bitmap(void);
ValueProfNode *__llvm_profile_begin_vnodes();
ValueProfNode *__llvm_profile_end_vnodes();
uint32_t *__llvm_profile_begin_orderfile();
@ -101,11 +103,11 @@ void __llvm_profile_reset_counters(void);
/*!
* \brief Merge profile data from buffer.
*
* Read profile data form buffer \p Profile and merge with in-process profile
* counters. The client is expected to have checked or already knows the profile
* data in the buffer matches the in-process counter structure before calling
* it. Returns 0 (success) if the profile data is valid. Upon reading
* invalid/corrupted profile data, returns 1 (failure).
* Read profile data from buffer \p Profile and merge with in-process profile
* counters and bitmaps. The client is expected to have checked or already
* know the profile data in the buffer matches the in-process counter
* structure before calling it. Returns 0 (success) if the profile data is
* valid. Upon reading invalid/corrupted profile data, returns 1 (failure).
*/
int __llvm_profile_merge_from_buffer(const char *Profile, uint64_t Size);
@ -113,8 +115,8 @@ int __llvm_profile_merge_from_buffer(const char *Profile, uint64_t Size);
*
* Returns 0 (success) if the profile data in buffer \p Profile with size
* \p Size was generated by the same binary and therefore matches
* structurally the in-process counters. If the profile data in buffer is
* not compatible, the interface returns 1 (failure).
* structurally the in-process counters and bitmaps. If the profile data in
* buffer is not compatible, the interface returns 1 (failure).
*/
int __llvm_profile_check_compatibility(const char *Profile,
uint64_t Size);
@ -276,6 +278,10 @@ uint64_t __llvm_profile_get_num_counters(const char *Begin, const char *End);
/*! \brief Get the size of the profile counters section in bytes. */
uint64_t __llvm_profile_get_counters_size(const char *Begin, const char *End);
/*! \brief Get the number of bytes in the profile bitmap section. */
uint64_t __llvm_profile_get_num_bitmap_bytes(const char *Begin,
const char *End);
/* ! \brief Given the sizes of the data and counter information, return the
* number of padding bytes before and after the counters, and after the names,
* in the raw profile.
@ -286,8 +292,9 @@ uint64_t __llvm_profile_get_counters_size(const char *Begin, const char *End);
* needed to achieve that.
*/
void __llvm_profile_get_padding_sizes_for_counters(
uint64_t DataSize, uint64_t CountersSize, uint64_t NamesSize,
uint64_t *PaddingBytesBeforeCounters, uint64_t *PaddingBytesAfterCounters,
uint64_t DataSize, uint64_t CountersSize, uint64_t NumBitmapBytes,
uint64_t NamesSize, uint64_t *PaddingBytesBeforeCounters,
uint64_t *PaddingBytesAfterCounters, uint64_t *PaddingBytesAfterBitmap,
uint64_t *PaddingBytesAfterNames);
/*!

View File

@ -43,11 +43,14 @@ uint64_t __llvm_profile_get_size_for_buffer(void) {
const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
const char *CountersBegin = __llvm_profile_begin_counters();
const char *CountersEnd = __llvm_profile_end_counters();
const char *BitmapBegin = __llvm_profile_begin_bitmap();
const char *BitmapEnd = __llvm_profile_end_bitmap();
const char *NamesBegin = __llvm_profile_begin_names();
const char *NamesEnd = __llvm_profile_end_names();
return __llvm_profile_get_size_for_buffer_internal(
DataBegin, DataEnd, CountersBegin, CountersEnd, NamesBegin, NamesEnd);
DataBegin, DataEnd, CountersBegin, CountersEnd, BitmapBegin, BitmapEnd,
NamesBegin, NamesEnd);
}
COMPILER_RT_VISIBILITY
@ -83,6 +86,12 @@ uint64_t __llvm_profile_get_counters_size(const char *Begin, const char *End) {
__llvm_profile_counter_entry_size();
}
COMPILER_RT_VISIBILITY
uint64_t __llvm_profile_get_num_bitmap_bytes(const char *Begin,
const char *End) {
return (End - Begin);
}
/// Calculate the number of padding bytes needed to add to \p Offset in order
/// for (\p Offset + Padding) to be page-aligned.
static uint64_t calculateBytesNeededToPageAlign(uint64_t Offset) {
@ -102,13 +111,16 @@ static int needsCounterPadding(void) {
COMPILER_RT_VISIBILITY
void __llvm_profile_get_padding_sizes_for_counters(
uint64_t DataSize, uint64_t CountersSize, uint64_t NamesSize,
uint64_t *PaddingBytesBeforeCounters, uint64_t *PaddingBytesAfterCounters,
uint64_t DataSize, uint64_t CountersSize, uint64_t NumBitmapBytes,
uint64_t NamesSize, uint64_t *PaddingBytesBeforeCounters,
uint64_t *PaddingBytesAfterCounters, uint64_t *PaddingBytesAfterBitmapBytes,
uint64_t *PaddingBytesAfterNames) {
if (!needsCounterPadding()) {
*PaddingBytesBeforeCounters = 0;
*PaddingBytesAfterCounters =
__llvm_profile_get_num_padding_bytes(CountersSize);
*PaddingBytesAfterBitmapBytes =
__llvm_profile_get_num_padding_bytes(NumBitmapBytes);
*PaddingBytesAfterNames = __llvm_profile_get_num_padding_bytes(NamesSize);
return;
}
@ -118,31 +130,37 @@ void __llvm_profile_get_padding_sizes_for_counters(
*PaddingBytesBeforeCounters =
calculateBytesNeededToPageAlign(sizeof(__llvm_profile_header) + DataSize);
*PaddingBytesAfterCounters = calculateBytesNeededToPageAlign(CountersSize);
*PaddingBytesAfterBitmapBytes =
calculateBytesNeededToPageAlign(NumBitmapBytes);
*PaddingBytesAfterNames = calculateBytesNeededToPageAlign(NamesSize);
}
COMPILER_RT_VISIBILITY
uint64_t __llvm_profile_get_size_for_buffer_internal(
const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd,
const char *CountersBegin, const char *CountersEnd, const char *NamesBegin,
const char *NamesEnd) {
const char *CountersBegin, const char *CountersEnd, const char *BitmapBegin,
const char *BitmapEnd, const char *NamesBegin, const char *NamesEnd) {
/* Match logic in __llvm_profile_write_buffer(). */
const uint64_t NamesSize = (NamesEnd - NamesBegin) * sizeof(char);
uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);
uint64_t CountersSize =
__llvm_profile_get_counters_size(CountersBegin, CountersEnd);
const uint64_t NumBitmapBytes =
__llvm_profile_get_num_bitmap_bytes(BitmapBegin, BitmapEnd);
/* Determine how much padding is needed before/after the counters and after
* the names. */
uint64_t PaddingBytesBeforeCounters, PaddingBytesAfterCounters,
PaddingBytesAfterNames;
PaddingBytesAfterNames, PaddingBytesAfterBitmapBytes;
__llvm_profile_get_padding_sizes_for_counters(
DataSize, CountersSize, NamesSize, &PaddingBytesBeforeCounters,
&PaddingBytesAfterCounters, &PaddingBytesAfterNames);
DataSize, CountersSize, NumBitmapBytes, NamesSize,
&PaddingBytesBeforeCounters, &PaddingBytesAfterCounters,
&PaddingBytesAfterBitmapBytes, &PaddingBytesAfterNames);
return sizeof(__llvm_profile_header) + __llvm_write_binary_ids(NULL) +
DataSize + PaddingBytesBeforeCounters + CountersSize +
PaddingBytesAfterCounters + NamesSize + PaddingBytesAfterNames;
PaddingBytesAfterCounters + NumBitmapBytes +
PaddingBytesAfterBitmapBytes + NamesSize + PaddingBytesAfterNames;
}
COMPILER_RT_VISIBILITY
@ -160,9 +178,11 @@ COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer(char *Buffer) {
COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer_internal(
char *Buffer, const __llvm_profile_data *DataBegin,
const __llvm_profile_data *DataEnd, const char *CountersBegin,
const char *CountersEnd, const char *NamesBegin, const char *NamesEnd) {
const char *CountersEnd, const char *BitmapBegin, const char *BitmapEnd,
const char *NamesBegin, const char *NamesEnd) {
ProfDataWriter BufferWriter;
initBufferWriter(&BufferWriter, Buffer);
return lprofWriteDataImpl(&BufferWriter, DataBegin, DataEnd, CountersBegin,
CountersEnd, 0, NamesBegin, NamesEnd, 0);
CountersEnd, BitmapBegin, BitmapEnd, 0, NamesBegin,
NamesEnd, 0);
}

View File

@ -108,14 +108,18 @@ static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) {
const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
const char *CountersBegin = __llvm_profile_begin_counters();
const char *CountersEnd = __llvm_profile_end_counters();
const char *BitmapBegin = __llvm_profile_begin_bitmap();
const char *BitmapEnd = __llvm_profile_end_bitmap();
const char *NamesBegin = __llvm_profile_begin_names();
const char *NamesEnd = __llvm_profile_end_names();
const uint64_t NamesSize = (NamesEnd - NamesBegin) * sizeof(char);
uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);
uint64_t CountersSize =
__llvm_profile_get_counters_size(CountersBegin, CountersEnd);
uint64_t NumBitmapBytes =
__llvm_profile_get_num_bitmap_bytes(BitmapBegin, BitmapEnd);
/* Check that the counter and data sections in this image are
/* Check that the counter, bitmap, and data sections in this image are
* page-aligned. */
unsigned PageSize = getpagesize();
if ((intptr_t)CountersBegin % PageSize != 0) {
@ -123,6 +127,11 @@ static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) {
CountersBegin, PageSize);
return 1;
}
if ((intptr_t)BitmapBegin % PageSize != 0) {
PROF_ERR("Bitmap section not page-aligned (start = %p, pagesz = %u).\n",
BitmapBegin, PageSize);
return 1;
}
if ((intptr_t)DataBegin % PageSize != 0) {
PROF_ERR("Data section not page-aligned (start = %p, pagesz = %u).\n",
DataBegin, PageSize);
@ -132,10 +141,11 @@ static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) {
/* Determine how much padding is needed before/after the counters and
* after the names. */
uint64_t PaddingBytesBeforeCounters, PaddingBytesAfterCounters,
PaddingBytesAfterNames;
PaddingBytesAfterNames, PaddingBytesAfterBitmapBytes;
__llvm_profile_get_padding_sizes_for_counters(
DataSize, CountersSize, NamesSize, &PaddingBytesBeforeCounters,
&PaddingBytesAfterCounters, &PaddingBytesAfterNames);
DataSize, CountersSize, NumBitmapBytes, NamesSize,
&PaddingBytesBeforeCounters, &PaddingBytesAfterCounters,
&PaddingBytesAfterBitmapBytes, &PaddingBytesAfterNames);
uint64_t PageAlignedCountersLength = CountersSize + PaddingBytesAfterCounters;
uint64_t FileOffsetToCounters = CurrentFileOffset +
@ -155,6 +165,31 @@ static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) {
FileOffsetToCounters);
return 1;
}
/* Also mmap MCDC bitmap bytes. If there aren't any bitmap bytes, mmap()
* will fail with EINVAL. */
if (NumBitmapBytes == 0)
return 0;
uint64_t PageAlignedBitmapLength =
NumBitmapBytes + PaddingBytesAfterBitmapBytes;
uint64_t FileOffsetToBitmap =
CurrentFileOffset + sizeof(__llvm_profile_header) + DataSize +
PaddingBytesBeforeCounters + CountersSize + PaddingBytesAfterCounters;
void *BitmapMmap =
mmap((void *)BitmapBegin, PageAlignedBitmapLength, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_SHARED, Fileno, FileOffsetToBitmap);
if (BitmapMmap != BitmapBegin) {
PROF_ERR(
"Continuous counter sync mode is enabled, but mmap() failed (%s).\n"
" - BitmapBegin: %p\n"
" - PageAlignedBitmapLength: %" PRIu64 "\n"
" - Fileno: %d\n"
" - FileOffsetToBitmap: %" PRIu64 "\n",
strerror(errno), BitmapBegin, PageAlignedBitmapLength, Fileno,
FileOffsetToBitmap);
return 1;
}
return 0;
}
#elif defined(__ELF__) || defined(_WIN32)
@ -197,6 +232,8 @@ static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) {
const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
const char *CountersBegin = __llvm_profile_begin_counters();
const char *CountersEnd = __llvm_profile_end_counters();
const char *BitmapBegin = __llvm_profile_begin_bitmap();
const char *BitmapEnd = __llvm_profile_end_bitmap();
uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);
/* Get the file size. */
uint64_t FileSize = 0;
@ -218,6 +255,11 @@ static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) {
/* Return the memory allocated for counters to OS. */
lprofReleaseMemoryPagesToOS((uintptr_t)CountersBegin, (uintptr_t)CountersEnd);
/* BIAS MODE not supported yet for Bitmap (MCDC). */
/* Return the memory allocated for counters to OS. */
lprofReleaseMemoryPagesToOS((uintptr_t)BitmapBegin, (uintptr_t)BitmapEnd);
return 0;
}
#else

View File

@ -21,8 +21,8 @@
*/
uint64_t __llvm_profile_get_size_for_buffer_internal(
const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd,
const char *CountersBegin, const char *CountersEnd, const char *NamesBegin,
const char *NamesEnd);
const char *CountersBegin, const char *CountersEnd, const char *BitmapBegin,
const char *BitmapEnd, const char *NamesBegin, const char *NamesEnd);
/*!
* \brief Write instrumentation data to the given buffer, given explicit
@ -36,7 +36,8 @@ uint64_t __llvm_profile_get_size_for_buffer_internal(
int __llvm_profile_write_buffer_internal(
char *Buffer, const __llvm_profile_data *DataBegin,
const __llvm_profile_data *DataEnd, const char *CountersBegin,
const char *CountersEnd, const char *NamesBegin, const char *NamesEnd);
const char *CountersEnd, const char *BitmapBegin, const char *BitmapEnd,
const char *NamesBegin, const char *NamesEnd);
/*!
* The data structure describing the data to be written by the
@ -153,6 +154,7 @@ int lprofWriteDataImpl(ProfDataWriter *Writer,
const __llvm_profile_data *DataBegin,
const __llvm_profile_data *DataEnd,
const char *CountersBegin, const char *CountersEnd,
const char *BitmapBegin, const char *BitmapEnd,
VPDataReaderType *VPDataReader, const char *NamesBegin,
const char *NamesEnd, int SkipNameDataWrite);

View File

@ -66,6 +66,9 @@ int __llvm_profile_check_compatibility(const char *ProfileData,
Header->NumCounters !=
__llvm_profile_get_num_counters(__llvm_profile_begin_counters(),
__llvm_profile_end_counters()) ||
Header->NumBitmapBytes !=
__llvm_profile_get_num_bitmap_bytes(__llvm_profile_begin_bitmap(),
__llvm_profile_end_bitmap()) ||
Header->NamesSize != (uint64_t)(__llvm_profile_end_names() -
__llvm_profile_begin_names()) ||
Header->ValueKindLast != IPVK_Last)
@ -74,7 +77,8 @@ int __llvm_profile_check_compatibility(const char *ProfileData,
if (ProfileSize <
sizeof(__llvm_profile_header) + Header->BinaryIdsSize +
Header->NumData * sizeof(__llvm_profile_data) + Header->NamesSize +
Header->NumCounters * __llvm_profile_counter_entry_size())
Header->NumCounters * __llvm_profile_counter_entry_size() +
Header->NumBitmapBytes)
return 1;
for (SrcData = SrcDataStart,
@ -82,7 +86,8 @@ int __llvm_profile_check_compatibility(const char *ProfileData,
SrcData < SrcDataEnd; ++SrcData, ++DstData) {
if (SrcData->NameRef != DstData->NameRef ||
SrcData->FuncHash != DstData->FuncHash ||
SrcData->NumCounters != DstData->NumCounters)
SrcData->NumCounters != DstData->NumCounters ||
SrcData->NumBitmapBytes != DstData->NumBitmapBytes)
return 1;
}
@ -112,9 +117,11 @@ int __llvm_profile_merge_from_buffer(const char *ProfileData,
__llvm_profile_header *Header = (__llvm_profile_header *)ProfileData;
char *SrcCountersStart, *DstCounter;
const char *SrcCountersEnd, *SrcCounter;
const char *SrcBitmapStart;
const char *SrcNameStart;
const char *SrcValueProfDataStart, *SrcValueProfData;
uintptr_t CountersDelta = Header->CountersDelta;
uintptr_t BitmapDelta = Header->BitmapDelta;
SrcDataStart =
(__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header) +
@ -123,11 +130,12 @@ int __llvm_profile_merge_from_buffer(const char *ProfileData,
SrcCountersStart = (char *)SrcDataEnd;
SrcCountersEnd = SrcCountersStart +
Header->NumCounters * __llvm_profile_counter_entry_size();
SrcNameStart = SrcCountersEnd;
SrcBitmapStart = SrcCountersEnd;
SrcNameStart = SrcBitmapStart + Header->NumBitmapBytes;
SrcValueProfDataStart =
SrcNameStart + Header->NamesSize +
__llvm_profile_get_num_padding_bytes(Header->NamesSize);
if (SrcNameStart < SrcCountersStart)
if (SrcNameStart < SrcCountersStart || SrcNameStart < SrcBitmapStart)
return 1;
// Merge counters by iterating the entire counter section when debug info
@ -157,6 +165,8 @@ int __llvm_profile_merge_from_buffer(const char *ProfileData,
// extend CounterPtr to get the original value.
char *DstCounters =
(char *)((uintptr_t)DstData + signextIfWin64(DstData->CounterPtr));
char *DstBitmap =
(char *)((uintptr_t)DstData + signextIfWin64(DstData->BitmapPtr));
unsigned NVK = 0;
// SrcData is a serialized representation of the memory image. We need to
@ -186,6 +196,21 @@ int __llvm_profile_merge_from_buffer(const char *ProfileData,
}
}
const char *SrcBitmap =
SrcBitmapStart + ((uintptr_t)SrcData->BitmapPtr - BitmapDelta);
// BitmapDelta also needs to be decreased as we advance to the next data
// record.
BitmapDelta -= sizeof(*SrcData);
unsigned NB = SrcData->NumBitmapBytes;
// NumBitmapBytes may legitimately be 0. Just keep going.
if (NB != 0) {
if (SrcBitmap < SrcBitmapStart || (SrcBitmap + NB) > SrcNameStart)
return 1;
// Merge Src and Dst Bitmap bytes by simply ORing them together.
for (unsigned I = 0; I < NB; I++)
DstBitmap[I] |= SrcBitmap[I];
}
/* Now merge value profile data. */
if (!VPMergeHook)
continue;

View File

@ -187,6 +187,8 @@ void __llvm_profile_register_names_function(void *NamesStart,
// define these zero length variables in each of the above 4 sections.
static int dummy_cnts[0] COMPILER_RT_SECTION(
COMPILER_RT_SEG INSTR_PROF_CNTS_SECT_NAME);
static int dummy_bits[0] COMPILER_RT_SECTION(
COMPILER_RT_SEG INSTR_PROF_BITS_SECT_NAME);
static int dummy_data[0] COMPILER_RT_SECTION(
COMPILER_RT_SEG INSTR_PROF_DATA_SECT_NAME);
static const int dummy_name[0] COMPILER_RT_SECTION(
@ -202,8 +204,9 @@ static int dummy_vnds[0] COMPILER_RT_SECTION(
#pragma GCC diagnostic ignored "-Wcast-qual"
#endif
COMPILER_RT_VISIBILITY
void *__llvm_profile_keep[] = {(void *)&dummy_cnts, (void *)&dummy_data,
(void *)&dummy_name, (void *)&dummy_vnds};
void *__llvm_profile_keep[] = {(void *)&dummy_cnts, (void *)&dummy_bits,
(void *)&dummy_data, (void *)&dummy_name,
(void *)&dummy_vnds};
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif

View File

@ -31,6 +31,11 @@ extern char
COMPILER_RT_VISIBILITY
extern char CountersEnd __asm("section$end$__DATA$" INSTR_PROF_CNTS_SECT_NAME);
COMPILER_RT_VISIBILITY
extern char
BitmapStart __asm("section$start$__DATA$" INSTR_PROF_BITS_SECT_NAME);
COMPILER_RT_VISIBILITY
extern char BitmapEnd __asm("section$end$__DATA$" INSTR_PROF_BITS_SECT_NAME);
COMPILER_RT_VISIBILITY
extern uint32_t
OrderFileStart __asm("section$start$__DATA$" INSTR_PROF_ORDERFILE_SECT_NAME);
@ -56,6 +61,10 @@ char *__llvm_profile_begin_counters(void) { return &CountersStart; }
COMPILER_RT_VISIBILITY
char *__llvm_profile_end_counters(void) { return &CountersEnd; }
COMPILER_RT_VISIBILITY
char *__llvm_profile_begin_bitmap(void) { return &BitmapStart; }
COMPILER_RT_VISIBILITY
char *__llvm_profile_end_bitmap(void) { return &BitmapEnd; }
COMPILER_RT_VISIBILITY
uint32_t *__llvm_profile_begin_orderfile(void) { return &OrderFileStart; }
COMPILER_RT_VISIBILITY

View File

@ -35,6 +35,8 @@
#define PROF_NAME_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_NAME_COMMON)
#define PROF_CNTS_START INSTR_PROF_SECT_START(INSTR_PROF_CNTS_COMMON)
#define PROF_CNTS_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_CNTS_COMMON)
#define PROF_BITS_START INSTR_PROF_SECT_START(INSTR_PROF_BITS_COMMON)
#define PROF_BITS_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_BITS_COMMON)
#define PROF_ORDERFILE_START INSTR_PROF_SECT_START(INSTR_PROF_ORDERFILE_COMMON)
#define PROF_VNODES_START INSTR_PROF_SECT_START(INSTR_PROF_VNODES_COMMON)
#define PROF_VNODES_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_VNODES_COMMON)
@ -48,6 +50,8 @@ extern __llvm_profile_data PROF_DATA_STOP COMPILER_RT_VISIBILITY
COMPILER_RT_WEAK;
extern char PROF_CNTS_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
extern char PROF_CNTS_STOP COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
extern char PROF_BITS_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
extern char PROF_BITS_STOP COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
extern uint32_t PROF_ORDERFILE_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
extern char PROF_NAME_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
extern char PROF_NAME_STOP COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
@ -74,6 +78,12 @@ COMPILER_RT_VISIBILITY char *__llvm_profile_begin_counters(void) {
COMPILER_RT_VISIBILITY char *__llvm_profile_end_counters(void) {
return &PROF_CNTS_STOP;
}
COMPILER_RT_VISIBILITY char *__llvm_profile_begin_bitmap(void) {
return &PROF_BITS_START;
}
COMPILER_RT_VISIBILITY char *__llvm_profile_end_bitmap(void) {
return &PROF_BITS_STOP;
}
COMPILER_RT_VISIBILITY uint32_t *__llvm_profile_begin_orderfile(void) {
return &PROF_ORDERFILE_START;
}

View File

@ -88,6 +88,10 @@ COMPILER_RT_VISIBILITY
char *__llvm_profile_begin_counters(void) { return CountersFirst; }
COMPILER_RT_VISIBILITY
char *__llvm_profile_end_counters(void) { return CountersLast; }
COMPILER_RT_VISIBILITY
char *__llvm_profile_begin_bitmap(void) { return BitmapFirst; }
COMPILER_RT_VISIBILITY
char *__llvm_profile_end_bitmap(void) { return BitmapLast; }
/* TODO: correctly set up OrderFileFirst. */
COMPILER_RT_VISIBILITY
uint32_t *__llvm_profile_begin_orderfile(void) { return OrderFileFirst; }

View File

@ -14,6 +14,7 @@
#if defined(_MSC_VER)
/* Merge read-write sections into .data. */
#pragma comment(linker, "/MERGE:.lprfc=.data")
#pragma comment(linker, "/MERGE:.lprfb=.data")
#pragma comment(linker, "/MERGE:.lprfd=.data")
#pragma comment(linker, "/MERGE:.lprfv=.data")
#pragma comment(linker, "/MERGE:.lprfnd=.data")
@ -30,6 +31,8 @@
#pragma section(".lprfd$Z", read, write)
#pragma section(".lprfc$A", read, write)
#pragma section(".lprfc$Z", read, write)
#pragma section(".lprfb$A", read, write)
#pragma section(".lprfb$Z", read, write)
#pragma section(".lorderfile$A", read, write)
#pragma section(".lprfnd$A", read, write)
#pragma section(".lprfnd$Z", read, write)
@ -43,6 +46,8 @@ const char COMPILER_RT_SECTION(".lprfn$Z") NamesEnd = '\0';
char COMPILER_RT_SECTION(".lprfc$A") CountersStart;
char COMPILER_RT_SECTION(".lprfc$Z") CountersEnd;
char COMPILER_RT_SECTION(".lprfb$A") BitmapStart;
char COMPILER_RT_SECTION(".lprfb$Z") BitmapEnd;
uint32_t COMPILER_RT_SECTION(".lorderfile$A") OrderFileStart;
ValueProfNode COMPILER_RT_SECTION(".lprfnd$A") VNodesStart;
@ -58,6 +63,8 @@ const char *__llvm_profile_end_names(void) { return &NamesEnd; }
char *__llvm_profile_begin_counters(void) { return &CountersStart + 1; }
char *__llvm_profile_end_counters(void) { return &CountersEnd; }
char *__llvm_profile_begin_bitmap(void) { return &BitmapStart + 1; }
char *__llvm_profile_end_bitmap(void) { return &BitmapEnd; }
uint32_t *__llvm_profile_begin_orderfile(void) { return &OrderFileStart; }
ValueProfNode *__llvm_profile_begin_vnodes(void) { return &VNodesStart + 1; }

View File

@ -246,17 +246,20 @@ COMPILER_RT_VISIBILITY int lprofWriteData(ProfDataWriter *Writer,
const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
const char *CountersBegin = __llvm_profile_begin_counters();
const char *CountersEnd = __llvm_profile_end_counters();
const char *BitmapBegin = __llvm_profile_begin_bitmap();
const char *BitmapEnd = __llvm_profile_end_bitmap();
const char *NamesBegin = __llvm_profile_begin_names();
const char *NamesEnd = __llvm_profile_end_names();
return lprofWriteDataImpl(Writer, DataBegin, DataEnd, CountersBegin,
CountersEnd, VPDataReader, NamesBegin, NamesEnd,
SkipNameDataWrite);
CountersEnd, BitmapBegin, BitmapEnd, VPDataReader,
NamesBegin, NamesEnd, SkipNameDataWrite);
}
COMPILER_RT_VISIBILITY int
lprofWriteDataImpl(ProfDataWriter *Writer, const __llvm_profile_data *DataBegin,
const __llvm_profile_data *DataEnd,
const char *CountersBegin, const char *CountersEnd,
const char *BitmapBegin, const char *BitmapEnd,
VPDataReaderType *VPDataReader, const char *NamesBegin,
const char *NamesEnd, int SkipNameDataWrite) {
int DebugInfoCorrelate =
@ -271,6 +274,8 @@ lprofWriteDataImpl(ProfDataWriter *Writer, const __llvm_profile_data *DataBegin,
__llvm_profile_get_counters_size(CountersBegin, CountersEnd);
const uint64_t NumCounters =
__llvm_profile_get_num_counters(CountersBegin, CountersEnd);
const uint64_t NumBitmapBytes =
__llvm_profile_get_num_bitmap_bytes(BitmapBegin, BitmapEnd);
const uint64_t NamesSize = DebugInfoCorrelate ? 0 : NamesEnd - NamesBegin;
/* Create the header. */
@ -279,11 +284,11 @@ lprofWriteDataImpl(ProfDataWriter *Writer, const __llvm_profile_data *DataBegin,
/* Determine how much padding is needed before/after the counters and after
* the names. */
uint64_t PaddingBytesBeforeCounters, PaddingBytesAfterCounters,
PaddingBytesAfterNames;
PaddingBytesAfterNames, PaddingBytesAfterBitmapBytes;
__llvm_profile_get_padding_sizes_for_counters(
DataSectionSize, CountersSectionSize, NamesSize,
DataSectionSize, CountersSectionSize, NumBitmapBytes, NamesSize,
&PaddingBytesBeforeCounters, &PaddingBytesAfterCounters,
&PaddingBytesAfterNames);
&PaddingBytesAfterBitmapBytes, &PaddingBytesAfterNames);
{
/* Initialize header structure. */
@ -295,6 +300,7 @@ lprofWriteDataImpl(ProfDataWriter *Writer, const __llvm_profile_data *DataBegin,
* CountersDelta to match. */
#ifdef _WIN64
Header.CountersDelta = (uint32_t)Header.CountersDelta;
Header.BitmapDelta = (uint32_t)Header.BitmapDelta;
#endif
/* The data and names sections are omitted in lightweight mode. */
@ -319,6 +325,8 @@ lprofWriteDataImpl(ProfDataWriter *Writer, const __llvm_profile_data *DataBegin,
{NULL, sizeof(uint8_t), PaddingBytesBeforeCounters, 1},
{CountersBegin, sizeof(uint8_t), CountersSectionSize, 0},
{NULL, sizeof(uint8_t), PaddingBytesAfterCounters, 1},
{BitmapBegin, sizeof(uint8_t), NumBitmapBytes, 0},
{NULL, sizeof(uint8_t), PaddingBytesAfterBitmapBytes, 1},
{(SkipNameDataWrite || DebugInfoCorrelate) ? NULL : NamesBegin,
sizeof(uint8_t), NamesSize, 0},
{NULL, sizeof(uint8_t), PaddingBytesAfterNames, 1}};

View File

@ -25,17 +25,18 @@ const char *__llvm_profile_begin_names(void);
const char *__llvm_profile_end_names(void);
char *__llvm_profile_begin_counters(void);
char *__llvm_profile_end_counters(void);
char *__llvm_profile_begin_bitmap(void);
char *__llvm_profile_end_bitmap(void);
uint64_t __llvm_profile_get_size_for_buffer_internal(
const void *DataBegin, const void *DataEnd, const char *CountersBegin,
const char *CountersEnd, const char *NamesBegin, const char *NamesEnd);
const char *CountersEnd, const char *BitmapBegin, const char *BitmapEnd,
const char *NamesBegin, const char *NamesEnd);
int __llvm_profile_write_buffer_internal(char *Buffer, const void *DataBegin,
const void *DataEnd,
const char *CountersBegin,
const char *CountersEnd,
const char *NamesBegin,
const char *NamesEnd);
int __llvm_profile_write_buffer_internal(
char *Buffer, const void *DataBegin, const void *DataEnd,
const char *CountersBegin, const char *CountersEnd, const char *BitmapBegin,
const char *BitmapEnd, const char *NamesBegin, const char *NamesEnd);
void __llvm_profile_set_dumped(void);
@ -43,12 +44,14 @@ int main(int argc, const char *argv[]) {
uint64_t bufsize = __llvm_profile_get_size_for_buffer_internal(
__llvm_profile_begin_data(), __llvm_profile_end_data(),
__llvm_profile_begin_counters(), __llvm_profile_end_counters(),
__llvm_profile_begin_bitmap(), __llvm_profile_end_bitmap(),
__llvm_profile_begin_names(), __llvm_profile_end_names());
char *buf = malloc(bufsize);
int ret = __llvm_profile_write_buffer_internal(buf,
__llvm_profile_begin_data(), __llvm_profile_end_data(),
int ret = __llvm_profile_write_buffer_internal(
buf, __llvm_profile_begin_data(), __llvm_profile_end_data(),
__llvm_profile_begin_counters(), __llvm_profile_end_counters(),
__llvm_profile_begin_bitmap(), __llvm_profile_end_bitmap(),
__llvm_profile_begin_names(), __llvm_profile_end_names());
if (ret != 0) {

View File

@ -13954,6 +13954,144 @@ pass will generate the appropriate data structures and replace the
``llvm.instrprof.value.profile`` intrinsic with the call to the profile
runtime library with proper arguments.
'``llvm.instrprof.mcdc.parameters``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Syntax:
"""""""
::
declare void @llvm.instrprof.mcdc.parameters(ptr <name>, i64 <hash>,
i32 <bitmap-bytes>)
Overview:
"""""""""
The '``llvm.instrprof.mcdc.parameters``' intrinsic is used to initiate MC/DC
code coverage instrumentation for a function.
Arguments:
""""""""""
The first argument is a pointer to a global variable containing the
name of the entity being instrumented. This should generally be the
(mangled) function name for a set of counters.
The second argument is a hash value that can be used by the consumer
of the profile data to detect changes to the instrumented source.
The third argument is the number of bitmap bytes required by the function to
record the number of test vectors executed for each boolean expression.
Semantics:
""""""""""
This intrinsic represents basic MC/DC parameters initiating one or more MC/DC
instrumentation sequences in a function. It will cause the ``-instrprof`` pass
to generate the appropriate data structures and the code to instrument MC/DC
test vectors in a format that can be written out by a compiler runtime and
consumed via the ``llvm-profdata`` tool.
'``llvm.instrprof.mcdc.condbitmap.update``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Syntax:
"""""""
::
declare void @llvm.instrprof.mcdc.condbitmap.update(ptr <name>, i64 <hash>,
i32 <condition-id>,
ptr <mcdc-temp-addr>,
i1 <bool-value>)
Overview:
"""""""""
The '``llvm.instrprof.mcdc.condbitmap.update``' intrinsic is used to track
MC/DC condition evaluation for each condition in a boolean expression.
Arguments:
""""""""""
The first argument is a pointer to a global variable containing the
name of the entity being instrumented. This should generally be the
(mangled) function name for a set of counters.
The second argument is a hash value that can be used by the consumer
of the profile data to detect changes to the instrumented source.
The third argument is an ID of a condition to track. This value is used as a
bit index into the condition bitmap.
The fourth argument is the address of the condition bitmap.
The fifth argument is the boolean value representing the evaluation of the
condition (true or false)
Semantics:
""""""""""
This intrinsic represents the update of a condition bitmap that is local to a
function and will cause the ``-instrprof`` pass to generate the code to
instrument the control flow around each condition in a boolean expression. The
ID of each condition corresponds to a bit index in the condition bitmap which
is set based on the evaluation of the condition.
'``llvm.instrprof.mcdc.tvbitmap.update``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Syntax:
"""""""
::
declare void @llvm.instrprof.mcdc.tvbitmap.update(ptr <name>, i64 <hash>,
i32 <bitmap-bytes>)
i32 <bitmap-index>,
ptr <mcdc-temp-addr>)
Overview:
"""""""""
The '``llvm.instrprof.mcdc.tvbitmap.update``' intrinsic is used to track MC/DC
test vector execution after each boolean expression has been fully executed.
The overall value of the condition bitmap, after it has been successively
updated using the '``llvm.instrprof.mcdc.condbitmap.update``' intrinsic with
the true or false evaluation of each condition, uniquely identifies an executed
MC/DC test vector and is used as a bit index into the global test vector
bitmap.
Arguments:
""""""""""
The first argument is a pointer to a global variable containing the
name of the entity being instrumented. This should generally be the
(mangled) function name for a set of counters.
The second argument is a hash value that can be used by the consumer
of the profile data to detect changes to the instrumented source.
The third argument is the number of bitmap bytes required by the function to
record the number of test vectors executed for each boolean expression.
The fourth argument is the byte index into the global test vector bitmap
corresponding to the function.
The fifth argument is the address of the condition bitmap, which contains a
value representing an executed MC/DC test vector. It is loaded and used as the
bit index of the test vector bitmap.
Semantics:
""""""""""
This intrinsic represents the final operation of an MC/DC instrumentation
sequence and will cause the ``-instrprof`` pass to generate the code to
instrument an update of a function's global test vector bitmap to indicate that
a test vector has been executed. The global test vector bitmap can be consumed
by the ``llvm-profdata`` and ``llvm-cov`` tools.
'``llvm.thread.pointer``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -1424,6 +1424,11 @@ public:
ConstantInt *getHash() const {
return cast<ConstantInt>(const_cast<Value *>(getArgOperand(1)));
}
};
/// A base class for all instrprof counter intrinsics.
class InstrProfCntrInstBase : public InstrProfInstBase {
public:
// The number of counters for the instrumented function.
ConstantInt *getNumCounters() const;
// The index of the counter that this instruction acts on.
@ -1431,7 +1436,7 @@ public:
};
/// This represents the llvm.instrprof.cover intrinsic.
class InstrProfCoverInst : public InstrProfInstBase {
class InstrProfCoverInst : public InstrProfCntrInstBase {
public:
static bool classof(const IntrinsicInst *I) {
return I->getIntrinsicID() == Intrinsic::instrprof_cover;
@ -1442,7 +1447,7 @@ public:
};
/// This represents the llvm.instrprof.increment intrinsic.
class InstrProfIncrementInst : public InstrProfInstBase {
class InstrProfIncrementInst : public InstrProfCntrInstBase {
public:
static bool classof(const IntrinsicInst *I) {
return I->getIntrinsicID() == Intrinsic::instrprof_increment ||
@ -1466,7 +1471,7 @@ public:
};
/// This represents the llvm.instrprof.timestamp intrinsic.
class InstrProfTimestampInst : public InstrProfInstBase {
class InstrProfTimestampInst : public InstrProfCntrInstBase {
public:
static bool classof(const IntrinsicInst *I) {
return I->getIntrinsicID() == Intrinsic::instrprof_timestamp;
@ -1477,7 +1482,7 @@ public:
};
/// This represents the llvm.instrprof.value.profile intrinsic.
class InstrProfValueProfileInst : public InstrProfInstBase {
class InstrProfValueProfileInst : public InstrProfCntrInstBase {
public:
static bool classof(const IntrinsicInst *I) {
return I->getIntrinsicID() == Intrinsic::instrprof_value_profile;
@ -1500,6 +1505,87 @@ public:
}
};
/// A base class for instrprof mcdc intrinsics that require global bitmap bytes.
class InstrProfMCDCBitmapInstBase : public InstrProfInstBase {
public:
static bool classof(const IntrinsicInst *I) {
return I->getIntrinsicID() == Intrinsic::instrprof_mcdc_parameters ||
I->getIntrinsicID() == Intrinsic::instrprof_mcdc_tvbitmap_update;
}
static bool classof(const Value *V) {
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
}
/// \return The number of bytes used for the MCDC bitmaps for the instrumented
/// function.
ConstantInt *getNumBitmapBytes() const {
return cast<ConstantInt>(const_cast<Value *>(getArgOperand(2)));
}
};
/// This represents the llvm.instrprof.mcdc.parameters intrinsic.
class InstrProfMCDCBitmapParameters : public InstrProfMCDCBitmapInstBase {
public:
static bool classof(const IntrinsicInst *I) {
return I->getIntrinsicID() == Intrinsic::instrprof_mcdc_parameters;
}
static bool classof(const Value *V) {
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
}
};
/// This represents the llvm.instrprof.mcdc.tvbitmap.update intrinsic.
class InstrProfMCDCTVBitmapUpdate : public InstrProfMCDCBitmapInstBase {
public:
static bool classof(const IntrinsicInst *I) {
return I->getIntrinsicID() == Intrinsic::instrprof_mcdc_tvbitmap_update;
}
static bool classof(const Value *V) {
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
}
/// \return The index of the TestVector Bitmap upon which this intrinsic
/// acts.
ConstantInt *getBitmapIndex() const {
return cast<ConstantInt>(const_cast<Value *>(getArgOperand(3)));
}
/// \return The address of the corresponding condition bitmap containing
/// the index of the TestVector to update within the TestVector Bitmap.
Value *getMCDCCondBitmapAddr() const {
return cast<Value>(const_cast<Value *>(getArgOperand(4)));
}
};
/// This represents the llvm.instrprof.mcdc.condbitmap.update intrinsic.
/// It does not pertain to global bitmap updates or parameters and so doesn't
/// inherit from InstrProfMCDCBitmapInstBase.
class InstrProfMCDCCondBitmapUpdate : public InstrProfInstBase {
public:
static bool classof(const IntrinsicInst *I) {
return I->getIntrinsicID() == Intrinsic::instrprof_mcdc_condbitmap_update;
}
static bool classof(const Value *V) {
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
}
/// \return The ID of the condition to update.
ConstantInt *getCondID() const {
return cast<ConstantInt>(const_cast<Value *>(getArgOperand(2)));
}
/// \return The address of the corresponding condition bitmap.
Value *getMCDCCondBitmapAddr() const {
return cast<Value>(const_cast<Value *>(getArgOperand(3)));
}
/// \return The boolean value to set in the condition bitmap for the
/// corresponding condition ID. This represents how the condition evaluated.
Value *getCondBool() const {
return cast<Value>(const_cast<Value *>(getArgOperand(4)));
}
};
class PseudoProbeInst : public IntrinsicInst {
public:
static bool classof(const IntrinsicInst *I) {

View File

@ -909,6 +909,21 @@ def int_instrprof_value_profile : Intrinsic<[],
llvm_i64_ty, llvm_i32_ty,
llvm_i32_ty]>;
// A parameter configuration for instrumentation based MCDC profiling.
def int_instrprof_mcdc_parameters : Intrinsic<[],
[llvm_ptr_ty, llvm_i64_ty,
llvm_i32_ty]>;
// A test vector bitmap update for instrumentation based MCDC profiling.
def int_instrprof_mcdc_tvbitmap_update : Intrinsic<[],
[llvm_ptr_ty, llvm_i64_ty,
llvm_i32_ty, llvm_i32_ty, llvm_ptr_ty]>;
// A condition bitmap value update for instrumentation based MCDC profiling.
def int_instrprof_mcdc_condbitmap_update : Intrinsic<[],
[llvm_ptr_ty, llvm_i64_ty,
llvm_i32_ty, llvm_ptr_ty, llvm_i1_ty]>;
def int_call_preallocated_setup : DefaultAttrsIntrinsic<[llvm_token_ty], [llvm_i32_ty]>;
def int_call_preallocated_arg : DefaultAttrsIntrinsic<[llvm_ptr_ty], [llvm_token_ty, llvm_i32_ty]>;
def int_call_preallocated_teardown : DefaultAttrsIntrinsic<[], [llvm_token_ty]>;

View File

@ -1027,7 +1027,9 @@ enum CovMapVersion {
// Compilation directory is stored separately and combined with relative
// filenames to produce an absolute file path.
Version6 = 5,
// The current version is Version6.
// Branch regions extended and Decision Regions added for MC/DC.
Version7 = 6,
// The current version is Version7.
CurrentVersion = INSTR_PROF_COVMAP_VERSION
};

View File

@ -96,6 +96,9 @@ inline StringRef getInstrProfDataVarPrefix() { return "__profd_"; }
/// Return the name prefix of profile counter variables.
inline StringRef getInstrProfCountersVarPrefix() { return "__profc_"; }
/// Return the name prefix of profile bitmap variables.
inline StringRef getInstrProfBitmapVarPrefix() { return "__profbm_"; }
/// Return the name prefix of value profile variables.
inline StringRef getInstrProfValuesVarPrefix() { return "__profvp_"; }
@ -338,6 +341,7 @@ enum class instrprof_error {
invalid_prof,
hash_mismatch,
count_mismatch,
bitmap_mismatch,
counter_overflow,
value_site_count_mismatch,
compress_failed,
@ -693,18 +697,23 @@ struct InstrProfValueSiteRecord {
/// Profiling information for a single function.
struct InstrProfRecord {
std::vector<uint64_t> Counts;
std::vector<uint8_t> BitmapBytes;
InstrProfRecord() = default;
InstrProfRecord(std::vector<uint64_t> Counts) : Counts(std::move(Counts)) {}
InstrProfRecord(std::vector<uint64_t> Counts,
std::vector<uint8_t> BitmapBytes)
: Counts(std::move(Counts)), BitmapBytes(std::move(BitmapBytes)) {}
InstrProfRecord(InstrProfRecord &&) = default;
InstrProfRecord(const InstrProfRecord &RHS)
: Counts(RHS.Counts),
: Counts(RHS.Counts), BitmapBytes(RHS.BitmapBytes),
ValueData(RHS.ValueData
? std::make_unique<ValueProfData>(*RHS.ValueData)
: nullptr) {}
InstrProfRecord &operator=(InstrProfRecord &&) = default;
InstrProfRecord &operator=(const InstrProfRecord &RHS) {
Counts = RHS.Counts;
BitmapBytes = RHS.BitmapBytes;
if (!RHS.ValueData) {
ValueData = nullptr;
return *this;
@ -883,6 +892,11 @@ struct NamedInstrProfRecord : InstrProfRecord {
NamedInstrProfRecord(StringRef Name, uint64_t Hash,
std::vector<uint64_t> Counts)
: InstrProfRecord(std::move(Counts)), Name(Name), Hash(Hash) {}
NamedInstrProfRecord(StringRef Name, uint64_t Hash,
std::vector<uint64_t> Counts,
std::vector<uint8_t> BitmapBytes)
: InstrProfRecord(std::move(Counts), std::move(BitmapBytes)), Name(Name),
Hash(Hash) {}
static bool hasCSFlagInHash(uint64_t FuncHash) {
return ((FuncHash >> CS_FLAG_IN_FUNC_HASH) & 1);
@ -1014,7 +1028,9 @@ enum ProfVersion {
Version9 = 9,
// An additional (optional) temporal profile traces section is added.
Version10 = 10,
// The current version is 10.
// An additional field is used for bitmap bytes.
Version11 = 11,
// The current version is 11.
CurrentVersion = INSTR_PROF_INDEX_VERSION
};
const uint64_t Version = ProfVersion::CurrentVersion;
@ -1152,6 +1168,7 @@ namespace RawInstrProf {
// Version 6: Added binary id.
// Version 7: Reorder binary id and include version in signature.
// Version 8: Use relative counter pointer.
// Version 9: Added relative bitmap bytes pointer and count used by MC/DC.
const uint64_t Version = INSTR_PROF_RAW_VERSION;
template <class IntPtrT> inline uint64_t getMagic();

View File

@ -76,6 +76,7 @@ INSTR_PROF_DATA(const uint64_t, llvm::Type::getInt64Ty(Ctx), FuncHash, \
ConstantInt::get(llvm::Type::getInt64Ty(Ctx), \
Inc->getHash()->getZExtValue()))
INSTR_PROF_DATA(const IntPtrT, IntPtrTy, CounterPtr, RelativeCounterPtr)
INSTR_PROF_DATA(const IntPtrT, IntPtrTy, BitmapPtr, RelativeBitmapPtr)
/* This is used to map function pointers for the indirect call targets to
* function name hashes during the conversion from raw to merged profile
* data.
@ -87,7 +88,9 @@ INSTR_PROF_DATA(IntPtrT, llvm::Type::getInt8PtrTy(Ctx), Values, \
INSTR_PROF_DATA(const uint32_t, llvm::Type::getInt32Ty(Ctx), NumCounters, \
ConstantInt::get(llvm::Type::getInt32Ty(Ctx), NumCounters))
INSTR_PROF_DATA(const uint16_t, Int16ArrayTy, NumValueSites[IPVK_Last+1], \
ConstantArray::get(Int16ArrayTy, Int16ArrayVals))
ConstantArray::get(Int16ArrayTy, Int16ArrayVals)) \
INSTR_PROF_DATA(const uint32_t, llvm::Type::getInt32Ty(Ctx), NumBitmapBytes, \
ConstantInt::get(llvm::Type::getInt32Ty(Ctx), NumBitmapBytes))
#undef INSTR_PROF_DATA
/* INSTR_PROF_DATA end. */
@ -132,9 +135,13 @@ INSTR_PROF_RAW_HEADER(uint64_t, NumData, NumData)
INSTR_PROF_RAW_HEADER(uint64_t, PaddingBytesBeforeCounters, PaddingBytesBeforeCounters)
INSTR_PROF_RAW_HEADER(uint64_t, NumCounters, NumCounters)
INSTR_PROF_RAW_HEADER(uint64_t, PaddingBytesAfterCounters, PaddingBytesAfterCounters)
INSTR_PROF_RAW_HEADER(uint64_t, NumBitmapBytes, NumBitmapBytes)
INSTR_PROF_RAW_HEADER(uint64_t, PaddingBytesAfterBitmapBytes, PaddingBytesAfterBitmapBytes)
INSTR_PROF_RAW_HEADER(uint64_t, NamesSize, NamesSize)
INSTR_PROF_RAW_HEADER(uint64_t, CountersDelta,
(uintptr_t)CountersBegin - (uintptr_t)DataBegin)
INSTR_PROF_RAW_HEADER(uint64_t, BitmapDelta,
(uintptr_t)BitmapBegin - (uintptr_t)DataBegin)
INSTR_PROF_RAW_HEADER(uint64_t, NamesDelta, (uintptr_t)NamesBegin)
INSTR_PROF_RAW_HEADER(uint64_t, ValueKindLast, IPVK_Last)
#undef INSTR_PROF_RAW_HEADER
@ -267,6 +274,9 @@ INSTR_PROF_SECT_ENTRY(IPSK_data, \
INSTR_PROF_SECT_ENTRY(IPSK_cnts, \
INSTR_PROF_QUOTE(INSTR_PROF_CNTS_COMMON), \
INSTR_PROF_CNTS_COFF, "__DATA,")
INSTR_PROF_SECT_ENTRY(IPSK_bitmap, \
INSTR_PROF_QUOTE(INSTR_PROF_BITS_COMMON), \
INSTR_PROF_BITS_COFF, "__DATA,")
INSTR_PROF_SECT_ENTRY(IPSK_name, \
INSTR_PROF_QUOTE(INSTR_PROF_NAME_COMMON), \
INSTR_PROF_NAME_COFF, "__DATA,")
@ -645,11 +655,11 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
(uint64_t)'f' << 16 | (uint64_t)'R' << 8 | (uint64_t)129
/* Raw profile format version (start from 1). */
#define INSTR_PROF_RAW_VERSION 8
#define INSTR_PROF_RAW_VERSION 9
/* Indexed profile format version (start from 1). */
#define INSTR_PROF_INDEX_VERSION 10
#define INSTR_PROF_INDEX_VERSION 11
/* Coverage mapping format version (start from 0). */
#define INSTR_PROF_COVMAP_VERSION 5
#define INSTR_PROF_COVMAP_VERSION 6
/* 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
@ -686,6 +696,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_DATA_COMMON __llvm_prf_data
#define INSTR_PROF_NAME_COMMON __llvm_prf_names
#define INSTR_PROF_CNTS_COMMON __llvm_prf_cnts
#define INSTR_PROF_BITS_COMMON __llvm_prf_bits
#define INSTR_PROF_VALS_COMMON __llvm_prf_vals
#define INSTR_PROF_VNODES_COMMON __llvm_prf_vnds
#define INSTR_PROF_COVMAP_COMMON __llvm_covmap
@ -697,6 +708,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_DATA_COFF ".lprfd$M"
#define INSTR_PROF_NAME_COFF ".lprfn$M"
#define INSTR_PROF_CNTS_COFF ".lprfc$M"
#define INSTR_PROF_BITS_COFF ".lprfb$M"
#define INSTR_PROF_VALS_COFF ".lprfv$M"
#define INSTR_PROF_VNODES_COFF ".lprfnd$M"
#define INSTR_PROF_COVMAP_COFF ".lcovmap$M"
@ -708,6 +720,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_DATA_SECT_NAME INSTR_PROF_DATA_COFF
#define INSTR_PROF_NAME_SECT_NAME INSTR_PROF_NAME_COFF
#define INSTR_PROF_CNTS_SECT_NAME INSTR_PROF_CNTS_COFF
#define INSTR_PROF_BITS_SECT_NAME INSTR_PROF_BITS_COFF
/* Array of pointers. Each pointer points to a list
* of value nodes associated with one value site.
*/
@ -722,6 +735,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_DATA_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_DATA_COMMON)
#define INSTR_PROF_NAME_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_NAME_COMMON)
#define INSTR_PROF_CNTS_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_CNTS_COMMON)
#define INSTR_PROF_BITS_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_BITS_COMMON)
/* Array of pointers. Each pointer points to a list
* of value nodes associated with one value site.
*/

View File

@ -323,11 +323,14 @@ private:
// the variant types of the profile.
uint64_t Version;
uint64_t CountersDelta;
uint64_t BitmapDelta;
uint64_t NamesDelta;
const RawInstrProf::ProfileData<IntPtrT> *Data;
const RawInstrProf::ProfileData<IntPtrT> *DataEnd;
const char *CountersStart;
const char *CountersEnd;
const char *BitmapStart;
const char *BitmapEnd;
const char *NamesStart;
const char *NamesEnd;
// After value profile is all read, this pointer points to
@ -428,6 +431,7 @@ private:
Error readName(NamedInstrProfRecord &Record);
Error readFuncHash(NamedInstrProfRecord &Record);
Error readRawCounts(InstrProfRecord &Record);
Error readRawBitmapBytes(InstrProfRecord &Record);
Error readValueProfilingData(InstrProfRecord &Record);
bool atEnd() const { return Data == DataEnd; }
@ -440,6 +444,7 @@ private:
// As we advance to the next record, we maintain the correct CountersDelta
// with respect to the next record.
CountersDelta -= sizeof(*Data);
BitmapDelta -= sizeof(*Data);
}
Data++;
ValueDataStart += CurValueDataSize;
@ -733,6 +738,10 @@ public:
Error getFunctionCounts(StringRef FuncName, uint64_t FuncHash,
std::vector<uint64_t> &Counts);
/// Fill Bitmap Bytes with the profile data for the given function name.
Error getFunctionBitmapBytes(StringRef FuncName, uint64_t FuncHash,
std::vector<uint8_t> &BitmapBytes);
/// Return the maximum of all known function counts.
/// \c UseCS indicates whether to use the context-sensitive count.
uint64_t getMaximumFunctionCount(bool UseCS) {

View File

@ -50,6 +50,7 @@ private:
uint32_t NumValueSites[IPVK_Last + 1];
GlobalVariable *RegionCounters = nullptr;
GlobalVariable *DataVar = nullptr;
GlobalVariable *RegionBitmaps = nullptr;
PerFunctionProfileData() {
memset(NumValueSites, 0, sizeof(uint32_t) * (IPVK_Last + 1));
@ -105,20 +106,59 @@ private:
/// Force emitting of name vars for unused functions.
void lowerCoverageData(GlobalVariable *CoverageNamesVar);
/// Replace instrprof.mcdc.tvbitmask.update with a shift and or instruction
/// using the index represented by the a temp value into a bitmap.
void lowerMCDCTestVectorBitmapUpdate(InstrProfMCDCTVBitmapUpdate *Ins);
/// Replace instrprof.mcdc.temp.update with a shift and or instruction using
/// the corresponding condition ID.
void lowerMCDCCondBitmapUpdate(InstrProfMCDCCondBitmapUpdate *Ins);
/// Compute the address of the counter value that this profiling instruction
/// acts on.
Value *getCounterAddress(InstrProfInstBase *I);
Value *getCounterAddress(InstrProfCntrInstBase *I);
/// Get the region counters for an increment, creating them if necessary.
///
/// If the counter array doesn't yet exist, the profile data variables
/// referring to them will also be created.
GlobalVariable *getOrCreateRegionCounters(InstrProfInstBase *Inc);
GlobalVariable *getOrCreateRegionCounters(InstrProfCntrInstBase *Inc);
/// Create the region counters.
GlobalVariable *createRegionCounters(InstrProfInstBase *Inc, StringRef Name,
GlobalVariable *createRegionCounters(InstrProfCntrInstBase *Inc,
StringRef Name,
GlobalValue::LinkageTypes Linkage);
/// Compute the address of the test vector bitmap that this profiling
/// instruction acts on.
Value *getBitmapAddress(InstrProfMCDCTVBitmapUpdate *I);
/// Get the region bitmaps for an increment, creating them if necessary.
///
/// If the bitmap array doesn't yet exist, the profile data variables
/// referring to them will also be created.
GlobalVariable *getOrCreateRegionBitmaps(InstrProfMCDCBitmapInstBase *Inc);
/// Create the MC/DC bitmap as a byte-aligned array of bytes associated with
/// an MC/DC Decision region. The number of bytes required is indicated by
/// the intrinsic used (type InstrProfMCDCBitmapInstBase). This is called
/// as part of setupProfileSection() and is conceptually very similar to
/// what is done for profile data counters in createRegionCounters().
GlobalVariable *createRegionBitmaps(InstrProfMCDCBitmapInstBase *Inc,
StringRef Name,
GlobalValue::LinkageTypes Linkage);
/// Set Comdat property of GV, if required.
void maybeSetComdat(GlobalVariable *GV, Function *Fn, StringRef VarName);
/// Setup the sections into which counters and bitmaps are allocated.
GlobalVariable *setupProfileSection(InstrProfInstBase *Inc,
InstrProfSectKind IPSK);
/// Create INSTR_PROF_DATA variable for counters and bitmaps.
void createDataVariable(InstrProfCntrInstBase *Inc,
InstrProfMCDCBitmapParameters *Update);
/// Emit the section with compressed function names.
void emitNameData();

View File

@ -7197,6 +7197,12 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
llvm_unreachable("instrprof failed to lower a timestamp");
case Intrinsic::instrprof_value_profile:
llvm_unreachable("instrprof failed to lower a value profiling call");
case Intrinsic::instrprof_mcdc_parameters:
llvm_unreachable("instrprof failed to lower mcdc parameters");
case Intrinsic::instrprof_mcdc_tvbitmap_update:
llvm_unreachable("instrprof failed to lower an mcdc tvbitmap update");
case Intrinsic::instrprof_mcdc_condbitmap_update:
llvm_unreachable("instrprof failed to lower an mcdc condbitmap update");
case Intrinsic::localescape: {
MachineFunction &MF = DAG.getMachineFunction();
const TargetInstrInfo *TII = DAG.getSubtarget().getInstrInfo();

View File

@ -270,13 +270,13 @@ int llvm::Intrinsic::lookupLLVMIntrinsicByName(ArrayRef<const char *> NameTable,
return -1;
}
ConstantInt *InstrProfInstBase::getNumCounters() const {
ConstantInt *InstrProfCntrInstBase::getNumCounters() const {
if (InstrProfValueProfileInst::classof(this))
llvm_unreachable("InstrProfValueProfileInst does not have counters!");
return cast<ConstantInt>(const_cast<Value *>(getArgOperand(2)));
}
ConstantInt *InstrProfInstBase::getIndex() const {
ConstantInt *InstrProfCntrInstBase::getIndex() const {
if (InstrProfValueProfileInst::classof(this))
llvm_unreachable("Please use InstrProfValueProfileInst::getIndex()");
return cast<ConstantInt>(const_cast<Value *>(getArgOperand(3)));

View File

@ -783,6 +783,7 @@ Expected<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get(
case CovMapVersion::Version4:
case CovMapVersion::Version5:
case CovMapVersion::Version6:
case CovMapVersion::Version7:
// Decompress the name data.
if (Error E = P.create(P.getNameData()))
return std::move(E);
@ -801,6 +802,9 @@ Expected<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get(
else if (Version == CovMapVersion::Version6)
return std::make_unique<VersionedCovMapFuncRecordReader<
CovMapVersion::Version6, IntPtrT, Endian>>(P, R, D, F);
else if (Version == CovMapVersion::Version7)
return std::make_unique<VersionedCovMapFuncRecordReader<
CovMapVersion::Version7, IntPtrT, Endian>>(P, R, D, F);
}
llvm_unreachable("Unsupported version");
}

View File

@ -136,6 +136,9 @@ static std::string getInstrProfErrString(instrprof_error Err,
case instrprof_error::count_mismatch:
OS << "function basic block count change detected (counter mismatch)";
break;
case instrprof_error::bitmap_mismatch:
OS << "function bitmap size change detected (bitmap size mismatch)";
break;
case instrprof_error::counter_overflow:
OS << "counter overflow";
break;
@ -815,6 +818,18 @@ void InstrProfRecord::merge(InstrProfRecord &Other, uint64_t Weight,
Warn(instrprof_error::counter_overflow);
}
// If the number of bitmap bytes doesn't match we either have bad data
// or a hash collision.
if (BitmapBytes.size() != Other.BitmapBytes.size()) {
Warn(instrprof_error::bitmap_mismatch);
return;
}
// Bitmap bytes are merged by simply ORing them together.
for (size_t I = 0, E = Other.BitmapBytes.size(); I < E; ++I) {
BitmapBytes[I] = Other.BitmapBytes[I] | BitmapBytes[I];
}
for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind)
mergeValueProfData(Kind, Other, Weight, Warn);
}
@ -1487,9 +1502,11 @@ Expected<Header> Header::readFromBuffer(const unsigned char *Buffer) {
// When a new field is added in the header add a case statement here to
// populate it.
static_assert(
IndexedInstrProf::ProfVersion::CurrentVersion == Version10,
IndexedInstrProf::ProfVersion::CurrentVersion == Version11,
"Please update the reading code below if a new field has been added, "
"if not add a case statement to fall through to the latest version.");
case 11ull:
[[fallthrough]];
case 10ull:
H.TemporalProfTracesOffset =
read(Buffer, offsetOf(&Header::TemporalProfTracesOffset));
@ -1513,10 +1530,12 @@ size_t Header::size() const {
// When a new field is added to the header add a case statement here to
// compute the size as offset of the new field + size of the new field. This
// relies on the field being added to the end of the list.
static_assert(IndexedInstrProf::ProfVersion::CurrentVersion == Version10,
static_assert(IndexedInstrProf::ProfVersion::CurrentVersion == Version11,
"Please update the size computation below if a new field has "
"been added to the header, if not add a case statement to "
"fall through to the latest version.");
case 11ull:
[[fallthrough]];
case 10ull:
return offsetOf(&Header::TemporalProfTracesOffset) +
sizeof(Header::TemporalProfTracesOffset);

View File

@ -210,11 +210,15 @@ void InstrProfCorrelatorImpl<IntPtrT>::addProbe(StringRef FunctionName,
// In this mode, CounterPtr actually stores the section relative address
// of the counter.
maybeSwap<IntPtrT>(CounterOffset),
// TODO: MC/DC is not yet supported.
/*BitmapOffset=*/maybeSwap<IntPtrT>(0),
maybeSwap<IntPtrT>(FunctionPtr),
// TODO: Value profiling is not yet supported.
/*ValuesPtr=*/maybeSwap<IntPtrT>(0),
maybeSwap<uint32_t>(NumCounters),
/*NumValueSites=*/{maybeSwap<uint16_t>(0), maybeSwap<uint16_t>(0)},
// TODO: MC/DC is not yet supported.
/*NumBitmapBytes=*/maybeSwap<uint32_t>(0),
});
NamesVec.push_back(FunctionName.str());
}

View File

@ -434,6 +434,29 @@ Error TextInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) {
Record.Counts.push_back(Count);
}
// Bitmap byte information is indicated with special character.
if (Line->startswith("$")) {
Record.BitmapBytes.clear();
// Read the number of bitmap bytes.
uint64_t NumBitmapBytes;
if ((Line++)->drop_front(1).trim().getAsInteger(0, NumBitmapBytes))
return error(instrprof_error::malformed,
"number of bitmap bytes is not a valid integer");
if (NumBitmapBytes != 0) {
// Read each bitmap and fill our internal storage with the values.
Record.BitmapBytes.reserve(NumBitmapBytes);
for (uint8_t I = 0; I < NumBitmapBytes; ++I) {
if (Line.is_at_end())
return error(instrprof_error::truncated);
uint8_t BitmapByte;
if ((Line++)->getAsInteger(0, BitmapByte))
return error(instrprof_error::malformed,
"bitmap byte is not a valid integer");
Record.BitmapBytes.push_back(BitmapByte);
}
}
}
// Check if value profile data exists and read it if so.
if (Error E = readValueProfileData(Record))
return error(std::move(E));
@ -550,11 +573,14 @@ Error RawInstrProfReader<IntPtrT>::readHeader(
return error(instrprof_error::bad_header);
CountersDelta = swap(Header.CountersDelta);
BitmapDelta = swap(Header.BitmapDelta);
NamesDelta = swap(Header.NamesDelta);
auto NumData = swap(Header.NumData);
auto PaddingBytesBeforeCounters = swap(Header.PaddingBytesBeforeCounters);
auto CountersSize = swap(Header.NumCounters) * getCounterTypeSize();
auto PaddingBytesAfterCounters = swap(Header.PaddingBytesAfterCounters);
auto NumBitmapBytes = swap(Header.NumBitmapBytes);
auto PaddingBytesAfterBitmapBytes = swap(Header.PaddingBytesAfterBitmapBytes);
auto NamesSize = swap(Header.NamesSize);
ValueKindLast = swap(Header.ValueKindLast);
@ -564,8 +590,10 @@ Error RawInstrProfReader<IntPtrT>::readHeader(
// Profile data starts after profile header and binary ids if exist.
ptrdiff_t DataOffset = sizeof(RawInstrProf::Header) + BinaryIdsSize;
ptrdiff_t CountersOffset = DataOffset + DataSize + PaddingBytesBeforeCounters;
ptrdiff_t NamesOffset =
ptrdiff_t BitmapOffset =
CountersOffset + CountersSize + PaddingBytesAfterCounters;
ptrdiff_t NamesOffset =
BitmapOffset + NumBitmapBytes + PaddingBytesAfterBitmapBytes;
ptrdiff_t ValueDataOffset = NamesOffset + NamesSize + PaddingSize;
auto *Start = reinterpret_cast<const char *>(&Header);
@ -594,6 +622,8 @@ Error RawInstrProfReader<IntPtrT>::readHeader(
reinterpret_cast<const uint8_t *>(&Header) + sizeof(RawInstrProf::Header);
CountersStart = Start + CountersOffset;
CountersEnd = CountersStart + CountersSize;
BitmapStart = Start + BitmapOffset;
BitmapEnd = BitmapStart + NumBitmapBytes;
ValueDataStart = reinterpret_cast<const uint8_t *>(Start + ValueDataOffset);
const uint8_t *BufferEnd = (const uint8_t *)DataBuffer->getBufferEnd();
@ -684,6 +714,49 @@ Error RawInstrProfReader<IntPtrT>::readRawCounts(
return success();
}
template <class IntPtrT>
Error RawInstrProfReader<IntPtrT>::readRawBitmapBytes(InstrProfRecord &Record) {
uint32_t NumBitmapBytes = swap(Data->NumBitmapBytes);
Record.BitmapBytes.clear();
Record.BitmapBytes.reserve(NumBitmapBytes);
// It's possible MCDC is either not enabled or only used for some functions
// and not others. So if we record 0 bytes, just move on.
if (NumBitmapBytes == 0)
return success();
// BitmapDelta decreases as we advance to the next data record.
ptrdiff_t BitmapOffset = swap(Data->BitmapPtr) - BitmapDelta;
if (BitmapOffset < 0)
return error(
instrprof_error::malformed,
("bitmap offset " + Twine(BitmapOffset) + " is negative").str());
if (BitmapOffset >= BitmapEnd - BitmapStart)
return error(instrprof_error::malformed,
("bitmap offset " + Twine(BitmapOffset) +
" is greater than the maximum bitmap offset " +
Twine(BitmapEnd - BitmapStart - 1))
.str());
uint64_t MaxNumBitmapBytes =
(BitmapEnd - (BitmapStart + BitmapOffset)) / sizeof(uint8_t);
if (NumBitmapBytes > MaxNumBitmapBytes)
return error(instrprof_error::malformed,
("number of bitmap bytes " + Twine(NumBitmapBytes) +
" is greater than the maximum number of bitmap bytes " +
Twine(MaxNumBitmapBytes))
.str());
for (uint32_t I = 0; I < NumBitmapBytes; I++) {
const char *Ptr = BitmapStart + BitmapOffset + I;
Record.BitmapBytes.push_back(swap(*Ptr));
}
return success();
}
template <class IntPtrT>
Error RawInstrProfReader<IntPtrT>::readValueProfilingData(
InstrProfRecord &Record) {
@ -734,6 +807,10 @@ Error RawInstrProfReader<IntPtrT>::readNextRecord(NamedInstrProfRecord &Record)
if (Error E = readRawCounts(Record))
return error(std::move(E));
// Read raw bitmap bytes and set Record.
if (Error E = readRawBitmapBytes(Record))
return error(std::move(E));
// Read value data and set Record.
if (Error E = readValueProfilingData(Record))
return error(std::move(E));
@ -795,6 +872,7 @@ data_type InstrProfLookupTrait::ReadData(StringRef K, const unsigned char *D,
DataBuffer.clear();
std::vector<uint64_t> CounterBuffer;
std::vector<uint8_t> BitmapByteBuffer;
const unsigned char *End = D + N;
while (D < End) {
@ -823,7 +901,26 @@ data_type InstrProfLookupTrait::ReadData(StringRef K, const unsigned char *D,
CounterBuffer.push_back(
endian::readNext<uint64_t, llvm::endianness::little, unaligned>(D));
DataBuffer.emplace_back(K, Hash, std::move(CounterBuffer));
// Read bitmap bytes for GET_VERSION(FormatVersion) > 10.
if (GET_VERSION(FormatVersion) > IndexedInstrProf::ProfVersion::Version10) {
uint64_t BitmapBytes = 0;
if (D + sizeof(uint64_t) > End)
return data_type();
BitmapBytes =
endian::readNext<uint64_t, llvm::endianness::little, unaligned>(D);
// Read bitmap byte values.
if (D + BitmapBytes * sizeof(uint8_t) > End)
return data_type();
BitmapByteBuffer.clear();
BitmapByteBuffer.reserve(BitmapBytes);
for (uint64_t J = 0; J < BitmapBytes; ++J)
BitmapByteBuffer.push_back(static_cast<uint8_t>(
endian::readNext<uint64_t, llvm::endianness::little, unaligned>(
D)));
}
DataBuffer.emplace_back(K, Hash, std::move(CounterBuffer),
std::move(BitmapByteBuffer));
// Read value profiling data.
if (GET_VERSION(FormatVersion) > IndexedInstrProf::ProfVersion::Version2 &&
@ -1337,6 +1434,16 @@ Error IndexedInstrProfReader::getFunctionCounts(StringRef FuncName,
return success();
}
Error IndexedInstrProfReader::getFunctionBitmapBytes(
StringRef FuncName, uint64_t FuncHash, std::vector<uint8_t> &BitmapBytes) {
Expected<InstrProfRecord> Record = getInstrProfRecord(FuncName, FuncHash);
if (Error E = Record.takeError())
return error(std::move(E));
BitmapBytes = Record.get().BitmapBytes;
return success();
}
Error IndexedInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) {
ArrayRef<NamedInstrProfRecord> Data;

View File

@ -132,6 +132,8 @@ public:
M += sizeof(uint64_t); // The function hash
M += sizeof(uint64_t); // The size of the Counts vector
M += ProfRecord.Counts.size() * sizeof(uint64_t);
M += sizeof(uint64_t); // The size of the Bitmap vector
M += ProfRecord.BitmapBytes.size() * sizeof(uint64_t);
// Value data
M += ValueProfData::getSize(ProfileData.second);
@ -161,6 +163,10 @@ public:
for (uint64_t I : ProfRecord.Counts)
LE.write<uint64_t>(I);
LE.write<uint64_t>(ProfRecord.BitmapBytes.size());
for (uint64_t I : ProfRecord.BitmapBytes)
LE.write<uint64_t>(I);
// Write value data
std::unique_ptr<ValueProfData> VDataPtr =
ValueProfData::serializeFrom(ProfileData.second);
@ -380,6 +386,8 @@ bool InstrProfWriter::shouldEncodeData(const ProfilingData &PD) {
const InstrProfRecord &IPR = Func.second;
if (llvm::any_of(IPR.Counts, [](uint64_t Count) { return Count > 0; }))
return true;
if (llvm::any_of(IPR.BitmapBytes, [](uint8_t Byte) { return Byte > 0; }))
return true;
}
return false;
}
@ -703,6 +711,17 @@ void InstrProfWriter::writeRecordInText(StringRef Name, uint64_t Hash,
for (uint64_t Count : Func.Counts)
OS << Count << "\n";
if (Func.BitmapBytes.size() > 0) {
OS << "# Num Bitmap Bytes:\n$" << Func.BitmapBytes.size() << "\n";
OS << "# Bitmap Byte Values:\n";
for (uint8_t Byte : Func.BitmapBytes) {
OS << "0x";
OS.write_hex(Byte);
OS << "\n";
}
OS << "\n";
}
uint32_t NumValueKinds = Func.getNumValueKinds();
if (!NumValueKinds) {
OS << "\n";

View File

@ -432,6 +432,15 @@ bool InstrProfiling::lowerIntrinsics(Function *F) {
} else if (auto *IPVP = dyn_cast<InstrProfValueProfileInst>(&Instr)) {
lowerValueProfileInst(IPVP);
MadeChange = true;
} else if (auto *IPMP = dyn_cast<InstrProfMCDCBitmapParameters>(&Instr)) {
IPMP->eraseFromParent();
MadeChange = true;
} else if (auto *IPBU = dyn_cast<InstrProfMCDCTVBitmapUpdate>(&Instr)) {
lowerMCDCTestVectorBitmapUpdate(IPBU);
MadeChange = true;
} else if (auto *IPTU = dyn_cast<InstrProfMCDCCondBitmapUpdate>(&Instr)) {
lowerMCDCCondBitmapUpdate(IPTU);
MadeChange = true;
}
}
}
@ -546,19 +555,33 @@ bool InstrProfiling::run(
// the instrumented function. This is counting the number of instrumented
// target value sites to enter it as field in the profile data variable.
for (Function &F : M) {
InstrProfInstBase *FirstProfInst = nullptr;
for (BasicBlock &BB : F)
for (auto I = BB.begin(), E = BB.end(); I != E; I++)
InstrProfCntrInstBase *FirstProfInst = nullptr;
InstrProfMCDCBitmapParameters *FirstProfMCDCParams = nullptr;
for (BasicBlock &BB : F) {
for (auto I = BB.begin(), E = BB.end(); I != E; I++) {
if (auto *Ind = dyn_cast<InstrProfValueProfileInst>(I))
computeNumValueSiteCounts(Ind);
else if (FirstProfInst == nullptr &&
(isa<InstrProfIncrementInst>(I) || isa<InstrProfCoverInst>(I)))
FirstProfInst = dyn_cast<InstrProfInstBase>(I);
else {
if (FirstProfInst == nullptr &&
(isa<InstrProfIncrementInst>(I) || isa<InstrProfCoverInst>(I)))
FirstProfInst = dyn_cast<InstrProfCntrInstBase>(I);
if (FirstProfMCDCParams == nullptr)
FirstProfMCDCParams = dyn_cast<InstrProfMCDCBitmapParameters>(I);
}
}
}
// Value profiling intrinsic lowering requires per-function profile data
// variable to be created first.
if (FirstProfInst != nullptr)
// If the MCDCBitmapParameters intrinsic was seen, create the bitmaps.
if (FirstProfMCDCParams != nullptr) {
static_cast<void>(getOrCreateRegionBitmaps(FirstProfMCDCParams));
}
// Use a profile intrinsic to create the region counters and data variable.
// Also create the data variable based on the MCDCParams.
if (FirstProfInst != nullptr) {
static_cast<void>(getOrCreateRegionCounters(FirstProfInst));
createDataVariable(FirstProfInst, FirstProfMCDCParams);
}
}
for (Function &F : M)
@ -672,7 +695,7 @@ void InstrProfiling::lowerValueProfileInst(InstrProfValueProfileInst *Ind) {
Ind->eraseFromParent();
}
Value *InstrProfiling::getCounterAddress(InstrProfInstBase *I) {
Value *InstrProfiling::getCounterAddress(InstrProfCntrInstBase *I) {
auto *Counters = getOrCreateRegionCounters(I);
IRBuilder<> Builder(I);
@ -712,6 +735,25 @@ Value *InstrProfiling::getCounterAddress(InstrProfInstBase *I) {
return Builder.CreateIntToPtr(Add, Addr->getType());
}
Value *InstrProfiling::getBitmapAddress(InstrProfMCDCTVBitmapUpdate *I) {
auto *Bitmaps = getOrCreateRegionBitmaps(I);
IRBuilder<> Builder(I);
auto *Addr = Builder.CreateConstInBoundsGEP2_32(
Bitmaps->getValueType(), Bitmaps, 0, I->getBitmapIndex()->getZExtValue());
if (isRuntimeCounterRelocationEnabled()) {
LLVMContext &Ctx = M->getContext();
Ctx.diagnose(DiagnosticInfoPGOProfile(
M->getName().data(),
Twine("Runtime counter relocation is presently not supported for MC/DC "
"bitmaps."),
DS_Warning));
}
return Addr;
}
void InstrProfiling::lowerCover(InstrProfCoverInst *CoverInstruction) {
auto *Addr = getCounterAddress(CoverInstruction);
IRBuilder<> Builder(CoverInstruction);
@ -771,6 +813,86 @@ void InstrProfiling::lowerCoverageData(GlobalVariable *CoverageNamesVar) {
CoverageNamesVar->eraseFromParent();
}
void InstrProfiling::lowerMCDCTestVectorBitmapUpdate(
InstrProfMCDCTVBitmapUpdate *Update) {
IRBuilder<> Builder(Update);
auto *Int8Ty = Type::getInt8Ty(M->getContext());
auto *Int8PtrTy = Type::getInt8PtrTy(M->getContext());
auto *Int32Ty = Type::getInt32Ty(M->getContext());
auto *Int64Ty = Type::getInt64Ty(M->getContext());
auto *MCDCCondBitmapAddr = Update->getMCDCCondBitmapAddr();
auto *BitmapAddr = getBitmapAddress(Update);
// Load Temp Val.
// %mcdc.temp = load i32, ptr %mcdc.addr, align 4
auto *Temp = Builder.CreateLoad(Int32Ty, MCDCCondBitmapAddr, "mcdc.temp");
// Calculate byte offset using div8.
// %1 = lshr i32 %mcdc.temp, 3
auto *BitmapByteOffset = Builder.CreateLShr(Temp, 0x3);
// Add byte offset to section base byte address.
// %2 = zext i32 %1 to i64
// %3 = add i64 ptrtoint (ptr @__profbm_test to i64), %2
auto *BitmapByteAddr =
Builder.CreateAdd(Builder.CreatePtrToInt(BitmapAddr, Int64Ty),
Builder.CreateZExtOrBitCast(BitmapByteOffset, Int64Ty));
// Convert to a pointer.
// %4 = inttoptr i32 %3 to ptr
BitmapByteAddr = Builder.CreateIntToPtr(BitmapByteAddr, Int8PtrTy);
// Calculate bit offset into bitmap byte by using div8 remainder (AND ~8)
// %5 = and i32 %mcdc.temp, 7
// %6 = trunc i32 %5 to i8
auto *BitToSet = Builder.CreateTrunc(Builder.CreateAnd(Temp, 0x7), Int8Ty);
// Shift bit offset left to form a bitmap.
// %7 = shl i8 1, %6
auto *ShiftedVal = Builder.CreateShl(Builder.getInt8(0x1), BitToSet);
// Load profile bitmap byte.
// %mcdc.bits = load i8, ptr %4, align 1
auto *Bitmap = Builder.CreateLoad(Int8Ty, BitmapByteAddr, "mcdc.bits");
// Perform logical OR of profile bitmap byte and shifted bit offset.
// %8 = or i8 %mcdc.bits, %7
auto *Result = Builder.CreateOr(Bitmap, ShiftedVal);
// Store the updated profile bitmap byte.
// store i8 %8, ptr %3, align 1
Builder.CreateStore(Result, BitmapByteAddr);
Update->eraseFromParent();
}
void InstrProfiling::lowerMCDCCondBitmapUpdate(
InstrProfMCDCCondBitmapUpdate *Update) {
IRBuilder<> Builder(Update);
auto *Int32Ty = Type::getInt32Ty(M->getContext());
auto *MCDCCondBitmapAddr = Update->getMCDCCondBitmapAddr();
// Load the MCDC temporary value from the stack.
// %mcdc.temp = load i32, ptr %mcdc.addr, align 4
auto *Temp = Builder.CreateLoad(Int32Ty, MCDCCondBitmapAddr, "mcdc.temp");
// Zero-extend the evaluated condition boolean value (0 or 1) by 32bits.
// %1 = zext i1 %tobool to i32
auto *CondV_32 = Builder.CreateZExt(Update->getCondBool(), Int32Ty);
// Shift the boolean value left (by the condition's ID) to form a bitmap.
// %2 = shl i32 %1, <Update->getCondID()>
auto *ShiftedVal = Builder.CreateShl(CondV_32, Update->getCondID());
// Perform logical OR of the bitmap against the loaded MCDC temporary value.
// %3 = or i32 %mcdc.temp, %2
auto *Result = Builder.CreateOr(Temp, ShiftedVal);
// Store the updated temporary value back to the stack.
// store i32 %3, ptr %mcdc.addr, align 4
Builder.CreateStore(Result, MCDCCondBitmapAddr);
Update->eraseFromParent();
}
/// Get the name of a profiling variable for a particular function.
static std::string getVarName(InstrProfInstBase *Inc, StringRef Prefix,
bool &Renamed) {
@ -926,37 +1048,31 @@ static bool needsRuntimeRegistrationOfSectionRange(const Triple &TT) {
return true;
}
GlobalVariable *
InstrProfiling::createRegionCounters(InstrProfInstBase *Inc, StringRef Name,
GlobalValue::LinkageTypes Linkage) {
uint64_t NumCounters = Inc->getNumCounters()->getZExtValue();
auto &Ctx = M->getContext();
GlobalVariable *GV;
if (isa<InstrProfCoverInst>(Inc)) {
auto *CounterTy = Type::getInt8Ty(Ctx);
auto *CounterArrTy = ArrayType::get(CounterTy, NumCounters);
// TODO: `Constant::getAllOnesValue()` does not yet accept an array type.
std::vector<Constant *> InitialValues(NumCounters,
Constant::getAllOnesValue(CounterTy));
GV = new GlobalVariable(*M, CounterArrTy, false, Linkage,
ConstantArray::get(CounterArrTy, InitialValues),
Name);
GV->setAlignment(Align(1));
} else {
auto *CounterTy = ArrayType::get(Type::getInt64Ty(Ctx), NumCounters);
GV = new GlobalVariable(*M, CounterTy, false, Linkage,
Constant::getNullValue(CounterTy), Name);
GV->setAlignment(Align(8));
}
return GV;
void InstrProfiling::maybeSetComdat(GlobalVariable *GV, Function *Fn,
StringRef VarName) {
bool DataReferencedByCode = profDataReferencedByCode(*M);
bool NeedComdat = needsComdatForCounter(*Fn, *M);
bool UseComdat = (NeedComdat || TT.isOSBinFormatELF());
if (!UseComdat)
return;
StringRef GroupName =
TT.isOSBinFormatCOFF() && DataReferencedByCode ? GV->getName() : VarName;
Comdat *C = M->getOrInsertComdat(GroupName);
if (!NeedComdat)
C->setSelectionKind(Comdat::NoDeduplicate);
GV->setComdat(C);
// COFF doesn't allow the comdat group leader to have private linkage, so
// upgrade private linkage to internal linkage to produce a symbol table
// entry.
if (TT.isOSBinFormatCOFF() && GV->hasPrivateLinkage())
GV->setLinkage(GlobalValue::InternalLinkage);
}
GlobalVariable *
InstrProfiling::getOrCreateRegionCounters(InstrProfInstBase *Inc) {
GlobalVariable *InstrProfiling::setupProfileSection(InstrProfInstBase *Inc,
InstrProfSectKind IPSK) {
GlobalVariable *NamePtr = Inc->getName();
auto &PD = ProfileDataMap[NamePtr];
if (PD.RegionCounters)
return PD.RegionCounters;
// Match the linkage and visibility of the name global.
Function *Fn = Inc->getParent()->getParent();
@ -995,42 +1111,100 @@ InstrProfiling::getOrCreateRegionCounters(InstrProfInstBase *Inc) {
// nodeduplicate COMDAT which is lowered to a zero-flag section group. This
// allows -z start-stop-gc to discard the entire group when the function is
// discarded.
bool DataReferencedByCode = profDataReferencedByCode(*M);
bool NeedComdat = needsComdatForCounter(*Fn, *M);
bool Renamed;
std::string CntsVarName =
getVarName(Inc, getInstrProfCountersVarPrefix(), Renamed);
std::string DataVarName =
getVarName(Inc, getInstrProfDataVarPrefix(), Renamed);
auto MaybeSetComdat = [&](GlobalVariable *GV) {
bool UseComdat = (NeedComdat || TT.isOSBinFormatELF());
if (UseComdat) {
StringRef GroupName = TT.isOSBinFormatCOFF() && DataReferencedByCode
? GV->getName()
: CntsVarName;
Comdat *C = M->getOrInsertComdat(GroupName);
if (!NeedComdat)
C->setSelectionKind(Comdat::NoDeduplicate);
GV->setComdat(C);
// COFF doesn't allow the comdat group leader to have private linkage, so
// upgrade private linkage to internal linkage to produce a symbol table
// entry.
if (TT.isOSBinFormatCOFF() && GV->hasPrivateLinkage())
GV->setLinkage(GlobalValue::InternalLinkage);
}
};
GlobalVariable *Ptr;
StringRef VarPrefix;
std::string VarName;
if (IPSK == IPSK_cnts) {
VarPrefix = getInstrProfCountersVarPrefix();
VarName = getVarName(Inc, VarPrefix, Renamed);
InstrProfCntrInstBase *CntrIncrement = dyn_cast<InstrProfCntrInstBase>(Inc);
Ptr = createRegionCounters(CntrIncrement, VarName, Linkage);
} else if (IPSK == IPSK_bitmap) {
VarPrefix = getInstrProfBitmapVarPrefix();
VarName = getVarName(Inc, VarPrefix, Renamed);
InstrProfMCDCBitmapInstBase *BitmapUpdate =
dyn_cast<InstrProfMCDCBitmapInstBase>(Inc);
Ptr = createRegionBitmaps(BitmapUpdate, VarName, Linkage);
} else {
llvm_unreachable("Profile Section must be for Counters or Bitmaps");
}
Ptr->setVisibility(Visibility);
// Put the counters and bitmaps in their own sections so linkers can
// remove unneeded sections.
Ptr->setSection(getInstrProfSectionName(IPSK, TT.getObjectFormat()));
Ptr->setLinkage(Linkage);
maybeSetComdat(Ptr, Fn, VarName);
return Ptr;
}
GlobalVariable *
InstrProfiling::createRegionBitmaps(InstrProfMCDCBitmapInstBase *Inc,
StringRef Name,
GlobalValue::LinkageTypes Linkage) {
uint64_t NumBytes = Inc->getNumBitmapBytes()->getZExtValue();
auto *BitmapTy = ArrayType::get(Type::getInt8Ty(M->getContext()), NumBytes);
auto GV = new GlobalVariable(*M, BitmapTy, false, Linkage,
Constant::getNullValue(BitmapTy), Name);
GV->setAlignment(Align(1));
return GV;
}
GlobalVariable *
InstrProfiling::getOrCreateRegionBitmaps(InstrProfMCDCBitmapInstBase *Inc) {
GlobalVariable *NamePtr = Inc->getName();
auto &PD = ProfileDataMap[NamePtr];
if (PD.RegionBitmaps)
return PD.RegionBitmaps;
// If RegionBitmaps doesn't already exist, create it by first setting up
// the corresponding profile section.
auto *BitmapPtr = setupProfileSection(Inc, IPSK_bitmap);
PD.RegionBitmaps = BitmapPtr;
return PD.RegionBitmaps;
}
GlobalVariable *
InstrProfiling::createRegionCounters(InstrProfCntrInstBase *Inc, StringRef Name,
GlobalValue::LinkageTypes Linkage) {
uint64_t NumCounters = Inc->getNumCounters()->getZExtValue();
LLVMContext &Ctx = M->getContext();
auto &Ctx = M->getContext();
GlobalVariable *GV;
if (isa<InstrProfCoverInst>(Inc)) {
auto *CounterTy = Type::getInt8Ty(Ctx);
auto *CounterArrTy = ArrayType::get(CounterTy, NumCounters);
// TODO: `Constant::getAllOnesValue()` does not yet accept an array type.
std::vector<Constant *> InitialValues(NumCounters,
Constant::getAllOnesValue(CounterTy));
GV = new GlobalVariable(*M, CounterArrTy, false, Linkage,
ConstantArray::get(CounterArrTy, InitialValues),
Name);
GV->setAlignment(Align(1));
} else {
auto *CounterTy = ArrayType::get(Type::getInt64Ty(Ctx), NumCounters);
GV = new GlobalVariable(*M, CounterTy, false, Linkage,
Constant::getNullValue(CounterTy), Name);
GV->setAlignment(Align(8));
}
return GV;
}
auto *CounterPtr = createRegionCounters(Inc, CntsVarName, Linkage);
CounterPtr->setVisibility(Visibility);
CounterPtr->setSection(
getInstrProfSectionName(IPSK_cnts, TT.getObjectFormat()));
CounterPtr->setLinkage(Linkage);
MaybeSetComdat(CounterPtr);
GlobalVariable *
InstrProfiling::getOrCreateRegionCounters(InstrProfCntrInstBase *Inc) {
GlobalVariable *NamePtr = Inc->getName();
auto &PD = ProfileDataMap[NamePtr];
if (PD.RegionCounters)
return PD.RegionCounters;
// If RegionCounters doesn't already exist, create it by first setting up
// the corresponding profile section.
auto *CounterPtr = setupProfileSection(Inc, IPSK_cnts);
PD.RegionCounters = CounterPtr;
if (DebugInfoCorrelate) {
LLVMContext &Ctx = M->getContext();
Function *Fn = Inc->getParent()->getParent();
if (auto *SP = Fn->getSubprogram()) {
DIBuilder DB(*M, true, SP->getUnit());
Metadata *FunctionNameAnnotation[] = {
@ -1059,8 +1233,50 @@ InstrProfiling::getOrCreateRegionCounters(InstrProfInstBase *Inc) {
CounterPtr->addDebugInfo(DICounter);
DB.finalize();
}
// Mark the counter variable as used so that it isn't optimized out.
CompilerUsedVars.push_back(PD.RegionCounters);
}
return PD.RegionCounters;
}
void InstrProfiling::createDataVariable(InstrProfCntrInstBase *Inc,
InstrProfMCDCBitmapParameters *Params) {
// When debug information is correlated to profile data, a data variable
// is not needed.
if (DebugInfoCorrelate)
return;
GlobalVariable *NamePtr = Inc->getName();
auto &PD = ProfileDataMap[NamePtr];
LLVMContext &Ctx = M->getContext();
Function *Fn = Inc->getParent()->getParent();
GlobalValue::LinkageTypes Linkage = NamePtr->getLinkage();
GlobalValue::VisibilityTypes Visibility = NamePtr->getVisibility();
// Due to the limitation of binder as of 2021/09/28, the duplicate weak
// symbols in the same csect won't be discarded. When there are duplicate weak
// symbols, we can NOT guarantee that the relocations get resolved to the
// intended weak symbol, so we can not ensure the correctness of the relative
// CounterPtr, so we have to use private linkage for counter and data symbols.
if (TT.isOSBinFormatXCOFF()) {
Linkage = GlobalValue::PrivateLinkage;
Visibility = GlobalValue::DefaultVisibility;
}
bool DataReferencedByCode = profDataReferencedByCode(*M);
bool NeedComdat = needsComdatForCounter(*Fn, *M);
bool Renamed;
// The Data Variable section is anchored to profile counters.
std::string CntsVarName =
getVarName(Inc, getInstrProfCountersVarPrefix(), Renamed);
std::string DataVarName =
getVarName(Inc, getInstrProfDataVarPrefix(), Renamed);
auto *Int8PtrTy = Type::getInt8PtrTy(Ctx);
// Allocate statically the array of pointers to value profile nodes for
// the current function.
@ -1078,16 +1294,17 @@ InstrProfiling::getOrCreateRegionCounters(InstrProfInstBase *Inc) {
ValuesVar->setSection(
getInstrProfSectionName(IPSK_vals, TT.getObjectFormat()));
ValuesVar->setAlignment(Align(8));
MaybeSetComdat(ValuesVar);
maybeSetComdat(ValuesVar, Fn, CntsVarName);
ValuesPtrExpr =
ConstantExpr::getBitCast(ValuesVar, Type::getInt8PtrTy(Ctx));
}
if (DebugInfoCorrelate) {
// Mark the counter variable as used so that it isn't optimized out.
CompilerUsedVars.push_back(PD.RegionCounters);
return PD.RegionCounters;
}
uint64_t NumCounters = Inc->getNumCounters()->getZExtValue();
auto *CounterPtr = PD.RegionCounters;
uint64_t NumBitmapBytes = 0;
if (Params != nullptr)
NumBitmapBytes = Params->getNumBitmapBytes()->getZExtValue();
// Create data variable.
auto *IntPtrTy = M->getDataLayout().getIntPtrType(M->getContext());
@ -1130,6 +1347,16 @@ InstrProfiling::getOrCreateRegionCounters(InstrProfInstBase *Inc) {
ConstantExpr::getSub(ConstantExpr::getPtrToInt(CounterPtr, IntPtrTy),
ConstantExpr::getPtrToInt(Data, IntPtrTy));
// Bitmaps are relative to the same data variable as profile counters.
GlobalVariable *BitmapPtr = PD.RegionBitmaps;
Constant *RelativeBitmapPtr = ConstantInt::get(IntPtrTy, 0);
if (BitmapPtr != nullptr) {
RelativeBitmapPtr =
ConstantExpr::getSub(ConstantExpr::getPtrToInt(BitmapPtr, IntPtrTy),
ConstantExpr::getPtrToInt(Data, IntPtrTy));
}
Constant *DataVals[] = {
#define INSTR_PROF_DATA(Type, LLVMType, Name, Init) Init,
#include "llvm/ProfileData/InstrProfData.inc"
@ -1139,7 +1366,7 @@ InstrProfiling::getOrCreateRegionCounters(InstrProfInstBase *Inc) {
Data->setVisibility(Visibility);
Data->setSection(getInstrProfSectionName(IPSK_data, TT.getObjectFormat()));
Data->setAlignment(Align(INSTR_PROF_DATA_ALIGNMENT));
MaybeSetComdat(Data);
maybeSetComdat(Data, Fn, CntsVarName);
PD.DataVar = Data;
@ -1151,8 +1378,6 @@ InstrProfiling::getOrCreateRegionCounters(InstrProfInstBase *Inc) {
NamePtr->setLinkage(GlobalValue::PrivateLinkage);
// Collect the referenced names to be used by emitNameData.
ReferencedNames.push_back(NamePtr);
return PD.RegionCounters;
}
void InstrProfiling::emitVNodes() {

View File

@ -0,0 +1,53 @@
; Check that MC/DC intrinsics are properly lowered
; RUN: opt < %s -passes=instrprof -S | FileCheck %s
; RUN: opt < %s -passes=instrprof -runtime-counter-relocation -S 2>&1 | FileCheck %s --check-prefix RELOC
; RELOC: Runtime counter relocation is presently not supported for MC/DC bitmaps
target triple = "x86_64-unknown-linux-gnu"
@__profn_test = private constant [4 x i8] c"test"
; CHECK: @__profbm_test = private global [1 x i8] zeroinitializer, section "__llvm_prf_bits", comdat, align 1
define dso_local void @test(i32 noundef %A) {
entry:
%A.addr = alloca i32, align 4
%mcdc.addr = alloca i32, align 4
call void @llvm.instrprof.cover(ptr @__profn_test, i64 99278, i32 5, i32 0)
; CHECK: store i8 0, ptr @__profc_test, align 1
call void @llvm.instrprof.mcdc.parameters(ptr @__profn_test, i64 99278, i32 1)
store i32 0, ptr %mcdc.addr, align 4
%0 = load i32, ptr %A.addr, align 4
%tobool = icmp ne i32 %0, 0
call void @llvm.instrprof.mcdc.condbitmap.update(ptr @__profn_test, i64 99278, i32 0, ptr %mcdc.addr, i1 %tobool)
; CHECK: %mcdc.temp = load i32, ptr %mcdc.addr, align 4
; CHECK-NEXT: %1 = zext i1 %tobool to i32
; CHECK-NEXT: %2 = shl i32 %1, 0
; CHECK-NEXT: %3 = or i32 %mcdc.temp, %2
; CHECK-NEXT: store i32 %3, ptr %mcdc.addr, align 4
call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @__profn_test, i64 99278, i32 1, i32 0, ptr %mcdc.addr)
; CHECK: %mcdc.temp1 = load i32, ptr %mcdc.addr, align 4
; CHECK-NEXT: %4 = lshr i32 %mcdc.temp1, 3
; CHECK-NEXT: %5 = zext i32 %4 to i64
; CHECK-NEXT: %6 = add i64 ptrtoint (ptr @__profbm_test to i64), %5
; CHECK-NEXT: %7 = inttoptr i64 %6 to ptr
; CHECK-NEXT: %8 = and i32 %mcdc.temp1, 7
; CHECK-NEXT: %9 = trunc i32 %8 to i8
; CHECK-NEXT: %10 = shl i8 1, %9
; CHECK-NEXT: %mcdc.bits = load i8, ptr %7, align 1
; CHECK-NEXT: %11 = or i8 %mcdc.bits, %10
; CHECK-NEXT: store i8 %11, ptr %7, align 1
ret void
}
declare void @llvm.instrprof.cover(ptr, i64, i32, i32)
declare void @llvm.instrprof.mcdc.parameters(ptr, i64, i32)
declare void @llvm.instrprof.mcdc.condbitmap.update(ptr, i64, i32, ptr, i1)
declare void @llvm.instrprof.mcdc.tvbitmap.update(ptr, i64, i32, i32, ptr)

View File

@ -13,9 +13,9 @@ $foo = comdat any
; CHECK: @__llvm_profile_raw_version = hidden constant i64 {{[0-9]+}}, comdat
; CHECK-NOT: __profn__stdin__foo
; CHECK: @__profc__stdin__foo.[[#FOO_HASH]] = private global [1 x i64] zeroinitializer, section "__llvm_prf_cnts", comdat, align 8
; CHECK: @__profd__stdin__foo.[[#FOO_HASH]] = private global { i64, i64, i64, ptr, ptr, i32, [2 x i16] } { i64 {{.*}}, i64 [[#FOO_HASH]], i64 sub (i64 ptrtoint (ptr @__profc__stdin__foo.742261418966908927 to i64), i64 ptrtoint (ptr @__profd__stdin__foo.742261418966908927 to i64)), ptr null
; CHECK: @__profd__stdin__foo.[[#FOO_HASH]] = private global { i64, i64, i64, i64, ptr, ptr, i32, [2 x i16], i32 } { i64 {{.*}}, i64 [[#FOO_HASH]], i64 sub (i64 ptrtoint (ptr @__profc__stdin__foo.742261418966908927 to i64), i64 ptrtoint (ptr @__profd__stdin__foo.742261418966908927 to i64)), i64 0, ptr null
; CHECK-NOT: @foo
; CHECK-SAME: , ptr null, i32 1, [2 x i16] zeroinitializer }, section "__llvm_prf_data", comdat($__profc__stdin__foo.[[#FOO_HASH]]), align 8
; CHECK-SAME: , ptr null, i32 1, [2 x i16] zeroinitializer, i32 0 }, section "__llvm_prf_data", comdat($__profc__stdin__foo.[[#FOO_HASH]]), align 8
; CHECK: @__llvm_prf_nm
; CHECK: @llvm.compiler.used

View File

@ -5,13 +5,15 @@
// INSTR_PROF_RAW_HEADER(uint64_t, BinaryIdsSize, __llvm_write_binary_ids(NULL))
// INSTR_PROF_RAW_HEADER(uint64_t, DataSize, DataSize)
// INSTR_PROF_RAW_HEADER(uint64_t, CountersSize, CountersSize)
// INSTR_PROF_RAW_HEADER(uint64_t, NumBitmaskBytes, NumBitmaskBytes)
// INSTR_PROF_RAW_HEADER(uint64_t, NamesSize, NamesSize)
// INSTR_PROF_RAW_HEADER(uint64_t, CountersDelta, (uintptr_t)CountersBegin)
// INSTR_PROF_RAW_HEADER(uint64_t, BitmaskDelta, (uintptr_t)BitmaskBegin)
// INSTR_PROF_RAW_HEADER(uint64_t, NamesDelta, (uintptr_t)NamesBegin)
// INSTR_PROF_RAW_HEADER(uint64_t, ValueKindLast, IPVK_Last)
RUN: printf '\201rforpl\377' > %t.profraw
RUN: printf '\10\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\11\0\0\0\0\0\0\0' >> %t.profraw
// There will be 2 20-byte binary IDs, so the total Binary IDs size will be 64 bytes.
// 2 * 8 binary ID sizes
// + 2 * 20 binary IDs (of size 20)
@ -23,8 +25,11 @@ RUN: printf '\2\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\3\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\20\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\4\0\1\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\4\0\2\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
@ -51,14 +56,18 @@ RUN: printf '\1\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\4\0\1\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\1\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\067\265\035\031\112\165\023\344' >> %t.profraw
RUN: printf '\02\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\xd8\xff\3\0\1\0\0\0' >> %t.profraw
RUN: printf '\xc8\xff\3\0\1\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\02\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\023\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\067\0\0\0\0\0\0\0' >> %t.profraw

View File

@ -87,3 +87,26 @@ large_numbers
# FORMATV4: Total functions: 3
# FORMATV4: Maximum function count: 2305843009213693952
# FORMATV4: Maximum internal block count: 1152921504606846976
# RUN: llvm-profdata show %S/Inputs/compat.profdata.v10 -all-functions --counts | FileCheck %s -check-prefix=FORMATV10
# FORMATV10: Counters:
# FORMATV10: large_numbers:
# FORMATV10: Hash: 0x3fffffffffffffff
# FORMATV10: Counters: 6
# FORMATV10: Function count: 2305843009213693952
# FORMATV10: Block counts: [1152921504606846976, 576460752303423488, 288230376151711744, 144115188075855872, 72057594037927936]
# FORMATV10: name with spaces:
# FORMATV10: Hash: 0x0000000000000400
# FORMATV10: Counters: 2
# FORMATV10: Function count: 0
# FORMATV10: Block counts: [0]
# FORMATV10: function_count_only:
# FORMATV10: Hash: 0x0000000000000000
# FORMATV10: Counters: 1
# FORMATV10: Function count: 97531
# FORMATV10: Block counts: []
# FORMATV10: Functions shown: 3
# FORMATV10: Total functions: 3
# FORMATV10: Maximum function count: 2305843009213693952
# FORMATV10: Maximum internal block count: 1152921504606846976

View File

@ -1,5 +1,5 @@
RUN: printf '\201rforpl\377' > %t.profraw
RUN: printf '\10\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\11\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\40\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
@ -9,6 +9,9 @@ RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
// Check for a corrupted size being too large past the end of the file.
RUN: printf '\7\7\7\7\7\7\7\7' >> %t.profraw

View File

@ -5,20 +5,25 @@
// INSTR_PROF_RAW_HEADER(uint64_t, BinaryIdsSize, __llvm_write_binary_ids(NULL))
// INSTR_PROF_RAW_HEADER(uint64_t, DataSize, DataSize)
// INSTR_PROF_RAW_HEADER(uint64_t, CountersSize, CountersSize)
// INSTR_PROF_RAW_HEADER(uint64_t, NumBitmaskBytes, NumBitmaskBytes)
// INSTR_PROF_RAW_HEADER(uint64_t, NamesSize, NamesSize)
// INSTR_PROF_RAW_HEADER(uint64_t, CountersDelta, (uintptr_t)CountersBegin)
// INSTR_PROF_RAW_HEADER(uint64_t, BitmaskDelta, (uintptr_t)BitmaskBegin)
// INSTR_PROF_RAW_HEADER(uint64_t, NamesDelta, (uintptr_t)NamesBegin)
// INSTR_PROF_RAW_HEADER(uint64_t, ValueKindLast, IPVK_Last)
RUN: printf '\201rforpl\377' > %t.profraw
RUN: printf '\10\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\11\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\1\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\1\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\10\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\4\0\1\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\4\0\2\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
@ -35,7 +40,9 @@ RUN: printf '\1\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\4\0\1\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\1\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\023\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\3\0foo\0\0\0' >> %t.profraw

View File

@ -5,20 +5,26 @@
// INSTR_PROF_RAW_HEADER(uint64_t, BinaryIdsSize, __llvm_write_binary_ids(NULL))
// INSTR_PROF_RAW_HEADER(uint64_t, DataSize, DataSize)
// INSTR_PROF_RAW_HEADER(uint64_t, CountersSize, CountersSize)
// INSTR_PROF_RAW_HEADER(uint64_t, NumBitmaskBytes, NumBitmaskBytes)
// INSTR_PROF_RAW_HEADER(uint64_t, NamesSize, NamesSize)
// INSTR_PROF_RAW_HEADER(uint64_t, CountersDelta, (uintptr_t)CountersBegin)
// INSTR_PROF_RAW_HEADER(uint64_t, BitmaskDelta, (uintptr_t)BitmaskBegin)
// INSTR_PROF_RAW_HEADER(uint64_t, NamesDelta, (uintptr_t)NamesBegin)
// INSTR_PROF_RAW_HEADER(uint64_t, ValueKindLast, IPVK_Last)
RUN: printf '\201rforpl\377' > %t.profraw
RUN: printf '\10\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\11\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\1\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\1\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\10\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\4\0\1\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\4\0\2\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
@ -35,8 +41,10 @@ RUN: printf '\1\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\4\0\1\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
// Make NumCounters = 0 so that we get "number of counters is zero" error message
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\023\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\3\0foo\0\0\0' >> %t.profraw

View File

@ -5,20 +5,25 @@
// INSTR_PROF_RAW_HEADER(uint64_t, BinaryIdsSize, __llvm_write_binary_ids(NULL))
// INSTR_PROF_RAW_HEADER(uint64_t, DataSize, DataSize)
// INSTR_PROF_RAW_HEADER(uint64_t, CountersSize, CountersSize)
// INSTR_PROF_RAW_HEADER(uint64_t, NumBitmaskBytes, NumBitmaskBytes)
// INSTR_PROF_RAW_HEADER(uint64_t, NamesSize, NamesSize)
// INSTR_PROF_RAW_HEADER(uint64_t, CountersDelta, (uintptr_t)CountersBegin)
// INSTR_PROF_RAW_HEADER(uint64_t, BitmaskDelta, (uintptr_t)BitmaskBegin)
// INSTR_PROF_RAW_HEADER(uint64_t, NamesDelta, (uintptr_t)NamesBegin)
// INSTR_PROF_RAW_HEADER(uint64_t, ValueKindLast, IPVK_Last)
RUN: printf '\201rforpl\377' > %t.profraw
RUN: printf '\10\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\11\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\1\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\2\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\10\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\6\0\1\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\6\0\2\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
@ -38,10 +43,12 @@ RUN: printf '\02\0\0\0\0\0\0\0' >> %t.profraw
// Octal '\11' is 9 in decimal: this should push CounterOffset to 1. As there are two counters,
// the profile reader should error out.
RUN: printf '\11\0\6\0\1\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\02\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
// Counter Section

View File

@ -0,0 +1,201 @@
# Test MC/DC bitmap reading and merging.
# Merge as profdata.
RUN: split-file %s %t
RUN: llvm-profdata merge %t/mcdc-1.proftext %t/mcdc-2.proftext -o %t.profdata
RUN: llvm-profdata show %t.profdata --text -all-functions | FileCheck %s --check-prefix=MCDC
# Merge as proftext.
RUN: llvm-profdata merge %t/mcdc-1.proftext %t/mcdc-2.proftext -o %t.proftext
RUN: llvm-profdata show %t.proftext --text -all-functions | FileCheck %s --check-prefix=MCDC
MCDC: # Num Bitmap Bytes:
MCDC-NEXT: $1
MCDC-NEXT: # Bitmap Byte Values:
MCDC-NEXT: a
MCDC: # Num Bitmap Bytes:
MCDC-NEXT: $2
MCDC-NEXT: # Bitmap Byte Values:
MCDC-NEXT: 0x29
MCDC-NEXT: 0x0
# Merge as profdata.
RUN: llvm-profdata merge %t/mcdc-3.proftext %t/mcdc-4.proftext -o %t.profdata
RUN: llvm-profdata show %t.profdata --text -all-functions | FileCheck %s --check-prefix=MCDC2
# Merge as proftext.
RUN: llvm-profdata merge %t/mcdc-3.proftext %t/mcdc-4.proftext -o %t.proftext
RUN: llvm-profdata show %t.proftext --text -all-functions | FileCheck %s --check-prefix=MCDC2
MCDC2: # Num Bitmap Bytes:
MCDC2-NEXT: $8
MCDC2-NEXT: # Bitmap Byte Values:
MCDC2-NEXT: 0x1
MCDC2-NEXT: 0x2
MCDC2-NEXT: 0x3
MCDC2-NEXT: 0xf
MCDC2-NEXT: 0xf
MCDC2-NEXT: 0xe
MCDC2-NEXT: 0xf
MCDC2-NEXT: 0xa
# Incompatible size mismatch.
RUN: llvm-profdata merge %t/mcdc-2.proftext %t/mcdc-4.proftext -o %t.profdata 2>&1 | FileCheck %s --check-prefix=MCDC3
# Merge as proftext
RUN: llvm-profdata merge %t/mcdc-2.proftext %t/mcdc-4.proftext -o %t.proftext 2>&1 | FileCheck %s --check-prefix=MCDC3
MCDC3: function bitmap size change detected (bitmap size mismatch)
# Invalid number of bitmap bytes.
RUN: not llvm-profdata merge %t/mcdc-3.proftext %t/mcdc-err0.proftext -o %t.proftext 2>&1 | FileCheck %s --check-prefix=MCDC4
MCDC4: malformed instrumentation profile data: number of bitmap bytes is not a valid integer
# Invalid bitmap byte.
RUN: not llvm-profdata merge %t/mcdc-3.proftext %t/mcdc-err1.proftext -o %t.proftext 2>&1 | FileCheck %s --check-prefix=MCDC5
MCDC5: malformed instrumentation profile data: bitmap byte is not a valid integer
;--- mcdc-1.proftext
main
# Func Hash:
702755447896
# Num Counters:
4
# Counter Values:
1
0
1
0
# Num Bitmask Bytes:
$1
# Bitmask Byte Values:
2
;--- mcdc-2.proftext
main
# Func Hash:
702755447896
# Num Counters:
4
# Counter Values:
1
1
1
1
# Num Bitmask Bytes:
$1
# Bitmask Byte Values:
8
test3
# Func Hash:
15288018065
# Num Counters:
6
# Counter Values:
4
2
1
0
0
2
# Num Bitmask Bytes:
$0x2
# Bitmask Byte Values:
0x29
0x0
;--- mcdc-3.proftext
test3
# Func Hash:
15288018065
# Num Counters:
6
# Counter Values:
4
2
1
0
0
2
# Num Bitmask Bytes:
$8
# Bitmask Byte Values:
0x0
0x2
0x3
0xf
0xf
0xa
0xc
0x2
;--- mcdc-4.proftext
test3
# Func Hash:
15288018065
# Num Counters:
6
# Counter Values:
4
2
1
0
0
2
# Num Bitmask Bytes:
$ 8
# Bitmask Byte Values:
1
2
3
4
5
6
7
8
;--- mcdc-err0.proftext
test3
# Func Hash:
15288018065
# Num Counters:
6
# Counter Values:
4
2
1
0
0
2
# Num Bitmask Bytes:
$8.9
# Bitmask Byte Values:
1
2
3
4
5
6
7
8
;--- mcdc-err1.proftext
test3
# Func Hash:
15288018065
# Num Counters:
6
# Counter Values:
4
2
1
0
0
2
# Num Bitmask Bytes:
$8
# Bitmask Byte Values:
1
2
3
4
5.4
6
7
8

View File

@ -1,5 +1,5 @@
RUN: printf '\201rforpl\377' > %t.profraw
RUN: printf '\10\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\11\0\0\0\0\0\0\0' >> %t.profraw
// We should fail on this because the binary IDs is not a multiple of 8 bytes.
RUN: printf '\77\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw

View File

@ -8,6 +8,9 @@ RUN: printf '\0\0\0\0\0\0\0\2' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\3' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\20' >> %t
RUN: printf '\0\0\0\1\0\4\0\0' >> %t
RUN: printf '\0\0\0\2\0\4\0\0' >> %t

View File

@ -1,37 +1,46 @@
RUN: printf '\377lprofR\201' > %t
RUN: printf '\0\0\0\0\0\0\0\10' >> %t
RUN: printf '\0\0\0\0\0\0\0\11' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\2' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\3' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\4' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\20' >> %t
RUN: printf '\0\0\0\0\1\0\0\0' >> %t
RUN: printf '\0\0\0\0\3\0\0\0' >> %t
RUN: printf '\0\0\0\0\2\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\134\370\302\114\333\030\275\254' >> %t
RUN: printf '\0\0\0\0\0\0\0\1' >> %t
RUN: printf '\1\0\0\0' >> %t
RUN: printf '\3\0\0\0' >> %t
RUN: printf '\0\0\0\0' >> %t
RUN: printf '\0\0\0\0' >> %t
RUN: printf '\0\0\0\1' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\3' >> %t
RUN: printf '\0\0\0\0' >> %t
RUN: printf '\344\023\165\112\031\035\265\067' >> %t
RUN: printf '\0\0\0\0\0\0\0\2' >> %t
RUN: printf '\0\xff\xff\xe0' >> %t
RUN: printf '\0\xff\xff\xd8' >> %t
RUN: printf '\2\xff\xff\xd3' >> %t
RUN: printf '\0\0\0\0' >> %t
RUN: printf '\0\0\0\0' >> %t
RUN: printf '\0\0\0\2' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\1' >> %t
RUN: printf '\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\023' >> %t
RUN: printf '\0\0\0\0\0\0\0\067' >> %t
RUN: printf '\0\0\0\0\0\0\0\101' >> %t
RUN: printf '\125\125\125\052' >> %t
RUN: printf '\7\0foo\1bar\0\0\0\0\0\0\0' >> %t
RUN: llvm-profdata show %t -all-functions -counts | FileCheck %s
RUN: llvm-profdata show %t -all-functions -text | FileCheck %s -check-prefix=MCDC
CHECK: Counters:
CHECK: foo:
@ -48,3 +57,14 @@ CHECK: Functions shown: 2
CHECK: Total functions: 2
CHECK: Maximum function count: 55
CHECK: Maximum internal block count: 65
MCDC: Num Bitmap Bytes:
MCDC-NEXT: $3
MCDC-NEXT: Bitmap Byte Values:
MCDC-NEXT: 55
MCDC-NEXT: 55
MCDC-NEXT: 55
MCDC: Num Bitmap Bytes:
MCDC-NEXT: $1
MCDC-NEXT: Bitmap Byte Values:
MCDC-NEXT: 0x2a

View File

@ -1,37 +1,46 @@
RUN: printf '\201Rforpl\377' > %t
RUN: printf '\10\0\0\0\0\0\0\0' >> %t
RUN: printf '\11\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\2\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\3\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\4\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\20\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\1\0\0\0\0' >> %t
RUN: printf '\0\0\0\3\0\0\0\0' >> %t
RUN: printf '\0\0\0\2\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\254\275\030\333\114\302\370\134' >> %t
RUN: printf '\1\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\1' >> %t
RUN: printf '\0\0\0\3' >> %t
RUN: printf '\0\0\0\0' >> %t
RUN: printf '\0\0\0\0' >> %t
RUN: printf '\1\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\3\0\0\0' >> %t
RUN: printf '\0\0\0\0' >> %t
RUN: printf '\067\265\035\031\112\165\023\344' >> %t
RUN: printf '\02\0\0\0\0\0\0\0' >> %t
RUN: printf '\xe0\xff\xff\0' >> %t
RUN: printf '\xd8\xff\xff\0' >> %t
RUN: printf '\xd3\xff\xff\2' >> %t
RUN: printf '\0\0\0\0' >> %t
RUN: printf '\0\0\0\0' >> %t
RUN: printf '\2\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\1\0\0\0' >> %t
RUN: printf '\0\0\0\0' >> %t
RUN: printf '\023\0\0\0\0\0\0\0' >> %t
RUN: printf '\067\0\0\0\0\0\0\0' >> %t
RUN: printf '\101\0\0\0\0\0\0\0' >> %t
RUN: printf '\125\125\125\052' >> %t
RUN: printf '\7\0foo\1bar\0\0\0\0\0\0\0' >> %t
RUN: llvm-profdata show %t -all-functions -counts | FileCheck %s
RUN: llvm-profdata show %t -all-functions -text | FileCheck %s -check-prefix=MCDC
CHECK: Counters:
CHECK: foo:
@ -48,3 +57,14 @@ CHECK: Functions shown: 2
CHECK: Total functions: 2
CHECK: Maximum function count: 55
CHECK: Maximum internal block count: 65
MCDC: Num Bitmap Bytes:
MCDC-NEXT: $3
MCDC-NEXT: Bitmap Byte Values:
MCDC-NEXT: 55
MCDC-NEXT: 55
MCDC-NEXT: 55
MCDC: Num Bitmap Bytes:
MCDC-NEXT: $1
MCDC-NEXT: Bitmap Byte Values:
MCDC-NEXT: 0x2a

View File

@ -1,35 +1,44 @@
RUN: printf '\377lprofr\201' > %t
RUN: printf '\0\0\0\0\0\0\0\10' >> %t
RUN: printf '\0\0\0\0\0\0\0\11' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\2' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\3' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\4' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\20' >> %t
RUN: printf '\0\0\0\1\0\4\0\0' >> %t
RUN: printf '\0\0\0\3\0\4\0\0' >> %t
RUN: printf '\0\0\0\2\0\4\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\134\370\302\114\333\030\275\254' >> %t
RUN: printf '\0\0\0\0\0\0\0\1' >> %t
RUN: printf '\0\0\0\1\0\4\0\0' >> %t
RUN: printf '\0\0\0\3\0\4\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\1\0\0\0\0' >> %t
RUN: printf '\0\0\0\3\0\0\0\0' >> %t
RUN: printf '\344\023\165\112\031\035\265\067' >> %t
RUN: printf '\0\0\0\0\0\0\0\02' >> %t
RUN: printf '\0\0\0\1\0\3\xff\xd8' >> %t
RUN: printf '\0\0\0\1\0\3\xff\xc8' >> %t
RUN: printf '\0\0\0\3\0\3\xff\xc3' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\02\0\0\0\0' >> %t
RUN: printf '\0\0\0\1\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\023' >> %t
RUN: printf '\0\0\0\0\0\0\0\067' >> %t
RUN: printf '\0\0\0\0\0\0\0\101' >> %t
RUN: printf '\125\125\125\052' >> %t
RUN: printf '\7\0foo\1bar\0\0\0\0\0\0\0' >> %t
RUN: llvm-profdata show %t -all-functions -counts | FileCheck %s
RUN: llvm-profdata show %t -all-functions -text | FileCheck %s -check-prefix=MCDC
CHECK: Counters:
CHECK: foo:
@ -46,3 +55,14 @@ CHECK: Functions shown: 2
CHECK: Total functions: 2
CHECK: Maximum function count: 55
CHECK: Maximum internal block count: 65
MCDC: Num Bitmap Bytes:
MCDC-NEXT: $3
MCDC-NEXT: Bitmap Byte Values:
MCDC-NEXT: 55
MCDC-NEXT: 55
MCDC-NEXT: 55
MCDC: Num Bitmap Bytes:
MCDC-NEXT: $1
MCDC-NEXT: Bitmap Byte Values:
MCDC-NEXT: 0x2a

View File

@ -1,35 +1,44 @@
RUN: printf '\201rforpl\377' > %t
RUN: printf '\10\0\0\0\0\0\0\0' >> %t
RUN: printf '\11\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\2\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\3\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\4\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\20\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\4\0\1\0\0\0' >> %t
RUN: printf '\0\0\4\0\3\0\0\0' >> %t
RUN: printf '\0\0\4\0\2\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\254\275\030\333\114\302\370\134' >> %t
RUN: printf '\1\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\4\0\1\0\0\0' >> %t
RUN: printf '\0\0\4\0\3\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\1\0\0\0\0\0\0\0' >> %t
RUN: printf '\3\0\0\0\0\0\0\0' >> %t
RUN: printf '\067\265\035\031\112\165\023\344' >> %t
RUN: printf '\02\0\0\0\0\0\0\0' >> %t
RUN: printf '\xd8\xff\3\0\1\0\0\0' >> %t
RUN: printf '\xc8\xff\3\0\1\0\0\0' >> %t
RUN: printf '\xc3\xff\3\0\3\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\02\0\0\0\0\0\0\0' >> %t
RUN: printf '\1\0\0\0\0\0\0\0' >> %t
RUN: printf '\023\0\0\0\0\0\0\0' >> %t
RUN: printf '\067\0\0\0\0\0\0\0' >> %t
RUN: printf '\101\0\0\0\0\0\0\0' >> %t
RUN: printf '\125\125\125\052' >> %t
RUN: printf '\7\0foo\1bar\0\0\0\0\0\0\0' >> %t
RUN: llvm-profdata show %t -all-functions -counts | FileCheck %s
RUN: llvm-profdata show %t -all-functions -text | FileCheck %s -check-prefix=MCDC
CHECK: Counters:
CHECK: foo:
@ -46,3 +55,14 @@ CHECK: Functions shown: 2
CHECK: Total functions: 2
CHECK: Maximum function count: 55
CHECK: Maximum internal block count: 65
MCDC: Num Bitmap Bytes:
MCDC-NEXT: $3
MCDC-NEXT: Bitmap Byte Values:
MCDC-NEXT: 55
MCDC-NEXT: 55
MCDC-NEXT: 55
MCDC: Num Bitmap Bytes:
MCDC-NEXT: $1
MCDC-NEXT: Bitmap Byte Values:
MCDC-NEXT: 0x2a

View File

@ -1,12 +1,15 @@
RUN: printf '\201rforpl\377' > %t-foo.profraw
RUN: printf '\10\0\0\0\0\0\0\0' >> %t-foo.profraw
RUN: printf '\11\0\0\0\0\0\0\0' >> %t-foo.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t-foo.profraw
RUN: printf '\1\0\0\0\0\0\0\0' >> %t-foo.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t-foo.profraw
RUN: printf '\1\0\0\0\0\0\0\0' >> %t-foo.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t-foo.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t-foo.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t-foo.profraw
RUN: printf '\10\0\0\0\0\0\0\0' >> %t-foo.profraw
RUN: printf '\0\0\4\0\1\0\0\0' >> %t-foo.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t-foo.profraw
RUN: printf '\0\0\4\0\2\0\0\0' >> %t-foo.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t-foo.profraw
@ -15,20 +18,25 @@ RUN: printf '\1\0\0\0\0\0\0\0' >> %t-foo.profraw
RUN: printf '\0\0\4\0\1\0\0\0' >> %t-foo.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t-foo.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t-foo.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t-foo.profraw
RUN: printf '\1\0\0\0\0\0\0\0' >> %t-foo.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t-foo.profraw
RUN: printf '\023\0\0\0\0\0\0\0' >> %t-foo.profraw
RUN: printf '\3\0foo\0\0\0' >> %t-foo.profraw
RUN: printf '\201rforpl\377' > %t-bar.profraw
RUN: printf '\10\0\0\0\0\0\0\0' >> %t-bar.profraw
RUN: printf '\11\0\0\0\0\0\0\0' >> %t-bar.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t-bar.profraw
RUN: printf '\1\0\0\0\0\0\0\0' >> %t-bar.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t-bar.profraw
RUN: printf '\2\0\0\0\0\0\0\0' >> %t-bar.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t-bar.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t-bar.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t-bar.profraw
RUN: printf '\10\0\0\0\0\0\0\0' >> %t-bar.profraw
RUN: printf '\0\0\6\0\1\0\0\0' >> %t-bar.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t-bar.profraw
RUN: printf '\0\0\6\0\2\0\0\0' >> %t-bar.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t-bar.profraw
@ -37,7 +45,9 @@ RUN: printf '\02\0\0\0\0\0\0\0' >> %t-bar.profraw
RUN: printf '\0\0\6\0\1\0\0\0' >> %t-bar.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t-bar.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t-bar.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t-bar.profraw
RUN: printf '\02\0\0\0\0\0\0\0' >> %t-bar.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t-bar.profraw
RUN: printf '\067\0\0\0\0\0\0\0' >> %t-bar.profraw
RUN: printf '\101\0\0\0\0\0\0\0' >> %t-bar.profraw