Index: llvm/docs/CommandGuide/llvm-profdata.rst
===================================================================
--- llvm/docs/CommandGuide/llvm-profdata.rst
+++ llvm/docs/CommandGuide/llvm-profdata.rst
@@ -17,6 +17,7 @@
 
 * :ref:`merge <profdata-merge>`
 * :ref:`show <profdata-show>`
+* :ref:`overlap <profdata-overlap>`
 
 .. program:: llvm-profdata merge
 
@@ -231,6 +232,72 @@
  Only show context sensitive profile counts. The default is to filter all
  context sensitive profile counts.
 
+.. program:: llvm-profdata overlap
+
+.. _profdata-overlap:
+
+OVERLAP
+-------
+
+SYNOPSIS
+^^^^^^^^
+
+:program:`llvm-profdata overlap` [*options*] [*base profile file*] [*test profile file*]
+
+DESCRIPTION
+^^^^^^^^^^^
+
+:program:`llvm-profdata overlap` takes two profile data files and displays the
+*overlap* of counter distribution between the whole files and between any of the
+specified functions.
+
+In this command, *overlap* is defined as follows:
+Suppose *base profile file* has the following counts:
+{c1_1, c1_2, ..., c1_n, c1_u_1, c2_u_2, ..., c2_u_s},
+and *test profile file* has
+{c2_1, c2_2, ..., c2_n, c2_v_1, c2_v_2, ..., c2_v_t}.
+Here c{1|2}_i (i = 1 .. n) are matched counters and c1_u_i (i = 1 .. s) and
+c2_v_i (i = 1 .. v) are unmatched counters (or counters only existing in)
+*base profile file* and *test profile file*, respectively.
+Let sum_1 = c1_1 + c1_2 +  ... + c1_n +  c1_u_1 + c2_u_2 + ... + c2_u_s, and
+sum_2 = c2_1 + c2_2 + ... + c2_n + c2_v_1 + c2_v_2 + ... + c2_v_t.
+*overlap* = min(c1_1/sum_1, c2_1/sum_2) + min(c1_2/sum_1, c2_2/sum_2) + ...
+            min(c1_n/sum_1, c2_n/sum_2).
+
+The result overlap distribution is a percentage number, ranging from 0.0% to
+100.0%, where 0.0% means there is no overlap and 100.0% means a perfect
+overlap.
+
+Here is an example, if *base profile file* has counts of {400, 600}, and
+*test profile file* has matched counts of {60000, 40000}. The *overlap* is 80%.
+
+
+OPTIONS
+^^^^^^^
+
+.. option:: -function=string
+
+ Print details for a function if the function's name contains the given string.
+
+.. option:: -help
+
+ Print a summary of command line options.
+
+.. option:: -o=output or -o output
+
+ Specify the output file name.  If *output* is ``-`` or it isn't specified,
+ then the output is sent to standard output.
+
+.. option:: -value-cutoff=n
+
+ Show only those functions whose max count values are greater or equal to ``n``.
+ By default, the value-cutoff is set to max of unsigned long long.
+
+.. option:: -cs
+
+ Only show overlap for the context sensitive profile counts. The default is to show
+ non-context sensitive profile counts.
+
 EXIT STATUS
 -----------
 
Index: llvm/include/llvm/ProfileData/InstrProf.h
===================================================================
--- llvm/include/llvm/ProfileData/InstrProf.h
+++ llvm/include/llvm/ProfileData/InstrProf.h
@@ -590,6 +590,70 @@
   return PGOName.drop_front(S + 1);
 }
 
+// To store the sums of profile count values, or the percentage of
+// the sums of the total count values.
+struct CountSumOrPercent {
+  uint64_t NumEntries;
+  double EdgeCount;
+  double ValueCounts[IPVK_Last - IPVK_First + 1];
+  CountSumOrPercent() : NumEntries(0), EdgeCount(0.0f), ValueCounts() {}
+  void reset() {
+    NumEntries = 0;
+    EdgeCount = 0.0f;
+    for (unsigned I = 0; I < IPVK_Last - IPVK_First + 1; I++)
+      ValueCounts[I] = 0.0f;
+  }
+};
+
+// Function level or program level overlap information.
+struct OverlapStats {
+  enum OverlapStatsLevel {ProgramLevel, FunctionLevel};
+  // Sum of the total count values for the base profile.
+  CountSumOrPercent BaseSum;
+  // Sum of the total count values for the test profile.
+  CountSumOrPercent TestSum;
+  // Overlap lap score. Should be in range of [0.0f to 1.0f].
+  CountSumOrPercent Overlap;
+  CountSumOrPercent Mismatch;
+  CountSumOrPercent Unique;
+  OverlapStatsLevel Level;
+  const std::string *BaseFilename;
+  const std::string *TestFilename;
+  StringRef FuncName;
+  uint64_t FuncHash;
+  bool Valid;
+
+  OverlapStats(OverlapStatsLevel L = ProgramLevel)
+      : Level(L), BaseFilename(nullptr), TestFilename(nullptr), FuncHash(0),
+        Valid(false) {}
+
+  void dump(raw_fd_ostream &OS) const;
+
+  void setFuncInfo(StringRef Name, uint64_t Hash) {
+    FuncName = Name;
+    FuncHash = Hash;
+  }
+
+  Error getCountSums(const std::string &BaseFilename,
+                     const std::string &TestFilename, bool IsCS);
+  void addOneMismatch(const CountSumOrPercent &MismatchFunc);
+  void addOneUnique(const CountSumOrPercent &UniqueFunc);
+
+  static inline double score(uint64_t Val1, uint64_t Val2, double Sum1,
+                             double Sum2) {
+    if (Sum1 < 1.0f || Sum2 < 1.0f)
+      return 0.0f;
+    return std::min(Val1 / Sum1, Val2 / Sum2);
+  }
+};
+
+// This is used to filter the functions whose overlap information
+// to be output.
+struct OverlapFuncFilters {
+  uint64_t ValueCutoff;
+  const std::string NameFilter;
+};
+
 struct InstrProfValueSiteRecord {
   /// Value profiling data pairs at a given value site.
   std::list<InstrProfValueData> ValueData;
@@ -615,6 +679,10 @@
              function_ref<void(instrprof_error)> Warn);
   /// Scale up value profile data counts.
   void scale(uint64_t Weight, function_ref<void(instrprof_error)> Warn);
+
+  /// Compute the overlap b/w this record and Input record.
+  void overlap(InstrProfValueSiteRecord &Input, uint32_t ValueKind,
+               OverlapStats &Overlap, OverlapStats &FuncLevelOverlap);
 };
 
 /// Profiling information for a single function.
@@ -703,6 +771,18 @@
   /// Clear value data entries
   void clearValueData() { ValueData = nullptr; }
 
+  /// Compute the sums of all counts and store in Sum.
+  void getCountSums(CountSumOrPercent &Sum) const;
+
+  /// Compute the overlap b/w this IntrprofRecord and Other.
+  void overlap(InstrProfRecord &Other, OverlapStats &Overlap,
+               OverlapStats &FuncLevelOverlap, uint64_t ValueCutoff);
+
+  /// Compute the overlap of value profile counts.
+  void overlapValueProfData(uint32_t ValueKind, InstrProfRecord &Src,
+                            OverlapStats &Overlap,
+                            OverlapStats &FuncLevelOverlap);
+
 private:
   struct ValueProfData {
     std::vector<InstrProfValueSiteRecord> IndirectCallSites;
@@ -1060,5 +1140,4 @@
 void createProfileFileNameVar(Module &M, StringRef InstrProfileOutput);
 
 } // end namespace llvm
-
 #endif // LLVM_PROFILEDATA_INSTRPROF_H
Index: llvm/include/llvm/ProfileData/InstrProfReader.h
===================================================================
--- llvm/include/llvm/ProfileData/InstrProfReader.h
+++ llvm/include/llvm/ProfileData/InstrProfReader.h
@@ -91,6 +91,9 @@
   /// compiler.
   virtual InstrProfSymtab &getSymtab() = 0;
 
+  /// Compute the sum of counts and return in Sum.
+  void getCountSums(CountSumOrPercent &Sum, bool IsCS);
+
 protected:
   std::unique_ptr<InstrProfSymtab> Symtab;
 
Index: llvm/include/llvm/ProfileData/InstrProfWriter.h
===================================================================
--- llvm/include/llvm/ProfileData/InstrProfWriter.h
+++ llvm/include/llvm/ProfileData/InstrProfWriter.h
@@ -100,6 +100,11 @@
   // Internal interface for testing purpose only.
   void setValueProfDataEndianness(support::endianness Endianness);
   void setOutputSparse(bool Sparse);
+  // Compute the overlap b/w this object and Other. Program level result is
+  // stored in Overlap and function level result is stored in FuncLevelOverlap.
+  void overlapRecord(NamedInstrProfRecord &&Other, OverlapStats &Overlap,
+                     OverlapStats &FuncLevelOverlap,
+                     const OverlapFuncFilters &FuncFilter);
 
 private:
   void addRecord(StringRef Name, uint64_t Hash, InstrProfRecord &&I,
Index: llvm/lib/ProfileData/InstrProf.cpp
===================================================================
--- llvm/lib/ProfileData/InstrProf.cpp
+++ llvm/lib/ProfileData/InstrProf.cpp
@@ -29,6 +29,7 @@
 #include "llvm/IR/Metadata.h"
 #include "llvm/IR/Module.h"
 #include "llvm/IR/Type.h"
+#include "llvm/ProfileData/InstrProfReader.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Compiler.h"
@@ -478,6 +479,126 @@
   return Error::success();
 }
 
+void InstrProfRecord::getCountSums(CountSumOrPercent &Sum) const {
+  uint64_t FuncSum = 0;
+  Sum.NumEntries += Counts.size();
+  for (size_t F = 0, E = Counts.size(); F < E; ++F)
+    FuncSum += Counts[F];
+  Sum.EdgeCount += FuncSum;
+
+  for (uint32_t VK = IPVK_First; VK <= IPVK_Last; ++VK) {
+    uint64_t KindSum = 0;
+    uint32_t NumValueSites = getNumValueSites(VK);
+    for (size_t I = 0; I < NumValueSites; ++I) {
+      uint32_t NV = getNumValueDataForSite(VK, I);
+      std::unique_ptr<InstrProfValueData[]> VD = getValueForSite(VK, I);
+      for (uint32_t V = 0; V < NV; V++)
+        KindSum += VD[V].Count;
+    }
+    Sum.ValueCounts[VK] += KindSum;
+  }
+}
+
+void InstrProfValueSiteRecord::overlap(InstrProfValueSiteRecord &Input,
+                                       uint32_t ValueKind,
+                                       OverlapStats &Overlap,
+                                       OverlapStats &FuncLevelOverlap) {
+  this->sortByTargetValues();
+  Input.sortByTargetValues();
+  auto I = ValueData.begin();
+  auto IE = ValueData.end();
+  double Score = 0.0f, FuncLevelScore = 0.0f;
+  for (auto J = Input.ValueData.begin(), JE = Input.ValueData.end(); J != JE;
+       ++J) {
+    while (I != IE && I->Value < J->Value)
+      ++I;
+    if (I != IE && I->Value == J->Value) {
+      Score += OverlapStats::score(I->Count, J->Count,
+                                   Overlap.BaseSum.ValueCounts[ValueKind],
+                                   Overlap.TestSum.ValueCounts[ValueKind]);
+      FuncLevelScore += OverlapStats::score(
+          I->Count, J->Count, FuncLevelOverlap.BaseSum.ValueCounts[ValueKind],
+          FuncLevelOverlap.TestSum.ValueCounts[ValueKind]);
+      ++I;
+      continue;
+    }
+  }
+  Overlap.Overlap.ValueCounts[ValueKind] += Score;
+  FuncLevelOverlap.Overlap.ValueCounts[ValueKind] += FuncLevelScore;
+}
+
+// Return false on mismatch.
+void InstrProfRecord::overlapValueProfData(uint32_t ValueKind,
+                                           InstrProfRecord &Other,
+                                           OverlapStats &Overlap,
+                                           OverlapStats &FuncLevelOverlap) {
+  uint32_t ThisNumValueSites = getNumValueSites(ValueKind);
+  uint32_t OtherNumValueSites = Other.getNumValueSites(ValueKind);
+  assert(ThisNumValueSites == OtherNumValueSites);
+  if (!ThisNumValueSites)
+    return;
+
+  std::vector<InstrProfValueSiteRecord> &ThisSiteRecords =
+      getOrCreateValueSitesForKind(ValueKind);
+  MutableArrayRef<InstrProfValueSiteRecord> OtherSiteRecords =
+      Other.getValueSitesForKind(ValueKind);
+  for (uint32_t I = 0; I < ThisNumValueSites; I++)
+    ThisSiteRecords[I].overlap(OtherSiteRecords[I], ValueKind, Overlap,
+                               FuncLevelOverlap);
+}
+
+void InstrProfRecord::overlap(InstrProfRecord &Other, OverlapStats &Overlap,
+                              OverlapStats &FuncLevelOverlap,
+                              uint64_t ValueCutoff) {
+  // FuncLevel CountSum for other should already computed and nonzero.
+  assert(FuncLevelOverlap.TestSum.EdgeCount >= 1.0f);
+  getCountSums(FuncLevelOverlap.BaseSum);
+  bool Mismatch = (Counts.size() != Other.Counts.size());
+
+  // Check if the value profiles mismatch.
+  if (!Mismatch) {
+    for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) {
+      uint32_t ThisNumValueSites = getNumValueSites(Kind);
+      uint32_t OtherNumValueSites = Other.getNumValueSites(Kind);
+      if (ThisNumValueSites != OtherNumValueSites) {
+        Mismatch = true;
+        break;
+      }
+    }
+  }
+  if (Mismatch) {
+    Overlap.addOneMismatch(FuncLevelOverlap.TestSum);
+    return;
+  }
+
+  // Compute overlap for value counts.
+  for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind)
+    overlapValueProfData(Kind, Other, Overlap, FuncLevelOverlap);
+
+  double Score = 0.0;
+  uint64_t MaxCount = 0;
+  // Compute overlap for edge counts.
+  for (size_t I = 0, E = Other.Counts.size(); I < E; ++I) {
+    Score += OverlapStats::score(Counts[I], Other.Counts[I],
+                                 Overlap.BaseSum.EdgeCount,
+                                 Overlap.TestSum.EdgeCount);
+    MaxCount = std::max(Other.Counts[I], MaxCount);
+  }
+  Overlap.Overlap.EdgeCount += Score;
+  Overlap.Overlap.NumEntries += 1;
+
+  if (MaxCount >= ValueCutoff) {
+    double FuncScore = 0.0;
+    for (size_t I = 0, E = Other.Counts.size(); I < E; ++I)
+      FuncScore += OverlapStats::score(Counts[I], Other.Counts[I],
+                                       FuncLevelOverlap.BaseSum.EdgeCount,
+                                       FuncLevelOverlap.TestSum.EdgeCount);
+    FuncLevelOverlap.Overlap.EdgeCount += FuncScore;
+    FuncLevelOverlap.Overlap.NumEntries = Other.Counts.size();
+    FuncLevelOverlap.Valid = true;
+  }
+}
+
 void InstrProfValueSiteRecord::merge(InstrProfValueSiteRecord &Input,
                                      uint64_t Weight,
                                      function_ref<void(instrprof_error)> Warn) {
@@ -1046,4 +1167,107 @@
   }
 }
 
+Error OverlapStats::getCountSums(const std::string &BaseFilename,
+                                 const std::string &TestFilename, bool IsCS) {
+  auto getProfileSum = [IsCS](const std::string &Filename,
+                              CountSumOrPercent &Sum) -> Error {
+    auto ReaderOrErr = InstrProfReader::create(Filename);
+    if (Error E = ReaderOrErr.takeError()) {
+      return E;
+    }
+    auto Reader = std::move(ReaderOrErr.get());
+    Reader->getCountSums(Sum, IsCS);
+    return Error::success();
+  };
+  auto Ret = getProfileSum(BaseFilename, BaseSum);
+  if (Ret)
+    return std::move(Ret);
+  Ret = getProfileSum(TestFilename, TestSum);
+  if (Ret)
+    return std::move(Ret);
+  this->BaseFilename = &BaseFilename;
+  this->TestFilename = &TestFilename;
+  Valid = true;
+  return Error::success();
+}
+
+void OverlapStats::addOneMismatch(const CountSumOrPercent &MismatchFunc) {
+  Mismatch.NumEntries += 1;
+  Mismatch.EdgeCount += MismatchFunc.EdgeCount / TestSum.EdgeCount;
+  for (unsigned I = 0; I < IPVK_Last - IPVK_First + 1; I++) {
+    if (TestSum.ValueCounts[I] >= 1.0f)
+      Mismatch.ValueCounts[I] +=
+          MismatchFunc.ValueCounts[I] / TestSum.ValueCounts[I];
+  }
+}
+
+void OverlapStats::addOneUnique(const CountSumOrPercent &UniqueFunc) {
+  Unique.NumEntries += 1;
+  Unique.EdgeCount += UniqueFunc.EdgeCount / TestSum.EdgeCount;
+  for (unsigned I = 0; I < IPVK_Last - IPVK_First + 1; I++) {
+    if (TestSum.ValueCounts[I] >= 1.0f)
+      Unique.ValueCounts[I] +=
+          UniqueFunc.ValueCounts[I] / TestSum.ValueCounts[I];
+  }
+}
+
+void OverlapStats::dump(raw_fd_ostream &OS) const {
+  if (!Valid)
+    return;
+
+  const char *EntryName = (Level == ProgramLevel ? "functions" : "counters");
+  if (Level == ProgramLevel) {
+    OS << "Profile overlap infomation for base_profile: " << *BaseFilename
+       << " and test_profile: " << *TestFilename << "\nProgram level:\n";
+  } else {
+    OS << "Function level:\n"
+       << "  Function: " << FuncName << " (Hash=" << FuncHash << ")\n";
+  }
+
+  OS << "  EdgeProfile:\t(Overlap,\t# of " << EntryName << ")\n"
+     << "              \t" << format("%.3f%%", Overlap.EdgeCount * 100) << ",\t"
+     << Overlap.NumEntries << "\n";
+  if (Mismatch.NumEntries)
+    OS << "            \t(Mismatch:\t# of " << EntryName << ")\n"
+       << "            \t" << format("%.3f%%", Mismatch.EdgeCount * 100)
+       << ",\t" << Mismatch.NumEntries << "\n";
+  if (Unique.NumEntries)
+    OS << "            \t(Unique:\t# of " << EntryName << ")\n"
+       << "            \t" << format("%.3f%%", Unique.EdgeCount * 100) << ",\t"
+       << Unique.NumEntries << "\n";
+  OS << "  Base_profile count sum: " << format("%.0f", BaseSum.EdgeCount)
+     << "\n"
+     << "  Test_profile count sum: " << format("%.0f", TestSum.EdgeCount)
+     << "\n";
+
+  for (unsigned I = 0; I < IPVK_Last - IPVK_First + 1; I++) {
+    if (BaseSum.ValueCounts[I] < 1.0f && TestSum.ValueCounts[I] < 1.0f)
+      continue;
+    switch (I) {
+    case IPVK_IndirectCallTarget:
+      OS << "  IndirectCall";
+      break;
+    case IPVK_MemOPSize:
+      OS << "  MemOP";
+      break;
+    default:
+      OS << "  VP[" << I << "]";
+      break;
+    }
+    OS << ":\t(Overlap\n                "
+       << format("%.3f%%", Overlap.ValueCounts[I] * 100) << "\n";
+    if (Mismatch.NumEntries)
+      OS << "            \t(Mismatch)\n            \t"
+         << format("%.3f%%", Mismatch.ValueCounts[I] * 100) << "\n";
+    if (Unique.NumEntries)
+      OS << "            \t(Unique)\n            \t"
+         << format("%.3f%%", Unique.ValueCounts[I] * 100) << "\n";
+
+    OS << "  Base_profile count sum:\t"
+       << format("%.0f", BaseSum.ValueCounts[I]) << "\n"
+       << "  Test_profile count sum:\t"
+       << format("%.0f", TestSum.ValueCounts[I]) << "\n";
+  }
+}
+
 } // end namespace llvm
Index: llvm/lib/ProfileData/InstrProfReader.cpp
===================================================================
--- llvm/lib/ProfileData/InstrProfReader.cpp
+++ llvm/lib/ProfileData/InstrProfReader.cpp
@@ -900,3 +900,17 @@
   }
   return success();
 }
+
+void InstrProfReader::getCountSums(CountSumOrPercent &Sum, bool IsCS) {
+  uint64_t NumFuncs = 0;
+  for (const auto &Func : *this) {
+    if (isIRLevelProfile()) {
+      bool FuncIsCS = NamedInstrProfRecord::hasCSFlagInHash(Func.Hash);
+      if (FuncIsCS != IsCS)
+        continue;
+    }
+    Func.getCountSums(Sum);
+    ++NumFuncs;
+  }
+  Sum.NumEntries = NumFuncs;
+}
Index: llvm/lib/ProfileData/InstrProfWriter.cpp
===================================================================
--- llvm/lib/ProfileData/InstrProfWriter.cpp
+++ llvm/lib/ProfileData/InstrProfWriter.cpp
@@ -187,6 +187,40 @@
   addRecord(Name, Hash, std::move(I), Weight, Warn);
 }
 
+void InstrProfWriter::overlapRecord(NamedInstrProfRecord &&Other,
+                                    OverlapStats &Overlap,
+                                    OverlapStats &FuncLevelOverlap,
+                                    const OverlapFuncFilters &FuncFilter) {
+  auto Name = Other.Name;
+  auto Hash = Other.Hash;
+  Other.getCountSums(FuncLevelOverlap.TestSum);
+  if (FunctionData.find(Name) == FunctionData.end()) {
+    Overlap.addOneUnique(FuncLevelOverlap.TestSum);
+    return;
+  }
+  if (FuncLevelOverlap.TestSum.EdgeCount < 1.0f) {
+    Overlap.Overlap.NumEntries += 1;
+    return;
+  }
+  auto &ProfileDataMap = FunctionData[Name];
+  bool NewFunc;
+  ProfilingData::iterator Where;
+  std::tie(Where, NewFunc) =
+      ProfileDataMap.insert(std::make_pair(Hash, InstrProfRecord()));
+  if (NewFunc) {
+    Overlap.addOneMismatch(FuncLevelOverlap.TestSum);
+    return;
+  }
+  InstrProfRecord &Dest = Where->second;
+
+  uint64_t ValueCutoff = FuncFilter.ValueCutoff;
+  if (!FuncFilter.NameFilter.empty() &&
+      Name.find(FuncFilter.NameFilter) != Name.npos)
+    ValueCutoff = 0;
+
+  Dest.overlap(Other, Overlap, FuncLevelOverlap, ValueCutoff);
+}
+
 void InstrProfWriter::addRecord(StringRef Name, uint64_t Hash,
                                 InstrProfRecord &&I, uint64_t Weight,
                                 function_ref<void(Error)> Warn) {
Index: llvm/test/tools/llvm-profdata/Inputs/overlap_1.proftext
===================================================================
--- /dev/null
+++ llvm/test/tools/llvm-profdata/Inputs/overlap_1.proftext
@@ -0,0 +1,36 @@
+# IR level Instrumentation Flag
+:ir
+bar
+# Func Hash:
+12884901887
+# Num Counters:
+1
+# Counter Values:
+100000
+
+bar1
+# Func Hash:
+12884901887
+# Num Counters:
+1
+# Counter Values:
+100000
+
+foo
+# Func Hash:
+25571299074
+# Num Counters:
+2
+# Counter Values:
+40000
+60000
+
+main
+# Func Hash:
+29212902728
+# Num Counters:
+2
+# Counter Values:
+200000
+0
+
Index: llvm/test/tools/llvm-profdata/Inputs/overlap_1_cs.proftext
===================================================================
--- /dev/null
+++ llvm/test/tools/llvm-profdata/Inputs/overlap_1_cs.proftext
@@ -0,0 +1,11 @@
+# CSIR level Instrumentation Flag
+:csir
+bar
+# Func Hash:
+1152921534274394772
+# Num Counters:
+2
+# Counter Values:
+6000
+4000
+
Index: llvm/test/tools/llvm-profdata/Inputs/overlap_1_vp.proftext
===================================================================
--- /dev/null
+++ llvm/test/tools/llvm-profdata/Inputs/overlap_1_vp.proftext
@@ -0,0 +1,25 @@
+:IR
+foo
+# Func Hash:
+72057649435042473
+# Num Counters:
+2
+# Counter Values:
+40000
+60000
+# Num Value Kinds:
+2
+# ValueKind = IPVK_IndirectCallTarget:
+0
+# NumValueSites:
+1
+2
+bar1:40000
+bar2:60000
+# ValueKind = IPVK_MemOPSize:
+1
+# NumValueSites:
+1
+2
+1:40000
+4:60000
Index: llvm/test/tools/llvm-profdata/Inputs/overlap_2.proftext
===================================================================
--- /dev/null
+++ llvm/test/tools/llvm-profdata/Inputs/overlap_2.proftext
@@ -0,0 +1,36 @@
+# IR level Instrumentation Flag
+:ir
+bar
+# Func Hash:
+12884901887
+# Num Counters:
+1
+# Counter Values:
+10000
+
+bar2
+# Func Hash:
+12884901887
+# Num Counters:
+1
+# Counter Values:
+10000
+
+foo
+# Func Hash:
+25571299075
+# Num Counters:
+2
+# Counter Values:
+4000
+6000
+
+main
+# Func Hash:
+29212902728
+# Num Counters:
+2
+# Counter Values:
+20000
+0
+
Index: llvm/test/tools/llvm-profdata/Inputs/overlap_2_cs.proftext
===================================================================
--- /dev/null
+++ llvm/test/tools/llvm-profdata/Inputs/overlap_2_cs.proftext
@@ -0,0 +1,11 @@
+# CSIR level Instrumentation Flag
+:csir
+bar
+# Func Hash:
+1152921534274394772
+# Num Counters:
+2
+# Counter Values:
+4000
+6000
+
Index: llvm/test/tools/llvm-profdata/Inputs/overlap_2_vp.proftext
===================================================================
--- /dev/null
+++ llvm/test/tools/llvm-profdata/Inputs/overlap_2_vp.proftext
@@ -0,0 +1,25 @@
+:IR
+foo
+# Func Hash:
+72057649435042473
+# Num Counters:
+2
+# Counter Values:
+30000
+20000
+# Num Value Kinds:
+2
+# ValueKind = IPVK_IndirectCallTarget:
+0
+# NumValueSites:
+1
+2
+bar1:30000
+bar2:20000
+# ValueKind = IPVK_MemOPSize:
+1
+# NumValueSites:
+1
+2
+1:3000
+4:2000
Index: llvm/test/tools/llvm-profdata/overlap.test
===================================================================
--- /dev/null
+++ llvm/test/tools/llvm-profdata/overlap.test
@@ -0,0 +1,23 @@
+RUN: llvm-profdata overlap %p/Inputs/overlap_1.proftext %p/Inputs/overlap_2.proftext | FileCheck %s -check-prefix=OVERLAP
+RUN: llvm-profdata overlap -function=main %p/Inputs/overlap_1.proftext %p/Inputs/overlap_2.proftext | FileCheck %s -check-prefix=MAINFUNC -check-prefix=OVERLAP
+RUN: llvm-profdata overlap -value-cutoff=15000 %p/Inputs/overlap_1.proftext %p/Inputs/overlap_2.proftext | FileCheck %s -check-prefix=MAINFUNC -check-prefix=OVERLAP
+RUN: llvm-profdata merge %p/Inputs/overlap_1.proftext -o %t_1.profdata
+RUN: llvm-profdata merge %p/Inputs/overlap_2.proftext -o %t_2.profdata
+RUN: llvm-profdata overlap %t_1.profdata %t_2.profdata | FileCheck %s -check-prefix=OVERLAP
+
+MAINFUNC: Function level:
+MAINFUNC:   Function: main (Hash=29212902728)
+MAINFUNC:   EdgeProfile:  (Overlap,       # of counters)
+MAINFUNC:                 100.000%,       2
+MAINFUNC:   Base_profile count sum: 200000
+MAINFUNC:   Test_profile count sum: 20000
+OVERLAP: Profile overlap infomation for base_profile: {{.*}} and test_profile:
+OVERLAP: Program level:
+OVERLAP:   EdgeProfile:  (Overlap,       # of functions)
+OVERLAP:                 60.000%,        2
+OVERLAP:                 (Mismatch:      # of functions)
+OVERLAP:                 20.000%,        1
+OVERLAP:                 (Unique:        # of functions)
+OVERLAP:                 20.000%,        1
+OVERLAP:   Base_profile count sum: 500000
+OVERLAP:   Test_profile count sum: 50000
Index: llvm/test/tools/llvm-profdata/overlap_cs.test
===================================================================
--- /dev/null
+++ llvm/test/tools/llvm-profdata/overlap_cs.test
@@ -0,0 +1,10 @@
+RUN: llvm-profdata overlap -cs %p/Inputs/overlap_1_cs.proftext %p/Inputs/overlap_2_cs.proftext | FileCheck %s -check-prefix=OVERLAP
+RUN: llvm-profdata merge %p/Inputs/overlap_1_cs.proftext -o %t_1_cs.profdata
+RUN: llvm-profdata merge %p/Inputs/overlap_2_cs.proftext -o %t_2_cs.profdata
+RUN: llvm-profdata overlap -cs %t_1_cs.profdata %t_2_cs.profdata | FileCheck %s -check-prefix=OVERLAP
+OVERLAP: Profile overlap infomation for base_profile: {{.*}} and test_profile:
+OVERLAP: Program level:
+OVERLAP:   EdgeProfile:  (Overlap,       # of functions)
+OVERLAP:                 80.000%,        1
+OVERLAP:   Base_profile count sum: 10000
+OVERLAP:   Test_profile count sum: 10000
Index: llvm/test/tools/llvm-profdata/overlap_vp.test
===================================================================
--- /dev/null
+++ llvm/test/tools/llvm-profdata/overlap_vp.test
@@ -0,0 +1,19 @@
+RUN: llvm-profdata overlap %p/Inputs/overlap_1_vp.proftext %p/Inputs/overlap_2_vp.proftext | FileCheck %s -check-prefix=OVERLAP
+RUN: llvm-profdata merge %p/Inputs/overlap_1_vp.proftext -o %t_1_vp.profdata
+RUN: llvm-profdata merge %p/Inputs/overlap_2_vp.proftext -o %t_2_vp.profdata
+RUN: llvm-profdata overlap %t_1_vp.profdata %t_2_vp.profdata | FileCheck %s -check-prefix=OVERLAP
+OVERLAP: Profile overlap infomation for base_profile: {{.*}} and test_profile:
+OVERLAP: Program level:
+OVERLAP:   EdgeProfile:  (Overlap,       # of functions)
+OVERLAP:                 80.000%,        1
+OVERLAP:   Base_profile count sum: 100000
+OVERLAP:   Test_profile count sum: 50000
+OVERLAP:   IndirectCall: (Overlap
+OVERLAP:                 80.000%
+OVERLAP:   Base_profile count sum:       100000
+OVERLAP:   Test_profile count sum:       50000
+OVERLAP:   MemOP:        (Overlap
+OVERLAP:                 80.000%
+OVERLAP:   Base_profile count sum:       100000
+OVERLAP:   Test_profile count sum:       5000
+
Index: llvm/tools/llvm-profdata/llvm-profdata.cpp
===================================================================
--- llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -200,6 +200,31 @@
   }
 }
 
+/// Computer the overlap b/w profile BaseFilename and TestFileName,
+/// and store the program level result to Overlap.
+static void overlapInput(const std::string &BaseFilename,
+                         const std::string &TestFilename, WriterContext *WC,
+                         OverlapStats &Overlap,
+                         const OverlapFuncFilters &FuncFilter,
+                         raw_fd_ostream &OS, bool IsCS) {
+  auto ReaderOrErr = InstrProfReader::create(TestFilename);
+  if (Error E = ReaderOrErr.takeError()) {
+    // Skip the empty profiles by returning sliently.
+    instrprof_error IPE = InstrProfError::take(std::move(E));
+    if (IPE != instrprof_error::empty_raw_profile)
+      WC->Err = make_error<InstrProfError>(IPE);
+  }
+
+  auto Reader = std::move(ReaderOrErr.get());
+  for (auto &I : *Reader) {
+    OverlapStats FuncOverlap(OverlapStats::FunctionLevel);
+    FuncOverlap.setFuncInfo(I.Name, I.Hash);
+
+    WC->Writer.overlapRecord(std::move(I), Overlap, FuncOverlap, FuncFilter);
+    FuncOverlap.dump(OS);
+  }
+}
+
 /// Load an input into a writer context.
 static void loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
                       WriterContext *WC) {
@@ -608,6 +633,66 @@
   return 0;
 }
 
+/// Computer the overlap b/w profile BaseFilename and profile TestFilename.
+static void overlapInstrProfile(const std::string &BaseFilename,
+                                const std::string &TestFilename,
+                                const OverlapFuncFilters &FuncFilter,
+                                raw_fd_ostream &OS, bool IsCS) {
+  std::mutex ErrorLock;
+  SmallSet<instrprof_error, 4> WriterErrorCodes;
+  WriterContext Context(false, ErrorLock, WriterErrorCodes);
+  WeightedFile WeightedInput{BaseFilename, 1};
+  OverlapStats Overlap;
+  Error E = Overlap.getCountSums(BaseFilename, TestFilename, IsCS);
+  if (E)
+    exitWithError(std::move(E), "Error in getting profile count sums");
+  if (Overlap.BaseSum.EdgeCount < 1.0f) {
+    OS << "Sum of edge counts for profile " << BaseFilename << " is 0.\n";
+    exit(0);
+  }
+  if (Overlap.TestSum.EdgeCount < 1.0f) {
+    OS << "Sum of edge counts for profile " << TestFilename << " is 0.\n";
+    exit(0);
+  }
+  loadInput(WeightedInput, nullptr, &Context);
+  overlapInput(BaseFilename, TestFilename, &Context, Overlap, FuncFilter, OS,
+               IsCS);
+  Overlap.dump(OS);
+}
+
+static int overlap_main(int argc, const char *argv[]) {
+  cl::opt<std::string> BaseFilename(cl::Positional, cl::Required,
+                                    cl::desc("<base profile file>"));
+  cl::opt<std::string> TestFilename(cl::Positional, cl::Required,
+                                    cl::desc("<test profile file>"));
+  cl::opt<std::string> Output("output", cl::value_desc("output"),
+                                      cl::init("-"), cl::desc("Output file"));
+  cl::alias OutputA("o", cl::desc("Alias for --output"),
+                            cl::aliasopt(Output));
+  cl::opt<bool> IsCS("cs", cl::init(false),
+                       cl::desc("For context sensitive counts"));
+  cl::opt<unsigned long long> ValueCutoff(
+      "value-cutoff", cl::init(-1),
+      cl::desc(
+          "Function level overlap information for every function in test "
+          "profile with max count value greater then the parameter value"));
+  cl::opt<std::string> FuncNameFilter(
+      "function",
+      cl::desc("Function level overlap information for matching functions"));
+  cl::ParseCommandLineOptions(argc, argv, "LLVM profile data overlap tool\n");
+
+  std::error_code EC;
+  raw_fd_ostream OS(Output.data(), EC, sys::fs::F_Text);
+  if (EC)
+    exitWithErrorCode(EC, Output);
+
+  overlapInstrProfile(BaseFilename, TestFilename,
+                      OverlapFuncFilters{ValueCutoff, FuncNameFilter}, OS,
+                      IsCS);
+
+  return 0;
+}
+
 typedef struct ValueSitesStats {
   ValueSitesStats()
       : TotalNumValueSites(0), TotalNumValueSitesWithValueProfile(0),
@@ -882,7 +967,7 @@
 }
 
 static int show_main(int argc, const char *argv[]) {
-  cl::opt<std::string> Filename(cl::Positional, cl::Required,
+ cl::opt<std::string> Filename(cl::Positional, cl::Required,
                                 cl::desc("<profdata-file>"));
 
   cl::opt<bool> ShowCounts("counts", cl::init(false),
@@ -965,6 +1050,8 @@
       func = merge_main;
     else if (strcmp(argv[1], "show") == 0)
       func = show_main;
+    else if (strcmp(argv[1], "overlap") == 0)
+      func = overlap_main;
 
     if (func) {
       std::string Invocation(ProgName.str() + " " + argv[1]);
@@ -979,7 +1066,7 @@
              << "USAGE: " << ProgName << " <command> [args...]\n"
              << "USAGE: " << ProgName << " <command> -help\n\n"
              << "See each individual command --help for more details.\n"
-             << "Available commands: merge, show\n";
+             << "Available commands: merge, show, overlap\n";
       return 0;
     }
   }
@@ -989,6 +1076,6 @@
   else
     errs() << ProgName << ": Unknown command!\n";
 
-  errs() << "USAGE: " << ProgName << " <merge|show> [args...]\n";
+  errs() << "USAGE: " << ProgName << " <merge|show|overlap> [args...]\n";
   return 1;
 }