Index: include/llvm/ProfileData/InstrProf.h =================================================================== --- include/llvm/ProfileData/InstrProf.h +++ include/llvm/ProfileData/InstrProf.h @@ -413,19 +413,23 @@ if (Counts.size() != Other.Counts.size()) return instrprof_error::count_mismatch; + instrprof_error Result = instrprof_error::success; + uint64_t CounterMax = std::numeric_limits::max(); + for (size_t I = 0, E = Other.Counts.size(); I < E; ++I) { - if (Counts[I] + Other.Counts[I] < Counts[I]) - return instrprof_error::counter_overflow; - Counts[I] += Other.Counts[I]; + Counts[I] = SaturatingAdd(Counts[I], Other.Counts[I]); + if (Other.Counts[I] > 0 && Counts[I] == CounterMax) { + Result = instrprof_error::counter_overflow; + } } for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) { - instrprof_error result = mergeValueProfData(Kind, Other); - if (result != instrprof_error::success) - return result; + instrprof_error MergeValueResult = mergeValueProfData(Kind, Other); + if (Result == instrprof_error::success) + Result = MergeValueResult; } - return instrprof_error::success; + return Result; } inline support::endianness getHostEndianness() { Index: lib/ProfileData/InstrProfWriter.cpp =================================================================== --- lib/ProfileData/InstrProfWriter.cpp +++ lib/ProfileData/InstrProfWriter.cpp @@ -107,22 +107,24 @@ std::tie(Where, NewFunc) = ProfileDataMap.insert(std::make_pair(I.Hash, InstrProfRecord())); InstrProfRecord &Dest = Where->second; + + instrprof_error Result = instrprof_error::success; if (NewFunc) { // We've never seen a function with this name and hash, add it. Dest = std::move(I); } else { // We're updating a function we've seen before. instrprof_error MergeResult = Dest.merge(I); - if (MergeResult != instrprof_error::success) { - return MergeResult; - } + if (Result == instrprof_error::success) + Result = MergeResult; } // We keep track of the max function count as we go for simplicity. + // Update this statistic no matter the result of the merge. if (Dest.Counts[0] > MaxFunctionCount) MaxFunctionCount = Dest.Counts[0]; - return instrprof_error::success; + return Result; } std::pair InstrProfWriter::writeImpl(raw_ostream &OS) { Index: test/tools/llvm-profdata/overflow.proftext =================================================================== --- test/tools/llvm-profdata/overflow.proftext +++ test/tools/llvm-profdata/overflow.proftext @@ -1,12 +1,20 @@ -# RUN: llvm-profdata merge %s -o %t.out 2>&1 | FileCheck %s -# CHECK: overflow.proftext: overflow: Counter overflow +# RUN: llvm-profdata merge %s -o %t.out 2>&1 | FileCheck %s --check-prefix=MERGE +# RUN: llvm-profdata show %t.out | FileCheck %s --check-prefix=SHOW +# MERGE: overflow.proftext: overflow: Counter overflow +# SHOW: Total functions: 1 +# SHOW: Maximum function count: 18446744073709551615 +# SHOW: Maximum internal block count: 18446744073709551615 overflow 1 -1 +3 +18446744073709551615 9223372036854775808 +18446744073709551615 overflow 1 -1 +3 +9223372036854775808 9223372036854775808 +0 Index: unittests/ProfileData/InstrProfTest.cpp =================================================================== --- unittests/ProfileData/InstrProfTest.cpp +++ unittests/ProfileData/InstrProfTest.cpp @@ -354,7 +354,7 @@ const uint64_t Max = std::numeric_limits::max(); InstrProfRecord Record1("caller", 0x1234, {1}); - InstrProfRecord Record2("caller", 0x1234, {1}); + InstrProfRecord Record2("caller", 0x1234, {Max}); InstrProfRecord Record3("callee1", 0x1235, {3, 4}); Record1.reserveSites(IPVK_IndirectCallTarget, 1); @@ -375,6 +375,9 @@ // Verify saturation of counts. ErrorOr R = Reader->getInstrProfRecord("caller", 0x1234); ASSERT_TRUE(NoError(R.getError())); + + ASSERT_EQ(Max, R.get().Counts[0]); + ASSERT_EQ(1U, R.get().getNumValueSites(IPVK_IndirectCallTarget)); std::unique_ptr VD = R.get().getValueForSite(IPVK_IndirectCallTarget, 0);