Index: include/llvm/ProfileData/InstrProfReader.h =================================================================== --- include/llvm/ProfileData/InstrProfReader.h +++ include/llvm/ProfileData/InstrProfReader.h @@ -106,8 +106,13 @@ /// Iterator over the profile data. line_iterator Line; + // String table for holding a unique copy of all the strings in the profile. + InstrProfStringTable StringTable; + TextInstrProfReader(const TextInstrProfReader &) = delete; TextInstrProfReader &operator=(const TextInstrProfReader &) = delete; + std::error_code readValueProfileData(InstrProfRecord &Record); + public: TextInstrProfReader(std::unique_ptr DataBuffer_) : DataBuffer(std::move(DataBuffer_)), Line(*DataBuffer, true, '#') {} Index: lib/ProfileData/InstrProfReader.cpp =================================================================== --- lib/ProfileData/InstrProfReader.cpp +++ lib/ProfileData/InstrProfReader.cpp @@ -109,6 +109,63 @@ [](char c) { return ::isprint(c) || ::isspace(c); }); } +#define CHECK_LINE_END(Line) \ + if (Line.is_at_end()) \ + return error(instrprof_error::truncated); +#define READ_NUM(Str, Dst) \ + if (Str.getAsInteger(10, (Dst))) \ + return error(instrprof_error::malformed); +#define VP_READ_ADVANCE(Val) \ + CHECK_LINE_END(Line); \ + uint32_t Val; \ + READ_NUM((*Line), Val); \ + Line++; + +std::error_code +TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) { + if (Line.is_at_end()) + return success(); + uint32_t NumValueKinds; + if (Line->getAsInteger(10, NumValueKinds)) { + // No value profile data + return success(); + } + if (NumValueKinds == 0 || NumValueKinds > IPVK_Last + 1) + return error(instrprof_error::malformed); + Line++; + + for (uint32_t VK = 0; VK < NumValueKinds; VK++) { + VP_READ_ADVANCE(ValueKind); + if (ValueKind > IPVK_Last) + return error(instrprof_error::malformed); + VP_READ_ADVANCE(NumValueSites); + if (!NumValueSites) + continue; + + Record.reserveSites(VK, NumValueSites); + for (uint32_t S = 0; S < NumValueSites; S++) { + VP_READ_ADVANCE(NumValueData); + + std::vector CurrentValues; + for (uint32_t V = 0; V < NumValueData; V++) { + CHECK_LINE_END(Line); + std::pair VD = Line->split(':'); + uint64_t TakenCount, Value; + READ_NUM(VD.second, TakenCount); + if (VK == IPVK_IndirectCallTarget) + Value = (uint64_t)StringTable.insertString(VD.first); + else { + READ_NUM(VD.first, Value); + } + CurrentValues.push_back({Value, TakenCount}); + Line++; + } + Record.addValueData(VK, S, CurrentValues.data(), NumValueData, nullptr); + } + } + return success(); +} + std::error_code TextInstrProfReader::readNextRecord(InstrProfRecord &Record) { // Skip empty lines and comments. while (!Line.is_at_end() && (Line->empty() || Line->startswith("#"))) @@ -147,6 +204,10 @@ Record.Counts.push_back(Count); } + // Check if value profile data exists and read it if so. + if (std::error_code EC = readValueProfileData(Record)) + return EC; + return success(); } Index: lib/ProfileData/InstrProfWriter.cpp =================================================================== --- lib/ProfileData/InstrProfWriter.cpp +++ lib/ProfileData/InstrProfWriter.cpp @@ -172,15 +172,47 @@ endian::Writer(OS).write(TableStart.second); } +static const char *ValueProfKindStr[] = { +#define VALUE_PROF_KIND(Enumerator, Value) #Enumerator, +#include "llvm/ProfileData/InstrProfData.inc" +}; + void InstrProfWriter::writeRecordInText(const InstrProfRecord &Func, raw_fd_ostream &OS) { OS << Func.Name << "\n"; OS << "# Func Hash:\n" << Func.Hash << "\n"; - OS << "# Num Counters:\n" < VD = Func.getValueForSite(VK, S); + for (uint32_t I = 0; I < ND; I++) { + if (VK == IPVK_IndirectCallTarget) + OS << reinterpret_cast(VD[I].Value) << ":" + << VD[I].Count << "\n"; + else + OS << VD[I].Value << ":" << VD[I].Count << "\n"; + } + } + } + OS << "\n"; } Index: test/tools/llvm-profdata/Inputs/vp-malform.proftext =================================================================== --- test/tools/llvm-profdata/Inputs/vp-malform.proftext +++ test/tools/llvm-profdata/Inputs/vp-malform.proftext @@ -0,0 +1,42 @@ +foo +# Func Hash: +10 +# Num Counters: +2 +# Counter Values: +999000 +359800 + +foo2 +# Func Hash: +10 +# Num Counters: +2 +# Counter Values: +1001000 +360200 + +main +# Func Hash: +16650 +# Num Counters: +4 +# Counter Values: +2 +2000 +2000000 +999000 +# NumValueKinds +1 +# Value Kind IPVK_IndirectCallTarget +0 +# NumSites +3 +# Values for each site +0 +2 +# !!!! Malformed Value/Count pair +foo+100 +foo2:1000 +1 +foo2:20000 Index: test/tools/llvm-profdata/Inputs/vp-malform2.proftext =================================================================== --- test/tools/llvm-profdata/Inputs/vp-malform2.proftext +++ test/tools/llvm-profdata/Inputs/vp-malform2.proftext @@ -0,0 +1,32 @@ +foo +# Func Hash: +10 +# Num Counters: +2 +# Counter Values: +999000 +359800 + +main +# Func Hash: +16650 +# Num Counters: +4 +# Counter Values: +2 +2000 +2000000 +999000 +# NumValueKinds +1 +# Value Kind IPVK_IndirectCallTarget +0 +# NumSites +3 +# Values for each site +0 +# !! Malformed value site, missing one value +2 +foo:100 +1 +foo2:20000 Index: test/tools/llvm-profdata/Inputs/vp-truncate.proftext =================================================================== --- test/tools/llvm-profdata/Inputs/vp-truncate.proftext +++ test/tools/llvm-profdata/Inputs/vp-truncate.proftext @@ -0,0 +1,36 @@ +foo +# Func Hash: +10 +# Num Counters: +2 +# Counter Values: +999000 +359800 + +foo2 +# Func Hash: +10 +# Num Counters: +2 +# Counter Values: +1001000 +360200 + +main +# Func Hash: +16650 +# Num Counters: +4 +# Counter Values: +2 +2000 +2000000 +999000 +# NumValueKinds +1 +# Value Kind IPVK_IndirectCallTarget +0 +# NumSites +3 +# Values for each site +0 Index: test/tools/llvm-profdata/text-format-errors.test =================================================================== --- test/tools/llvm-profdata/text-format-errors.test +++ test/tools/llvm-profdata/text-format-errors.test @@ -18,3 +18,12 @@ RUN: not llvm-profdata show %p/Inputs/text-format-errors.text.bin 2>&1 | FileCheck %s --check-prefix=BINARY BINARY: error: {{.+}}: Unrecognized instrumentation profile encoding format BINARY: Perhaps you forgot to use the -sample option? + +5- Detect malformed value profile data +RUN: not llvm-profdata show %p/Inputs/vp-malform.proftext 2>&1 | FileCheck %s --check-prefix=VP +RUN: not llvm-profdata show %p/Inputs/vp-malform2.proftext 2>&1 | FileCheck %s --check-prefix=VP +VP: Malformed instrumentation profile data + +6- Detect truncated value profile data +RUN: not llvm-profdata show %p/Inputs/vp-truncate.proftext 2>&1 | FileCheck %s --check-prefix=VPTRUNC +VPTRUNC: Truncated profile data Index: test/tools/llvm-profdata/value-prof.proftext =================================================================== --- test/tools/llvm-profdata/value-prof.proftext +++ test/tools/llvm-profdata/value-prof.proftext @@ -0,0 +1,61 @@ +# RUN: llvm-profdata show -ic-targets -all-functions %s | FileCheck %s --check-prefix=IC +# RUN: llvm-profdata show -ic-targets -counts -text -all-functions %s | FileCheck %s --check-prefix=ICTEXT +# RUN: llvm-profdata merge -o %t.profdata %s +# RUN: llvm-profdata show -ic-targets -all-functions %t.profdata | FileCheck %s --check-prefix=IC + +foo +# Func Hash: +10 +# Num Counters: +2 +# Counter Values: +999000 +359800 + +foo2 +# Func Hash: +10 +# Num Counters: +2 +# Counter Values: +1001000 +360200 + +main +# Func Hash: +16650 +# Num Counters: +4 +# Counter Values: +2 +2000 +2000000 +999000 +# NumValueKinds +1 +# Value Kind IPVK_IndirectCallTarget +0 +# NumSites +3 +# Values for each site +0 +2 +foo:100 +foo2:1000 +1 +foo2:20000 + +#IC: Indirect Call Site Count: 3 +#IC-NEXT: Indirect Target Results: +#IC-NEXT: [ 1, foo, 100 ] +#IC-NEXT: [ 1, foo2, 1000 ] +#IC-NEXT: [ 2, foo2, 20000 ] + +#ICTEXT: foo:100 +#ICTEXT-NEXT: foo2:1000 +#ICTEXT-NEXT: 1 +#ICTEXT-NEXT: foo2:20000 +# RUN: llvm-profdata show -ic-targets -all-functions %s | FileCheck %s --check-prefix=IC +# RUN: llvm-profdata show -ic-targets -counts -text -all-functions %s | FileCheck %s --check-prefix=ICTEXT +# RUN: llvm-profdata merge -o %t.profdata %s +# RUN: llvm-profdata show -ic-targets -all-functions %t.profdata | FileCheck %s --check-prefix=IC