[PGO] Value profiling support

This change introduces an instrumentation intrinsic instruction for
value profiling purposes, the lowering of the instrumentation intrinsic
and raw reader updates. The raw profile data files for llvm-profdata
testing are updated.

llvm-svn: 253484
This commit is contained in:
Betul Buyukkurt 2015-11-18 18:14:55 +00:00
parent 808385f1ae
commit 6fac1741c9
20 changed files with 414 additions and 77 deletions

View File

@ -9514,6 +9514,55 @@ structures and the code to increment the appropriate value, in a
format that can be written out by a compiler runtime and consumed via
the ``llvm-profdata`` tool.
'``llvm.instrprof_value_profile``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Syntax:
"""""""
::
declare void @llvm.instrprof_value_profile(i8* <name>, i64 <hash>,
i64 <value>, i32 <value_kind>,
i32 <index>)
Overview:
"""""""""
The '``llvm.instrprof_value_profile``' intrinsic can be emitted by a
frontend for use with instrumentation based profiling. This will be
lowered by the ``-instrprof`` pass to find out the target values,
instrumented expressions take in a program at runtime.
Arguments:
""""""""""
The first argument is a pointer to a global variable containing the
name of the entity being instrumented. ``name`` 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. It
is an error if ``hash`` differs between two instances of
``llvm.instrprof_*`` that refer to the same name.
The third argument is the value of the expression being profiled. The profiled
expression's value should be representable as an unsigned 64-bit value. The
fourth argument represents the kind of value profiling that is being done. The
supported value profiling kinds are enumerated through the
``InstrProfValueKind`` type declared in the
``<include/llvm/ProfileData/InstrProf.h>`` header file. The last argument is the
index of the instrumented expression within ``name``. It should be >= 0.
Semantics:
""""""""""
This intrinsic represents the point where a call to a runtime routine
should be inserted for value profiling of target expressions. ``-instrprof``
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.
Standard C Library Intrinsics
-----------------------------

View File

@ -372,6 +372,39 @@ namespace llvm {
return cast<ConstantInt>(const_cast<Value *>(getArgOperand(3)));
}
};
}
/// This represents the llvm.instrprof_value_profile intrinsic.
class InstrProfValueProfileInst : public IntrinsicInst {
public:
static inline bool classof(const IntrinsicInst *I) {
return I->getIntrinsicID() == Intrinsic::instrprof_value_profile;
}
static inline bool classof(const Value *V) {
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
}
GlobalVariable *getName() const {
return cast<GlobalVariable>(
const_cast<Value *>(getArgOperand(0))->stripPointerCasts());
}
ConstantInt *getHash() const {
return cast<ConstantInt>(const_cast<Value *>(getArgOperand(1)));
}
Value *getTargetValue() const {
return cast<Value>(const_cast<Value *>(getArgOperand(2)));
}
ConstantInt *getValueKind() const {
return cast<ConstantInt>(const_cast<Value *>(getArgOperand(3)));
}
// Returns the value site index.
ConstantInt *getIndex() const {
return cast<ConstantInt>(const_cast<Value *>(getArgOperand(4)));
}
};
} // namespace llvm
#endif

View File

@ -319,7 +319,15 @@ def int_instrprof_increment : Intrinsic<[],
[llvm_ptr_ty, llvm_i64_ty,
llvm_i32_ty, llvm_i32_ty],
[]>;
// A call to profile runtime for value profiling of target expressions
// through instrumentation based profiling.
def int_instrprof_value_profile : Intrinsic<[],
[llvm_ptr_ty, llvm_i64_ty,
llvm_i64_ty, llvm_i32_ty,
llvm_i32_ty],
[]>;
//===------------------- Standard C Library Intrinsics --------------------===//
//

View File

@ -265,7 +265,7 @@ struct InstrProfRecord {
inline void addValueData(uint32_t ValueKind, uint32_t Site,
InstrProfValueData *VData, uint32_t N,
ValueMapType *HashKeys);
/// Merge Value Profile ddata from Src record to this record for ValueKind.
/// Merge Value Profile data from Src record to this record for ValueKind.
inline instrprof_error mergeValueProfData(uint32_t ValueKind,
InstrProfRecord &Src);
@ -273,6 +273,12 @@ struct InstrProfRecord {
/// the writer instance.
inline void updateStrings(InstrProfStringTable *StrTab);
/// Clear value data entries
inline void clearValueData() {
for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind)
getValueSitesForKind(Kind).clear();
}
private:
std::vector<InstrProfValueSiteRecord> IndirectCallSites;
const std::vector<InstrProfValueSiteRecord> &
@ -292,6 +298,7 @@ private:
const_cast<const InstrProfRecord *>(this)
->getValueSitesForKind(ValueKind));
}
// Map indirect call target name hash to name string.
uint64_t remapValue(uint64_t Value, uint32_t ValueKind,
ValueMapType *HashKeys) {
@ -303,9 +310,8 @@ private:
std::lower_bound(HashKeys->begin(), HashKeys->end(), Value,
[](const std::pair<uint64_t, const char *> &LHS,
uint64_t RHS) { return LHS.first < RHS; });
assert(Result != HashKeys->end() &&
"Hash does not match any known keys\n");
Value = (uint64_t)Result->second;
if (Result != HashKeys->end())
Value = (uint64_t)Result->second;
break;
}
}
@ -464,7 +470,7 @@ struct ValueProfData {
// The number of value profile kinds that has value profile data.
// In this implementation, a value profile kind is considered to
// have profile data if the number of value profile sites for the
// kind is not zero. More aggressively, the implemnetation can
// kind is not zero. More aggressively, the implementation can
// choose to check the actual data value: if none of the value sites
// has any profiled values, the kind can be skipped.
uint32_t NumValueKinds;
@ -545,7 +551,7 @@ struct Header {
namespace RawInstrProf {
const uint64_t Version = 1;
const uint64_t Version = 2;
// Magic number to detect file format and endianness.
// Use 255 at one end, since no UTF-8 file can use that character. Avoid 0,
@ -577,7 +583,7 @@ inline uint64_t getMagic<uint32_t>() {
// compiler-rt/lib/profile/InstrProfiling.h.
// It should also match the synthesized type in
// Transforms/Instrumentation/InstrProfiling.cpp:getOrCreateRegionCounters.
template <class IntPtrT> struct ProfileData {
template <class IntPtrT> struct LLVM_ALIGNAS(8) ProfileData {
#define INSTR_PROF_DATA(Type, LLVMType, Name, Init) Type Name;
#include "llvm/ProfileData/InstrProfData.inc"
};
@ -594,6 +600,9 @@ struct Header {
const uint64_t NamesSize;
const uint64_t CountersDelta;
const uint64_t NamesDelta;
const uint64_t ValueKindLast;
const uint64_t ValueDataSize;
const uint64_t ValueDataDelta;
};
} // end namespace RawInstrProf

View File

@ -56,6 +56,12 @@ INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), NamePtr, \
INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt64PtrTy(Ctx), CounterPtr, \
ConstantExpr::getBitCast(CounterPtr, \
llvm::Type::getInt64PtrTy(Ctx)))
INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), FunctionPointer, \
FunctionAddr)
INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), Values, \
ConstantPointerNull::get(Int8PtrTy))
INSTR_PROF_DATA(const uint16_t, Int16ArrayTy, NumValueSites[IPVK_Last+1], \
ConstantArray::get(Int16ArrayTy, Int16ArrayVals))
// INSTR_PROF_DATA_END
#ifdef INSTR_PROF_DATA

View File

@ -20,10 +20,12 @@
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Support/EndianStream.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/LineIterator.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/OnDiskHashTable.h"
#include <iterator>
#include <map>
namespace llvm {
@ -132,15 +134,21 @@ class RawInstrProfReader : public InstrProfReader {
private:
/// The profile data file contents.
std::unique_ptr<MemoryBuffer> DataBuffer;
bool ShouldSwapBytes;
uint64_t CountersDelta;
uint64_t NamesDelta;
uint64_t ValueDataDelta;
const RawInstrProf::ProfileData<IntPtrT> *Data;
const RawInstrProf::ProfileData<IntPtrT> *DataEnd;
const uint64_t *CountersStart;
const char *NamesStart;
const uint8_t *ValueDataStart;
const char *ProfileEnd;
uint32_t ValueKindLast;
// String table for holding a unique copy of all the strings in the profile.
InstrProfStringTable StringTable;
InstrProfRecord::ValueMapType FunctionPtrToNameMap;
RawInstrProfReader(const RawInstrProfReader &) = delete;
RawInstrProfReader &operator=(const RawInstrProfReader &) = delete;
@ -159,10 +167,13 @@ private:
IntT swap(IntT Int) const {
return ShouldSwapBytes ? sys::getSwappedBytes(Int) : Int;
}
inline uint8_t getNumPaddingBytes(uint64_t SizeInBytes) {
return 7 & (sizeof(uint64_t) - SizeInBytes % sizeof(uint64_t));
}
std::error_code readName(InstrProfRecord &Record);
std::error_code readFuncHash(InstrProfRecord &Record);
std::error_code readRawCounts(InstrProfRecord &Record);
std::error_code readValueData(InstrProfRecord &Record);
bool atEnd() const { return Data == DataEnd; }
void advanceData() { Data++; }
@ -174,6 +185,15 @@ private:
ptrdiff_t Offset = (swap(NamePtr) - NamesDelta) / sizeof(char);
return NamesStart + Offset;
}
const uint8_t *getValueDataCounts(IntPtrT ValueCountsPtr) const {
ptrdiff_t Offset = (swap(ValueCountsPtr) - ValueDataDelta) / sizeof(uint8_t);
return ValueDataStart + Offset;
}
// This accepts an already byte-swapped ValueDataPtr argument.
const InstrProfValueData *getValueData(IntPtrT ValueDataPtr) const {
ptrdiff_t Offset = (ValueDataPtr - ValueDataDelta) / sizeof(uint8_t);
return reinterpret_cast<const InstrProfValueData*>(ValueDataStart + Offset);
}
};
typedef RawInstrProfReader<uint32_t> RawInstrProfReader32;
@ -303,6 +323,7 @@ private:
/// Fill Counts with the profile data for the given function name.
std::error_code getFunctionCounts(StringRef FuncName, uint64_t FuncHash,
std::vector<uint64_t> &Counts);
/// Return the maximum of all known function counts.
uint64_t getMaximumFunctionCount() { return MaxFunctionCount; }

View File

@ -5211,7 +5211,8 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
}
case Intrinsic::instrprof_increment:
llvm_unreachable("instrprof failed to lower an increment");
case Intrinsic::instrprof_value_profile:
llvm_unreachable("instrprof failed to lower a value profiling call");
case Intrinsic::localescape: {
MachineFunction &MF = DAG.getMachineFunction();
const TargetInstrInfo *TII = DAG.getSubtarget().getInstrInfo();

View File

@ -206,15 +206,21 @@ std::error_code RawInstrProfReader<IntPtrT>::readHeader(
CountersDelta = swap(Header.CountersDelta);
NamesDelta = swap(Header.NamesDelta);
ValueDataDelta = swap(Header.ValueDataDelta);
auto DataSize = swap(Header.DataSize);
auto CountersSize = swap(Header.CountersSize);
auto NamesSize = swap(Header.NamesSize);
auto ValueDataSize = swap(Header.ValueDataSize);
ValueKindLast = swap(Header.ValueKindLast);
auto DataSizeInBytes = DataSize * sizeof(RawInstrProf::ProfileData<IntPtrT>);
auto PaddingSize = getNumPaddingBytes(NamesSize);
ptrdiff_t DataOffset = sizeof(RawInstrProf::Header);
ptrdiff_t CountersOffset =
DataOffset + sizeof(RawInstrProf::ProfileData<IntPtrT>) * DataSize;
ptrdiff_t CountersOffset = DataOffset + DataSizeInBytes;
ptrdiff_t NamesOffset = CountersOffset + sizeof(uint64_t) * CountersSize;
size_t ProfileSize = NamesOffset + sizeof(char) * NamesSize;
ptrdiff_t ValueDataOffset = NamesOffset + NamesSize + PaddingSize;
size_t ProfileSize = ValueDataOffset + ValueDataSize;
auto *Start = reinterpret_cast<const char *>(&Header);
if (Start + ProfileSize > DataBuffer->getBufferEnd())
@ -225,8 +231,23 @@ std::error_code RawInstrProfReader<IntPtrT>::readHeader(
DataEnd = Data + DataSize;
CountersStart = reinterpret_cast<const uint64_t *>(Start + CountersOffset);
NamesStart = Start + NamesOffset;
ValueDataStart = reinterpret_cast<const uint8_t*>(Start + ValueDataOffset);
ProfileEnd = Start + ProfileSize;
FunctionPtrToNameMap.clear();
for (const RawInstrProf::ProfileData<IntPtrT> *I = Data; I != DataEnd; ++I) {
const IntPtrT FPtr = swap(I->FunctionPointer);
if (!FPtr)
continue;
StringRef FunctionName(getName(I->NamePtr), swap(I->NameSize));
const char* NameEntryPtr = StringTable.insertString(FunctionName);
FunctionPtrToNameMap.push_back(std::pair<const IntPtrT, const char*>
(FPtr, NameEntryPtr));
}
std::sort(FunctionPtrToNameMap.begin(), FunctionPtrToNameMap.end(), less_first());
FunctionPtrToNameMap.erase(std::unique(FunctionPtrToNameMap.begin(),
FunctionPtrToNameMap.end()),
FunctionPtrToNameMap.end());
return success();
}
@ -234,9 +255,8 @@ template <class IntPtrT>
std::error_code RawInstrProfReader<IntPtrT>::readName(InstrProfRecord &Record) {
Record.Name = StringRef(getName(Data->NamePtr), swap(Data->NameSize));
if (Record.Name.data() < NamesStart ||
Record.Name.data() + Record.Name.size() > DataBuffer->getBufferEnd())
Record.Name.data() + Record.Name.size() > (char*)ValueDataStart)
return error(instrprof_error::malformed);
return success();
}
@ -275,8 +295,54 @@ std::error_code RawInstrProfReader<IntPtrT>::readRawCounts(
}
template <class IntPtrT>
std::error_code
RawInstrProfReader<IntPtrT>::readNextRecord(InstrProfRecord &Record) {
std::error_code RawInstrProfReader<IntPtrT>::readValueData(
InstrProfRecord &Record) {
Record.clearValueData();
if (!Data->Values || (ValueDataDelta == 0))
return success();
// Read value data.
uint64_t NumVSites = 0;
for (uint32_t Kind = IPVK_First; Kind <= ValueKindLast; ++Kind)
NumVSites += swap(Data->NumValueSites[Kind]);
NumVSites += getNumPaddingBytes(NumVSites);
auto VDataCounts = makeArrayRef(getValueDataCounts(Data->Values), NumVSites);
// Check bounds.
if (VDataCounts.data() < ValueDataStart ||
VDataCounts.data() + VDataCounts.size() > (const uint8_t *)ProfileEnd)
return error(instrprof_error::malformed);
const InstrProfValueData *VDataPtr =
getValueData(swap(Data->Values) + NumVSites);
for (uint32_t Kind = IPVK_First; Kind <= ValueKindLast; ++Kind) {
NumVSites = swap(Data->NumValueSites[Kind]);
Record.reserveSites(Kind, NumVSites);
for (uint32_t VSite = 0; VSite < NumVSites; ++VSite) {
uint32_t VDataCount = VDataCounts[VSite];
if ((const char *)(VDataPtr + VDataCount) > ProfileEnd)
return error(instrprof_error::malformed);
std::vector<InstrProfValueData> CurrentValues;
CurrentValues.reserve(VDataCount);
for (uint32_t VIndex = 0; VIndex < VDataCount; ++VIndex) {
uint64_t TargetValue = swap(VDataPtr->Value);
uint64_t Count = swap(VDataPtr->Count);
CurrentValues.push_back({TargetValue, Count});
++VDataPtr;
}
Record.addValueData(Kind, VSite, CurrentValues.data(),
VDataCount, &FunctionPtrToNameMap);
}
}
return success();
}
template <class IntPtrT>
std::error_code RawInstrProfReader<IntPtrT>::readNextRecord(
InstrProfRecord &Record) {
if (atEnd())
if (std::error_code EC = readNextHeader(ProfileEnd))
return EC;
@ -293,6 +359,9 @@ RawInstrProfReader<IntPtrT>::readNextRecord(InstrProfRecord &Record) {
if (std::error_code EC = readRawCounts(Record))
return EC;
// Read value data and set Record.
if (std::error_code EC = readValueData(Record)) return EC;
// Iterate.
advanceData();
return success();

View File

@ -7,19 +7,18 @@
//
//===----------------------------------------------------------------------===//
//
// This pass lowers instrprof_increment intrinsics emitted by a frontend for
// profiling. It also builds the data structures and initialization code needed
// for updating execution counts and emitting the profile at runtime.
// This pass lowers instrprof_* intrinsics emitted by a frontend for profiling.
// It also builds the data structures and initialization code needed for
// updating execution counts and emitting the profile at runtime.
//
//===----------------------------------------------------------------------===//
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Transforms/Instrumentation.h"
#include "llvm/ADT/Triple.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Transforms/Instrumentation.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
using namespace llvm;
@ -50,7 +49,15 @@ public:
private:
InstrProfOptions Options;
Module *M;
DenseMap<GlobalVariable *, GlobalVariable *> RegionCounters;
typedef struct PerFunctionProfileData {
uint32_t NumValueSites[IPVK_Last+1];
GlobalVariable* RegionCounters;
GlobalVariable* DataVar;
PerFunctionProfileData() : RegionCounters(nullptr), DataVar(nullptr) {
memset(NumValueSites, 0, sizeof(uint32_t) * (IPVK_Last+1));
}
} PerFunctionProfileData;
DenseMap<GlobalVariable *, PerFunctionProfileData> ProfileDataMap;
std::vector<Value *> UsedVars;
bool isMachO() const {
@ -77,6 +84,12 @@ private:
return getInstrProfCoverageSectionName(isMachO());
}
/// Count the number of instrumented value sites for the function.
void computeNumValueSiteCounts(InstrProfValueProfileInst *Ins);
/// Replace instrprof_value_profile with a call to runtime library.
void lowerValueProfileInst(InstrProfValueProfileInst *Ins);
/// Replace instrprof_increment with an increment of the appropriate value.
void lowerIncrement(InstrProfIncrementInst *Inc);
@ -118,21 +131,37 @@ bool InstrProfiling::runOnModule(Module &M) {
bool MadeChange = false;
this->M = &M;
RegionCounters.clear();
ProfileDataMap.clear();
UsedVars.clear();
// We did not know how many value sites there would be inside
// 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)
for (BasicBlock &BB : F)
for (auto I = BB.begin(), E = BB.end(); I != E;)
if (auto *Inc = dyn_cast<InstrProfIncrementInst>(I++)) {
if (auto *Ind = dyn_cast<InstrProfValueProfileInst>(I++))
computeNumValueSiteCounts(Ind);
for (Function &F : M)
for (BasicBlock &BB : F)
for (auto I = BB.begin(), E = BB.end(); I != E;) {
auto Instr = I++;
if (auto *Inc = dyn_cast<InstrProfIncrementInst>(Instr)) {
lowerIncrement(Inc);
MadeChange = true;
} else if (auto *Ind = dyn_cast<InstrProfValueProfileInst>(Instr)) {
lowerValueProfileInst(Ind);
MadeChange = true;
}
}
if (GlobalVariable *Coverage =
M.getNamedGlobal(getCoverageMappingVarName())) {
lowerCoverageData(Coverage);
MadeChange = true;
}
if (!MadeChange)
return false;
@ -143,6 +172,54 @@ bool InstrProfiling::runOnModule(Module &M) {
return true;
}
static Constant *getOrInsertValueProfilingCall(Module &M) {
auto *VoidTy = Type::getVoidTy(M.getContext());
auto *VoidPtrTy = Type::getInt8PtrTy(M.getContext());
auto *Int32Ty = Type::getInt32Ty(M.getContext());
auto *Int64Ty = Type::getInt64Ty(M.getContext());
Type *ArgTypes[] = {Int64Ty, VoidPtrTy, Int32Ty};
auto *ValueProfilingCallTy =
FunctionType::get(VoidTy, makeArrayRef(ArgTypes), false);
return M.getOrInsertFunction("__llvm_profile_instrument_target",
ValueProfilingCallTy);
}
void InstrProfiling::computeNumValueSiteCounts(InstrProfValueProfileInst *Ind) {
GlobalVariable *Name = Ind->getName();
uint64_t ValueKind = Ind->getValueKind()->getZExtValue();
uint64_t Index = Ind->getIndex()->getZExtValue();
auto It = ProfileDataMap.find(Name);
if (It == ProfileDataMap.end()) {
PerFunctionProfileData PD;
PD.NumValueSites[ValueKind] = Index + 1;
ProfileDataMap[Name] = PD;
} else if (It->second.NumValueSites[ValueKind] <= Index)
It->second.NumValueSites[ValueKind] = Index + 1;
}
void InstrProfiling::lowerValueProfileInst(InstrProfValueProfileInst *Ind) {
GlobalVariable *Name = Ind->getName();
auto It = ProfileDataMap.find(Name);
assert(It != ProfileDataMap.end() && It->second.DataVar &&
"value profiling detected in function with no counter incerement");
GlobalVariable *DataVar = It->second.DataVar;
uint64_t ValueKind = Ind->getValueKind()->getZExtValue();
uint64_t Index = Ind->getIndex()->getZExtValue();
for (uint32_t Kind = IPVK_First; Kind < ValueKind; ++Kind)
Index += It->second.NumValueSites[Kind];
IRBuilder<> Builder(Ind);
Value* Args[3] = {Ind->getTargetValue(),
Builder.CreateBitCast(DataVar, Builder.getInt8PtrTy()),
Builder.getInt32(Index)};
Ind->replaceAllUsesWith(
Builder.CreateCall(getOrInsertValueProfilingCall(*M), Args));
Ind->eraseFromParent();
}
void InstrProfiling::lowerIncrement(InstrProfIncrementInst *Inc) {
GlobalVariable *Counters = getOrCreateRegionCounters(Inc);
@ -174,9 +251,10 @@ void InstrProfiling::lowerCoverageData(GlobalVariable *CoverageData) {
GlobalVariable *Name = cast<GlobalVariable>(V);
// If we have region counters for this name, we've already handled it.
auto It = RegionCounters.find(Name);
if (It != RegionCounters.end())
continue;
auto It = ProfileDataMap.find(Name);
if (It != ProfileDataMap.end())
if (It->second.RegionCounters)
continue;
// Move the name variable to the right section.
Name->setSection(getNameSection());
@ -191,12 +269,25 @@ static std::string getVarName(InstrProfIncrementInst *Inc, StringRef Prefix) {
return (Prefix + Name).str();
}
static inline bool shouldRecordFunctionAddr(Function *F) {
// Check the linkage
if (!F->hasLinkOnceLinkage() && !F->hasLocalLinkage() &&
!F->hasAvailableExternallyLinkage())
return true;
// Check uses of this function for other than direct calls or invokes to it.
return F->hasAddressTaken();
}
GlobalVariable *
InstrProfiling::getOrCreateRegionCounters(InstrProfIncrementInst *Inc) {
GlobalVariable *NamePtr = Inc->getName();
auto It = RegionCounters.find(NamePtr);
if (It != RegionCounters.end())
return It->second;
auto It = ProfileDataMap.find(NamePtr);
PerFunctionProfileData PD;
if (It != ProfileDataMap.end()) {
if (It->second.RegionCounters)
return It->second.RegionCounters;
PD = It->second;
}
// Move the name variable to the right section. Place them in a COMDAT group
// if the associated function is a COMDAT. This will make sure that
@ -225,22 +316,29 @@ InstrProfiling::getOrCreateRegionCounters(InstrProfIncrementInst *Inc) {
CounterPtr->setAlignment(8);
CounterPtr->setComdat(ProfileVarsComdat);
RegionCounters[Inc->getName()] = CounterPtr;
// Create data variable.
auto *Int8PtrTy = Type::getInt8PtrTy(Ctx);
auto *Int16Ty = Type::getInt16Ty(Ctx);
auto *Int16ArrayTy = ArrayType::get(Int16Ty, IPVK_Last+1);
Type *DataTypes[] = {
#define INSTR_PROF_DATA(Type, LLVMType, Name, Init) LLVMType,
#include "llvm/ProfileData/InstrProfData.inc"
};
auto *DataTy = StructType::get(Ctx, makeArrayRef(DataTypes));
Constant *FunctionAddr = shouldRecordFunctionAddr(Fn) ?
ConstantExpr::getBitCast(Fn, Int8PtrTy) :
ConstantPointerNull::get(Int8PtrTy);
Constant *Int16ArrayVals[IPVK_Last+1];
for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind)
Int16ArrayVals[Kind] = ConstantInt::get(Int16Ty, PD.NumValueSites[Kind]);
Constant *DataVals[] = {
#define INSTR_PROF_DATA(Type, LLVMType, Name, Init) Init,
#include "llvm/ProfileData/InstrProfData.inc"
};
auto *Data = new GlobalVariable(*M, DataTy, true, NamePtr->getLinkage(),
auto *Data = new GlobalVariable(*M, DataTy, false, NamePtr->getLinkage(),
ConstantStruct::get(DataTy, DataVals),
getVarName(Inc, getInstrProfDataVarPrefix()));
Data->setVisibility(NamePtr->getVisibility());
@ -248,6 +346,10 @@ InstrProfiling::getOrCreateRegionCounters(InstrProfIncrementInst *Inc) {
Data->setAlignment(8);
Data->setComdat(ProfileVarsComdat);
PD.RegionCounters = CounterPtr;
PD.DataVar = Data;
ProfileDataMap[NamePtr] = PD;
// Mark the data variable as used so that it isn't stripped out.
UsedVars.push_back(Data);
@ -341,7 +443,6 @@ void InstrProfiling::emitUses() {
LLVMUsed =
new GlobalVariable(*M, ATy, false, GlobalValue::AppendingLinkage,
ConstantArray::get(ATy, MergedVars), "llvm.used");
LLVMUsed->setSection("llvm.metadata");
}

View File

@ -10,7 +10,7 @@ $_Z3barIvEvv = comdat any
; CHECK: @__llvm_profile_name__Z3barIvEvv = linkonce_odr hidden constant [11 x i8] c"_Z3barIvEvv", section "{{.*}}__llvm_prf_names", comdat($__llvm_profile_vars__Z3barIvEvv), align 1
; CHECK: @__llvm_profile_counters__Z3barIvEvv = linkonce_odr hidden global [1 x i64] zeroinitializer, section "{{.*}}__llvm_prf_cnts", comdat($__llvm_profile_vars__Z3barIvEvv), align 8
; CHECK: @__llvm_profile_data__Z3barIvEvv = linkonce_odr hidden constant { i32, i32, i64, i8*, i64* } { i32 11, i32 1, i64 0, i8* getelementptr inbounds ([11 x i8], [11 x i8]* @__llvm_profile_name__Z3barIvEvv, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__llvm_profile_counters__Z3barIvEvv, i32 0, i32 0) }, section "{{.*}}__llvm_prf_data", comdat($__llvm_profile_vars__Z3barIvEvv), align 8
; CHECK: @__llvm_profile_data__Z3barIvEvv = linkonce_odr hidden global { i32, i32, i64, i8*, i64*, i8*, i8*, [1 x i16] } { i32 11, i32 1, i64 0, i8* getelementptr inbounds ([11 x i8], [11 x i8]* @__llvm_profile_name__Z3barIvEvv, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__llvm_profile_counters__Z3barIvEvv, i32 0, i32 0), i8* null, i8* null, [1 x i16] zeroinitializer }, section "{{.*}}__llvm_prf_data", comdat($__llvm_profile_vars__Z3barIvEvv), align 8
declare void @llvm.instrprof.increment(i8*, i64, i32, i32) #1

View File

@ -9,28 +9,28 @@
@__llvm_profile_name_foo_inline = linkonce_odr hidden constant [10 x i8] c"foo_inline"
; COMMON: @__llvm_profile_counters_foo = hidden global
; COMMON: @__llvm_profile_data_foo = hidden constant
; COMMON: @__llvm_profile_data_foo = hidden global
define void @foo() {
call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__llvm_profile_name_foo, i32 0, i32 0), i64 0, i32 1, i32 0)
ret void
}
; COMMON: @__llvm_profile_counters_foo_weak = weak hidden global
; COMMON: @__llvm_profile_data_foo_weak = weak hidden constant
; COMMON: @__llvm_profile_data_foo_weak = weak hidden global
define weak void @foo_weak() {
call void @llvm.instrprof.increment(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @__llvm_profile_name_foo_weak, i32 0, i32 0), i64 0, i32 1, i32 0)
ret void
}
; COMMON: @"__llvm_profile_counters_linkage.ll:foo_internal" = internal global
; COMMON: @"__llvm_profile_data_linkage.ll:foo_internal" = internal constant
; COMMON: @"__llvm_profile_data_linkage.ll:foo_internal" = internal global
define internal void @foo_internal() {
call void @llvm.instrprof.increment(i8* getelementptr inbounds ([23 x i8], [23 x i8]* @"__llvm_profile_name_linkage.ll:foo_internal", i32 0, i32 0), i64 0, i32 1, i32 0)
ret void
}
; COMMON: @__llvm_profile_counters_foo_inline = linkonce_odr hidden global
; COMMON: @__llvm_profile_data_foo_inline = linkonce_odr hidden constant
; COMMON: @__llvm_profile_data_foo_inline = linkonce_odr hidden global
define linkonce_odr void @foo_inline() {
call void @llvm.instrprof.increment(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @__llvm_profile_name_foo_inline, i32 0, i32 0), i64 0, i32 1, i32 0)
ret void

View File

@ -12,10 +12,11 @@
; MACHO: @__llvm_profile_counters_foo = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
; ELF: @__llvm_profile_counters_foo = hidden global [1 x i64] zeroinitializer, section "__llvm_prf_cnts", align 8
; MACHO: @__llvm_profile_data_foo = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8
; LINUX: @__llvm_profile_data_foo = hidden constant {{.*}}, section "__llvm_prf_data", align 8
; FREEBSD: @__llvm_profile_data_foo = hidden constant {{.*}}, section "__llvm_prf_data", align 8
; SOLARIS: @__llvm_profile_data_foo = hidden constant {{.*}}, section "__llvm_prf_data", align 8
; MACHO: @__llvm_profile_data_foo = hidden {{.*}}, section "__DATA,__llvm_prf_data", align 8
; LINUX: @__llvm_profile_data_foo = hidden {{.*}}, section "__llvm_prf_data", align 8
; FREEBSD: @__llvm_profile_data_foo = hidden {{.*}}, section "__llvm_prf_data", align 8
; SOLARIS: @__llvm_profile_data_foo = hidden {{.*}}, section "__llvm_prf_data", align 8
define void @foo() {
call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__llvm_profile_name_foo, i32 0, i32 0), i64 0, i32 1, i32 0)
ret void

View File

@ -10,21 +10,21 @@ target triple = "x86_64-apple-macosx10.10.0"
; CHECK: @baz_prof_name = hidden constant [3 x i8] c"baz", section "__DATA,__llvm_prf_names", align 1
; CHECK: @__llvm_profile_counters_foo = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
; CHECK: @__llvm_profile_data_foo = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8
; CHECK: @__llvm_profile_data_foo = hidden {{.*}}, section "__DATA,__llvm_prf_data", align 8
define void @foo() {
call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__llvm_profile_name_foo, i32 0, i32 0), i64 0, i32 1, i32 0)
ret void
}
; CHECK: @__llvm_profile_counters_bar = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
; CHECK: @__llvm_profile_data_bar = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8
; CHECK: @__llvm_profile_data_bar = hidden {{.*}}, section "__DATA,__llvm_prf_data", align 8
define void @bar() {
call void @llvm.instrprof.increment(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @__llvm_profile_name_bar, i32 0, i32 0), i64 0, i32 1, i32 0)
ret void
}
; CHECK: @__llvm_profile_counters_baz = hidden global [3 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
; CHECK: @__llvm_profile_data_baz = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8
; CHECK: @__llvm_profile_data_baz = hidden {{.*}}, section "__DATA,__llvm_prf_data", align 8
define void @baz() {
call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @baz_prof_name, i32 0, i32 0), i64 0, i32 3, i32 0)
call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @baz_prof_name, i32 0, i32 0), i64 0, i32 3, i32 1)

View File

@ -6,7 +6,7 @@ REGENERATE: $ SRC=path/to/llvm
REGENERATE: $ CFE=$SRC/tools/clang
REGENERATE: $ TESTDIR=$SRC/test/tools/llvm-profdata
REGENERATE: $ CFE_TESTDIR=$CFE/test/Profile
REGENERATE: $ clang -o a.out -fprofile-instr-generate $CFE_TESTDIR/test/Profile/c-general.c
REGENERATE: $ clang -o a.out -fprofile-instr-generate $CFE_TESTDIR/c-general.c
REGENERATE: $ LLVM_PROFILE_FILE=$TESTDIR/Inputs/c-general.profraw ./a.out
RUN: llvm-profdata show %p/Inputs/c-general.profraw -o - | FileCheck %s -check-prefix=CHECK
@ -14,11 +14,11 @@ RUN: llvm-profdata show %p/Inputs/c-general.profraw -o - --function=switches | F
SWITCHES-LABEL: Counters:
SWITCHES-NEXT: switches:
SWITCHES-NEXT: Hash: 0x0000000000000013
SWITCHES-NEXT: Hash: 0x2618e4f23f2e8daa
SWITCHES-NEXT: Counters: 19
SWITCHES-NEXT: Function count: 1
SWITCHES-LABEL: Functions shown: 1
CHECK-LABEL: Total functions: 11
CHECK-LABEL: Total functions: 12
CHECK-NEXT: Maximum function count: 1
CHECK-NEXT: Maximum internal block count: 100

View File

@ -1,27 +1,36 @@
RUN: printf '\377lprofR\201' > %t
RUN: printf '\0\0\0\0\0\0\0\1' >> %t
RUN: printf '\0\0\0\0\0\0\0\2' >> %t
RUN: printf '\0\0\0\0\0\0\0\2' >> %t
RUN: printf '\0\0\0\0\0\0\0\3' >> %t
RUN: printf '\0\0\0\0\0\0\0\6' >> %t
RUN: printf '\0\0\0\0\1\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 '\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\3' >> %t
RUN: printf '\0\0\0\1' >> %t
RUN: printf '\0\0\0\0\0\0\0\1' >> %t
RUN: printf '\2\0\0\0' >> %t
RUN: printf '\1\0\0\0' >> %t
RUN: printf '\0\0\0\0' >> %t
RUN: printf '\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\3' >> %t
RUN: printf '\0\0\0\2' >> %t
RUN: printf '\0\0\0\0\0\0\0\2' >> %t
RUN: printf '\2\0\0\03' >> %t
RUN: printf '\1\0\0\10' >> %t
RUN: printf '\0\0\0\0' >> %t
RUN: printf '\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\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 'foobar' >> %t
RUN: printf 'foobar\0\0' >> %t
RUN: llvm-profdata show %t -all-functions -counts | FileCheck %s

View File

@ -1,27 +1,36 @@
RUN: printf '\201Rforpl\377' > %t
RUN: printf '\1\0\0\0\0\0\0\0' >> %t
RUN: printf '\2\0\0\0\0\0\0\0' >> %t
RUN: printf '\2\0\0\0\0\0\0\0' >> %t
RUN: printf '\3\0\0\0\0\0\0\0' >> %t
RUN: printf '\6\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\1\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 '\0\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' >> %t
RUN: printf '\1\0\0\0' >> %t
RUN: printf '\1\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\2' >> %t
RUN: printf '\0\0\0\1' >> %t
RUN: printf '\0\0\0\0' >> %t
RUN: printf '\0\0\0\0' >> %t
RUN: printf '\0\0\0\0\0\0\0\0' >> %t
RUN: printf '\3\0\0\0' >> %t
RUN: printf '\2\0\0\0' >> %t
RUN: printf '\02\0\0\0\0\0\0\0' >> %t
RUN: printf '\03\0\0\2' >> %t
RUN: printf '\10\0\0\1' >> %t
RUN: printf '\0\0\0\0' >> %t
RUN: printf '\0\0\0\0' >> %t
RUN: printf '\0\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 'foobar' >> %t
RUN: printf 'foobar\0\0' >> %t
RUN: llvm-profdata show %t -all-functions -counts | FileCheck %s

View File

@ -1,27 +1,36 @@
RUN: printf '\377lprofr\201' > %t
RUN: printf '\0\0\0\0\0\0\0\1' >> %t
RUN: printf '\0\0\0\0\0\0\0\2' >> %t
RUN: printf '\0\0\0\0\0\0\0\2' >> %t
RUN: printf '\0\0\0\0\0\0\0\3' >> %t
RUN: printf '\0\0\0\0\0\0\0\6' >> %t
RUN: printf '\0\0\0\1\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 '\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\3' >> %t
RUN: printf '\0\0\0\1' >> %t
RUN: printf '\0\0\0\0\0\0\0\1' >> %t
RUN: printf '\0\0\0\2\0\4\0\0' >> %t
RUN: printf '\0\0\0\1\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\0\0\0\0\0' >> %t
RUN: printf '\0\0\0\3' >> %t
RUN: printf '\0\0\0\2' >> %t
RUN: printf '\0\0\0\0\0\0\0\02' >> %t
RUN: printf '\0\0\0\2\0\4\0\03' >> %t
RUN: printf '\0\0\0\1\0\4\0\10' >> %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\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 'foobar' >> %t
RUN: printf 'foobar\0\0' >> %t
RUN: llvm-profdata show %t -all-functions -counts | FileCheck %s

View File

@ -1,27 +1,36 @@
RUN: printf '\201rforpl\377' > %t
RUN: printf '\1\0\0\0\0\0\0\0' >> %t
RUN: printf '\2\0\0\0\0\0\0\0' >> %t
RUN: printf '\2\0\0\0\0\0\0\0' >> %t
RUN: printf '\3\0\0\0\0\0\0\0' >> %t
RUN: printf '\6\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\2\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 '\3\0\0\0' >> %t
RUN: printf '\1\0\0\0' >> %t
RUN: printf '\1\0\0\0\0\0\0\0' >> %t
RUN: printf '\0\0\4\0\2\0\0\0' >> %t
RUN: printf '\0\0\4\0\1\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 '\03\0\0\0' >> %t
RUN: printf '\02\0\0\0' >> %t
RUN: printf '\02\0\0\0\0\0\0\0' >> %t
RUN: printf '\03\0\4\0\2\0\0\0' >> %t
RUN: printf '\10\0\4\0\1\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 '\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 'foobar' >> %t
RUN: printf 'foobar\0\0' >> %t
RUN: llvm-profdata show %t -all-functions -counts | FileCheck %s

View File

@ -1,48 +1,51 @@
RUN: printf '\201rforpl\377' > %t-foo.profraw
RUN: printf '\1\0\0\0\0\0\0\0' >> %t-foo.profraw
RUN: printf '\2\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 '\1\0\0\0\0\0\0\0' >> %t-foo.profraw
RUN: printf '\3\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\4\0\2\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 '\3\0\0\0' >> %t-foo.profraw
RUN: printf '\1\0\0\0' >> %t-foo.profraw
RUN: printf '\1\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\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 '\023\0\0\0\0\0\0\0' >> %t-foo.profraw
RUN: printf 'foo' >> %t-foo.profraw
RUN: printf 'foo\0\0\0\0\0' >> %t-foo.profraw
RUN: printf '\201rforpl\377' > %t-bar.profraw
RUN: printf '\1\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 '\1\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 '\3\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\6\0\2\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 '\3\0\0\0' >> %t-bar.profraw
RUN: printf '\2\0\0\0' >> %t-bar.profraw
RUN: printf '\2\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\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 '\067\0\0\0\0\0\0\0' >> %t-bar.profraw
RUN: printf '\101\0\0\0\0\0\0\0' >> %t-bar.profraw
RUN: printf 'bar' >> %t-bar.profraw
RUN: printf 'bar\0\0\0\0\0' >> %t-bar.profraw
Versions of the profiles that are padded to eight byte alignment.
RUN: cat %t-foo.profraw > %t-foo-padded.profraw
RUN: printf '\0\0\0\0\0' >> %t-foo-padded.profraw
RUN: cat %t-bar.profraw > %t-bar-padded.profraw
RUN: printf '\0\0\0\0\0' >> %t-bar-padded.profraw
RUN: cat %t-foo-padded.profraw %t-bar.profraw > %t-pad-between.profraw
RUN: cat %t-foo-padded.profraw %t-bar-padded.profraw > %t-pad.profraw
RUN: llvm-profdata show %t-pad-between.profraw -all-functions -counts | FileCheck %s
RUN: cat %t-foo.profraw %t-bar.profraw > %t-pad.profraw
RUN: llvm-profdata show %t-pad.profraw -all-functions -counts | FileCheck %s
CHECK: Counters: