[llvm] Update for Code Coverage, Fixing Double Counts on Functions Compiled in Different Binaries and Merging of Conditional Compilation (PR #151771)

via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 1 14:00:18 PDT 2025


https://github.com/awearden created https://github.com/llvm/llvm-project/pull/151771

The following PR is addressing these two issues:
https://github.com/llvm/llvm-project/issues/148279
https://github.com/llvm/llvm-project/issues/148673

The current state of code coverage in llvm had two bugs that occurred when merging .profraw files. Issue 148279 occurred because of the way that llvm-profdata would map functions to their respective counter values. These mappings work by using the function name and the function control flow hash to map to their counters. So, if two functions with the same name and the same control flow appear in the .profraw files, their counters will be merged. My changes address this issue by using the object file along with the function name and the function control flow hash to map to the counters. This way, binaries compiled with the same function in different binaries can be differentiated. You can see the effect of this by using the --object-aware-hashing flag implemented in llvm-profdata, and the --merge-binary-coverage flag in llvm-cov.

Example workflow:
```
clang -fprofile-instr-generate -fcoverage-mapping -o x86_exec_1 myprogram.c fb.c -g
./x86_exec_1
cp default.profraw x86_exec_1.profraw

clang -o x86_exec_2 mypg.c fb.c -stdlib=libc++ -fprofile-instr-generate -fcoverage-mapping
./x86_exec_2
cp default.profraw x86_exec_2.profraw

llvm-profdata merge -o all.profdata --object-aware-hashing=x86_exec_2 x86_exec_2.profraw --object-aware-hashing=x86_exec_1 x86_exec_1.profraw

llvm-cov show --object=x86_exec_1 --object=x86_exec_2 --merge-binary-coverage --instr-profile=all.profdata
```
the llvm-lit test case "merge-same-func-diff-bin.c" located where the llvm-cov tests exist, tests if the double counts on main appear on the example shown in issue 148279.

This same workflow also addresses the conditional compilation problems in issue 148673. The reason this issue occurred was because of the way llvm-profdata created the hash values that mapped to the counters (as explained above) and because of the duplication checks in llvm-cov. If llvm-cov sees that a particular function name has already been processed, it will skip any other mentions of that particular function. So with my changes, if a function has been processed, it will merge the execution counts and any new regions that appear into the list of Regions that is held by the first instance of the function processed. Later this combined list of Regions is then processed so that the right counts show up on any Regions that were incorrectly labeled as a "Skipped Region" during the conditional compilation. The llvm-lit test case "merge-binary-coverage.c" will test for the right counts in a conditional compilation.

Lastly, these updates also add the --show-arch-executables flag in llvm-cov, which will allow the user to see the merged function coverage, along with the specific coverage from each executable. These sub-views will list the particular object file the coverage is refering too along with the architecture of the object file. The llvm-lit test case "merge-show-arch-exec.c" does a simple test of this feature.

Example of using --show-arch-executables:
```
clang -fprofile-instr-generate -fcoverage-mapping -o x86_exec_1 myprogram.c fb.c -g
./x86_exec_1
cp default.profraw x86_exec_1.profraw

clang -o x86_exec_2 mypg.c fb.c -stdlib=libc++ -fprofile-instr-generate -fcoverage-mapping
./x86_exec_2
cp default.profraw x86_exec_2.profraw

llvm-profdata merge -o all.profdata --object-aware-hashing=x86_exec_2 x86_exec_2.profraw --object-aware-hashing=x86_exec_1 x86_exec_1.profraw

llvm-cov show --object=x86_exec_1 --object=x86_exec_2 --merge-binary-coverage --show-arch-executables --instr-profile=all.profdata
```
@quic-akaryaki
@quic-areg
@quic-seaswara
@evodius96 
@chapuni 

>From 52d0d66504f992debfefecbde5dd1e852328f870 Mon Sep 17 00:00:00 2001
From: Andres Wearden <awearden at hu-awearden-lv.qualcomm.com>
Date: Tue, 1 Jul 2025 09:37:43 -0700
Subject: [PATCH 01/17] saving changes for llvm-cross arch feature

---
 llvm/include/llvm/ProfileData/InstrProf.h     | 207 ++++++++++--------
 .../llvm/ProfileData/InstrProfReader.h        |  55 +++--
 .../llvm/ProfileData/InstrProfWriter.h        |  85 ++++---
 llvm/lib/ProfileData/InstrProf.cpp            |  55 ++++-
 llvm/lib/ProfileData/InstrProfReader.cpp      |  42 +++-
 .../llvm-profdata-cross-arch/CMakeLists.txt   |  35 +++
 .../ELFSymbolReader.cpp                       |  90 ++++++++
 .../ELFSymbolReader.h                         |  31 +++
 .../llvm-profdata-cross-arch.cpp              | 112 ++++++++++
 llvm/tools/llvm-profdata/llvm-profdata.cpp    | 102 ++++++++-
 10 files changed, 643 insertions(+), 171 deletions(-)
 create mode 100644 llvm/tools/llvm-profdata-cross-arch/CMakeLists.txt
 create mode 100644 llvm/tools/llvm-profdata-cross-arch/ELFSymbolReader.cpp
 create mode 100644 llvm/tools/llvm-profdata-cross-arch/ELFSymbolReader.h
 create mode 100644 llvm/tools/llvm-profdata-cross-arch/llvm-profdata-cross-arch.cpp

diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h
index 544a59df43ed3..a786aadce6de1 100644
--- a/llvm/include/llvm/ProfileData/InstrProf.h
+++ b/llvm/include/llvm/ProfileData/InstrProf.h
@@ -69,18 +69,18 @@ struct PatchItem {
 // back patching.
 class ProfOStream {
 public:
-  ProfOStream(raw_fd_ostream &FD);
-  ProfOStream(raw_string_ostream &STR);
+  LLVM_ABI ProfOStream(raw_fd_ostream &FD);
+  LLVM_ABI ProfOStream(raw_string_ostream &STR);
 
-  [[nodiscard]] uint64_t tell() const;
-  void write(uint64_t V);
-  void write32(uint32_t V);
-  void writeByte(uint8_t V);
+  [[nodiscard]] LLVM_ABI uint64_t tell() const;
+  LLVM_ABI void write(uint64_t V);
+  LLVM_ABI void write32(uint32_t V);
+  LLVM_ABI void writeByte(uint8_t V);
 
   // \c patch can only be called when all data is written and flushed.
   // For raw_string_ostream, the patch is done on the target string
   // directly and it won't be reflected in the stream's internal buffer.
-  void patch(ArrayRef<PatchItem> P);
+  LLVM_ABI void patch(ArrayRef<PatchItem> P);
 
   // If \c OS is an instance of \c raw_fd_ostream, this field will be
   // true. Otherwise, \c OS will be an raw_string_ostream.
@@ -104,9 +104,9 @@ inline uint64_t getInstrMaxCountValue() {
 /// The name of the section depends on the object format type \p OF. If
 /// \p AddSegmentInfo is true, a segment prefix and additional linker hints may
 /// be added to the section name (this is the default).
-std::string getInstrProfSectionName(InstrProfSectKind IPSK,
-                                    Triple::ObjectFormatType OF,
-                                    bool AddSegmentInfo = true);
+LLVM_ABI std::string getInstrProfSectionName(InstrProfSectKind IPSK,
+                                             Triple::ObjectFormatType OF,
+                                             bool AddSegmentInfo = true);
 
 /// Return the name profile runtime entry point to do value profiling
 /// for a given site.
@@ -215,62 +215,64 @@ inline StringRef getInstrProfNameSeparator() { return "\01"; }
 
 /// Determines whether module targets a GPU eligable for PGO
 /// instrumentation
-bool isGPUProfTarget(const Module &M);
+LLVM_ABI bool isGPUProfTarget(const Module &M);
 
 /// Please use getIRPGOFuncName for LLVM IR instrumentation. This function is
 /// for front-end (Clang, etc) instrumentation.
 /// Return the modified name for function \c F suitable to be
 /// used the key for profile lookup. Variable \c InLTO indicates if this
 /// is called in LTO optimization passes.
-std::string getPGOFuncName(const Function &F, bool InLTO = false,
-                           uint64_t Version = INSTR_PROF_INDEX_VERSION);
+LLVM_ABI std::string
+getPGOFuncName(const Function &F, bool InLTO = false,
+               uint64_t Version = INSTR_PROF_INDEX_VERSION);
 
 /// Return the modified name for a function suitable to be
 /// used the key for profile lookup. The function's original
 /// name is \c RawFuncName and has linkage of type \c Linkage.
 /// The function is defined in module \c FileName.
-std::string getPGOFuncName(StringRef RawFuncName,
-                           GlobalValue::LinkageTypes Linkage,
-                           StringRef FileName,
-                           uint64_t Version = INSTR_PROF_INDEX_VERSION);
+LLVM_ABI std::string
+getPGOFuncName(StringRef RawFuncName, GlobalValue::LinkageTypes Linkage,
+               StringRef FileName, uint64_t Version = INSTR_PROF_INDEX_VERSION);
 
 /// \return the modified name for function \c F suitable to be
 /// used as the key for IRPGO profile lookup. \c InLTO indicates if this is
 /// called from LTO optimization passes.
-std::string getIRPGOFuncName(const Function &F, bool InLTO = false);
+LLVM_ABI std::string getIRPGOFuncName(const Function &F, bool InLTO = false);
 
 /// \return the filename and the function name parsed from the output of
 /// \c getIRPGOFuncName()
-std::pair<StringRef, StringRef> getParsedIRPGOName(StringRef IRPGOName);
+LLVM_ABI std::pair<StringRef, StringRef>
+getParsedIRPGOName(StringRef IRPGOName);
 
 /// Return the name of the global variable used to store a function
 /// name in PGO instrumentation. \c FuncName is the IRPGO function name
 /// (returned by \c getIRPGOFuncName) for LLVM IR instrumentation and PGO
 /// function name (returned by \c getPGOFuncName) for front-end instrumentation.
-std::string getPGOFuncNameVarName(StringRef FuncName,
-                                  GlobalValue::LinkageTypes Linkage);
+LLVM_ABI std::string getPGOFuncNameVarName(StringRef FuncName,
+                                           GlobalValue::LinkageTypes Linkage);
 
 /// Create and return the global variable for function name used in PGO
 /// instrumentation. \c FuncName is the IRPGO function name (returned by
 /// \c getIRPGOFuncName) for LLVM IR instrumentation and PGO function name
 /// (returned by \c getPGOFuncName) for front-end instrumentation.
-GlobalVariable *createPGOFuncNameVar(Function &F, StringRef PGOFuncName);
+LLVM_ABI GlobalVariable *createPGOFuncNameVar(Function &F,
+                                              StringRef PGOFuncName);
 
 /// Create and return the global variable for function name used in PGO
 /// instrumentation. \c FuncName is the IRPGO function name (returned by
 /// \c getIRPGOFuncName) for LLVM IR instrumentation and PGO function name
 /// (returned by \c getPGOFuncName) for front-end instrumentation.
-GlobalVariable *createPGOFuncNameVar(Module &M,
-                                     GlobalValue::LinkageTypes Linkage,
-                                     StringRef PGOFuncName);
+LLVM_ABI GlobalVariable *createPGOFuncNameVar(Module &M,
+                                              GlobalValue::LinkageTypes Linkage,
+                                              StringRef PGOFuncName);
 
 /// Return the initializer in string of the PGO name var \c NameVar.
-StringRef getPGOFuncNameVarInitializer(GlobalVariable *NameVar);
+LLVM_ABI StringRef getPGOFuncNameVarInitializer(GlobalVariable *NameVar);
 
 /// Given a PGO function name, remove the filename prefix and return
 /// the original (static) function name.
-StringRef getFuncNameWithoutPrefix(StringRef PGOFuncName,
-                                   StringRef FileName = "<unknown>");
+LLVM_ABI StringRef getFuncNameWithoutPrefix(StringRef PGOFuncName,
+                                            StringRef FileName = "<unknown>");
 
 /// Given a vector of strings (names of global objects like functions or,
 /// virtual tables) \c NameStrs, the method generates a combined string \c
@@ -281,28 +283,31 @@ StringRef getFuncNameWithoutPrefix(StringRef PGOFuncName,
 ///  third field is the uncompressed strings; otherwise it is the
 /// compressed string. When the string compression is off, the
 /// second field will have value zero.
-Error collectGlobalObjectNameStrings(ArrayRef<std::string> NameStrs,
-                                     bool doCompression, std::string &Result);
+LLVM_ABI Error collectGlobalObjectNameStrings(ArrayRef<std::string> NameStrs,
+                                              bool doCompression,
+                                              std::string &Result);
 
 /// Produce \c Result string with the same format described above. The input
 /// is vector of PGO function name variables that are referenced.
 /// The global variable element in 'NameVars' is a string containing the pgo
 /// name of a function. See `createPGOFuncNameVar` that creates these global
 /// variables.
-Error collectPGOFuncNameStrings(ArrayRef<GlobalVariable *> NameVars,
-                                std::string &Result, bool doCompression = true);
+LLVM_ABI Error collectPGOFuncNameStrings(ArrayRef<GlobalVariable *> NameVars,
+                                         std::string &Result,
+                                         bool doCompression = true);
 
-Error collectVTableStrings(ArrayRef<GlobalVariable *> VTables,
-                           std::string &Result, bool doCompression);
+LLVM_ABI Error collectVTableStrings(ArrayRef<GlobalVariable *> VTables,
+                                    std::string &Result, bool doCompression);
 
 /// Check if INSTR_PROF_RAW_VERSION_VAR is defined. This global is only being
 /// set in IR PGO compilation.
-bool isIRPGOFlagSet(const Module *M);
+LLVM_ABI bool isIRPGOFlagSet(const Module *M);
 
 /// Check if we can safely rename this Comdat function. Instances of the same
 /// comdat function may have different control flows thus can not share the
 /// same counter variable.
-bool canRenameComdatFunc(const Function &F, bool CheckAddressTaken = false);
+LLVM_ABI bool canRenameComdatFunc(const Function &F,
+                                  bool CheckAddressTaken = false);
 
 enum InstrProfValueKind : uint32_t {
 #define VALUE_PROF_KIND(Enumerator, Value, Descr) Enumerator = Value,
@@ -312,23 +317,24 @@ enum InstrProfValueKind : uint32_t {
 /// Get the value profile data for value site \p SiteIdx from \p InstrProfR
 /// and annotate the instruction \p Inst with the value profile meta data.
 /// Annotate up to \p MaxMDCount (default 3) number of records per value site.
-void annotateValueSite(Module &M, Instruction &Inst,
-                       const InstrProfRecord &InstrProfR,
-                       InstrProfValueKind ValueKind, uint32_t SiteIndx,
-                       uint32_t MaxMDCount = 3);
+LLVM_ABI void annotateValueSite(Module &M, Instruction &Inst,
+                                const InstrProfRecord &InstrProfR,
+                                InstrProfValueKind ValueKind, uint32_t SiteIndx,
+                                uint32_t MaxMDCount = 3);
 
 /// Same as the above interface but using an ArrayRef, as well as \p Sum.
 /// This function will not annotate !prof metadata on the instruction if the
 /// referenced array is empty.
-void annotateValueSite(Module &M, Instruction &Inst,
-                       ArrayRef<InstrProfValueData> VDs, uint64_t Sum,
-                       InstrProfValueKind ValueKind, uint32_t MaxMDCount);
+LLVM_ABI void annotateValueSite(Module &M, Instruction &Inst,
+                                ArrayRef<InstrProfValueData> VDs, uint64_t Sum,
+                                InstrProfValueKind ValueKind,
+                                uint32_t MaxMDCount);
 
 // TODO: Unify metadata name 'PGOFuncName' and 'PGOName', by supporting read
 // of this metadata for backward compatibility and generating 'PGOName' only.
 /// Extract the value profile data from \p Inst and returns them if \p Inst is
 /// annotated with value profile data. Returns an empty vector otherwise.
-SmallVector<InstrProfValueData, 4>
+LLVM_ABI SmallVector<InstrProfValueData, 4>
 getValueProfDataFromInst(const Instruction &Inst, InstrProfValueKind ValueKind,
                          uint32_t MaxNumValueData, uint64_t &TotalC,
                          bool GetNoICPValue = false);
@@ -338,32 +344,33 @@ inline StringRef getPGOFuncNameMetadataName() { return "PGOFuncName"; }
 inline StringRef getPGONameMetadataName() { return "PGOName"; }
 
 /// Return the PGOFuncName meta data associated with a function.
-MDNode *getPGOFuncNameMetadata(const Function &F);
+LLVM_ABI MDNode *getPGOFuncNameMetadata(const Function &F);
 
-std::string getPGOName(const GlobalVariable &V, bool InLTO = false);
+LLVM_ABI std::string getPGOName(const GlobalVariable &V, bool InLTO = false);
 
 /// Create the PGOFuncName meta data if PGOFuncName is different from
 /// function's raw name. This should only apply to internal linkage functions
 /// declared by users only.
 /// TODO: Update all callers to 'createPGONameMetadata' and deprecate this
 /// function.
-void createPGOFuncNameMetadata(Function &F, StringRef PGOFuncName);
+LLVM_ABI void createPGOFuncNameMetadata(Function &F, StringRef PGOFuncName);
 
 /// Create the PGOName metadata if a global object's PGO name is different from
 /// its mangled name. This should apply to local-linkage global objects only.
-void createPGONameMetadata(GlobalObject &GO, StringRef PGOName);
+LLVM_ABI void createPGONameMetadata(GlobalObject &GO, StringRef PGOName);
 
 /// Check if we can use Comdat for profile variables. This will eliminate
 /// the duplicated profile variables for Comdat functions.
-bool needsComdatForCounter(const GlobalObject &GV, const Module &M);
+LLVM_ABI bool needsComdatForCounter(const GlobalObject &GV, const Module &M);
 
 /// \c NameStrings is a string composed of one or more possibly encoded
 /// sub-strings. The substrings are separated by `\01` (returned by
 /// InstrProf.h:getInstrProfNameSeparator). This method decodes the string and
 /// calls `NameCallback` for each substring.
-Error readAndDecodeStrings(StringRef NameStrings,
-                           std::function<Error(StringRef)> NameCallback);
+LLVM_ABI Error readAndDecodeStrings(
+    StringRef NameStrings, std::function<Error(StringRef)> NameCallback);
 
+LLVM_ABI Error readAndDecodeStrings(StringRef NameStrings, std::function<Error(StringRef)> NameCallback, const std::string &Architecture);
 /// An enum describing the attributes of an instrumented profile.
 enum class InstrProfKind {
   Unknown = 0x0,
@@ -388,7 +395,7 @@ enum class InstrProfKind {
   LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/LoopEntriesInstrumentation)
 };
 
-const std::error_category &instrprof_category();
+LLVM_ABI const std::error_category &instrprof_category();
 
 enum class instrprof_error {
   success = 0,
@@ -431,16 +438,17 @@ struct TemporalProfTraceTy {
   /// Use a set of temporal profile traces to create a list of balanced
   /// partitioning function nodes used by BalancedPartitioning to generate a
   /// function order that reduces page faults during startup
-  static void createBPFunctionNodes(ArrayRef<TemporalProfTraceTy> Traces,
-                                    std::vector<BPFunctionNode> &Nodes,
-                                    bool RemoveOutlierUNs = true);
+  LLVM_ABI static void
+  createBPFunctionNodes(ArrayRef<TemporalProfTraceTy> Traces,
+                        std::vector<BPFunctionNode> &Nodes,
+                        bool RemoveOutlierUNs = true);
 };
 
 inline std::error_code make_error_code(instrprof_error E) {
   return std::error_code(static_cast<int>(E), instrprof_category());
 }
 
-class InstrProfError : public ErrorInfo<InstrProfError> {
+class LLVM_ABI InstrProfError : public ErrorInfo<InstrProfError> {
 public:
   InstrProfError(instrprof_error Err, const Twine &ErrStr = Twine())
       : Err(Err), Msg(ErrStr.str()) {
@@ -503,9 +511,14 @@ class InstrProfSymtab {
   // Returns the canonical name of the given PGOName. In a canonical name, all
   // suffixes that begins with "." except ".__uniq." are stripped.
   // FIXME: Unify this with `FunctionSamples::getCanonicalFnName`.
-  static StringRef getCanonicalName(StringRef PGOName);
+  LLVM_ABI static StringRef getCanonicalName(StringRef PGOName);
 
+  //ANDRES Function
+  const std::string &getArchitecture() {return Architecture;}
+  void setArchitecture(const std::string &Arch) {Architecture = Arch;}
+  //ANDRES Function
 private:
+  std::string Architecture;
   using AddrIntervalMap =
       IntervalMap<uint64_t, uint64_t, 4, IntervalMapHalfOpenInfo<uint64_t>>;
   StringRef Data;
@@ -537,7 +550,6 @@ class InstrProfSymtab {
   // This map is only populated and used by raw instr profile reader.
   AddrIntervalMap VTableAddrMap;
   bool Sorted = false;
-
   static StringRef getExternalSymbol() { return "** External Symbol **"; }
 
   // Add the function into the symbol table, by creating the following
@@ -577,22 +589,23 @@ class InstrProfSymtab {
   /// only initialize the symtab with reference to the data and
   /// the section base address. The decompression will be delayed
   /// until before it is used. See also \c create(StringRef) method.
-  Error create(object::SectionRef &Section);
+  LLVM_ABI Error create(object::SectionRef &Section);
 
   /// \c NameStrings is a string composed of one of more sub-strings
   ///  encoded in the format described in \c collectPGOFuncNameStrings.
   /// This method is a wrapper to \c readAndDecodeStrings method.
-  Error create(StringRef NameStrings);
+  LLVM_ABI Error create(StringRef NameStrings);
 
   /// Initialize symtab states with function names and vtable names. \c
   /// FuncNameStrings is a string composed of one or more encoded function name
   /// strings, and \c VTableNameStrings composes of one or more encoded vtable
   /// names. This interface is solely used by raw profile reader.
-  Error create(StringRef FuncNameStrings, StringRef VTableNameStrings);
+  LLVM_ABI Error create(StringRef FuncNameStrings, StringRef VTableNameStrings);
 
   /// Initialize 'this' with the set of vtable names encoded in
   /// \c CompressedVTableNames.
-  Error initVTableNamesFromCompressedStrings(StringRef CompressedVTableNames);
+  LLVM_ABI Error
+  initVTableNamesFromCompressedStrings(StringRef CompressedVTableNames);
 
   /// This interface is used by reader of CoverageMapping test
   /// format.
@@ -604,7 +617,8 @@ class InstrProfSymtab {
   /// indicates if this is called from LTO optimization passes.
   /// A canonical name, removing non-__uniq suffixes, is added if
   /// \c AddCanonical is true.
-  Error create(Module &M, bool InLTO = false, bool AddCanonical = true);
+  LLVM_ABI Error create(Module &M, bool InLTO = false,
+                        bool AddCanonical = true);
 
   /// Create InstrProfSymtab from a set of names iteratable from
   /// \p IterRange. This interface is used by IndexedProfReader.
@@ -620,6 +634,9 @@ class InstrProfSymtab {
 
   // Map the MD5 of the symbol name to the name.
   Error addSymbolName(StringRef SymbolName) {
+    StringRef FuncName;
+    StringRef ArchName;
+    std::tie(FuncName, ArchName) = SymbolName.split(":");
     if (SymbolName.empty())
       return make_error<InstrProfError>(instrprof_error::malformed,
                                         "symbol name is empty");
@@ -667,15 +684,15 @@ class InstrProfSymtab {
   }
 
   /// Return a function's hash, or 0, if the function isn't in this SymTab.
-  uint64_t getFunctionHashFromAddress(uint64_t Address);
+  LLVM_ABI uint64_t getFunctionHashFromAddress(uint64_t Address);
 
   /// Return a vtable's hash, or 0 if the vtable doesn't exist in this SymTab.
-  uint64_t getVTableHashFromAddress(uint64_t Address);
+  LLVM_ABI uint64_t getVTableHashFromAddress(uint64_t Address);
 
   /// Return function's PGO name from the function name's symbol
   /// address in the object file. If an error occurs, return
   /// an empty string.
-  StringRef getFuncName(uint64_t FuncNameAddress, size_t NameSize);
+  LLVM_ABI StringRef getFuncName(uint64_t FuncNameAddress, size_t NameSize);
 
   /// Return name of functions or global variables from the name's md5 hash
   /// value. If not found, return an empty string.
@@ -702,7 +719,7 @@ class InstrProfSymtab {
   inline StringRef getNameData() const { return Data; }
 
   /// Dump the symbols in this table.
-  void dumpNames(raw_ostream &OS) const;
+  LLVM_ABI void dumpNames(raw_ostream &OS) const;
 };
 
 Error InstrProfSymtab::create(StringRef D, uint64_t BaseAddr) {
@@ -814,17 +831,17 @@ struct OverlapStats {
 
   OverlapStats(OverlapStatsLevel L = ProgramLevel) : Level(L) {}
 
-  void dump(raw_fd_ostream &OS) const;
+  LLVM_ABI void dump(raw_fd_ostream &OS) const;
 
   void setFuncInfo(StringRef Name, uint64_t Hash) {
     FuncName = Name;
     FuncHash = Hash;
   }
 
-  Error accumulateCounts(const std::string &BaseFilename,
-                         const std::string &TestFilename, bool IsCS);
-  void addOneMismatch(const CountSumOrPercent &MismatchFunc);
-  void addOneUnique(const CountSumOrPercent &UniqueFunc);
+  LLVM_ABI Error accumulateCounts(const std::string &BaseFilename,
+                                  const std::string &TestFilename, bool IsCS);
+  LLVM_ABI void addOneMismatch(const CountSumOrPercent &MismatchFunc);
+  LLVM_ABI void addOneUnique(const CountSumOrPercent &UniqueFunc);
 
   static inline double score(uint64_t Val1, uint64_t Val2, double Sum1,
                              double Sum2) {
@@ -861,14 +878,15 @@ struct InstrProfValueSiteRecord {
 
   /// Merge data from another InstrProfValueSiteRecord
   /// Optionally scale merged counts by \p Weight.
-  void merge(InstrProfValueSiteRecord &Input, uint64_t Weight,
-             function_ref<void(instrprof_error)> Warn);
+  LLVM_ABI void merge(InstrProfValueSiteRecord &Input, uint64_t Weight,
+                      function_ref<void(instrprof_error)> Warn);
   /// Scale up value profile data counts by N (Numerator) / D (Denominator).
-  void scale(uint64_t N, uint64_t D, function_ref<void(instrprof_error)> Warn);
+  LLVM_ABI void scale(uint64_t N, uint64_t D,
+                      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);
+  LLVM_ABI void overlap(InstrProfValueSiteRecord &Input, uint32_t ValueKind,
+                        OverlapStats &Overlap, OverlapStats &FuncLevelOverlap);
 };
 
 /// Profiling information for a single function.
@@ -920,18 +938,19 @@ struct InstrProfRecord {
 
   /// Add ValueData for ValueKind at value Site.  We do not support adding sites
   /// out of order.  Site must go up from 0 one by one.
-  void addValueData(uint32_t ValueKind, uint32_t Site,
-                    ArrayRef<InstrProfValueData> VData,
-                    InstrProfSymtab *SymTab);
+  LLVM_ABI void addValueData(uint32_t ValueKind, uint32_t Site,
+                             ArrayRef<InstrProfValueData> VData,
+                             InstrProfSymtab *SymTab);
 
   /// Merge the counts in \p Other into this one.
   /// Optionally scale merged counts by \p Weight.
-  void merge(InstrProfRecord &Other, uint64_t Weight,
-             function_ref<void(instrprof_error)> Warn);
+  LLVM_ABI void merge(InstrProfRecord &Other, uint64_t Weight,
+                      function_ref<void(instrprof_error)> Warn);
 
   /// Scale up profile counts (including value profile data) by
   /// a factor of (N / D).
-  void scale(uint64_t N, uint64_t D, function_ref<void(instrprof_error)> Warn);
+  LLVM_ABI void scale(uint64_t N, uint64_t D,
+                      function_ref<void(instrprof_error)> Warn);
 
   /// Sort value profile data (per site) by count.
   void sortValueData() {
@@ -950,16 +969,16 @@ struct InstrProfRecord {
   void clearValueData() { ValueData = nullptr; }
 
   /// Compute the sums of all counts and store in Sum.
-  void accumulateCounts(CountSumOrPercent &Sum) const;
+  LLVM_ABI void accumulateCounts(CountSumOrPercent &Sum) const;
 
   /// Compute the overlap b/w this IntrprofRecord and Other.
-  void overlap(InstrProfRecord &Other, OverlapStats &Overlap,
-               OverlapStats &FuncLevelOverlap, uint64_t ValueCutoff);
+  LLVM_ABI 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);
+  LLVM_ABI void overlapValueProfData(uint32_t ValueKind, InstrProfRecord &Src,
+                                     OverlapStats &Overlap,
+                                     OverlapStats &FuncLevelOverlap);
 
   enum CountPseudoKind {
     NotPseudo = 0,
@@ -1187,15 +1206,15 @@ struct Header {
 
   // Reads a header struct from the buffer. Header fields are in machine native
   // endianness.
-  static Expected<Header> readFromBuffer(const unsigned char *Buffer);
+  LLVM_ABI static Expected<Header> readFromBuffer(const unsigned char *Buffer);
 
   // Returns the size of the header in bytes for all valid fields based on the
   // version. I.e a older version header will return a smaller size.
-  size_t size() const;
+  LLVM_ABI size_t size() const;
 
   // Return the indexed profile version, i.e., the least significant 32 bits
   // in Header.Version.
-  uint64_t getIndexedProfileVersion() const;
+  LLVM_ABI uint64_t getIndexedProfileVersion() const;
 };
 
 // Profile summary data recorded in the profile data file in indexed
@@ -1340,11 +1359,11 @@ struct Header {
 } // end namespace RawInstrProf
 
 // Create the variable for the profile file name.
-void createProfileFileNameVar(Module &M, StringRef InstrProfileOutput);
+LLVM_ABI void createProfileFileNameVar(Module &M, StringRef InstrProfileOutput);
 
 // Whether to compress function names in profile records, and filenames in
 // code coverage mappings. Used by the Instrumentation library and unit tests.
-extern cl::opt<bool> DoInstrProfNameCompression;
+LLVM_ABI extern cl::opt<bool> DoInstrProfNameCompression;
 
 } // end namespace llvm
 #endif // LLVM_PROFILEDATA_INSTRPROF_H
diff --git a/llvm/include/llvm/ProfileData/InstrProfReader.h b/llvm/include/llvm/ProfileData/InstrProfReader.h
index c250a9ede39bc..af3b305192aa3 100644
--- a/llvm/include/llvm/ProfileData/InstrProfReader.h
+++ b/llvm/include/llvm/ProfileData/InstrProfReader.h
@@ -18,10 +18,13 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/IR/ProfileSummary.h"
 #include "llvm/Object/BuildID.h"
+#include "llvm/ProfileData/DataAccessProf.h"
 #include "llvm/ProfileData/InstrProf.h"
 #include "llvm/ProfileData/InstrProfCorrelator.h"
 #include "llvm/ProfileData/MemProf.h"
+#include "llvm/ProfileData/MemProfSummary.h"
 #include "llvm/ProfileData/MemProfYAML.h"
+#include "llvm/Support/Compiler.h"
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/LineIterator.h"
@@ -156,9 +159,12 @@ class InstrProfReader {
   virtual InstrProfSymtab &getSymtab() = 0;
 
   /// Compute the sum of counts and return in Sum.
-  void accumulateCounts(CountSumOrPercent &Sum, bool IsCS);
+  LLVM_ABI void accumulateCounts(CountSumOrPercent &Sum, bool IsCS);
 
 protected:
+  //ANDRES Storing Architecture Information as a string
+  std::string Architecture;
+
   std::unique_ptr<InstrProfSymtab> Symtab;
   /// A list of temporal profile traces.
   SmallVector<TemporalProfTraceTy> TemporalProfTraces;
@@ -201,22 +207,25 @@ class InstrProfReader {
 
   /// Factory method to create an appropriately typed reader for the given
   /// instrprof file.
-  static Expected<std::unique_ptr<InstrProfReader>> create(
+  LLVM_ABI static Expected<std::unique_ptr<InstrProfReader>> create(
       const Twine &Path, vfs::FileSystem &FS,
       const InstrProfCorrelator *Correlator = nullptr,
       const object::BuildIDFetcher *BIDFetcher = nullptr,
       const InstrProfCorrelator::ProfCorrelatorKind BIDFetcherCorrelatorKind =
           InstrProfCorrelator::ProfCorrelatorKind::NONE,
-      std::function<void(Error)> Warn = nullptr);
+      std::function<void(Error)> Warn = nullptr, const std::string &Architecture = "");
 
-  static Expected<std::unique_ptr<InstrProfReader>> create(
+  LLVM_ABI static Expected<std::unique_ptr<InstrProfReader>> create(
       std::unique_ptr<MemoryBuffer> Buffer,
       const InstrProfCorrelator *Correlator = nullptr,
       const object::BuildIDFetcher *BIDFetcher = nullptr,
       const InstrProfCorrelator::ProfCorrelatorKind BIDFetcherCorrelatorKind =
           InstrProfCorrelator::ProfCorrelatorKind::NONE,
-      std::function<void(Error)> Warn = nullptr);
+      std::function<void(Error)> Warn = nullptr, const std::string &Architecture = "");
+  
+  const std::string &getArchitecture() {return Architecture;}
 
+  void setArchitecture(const std::string &Arch) {Architecture = Arch;}
   /// \param Weight for raw profiles use this as the temporal profile trace
   ///               weight
   /// \returns a list of temporal profile traces.
@@ -240,7 +249,7 @@ class InstrProfReader {
 ///
 /// Each record consists of a function name, a function hash, a number of
 /// counters, and then each counter value, in that order.
-class TextInstrProfReader : public InstrProfReader {
+class LLVM_ABI TextInstrProfReader : public InstrProfReader {
 private:
   /// The profile data file contents.
   std::unique_ptr<MemoryBuffer> DataBuffer;
@@ -533,7 +542,7 @@ class InstrProfLookupTrait {
   static StringRef GetInternalKey(StringRef K) { return K; }
   static StringRef GetExternalKey(StringRef K) { return K; }
 
-  hash_value_type ComputeHash(StringRef K);
+  LLVM_ABI hash_value_type ComputeHash(StringRef K);
 
   static std::pair<offset_type, offset_type>
   ReadKeyDataLength(const unsigned char *&D) {
@@ -550,9 +559,10 @@ class InstrProfLookupTrait {
     return StringRef((const char *)D, N);
   }
 
-  bool readValueProfilingData(const unsigned char *&D,
-                              const unsigned char *const End);
-  data_type ReadData(StringRef K, const unsigned char *D, offset_type N);
+  LLVM_ABI bool readValueProfilingData(const unsigned char *&D,
+                                       const unsigned char *const End);
+  LLVM_ABI data_type ReadData(StringRef K, const unsigned char *D,
+                              offset_type N);
 
   // Used for testing purpose only.
   void setValueProfDataEndianness(llvm::endianness Endianness) {
@@ -689,6 +699,8 @@ class IndexedMemProfReader {
   /// The MemProf version.
   memprof::IndexedVersion Version =
       static_cast<memprof::IndexedVersion>(memprof::MinimumSupportedVersion);
+  /// MemProf summary (if available, version >= 4).
+  std::unique_ptr<memprof::MemProfSummary> MemProfSum;
   /// MemProf profile schema (if available).
   memprof::MemProfSchema Schema;
   /// MemProf record profile data on-disk indexed via llvm::md5(FunctionName).
@@ -703,28 +715,34 @@ class IndexedMemProfReader {
   const unsigned char *CallStackBase = nullptr;
   // The number of elements in the radix tree array.
   unsigned RadixTreeSize = 0;
+  /// The data access profiles, deserialized from binary data.
+  std::unique_ptr<memprof::DataAccessProfData> DataAccessProfileData;
 
   Error deserializeV2(const unsigned char *Start, const unsigned char *Ptr);
   Error deserializeRadixTreeBased(const unsigned char *Start,
-                                  const unsigned char *Ptr);
+                                  const unsigned char *Ptr,
+                                  memprof::IndexedVersion Version);
 
 public:
   IndexedMemProfReader() = default;
 
-  Error deserialize(const unsigned char *Start, uint64_t MemProfOffset);
+  LLVM_ABI Error deserialize(const unsigned char *Start,
+                             uint64_t MemProfOffset);
 
-  Expected<memprof::MemProfRecord>
+  LLVM_ABI Expected<memprof::MemProfRecord>
   getMemProfRecord(const uint64_t FuncNameHash) const;
 
-  DenseMap<uint64_t, SmallVector<memprof::CallEdgeTy, 0>>
+  LLVM_ABI DenseMap<uint64_t, SmallVector<memprof::CallEdgeTy, 0>>
   getMemProfCallerCalleePairs() const;
 
   // Return the entire MemProf profile.
-  memprof::AllMemProfData getAllMemProfData() const;
+  LLVM_ABI memprof::AllMemProfData getAllMemProfData() const;
+
+  memprof::MemProfSummary *getSummary() const { return MemProfSum.get(); }
 };
 
 /// Reader for the indexed binary instrprof format.
-class IndexedInstrProfReader : public InstrProfReader {
+class LLVM_ABI IndexedInstrProfReader : public InstrProfReader {
 private:
   /// The profile data file contents.
   std::unique_ptr<MemoryBuffer> DataBuffer;
@@ -883,6 +901,11 @@ class IndexedInstrProfReader : public InstrProfReader {
     }
   }
 
+  /// Return the MemProf summary. Will be null if unavailable (version < 4).
+  memprof::MemProfSummary *getMemProfSummary() const {
+    return MemProfReader.getSummary();
+  }
+
   Error readBinaryIds(std::vector<llvm::object::BuildID> &BinaryIds) override;
   Error printBinaryIds(raw_ostream &OS) override;
 };
diff --git a/llvm/include/llvm/ProfileData/InstrProfWriter.h b/llvm/include/llvm/ProfileData/InstrProfWriter.h
index b72c901dbb5b2..f339fe2c2a9eb 100644
--- a/llvm/include/llvm/ProfileData/InstrProfWriter.h
+++ b/llvm/include/llvm/ProfileData/InstrProfWriter.h
@@ -19,8 +19,11 @@
 #include "llvm/ADT/StringMap.h"
 #include "llvm/IR/GlobalValue.h"
 #include "llvm/Object/BuildID.h"
+#include "llvm/ProfileData/DataAccessProf.h"
 #include "llvm/ProfileData/IndexedMemProfData.h"
 #include "llvm/ProfileData/InstrProf.h"
+#include "llvm/ProfileData/MemProfSummaryBuilder.h"
+#include "llvm/Support/Compiler.h"
 #include "llvm/Support/Error.h"
 #include <cstdint>
 #include <memory>
@@ -81,30 +84,36 @@ class InstrProfWriter {
   // Whether to generated random memprof hotness for testing.
   bool MemprofGenerateRandomHotness;
 
+  std::unique_ptr<memprof::DataAccessProfData> DataAccessProfileData;
+
+  // MemProf summary builder to which records are added as MemProf data is added
+  // to the writer.
+  memprof::MemProfSummaryBuilder MemProfSumBuilder;
+
 public:
   // For memprof testing, random hotness can be assigned to the contexts if
   // MemprofGenerateRandomHotness is enabled. The random seed can be either
   // provided by MemprofGenerateRandomHotnessSeed, or if that is 0, one will be
   // generated in the writer using the current time.
-  InstrProfWriter(bool Sparse = false,
-                  uint64_t TemporalProfTraceReservoirSize = 0,
-                  uint64_t MaxTemporalProfTraceLength = 0,
-                  bool WritePrevVersion = false,
-                  memprof::IndexedVersion MemProfVersionRequested =
-                      static_cast<memprof::IndexedVersion>(
-                          memprof::MinimumSupportedVersion),
-                  bool MemProfFullSchema = false,
-                  bool MemprofGenerateRandomHotness = false,
-                  unsigned MemprofGenerateRandomHotnessSeed = 0);
-  ~InstrProfWriter();
+  LLVM_ABI InstrProfWriter(bool Sparse = false,
+                           uint64_t TemporalProfTraceReservoirSize = 0,
+                           uint64_t MaxTemporalProfTraceLength = 0,
+                           bool WritePrevVersion = false,
+                           memprof::IndexedVersion MemProfVersionRequested =
+                               static_cast<memprof::IndexedVersion>(
+                                   memprof::MinimumSupportedVersion),
+                           bool MemProfFullSchema = false,
+                           bool MemprofGenerateRandomHotness = false,
+                           unsigned MemprofGenerateRandomHotnessSeed = 0);
+  LLVM_ABI ~InstrProfWriter();
 
   StringMap<ProfilingData> &getProfileData() { return FunctionData; }
 
   /// Add function counts for the given function. If there are already counts
   /// for this function and the hash and number of counts match, each counter is
   /// summed. Optionally scale counts by \p Weight.
-  void addRecord(NamedInstrProfRecord &&I, uint64_t Weight,
-                 function_ref<void(Error)> Warn);
+  LLVM_ABI void addRecord(NamedInstrProfRecord &&I, uint64_t Weight,
+                          function_ref<void(Error)> Warn);
   void addRecord(NamedInstrProfRecord &&I, function_ref<void(Error)> Warn) {
     addRecord(std::move(I), 1, Warn);
   }
@@ -112,42 +121,47 @@ class InstrProfWriter {
 
   /// Add \p SrcTraces using reservoir sampling where \p SrcStreamSize is the
   /// total number of temporal profiling traces the source has seen.
-  void addTemporalProfileTraces(SmallVectorImpl<TemporalProfTraceTy> &SrcTraces,
-                                uint64_t SrcStreamSize);
+  LLVM_ABI void
+  addTemporalProfileTraces(SmallVectorImpl<TemporalProfTraceTy> &SrcTraces,
+                           uint64_t SrcStreamSize);
 
   /// Add the entire MemProfData \p Incoming to the writer context.
-  bool addMemProfData(memprof::IndexedMemProfData Incoming,
-                      function_ref<void(Error)> Warn);
+  LLVM_ABI bool addMemProfData(memprof::IndexedMemProfData Incoming,
+                               function_ref<void(Error)> Warn);
 
   // Add a binary id to the binary ids list.
-  void addBinaryIds(ArrayRef<llvm::object::BuildID> BIs);
+  LLVM_ABI void addBinaryIds(ArrayRef<llvm::object::BuildID> BIs);
+
+  LLVM_ABI void addDataAccessProfData(
+      std::unique_ptr<memprof::DataAccessProfData> DataAccessProfile);
 
   /// Merge existing function counts from the given writer.
-  void mergeRecordsFromWriter(InstrProfWriter &&IPW,
-                              function_ref<void(Error)> Warn);
+  LLVM_ABI void mergeRecordsFromWriter(InstrProfWriter &&IPW,
+                                       function_ref<void(Error)> Warn);
 
   /// Write the profile to \c OS
-  Error write(raw_fd_ostream &OS);
+  LLVM_ABI Error write(raw_fd_ostream &OS);
 
   /// Write the profile to a string output stream \c OS
-  Error write(raw_string_ostream &OS);
+  LLVM_ABI Error write(raw_string_ostream &OS);
 
   /// Write the profile in text format to \c OS
-  Error writeText(raw_fd_ostream &OS);
+  LLVM_ABI Error writeText(raw_fd_ostream &OS);
 
   /// Write temporal profile trace data to the header in text format to \c OS
-  void writeTextTemporalProfTraceData(raw_fd_ostream &OS,
-                                      InstrProfSymtab &Symtab);
+  LLVM_ABI void writeTextTemporalProfTraceData(raw_fd_ostream &OS,
+                                               InstrProfSymtab &Symtab);
 
-  Error validateRecord(const InstrProfRecord &Func);
+  LLVM_ABI Error validateRecord(const InstrProfRecord &Func);
 
   /// Write \c Record in text format to \c OS
-  static void writeRecordInText(StringRef Name, uint64_t Hash,
-                                const InstrProfRecord &Counters,
-                                InstrProfSymtab &Symtab, raw_fd_ostream &OS);
+  LLVM_ABI static void writeRecordInText(StringRef Name, uint64_t Hash,
+                                         const InstrProfRecord &Counters,
+                                         InstrProfSymtab &Symtab,
+                                         raw_fd_ostream &OS);
 
   /// Write the profile, returning the raw data. For testing.
-  std::unique_ptr<MemoryBuffer> writeBuffer();
+  LLVM_ABI std::unique_ptr<MemoryBuffer> writeBuffer();
 
   /// Update the attributes of the current profile from the attributes
   /// specified. An error is returned if IR and FE profiles are mixed.
@@ -195,17 +209,18 @@ class InstrProfWriter {
   }
 
   // Internal interfaces for testing purpose only.
-  void setValueProfDataEndianness(llvm::endianness Endianness);
-  void setOutputSparse(bool Sparse);
+  LLVM_ABI void setValueProfDataEndianness(llvm::endianness Endianness);
+  LLVM_ABI void setOutputSparse(bool Sparse);
   void setMemProfVersionRequested(memprof::IndexedVersion Version) {
     MemProfVersionRequested = Version;
   }
   void setMemProfFullSchema(bool Full) { MemProfFullSchema = Full; }
   // 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);
+  LLVM_ABI void overlapRecord(NamedInstrProfRecord &&Other,
+                              OverlapStats &Overlap,
+                              OverlapStats &FuncLevelOverlap,
+                              const OverlapFuncFilters &FuncFilter);
 
 private:
   void addRecord(StringRef Name, uint64_t Hash, InstrProfRecord &&I,
diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp
index 368e3535fe905..ba852ac1405d8 100644
--- a/llvm/lib/ProfileData/InstrProf.cpp
+++ b/llvm/lib/ProfileData/InstrProf.cpp
@@ -572,6 +572,50 @@ Error InstrProfSymtab::addVTableWithName(GlobalVariable &VTable,
   return Error::success();
 }
 
+Error readAndDecodeStrings(StringRef NameStrings,
+                           std::function<Error(StringRef)> NameCallback, const std::string &Architecture) {
+  const uint8_t *P = NameStrings.bytes_begin();
+  const uint8_t *EndP = NameStrings.bytes_end();
+  while (P < EndP) {
+    uint32_t N;
+    uint64_t UncompressedSize = decodeULEB128(P, &N);
+    P += N;
+    uint64_t CompressedSize = decodeULEB128(P, &N);
+    P += N;
+    const bool IsCompressed = (CompressedSize != 0);
+    SmallVector<uint8_t, 128> UncompressedNameStrings;
+    StringRef NameStrings;
+    if (IsCompressed) {
+      if (!llvm::compression::zlib::isAvailable())
+        return make_error<InstrProfError>(instrprof_error::zlib_unavailable);
+
+      if (Error E = compression::zlib::decompress(ArrayRef(P, CompressedSize),
+                                                  UncompressedNameStrings,
+                                                  UncompressedSize)) {
+        consumeError(std::move(E));
+        return make_error<InstrProfError>(instrprof_error::uncompress_failed);
+      }
+      P += CompressedSize;
+      NameStrings = toStringRef(UncompressedNameStrings);
+    } else {
+      NameStrings =
+          StringRef(reinterpret_cast<const char *>(P), UncompressedSize);
+      P += UncompressedSize;
+    }
+    // Now parse the name strings.
+    SmallVector<StringRef, 0> Names;
+    StringRef ArchRef(Architecture); 
+    NameStrings.split(Names, getInstrProfNameSeparator());
+    for (StringRef &Name : Names)
+      if (Error E = NameCallback(Name.str()+ ":" + ArchRef.str()*/))
+        return E;
+
+    while (P < EndP && *P == 0)
+      P++;
+  }
+  return Error::success();
+}
+
 Error readAndDecodeStrings(StringRef NameStrings,
                            std::function<Error(StringRef)> NameCallback) {
   const uint8_t *P = NameStrings.bytes_begin();
@@ -616,21 +660,18 @@ Error readAndDecodeStrings(StringRef NameStrings,
 }
 
 Error InstrProfSymtab::create(StringRef NameStrings) {
-  return readAndDecodeStrings(
-      NameStrings,
-      std::bind(&InstrProfSymtab::addFuncName, this, std::placeholders::_1));
+  return readAndDecodeStrings(NameStrings, std::bind(&InstrProfSymtab::addFuncName, this, std::placeholders::_1));
 }
 
 Error InstrProfSymtab::create(StringRef FuncNameStrings,
                               StringRef VTableNameStrings) {
-  if (Error E = readAndDecodeStrings(FuncNameStrings,
-                                     std::bind(&InstrProfSymtab::addFuncName,
-                                               this, std::placeholders::_1)))
+  const std::string &Architecture = getArchitecture();                                
+  if (Error E = readAndDecodeStrings(FuncNameStrings, std::bind(&InstrProfSymtab::addFuncName, this, std::placeholders::_1), Architecture))
     return E;
 
   return readAndDecodeStrings(
       VTableNameStrings,
-      std::bind(&InstrProfSymtab::addVTableName, this, std::placeholders::_1));
+      std::bind(&InstrProfSymtab::addVTableName, this, std::placeholders::_1), Architecture);
 }
 
 Error InstrProfSymtab::initVTableNamesFromCompressedStrings(
diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp
index a1eb08362087f..d78bf4e468ab8 100644
--- a/llvm/lib/ProfileData/InstrProfReader.cpp
+++ b/llvm/lib/ProfileData/InstrProfReader.cpp
@@ -18,7 +18,7 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/IR/ProfileSummary.h"
 #include "llvm/ProfileData/InstrProf.h"
-// #include "llvm/ProfileData/MemProf.h"
+#include "llvm/ProfileData/MemProf.h"
 #include "llvm/ProfileData/MemProfRadixTree.h"
 #include "llvm/ProfileData/ProfileCommon.h"
 #include "llvm/ProfileData/SymbolRemappingReader.h"
@@ -28,6 +28,7 @@
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/VirtualFileSystem.h"
+#include "llvm/ProfileData/InstrProfReader.h"
 #include <algorithm>
 #include <cstddef>
 #include <cstdint>
@@ -153,25 +154,26 @@ static void printBinaryIdsInternal(raw_ostream &OS,
   }
 }
 
-Expected<std::unique_ptr<InstrProfReader>> InstrProfReader::create(
+Expected<std::unique_ptr<InstrProfReader>> InstrProfReader::create( //STEP 1
     const Twine &Path, vfs::FileSystem &FS,
     const InstrProfCorrelator *Correlator,
     const object::BuildIDFetcher *BIDFetcher,
     const InstrProfCorrelator::ProfCorrelatorKind BIDFetcherCorrelatorKind,
-    std::function<void(Error)> Warn) {
+    std::function<void(Error)> Warn, 
+    const std::string &Architecture) {
   // Set up the buffer to read.
   auto BufferOrError = setupMemoryBuffer(Path, FS);
   if (Error E = BufferOrError.takeError())
     return std::move(E);
   return InstrProfReader::create(std::move(BufferOrError.get()), Correlator,
-                                 BIDFetcher, BIDFetcherCorrelatorKind, Warn);
+                                 BIDFetcher, BIDFetcherCorrelatorKind, Warn, Architecture);
 }
 
 Expected<std::unique_ptr<InstrProfReader>> InstrProfReader::create(
     std::unique_ptr<MemoryBuffer> Buffer, const InstrProfCorrelator *Correlator,
     const object::BuildIDFetcher *BIDFetcher,
     const InstrProfCorrelator::ProfCorrelatorKind BIDFetcherCorrelatorKind,
-    std::function<void(Error)> Warn) {
+    std::function<void(Error)> Warn, const std::string &Architecture) {
   if (Buffer->getBufferSize() == 0)
     return make_error<InstrProfError>(instrprof_error::empty_raw_profile);
 
@@ -193,9 +195,12 @@ Expected<std::unique_ptr<InstrProfReader>> InstrProfReader::create(
     return make_error<InstrProfError>(instrprof_error::unrecognized_format);
 
   // Initialize the reader and return the result.
+
+  if(Result){
+    Result->setArchitecture(Architecture);
+  }
   if (Error E = initializeReader(*Result))
     return std::move(E);
-
   return std::move(Result);
 }
 
@@ -509,7 +514,7 @@ bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) {
 }
 
 template <class IntPtrT>
-Error RawInstrProfReader<IntPtrT>::readHeader() {
+Error RawInstrProfReader<IntPtrT>::readHeader() { //STEP 2
   if (!hasFormat(*DataBuffer))
     return error(instrprof_error::bad_magic);
   if (DataBuffer->getBufferSize() < sizeof(RawInstrProf::Header))
@@ -549,7 +554,10 @@ Error RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) {
 }
 
 template <class IntPtrT>
-Error RawInstrProfReader<IntPtrT>::createSymtab(InstrProfSymtab &Symtab) {
+Error RawInstrProfReader<IntPtrT>::createSymtab(InstrProfSymtab &Symtab) { //STEP 5
+  
+  Symtab.setArchitecture(Architecture)
+  
   if (Error E = Symtab.create(StringRef(NamesStart, NamesEnd - NamesStart),
                               StringRef(VNamesStart, VNamesEnd - VNamesStart)))
     return error(std::move(E));
@@ -580,7 +588,7 @@ Error RawInstrProfReader<IntPtrT>::createSymtab(InstrProfSymtab &Symtab) {
 template <class IntPtrT>
 Error RawInstrProfReader<IntPtrT>::readHeader(
     const RawInstrProf::Header &Header) {
-  Version = swap(Header.Version);
+  Version = swap(Header.Version); //STEP 4
   if (GET_VERSION(Version) != RawInstrProf::Version)
     return error(instrprof_error::raw_profile_version_mismatch,
                  ("Profile uses raw profile format version = " +
@@ -697,7 +705,7 @@ Error RawInstrProfReader<IntPtrT>::readHeader(
   ValueDataStart = reinterpret_cast<const uint8_t *>(Start + ValueDataOffset);
 
   std::unique_ptr<InstrProfSymtab> NewSymtab = std::make_unique<InstrProfSymtab>();
-  if (Error E = createSymtab(*NewSymtab))
+  if (Error E = createSymtab(*NewSymtab)) //IMPORTANT FUNCTION CALL
     return E;
 
   Symtab = std::move(NewSymtab);
@@ -1552,6 +1560,20 @@ memprof::AllMemProfData IndexedMemProfReader::getAllMemProfData() const {
     Pair.Record = std::move(*Record);
     AllMemProfData.HeapProfileRecords.push_back(std::move(Pair));
   }
+  // Populate the data access profiles for yaml output.
+  if (DataAccessProfileData != nullptr) {
+    for (const auto &[SymHandleRef, RecordRef] :
+         DataAccessProfileData->getRecords())
+      AllMemProfData.YamlifiedDataAccessProfiles.Records.push_back(
+          memprof::DataAccessProfRecord(SymHandleRef, RecordRef.AccessCount,
+                                        RecordRef.Locations));
+    for (StringRef ColdSymbol : DataAccessProfileData->getKnownColdSymbols())
+      AllMemProfData.YamlifiedDataAccessProfiles.KnownColdSymbols.push_back(
+          ColdSymbol.str());
+    for (uint64_t Hash : DataAccessProfileData->getKnownColdHashes())
+      AllMemProfData.YamlifiedDataAccessProfiles.KnownColdStrHashes.push_back(
+          Hash);
+  }
   return AllMemProfData;
 }
 
diff --git a/llvm/tools/llvm-profdata-cross-arch/CMakeLists.txt b/llvm/tools/llvm-profdata-cross-arch/CMakeLists.txt
new file mode 100644
index 0000000000000..b37f76db883b5
--- /dev/null
+++ b/llvm/tools/llvm-profdata-cross-arch/CMakeLists.txt
@@ -0,0 +1,35 @@
+cmake_minimum_required(VERSION 3.13)
+project(llvm-profdata-cross-arch)
+
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+# Find LLVM package
+find_package(LLVM REQUIRED CONFIG)
+
+message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
+message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
+
+# Set LLVM include and library directories
+include_directories(${LLVM_INCLUDE_DIRS})
+link_directories(${LLVM_LIBRARY_DIRS})
+add_definitions(${LLVM_DEFINITIONS})
+
+# Define the source files
+set(SOURCES
+    ELFSymbolReader.cpp
+    llvm-profdata-cross-arch.cpp
+)
+
+# Add the executable
+add_executable(llvm-profdata-cross-arch ${SOURCES})
+
+# Link against LLVM libraries
+llvm_map_components_to_libnames(llvm_libs
+    Core
+    Support
+    Object
+    Demangle
+)
+
+target_link_libraries(llvm-profdata-cross-arch ${llvm_libs})
diff --git a/llvm/tools/llvm-profdata-cross-arch/ELFSymbolReader.cpp b/llvm/tools/llvm-profdata-cross-arch/ELFSymbolReader.cpp
new file mode 100644
index 0000000000000..61076f4e72073
--- /dev/null
+++ b/llvm/tools/llvm-profdata-cross-arch/ELFSymbolReader.cpp
@@ -0,0 +1,90 @@
+#include "ELFSymbolReader.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Demangle/Demangle.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/TargetSelect.h"
+
+
+using namespace llvm;
+using namespace llvm::object;
+
+Expected<std::vector<FunctionSymbol>> ELFSymbolReader::readSymbols(StringRef File){
+    Expected<OwningBinary<Binary>> BinOrErr = createBinary(File);
+    if(!BinOrErr){
+        return BinOrErr.takeError();
+    }
+
+    const ELFObjectFileBase *Obj = dyn_cast<ELFObjectFileBase>(BinOrErr->getBinary());
+    if(!Obj){
+        return createStringError(inconvertibleErrorCode(), "Not an ELF");
+    }
+
+    std::vector<FunctionSymbol> Syms;
+
+    for(const SymbolRef &Sym : Obj->symbols()){
+        if(!(cantFail(Sym.getType()) & SymbolRef::ST_Function)){
+            continue;
+        }
+        if(cantFail(Sym.getFlags()) & SymbolRef::SF_Undefined){
+            continue;
+        }
+        Expected<StringRef> NameOrErr = Sym.getName();
+        if(!NameOrErr){
+            consumeError(NameOrErr.takeError());
+            continue;
+        }
+        StringRef FuncNameRef = *NameOrErr;
+        if(FuncNameRef.starts_with("__")){
+            continue;
+        }
+        
+        // Skip symbols not in executable sections (e.g., not in .text)
+        Expected<section_iterator> SecOrErr = Sym.getSection();
+        if (!SecOrErr || *SecOrErr == Obj->section_end()){
+            continue;
+        }
+        StringRef SectionName;
+        if (Expected<StringRef> NameOrErr = (*SecOrErr)->getName()) {
+            SectionName = *NameOrErr;
+            if (!SectionName.equals_insensitive(".text")){
+                continue;
+            }
+        } else {
+            consumeError(NameOrErr.takeError());
+            continue;
+        }
+
+
+        uint64_t Addr = cantFail(Sym.getAddress());
+        StringRef NameRef = cantFail(Sym.getName());
+
+        FunctionSymbol FS;
+        FS.Address = Addr;
+        FS.Name = NameRef.str();
+        FS.DemangledName = llvm::demangle(FS.Name);
+        Syms.push_back(std::move(FS));
+    }
+    return Syms;
+}
+
+Expected<std::string> ELFSymbolReader::detectArchitecture(StringRef File){
+    Expected<OwningBinary<Binary>> BinOrErr = createBinary(File);
+    if(!BinOrErr){
+        return BinOrErr.takeError();
+    }
+    
+    const ELFObjectFileBase *Obj = dyn_cast<ELFObjectFileBase>(BinOrErr->getBinary());
+    if(!Obj){
+        return createStringError(inconvertibleErrorCode(), "Not an ELF");
+    }
+    return std::string(Triple::getArchTypeName(Obj->getArch()));
+}
+
+std::string ELFSymbolReader::demangleName(StringRef N){
+    return llvm::demangle(N.str());
+}
\ No newline at end of file
diff --git a/llvm/tools/llvm-profdata-cross-arch/ELFSymbolReader.h b/llvm/tools/llvm-profdata-cross-arch/ELFSymbolReader.h
new file mode 100644
index 0000000000000..99f88498d3d41
--- /dev/null
+++ b/llvm/tools/llvm-profdata-cross-arch/ELFSymbolReader.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "llvm/Object/ELF.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Error.h"
+#include <string>
+#include <vector>
+
+namespace llvm {
+
+    struct FunctionSymbol {
+        uint64_t Address;
+        std::string Name;
+        std::string DemangledName;
+    };
+
+    class ELFSymbolReader {
+        public:
+            //Expected datatype is an llvm data type that will either have the type specified in the <> or contain an error message explaining why the error occurred.
+            static Expected<std::vector<FunctionSymbol>> readSymbols(StringRef Filename);
+
+            static Expected<std::string> detectArchitecture(StringRef Filename);
+
+            static std::string demangleName(StringRef MangledName);
+    };
+
+} // namespace llvm
+
+
+
+
diff --git a/llvm/tools/llvm-profdata-cross-arch/llvm-profdata-cross-arch.cpp b/llvm/tools/llvm-profdata-cross-arch/llvm-profdata-cross-arch.cpp
new file mode 100644
index 0000000000000..cbb904cc90161
--- /dev/null
+++ b/llvm/tools/llvm-profdata-cross-arch/llvm-profdata-cross-arch.cpp
@@ -0,0 +1,112 @@
+#include "ELFSymbolReader.h"
+#include "llvm/IR/Function.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <string>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+
+static cl::SubCommand AnalyzeSymbolsSubcommand("analyze-symbols", "Analyze symbols in ELF files for cross-arch profiling");
+static cl::SubCommand AnalyzeProfrawSubcommand("analyze-profraw", "Used to analyze mappings between source code and coverage data");
+
+static cl::list<std::string> ELFFiles(cl::Positional, cl::sub(AnalyzeSymbolsSubcommand), cl::desc("<elf-files>"), cl::OneOrMore);
+static cl::list<std::string> ProfrawFiles(cl::Positional, cl::sub(AnalyzeProfrawSubcommand), cl::desc("<profraw-files>"), cl::OneOrMore);
+
+static void findAndPrintMatches(const std::vector<std::vector<FunctionSymbol>> &AllSymbols, const std::vector<std::string> &Architectures) {
+    const std::vector<FunctionSymbol> &Symbols1 = AllSymbols[0];
+    const std::vector<FunctionSymbol> &Symbols2 = AllSymbols[1];
+
+    std::vector<std::pair<FunctionSymbol, FunctionSymbol>> Matches;
+
+    for (const FunctionSymbol &Sym1 : Symbols1) {
+        for (const FunctionSymbol &Sym2 : Symbols2) {
+            if (Sym1.Name == Sym2.Name) {
+                Matches.push_back({Sym1, Sym2});
+                continue;
+            }
+
+            if (!Sym1.DemangledName.empty() && !Sym2.DemangledName.empty() && Sym1.DemangledName == Sym2.DemangledName) {
+                Matches.push_back({Sym1, Sym2});
+                continue;
+            }
+        }
+    }
+
+    outs() << "Potential matches found: " << Matches.size() << "\n";
+    for (const auto &Match : Matches) {
+        if (Match.first.DemangledName == Match.second.DemangledName) {
+            outs() << " " << Match.first.DemangledName << " <-> " << Match.second.DemangledName << " (demangled match)\n";
+        } else {
+            outs() << " " << Match.first.Name << " <-> " << Match.second.Name << " (exact match)\n";
+        }
+    }
+
+    outs() << "\n" << Architectures[0] << "-only functions: " << (Symbols1.size() - Matches.size()) << "\n";
+    outs() << Architectures[1] << "-only functions: " << (Symbols2.size() - Matches.size()) << "\n";
+
+    if (!Matches.empty()) {
+        outs() << "\nSUCCESS: Found " << Matches.size() << " functions that exist in both architectures!\n";
+    } else {
+        outs() << "\nWARNING: No matching functions found between architectures.\n";
+    }
+}
+
+static int analyzeSymbols_main(StringRef ProgName) {
+    outs() << "=== Symbol Analysis ==\n\n";
+    std::vector<std::vector<FunctionSymbol>> AllSymbols;
+    std::vector<std::string> Architectures;
+
+    for (const std::string &Filename : ELFFiles) {
+        Expected<std::string> ArchOrErr = ELFSymbolReader::detectArchitecture(Filename);
+        if (!ArchOrErr) {
+            errs() << "Error detecting architecture for " << Filename << ": " << toString(ArchOrErr.takeError()) << "\n";
+            continue;
+        }
+
+        Expected<std::vector<FunctionSymbol>> SymbolsOrErr = ELFSymbolReader::readSymbols(Filename);
+        if (!SymbolsOrErr) {
+            errs() << "Error reading symbols from " << Filename << ": " << toString(SymbolsOrErr.takeError()) << "\n";
+            continue;
+        }
+
+        std::string Arch = ArchOrErr.get();
+        std::vector<FunctionSymbol> Symbols = SymbolsOrErr.get();
+
+        outs() << "File: " << Filename << "\n";
+        outs() << "Architecture: " << Arch << "\n";
+        outs() << "Functions found: " << Symbols.size() << "\n";
+
+        for (const FunctionSymbol &Symbol : Symbols) {
+            outs() << " 0x" << format("%08x", Symbol.Address) << ": " << Symbol.Name;
+            if (Symbol.DemangledName != Symbol.Name) {
+                outs() << " (" << Symbol.DemangledName << ")";
+            }
+            outs() << "\n";
+        }
+        outs() << "\n";
+
+        AllSymbols.push_back(std::move(Symbols));
+        Architectures.push_back(std::move(Arch));
+    }
+
+    if (AllSymbols.size() >= 2) {
+        outs() << "=== Cross-Architecture Analysis ==\n";
+        findAndPrintMatches(AllSymbols, Architectures);
+    }
+
+    return 0;
+}
+
+int main(int argc, const char *argv[]) {
+    cl::ParseCommandLineOptions(argc, argv, "LLVM cross-architecture profile analysis\n");
+    if (AnalyzeSymbolsSubcommand) {
+        return analyzeSymbols_main(argv[0]);
+    }
+
+    cl::PrintHelpMessage();
+    return 1;
+}
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 885e06df6c390..d5a9a33f47a9a 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -16,11 +16,13 @@
 #include "llvm/Debuginfod/HTTPClient.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/Object/Binary.h"
+#include "llvm/ProfileData/DataAccessProf.h"
 #include "llvm/ProfileData/InstrProfCorrelator.h"
 #include "llvm/ProfileData/InstrProfReader.h"
 #include "llvm/ProfileData/InstrProfWriter.h"
 #include "llvm/ProfileData/MemProf.h"
 #include "llvm/ProfileData/MemProfReader.h"
+#include "llvm/ProfileData/MemProfSummaryBuilder.h"
 #include "llvm/ProfileData/MemProfYAML.h"
 #include "llvm/ProfileData/ProfileCommon.h"
 #include "llvm/ProfileData/SampleProfReader.h"
@@ -29,6 +31,7 @@
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Discriminator.h"
 #include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/FormattedStream.h"
@@ -42,6 +45,7 @@
 #include "llvm/Support/VirtualFileSystem.h"
 #include "llvm/Support/WithColor.h"
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/Object/ObjectFile.h"
 #include <algorithm>
 #include <cmath>
 #include <optional>
@@ -651,9 +655,7 @@ struct WriterContext {
   std::mutex &ErrLock;
   SmallSet<instrprof_error, 4> &WriterErrorCodes;
 
-  WriterContext(bool IsSparse, std::mutex &ErrLock,
-                SmallSet<instrprof_error, 4> &WriterErrorCodes,
-                uint64_t ReservoirSize = 0, uint64_t MaxTraceLength = 0)
+  WriterContext(bool IsSparse, std::mutex &ErrLock, SmallSet<instrprof_error, 4> &WriterErrorCodes, uint64_t ReservoirSize = 0, uint64_t MaxTraceLength = 0)
       : Writer(IsSparse, ReservoirSize, MaxTraceLength, DoWritePrevVersion,
                MemProfVersionRequested, MemProfFullSchema,
                MemprofGenerateRandomHotness, MemprofGenerateRandomHotnessSeed),
@@ -688,6 +690,26 @@ static void overlapInput(const std::string &BaseFilename,
   }
 }
 
+//ANDRES FUNCTION
+Expected<std::string> getArchitectureFromExecutable(StringRef ExecutablePath){
+  ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrError = MemoryBuffer::getFile(ExecutablePath);
+  if(!BufferOrError){
+    return createStringError(BufferOrError.getError(), "Failed to load input file");
+  }
+
+  Expected<std::unique_ptr<object::ObjectFile>> ObjectOrError = object::ObjectFile::createObjectFile(BufferOrError.get()->getMemBufferRef());
+  if(!ObjectOrError){
+    return ObjectOrError.takeError();
+  }
+
+  std::unique_ptr<llvm::object::ObjectFile> &Object = ObjectOrError.get();
+
+  StringRef ArchStr = Object->getArch() != Triple::UnknownArch ? Triple::getArchTypeName(Object->getArch()) : "unknown";
+
+  return ArchStr.str();
+}
+//ANDRES FUNCTION
+
 /// Load an input into a writer context.
 static void
 loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
@@ -701,11 +723,35 @@ loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
   // invalid outside of this packaged task.
   std::string Filename = Input.Filename;
 
+  //ANDRES CODE
+  std::string ExecutableName;
+  std::string ProfileFile = Input.Filename;
+  std::string Architecture = "";
+
+  StringRef FilenameRef = Filename;
+  if(FilenameRef.contains(':')){
+    StringRef ExeRef, ProfRef;
+    std::tie(ExeRef, ProfRef) = FilenameRef.split(':');
+    if(!ExeRef.empty() && !ProfRef.empty()){
+      ExecutableName = ExeRef.str();
+      ProfileFile = ProfRef.str();
+    }
+    Expected<std::string> ArchOrError = getArchitectureFromExecutable(ExeRef);
+    if(ArchOrError){
+      Architecture = std::move(ArchOrError.get());
+    }else{
+      consumeError(ArchOrError.takeError());
+      Architecture = "unknown";
+    }
+  }
+  //ANDRES CODE
+
+
   using ::llvm::memprof::RawMemProfReader;
-  if (RawMemProfReader::hasFormat(Input.Filename)) {
-    auto ReaderOrErr = RawMemProfReader::create(Input.Filename, ProfiledBinary);
+  if (RawMemProfReader::hasFormat(ProfileFile)) {
+    auto ReaderOrErr = RawMemProfReader::create(ProfileFile, ProfiledBinary);
     if (!ReaderOrErr) {
-      exitWithError(ReaderOrErr.takeError(), Input.Filename);
+      exitWithError(ReaderOrErr.takeError(), ProfileFile);
     }
     std::unique_ptr<RawMemProfReader> Reader = std::move(ReaderOrErr.get());
     // Check if the profile types can be merged, e.g. clang frontend profiles
@@ -756,6 +802,8 @@ loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
 
     auto MemProfData = Reader->takeMemProfData();
 
+    auto DataAccessProfData = Reader->takeDataAccessProfData();
+
     // Check for the empty input in case the YAML file is invalid.
     if (MemProfData.Records.empty()) {
       WC->Errors.emplace_back(
@@ -764,6 +812,7 @@ loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
     }
 
     WC->Writer.addMemProfData(std::move(MemProfData), MemProfError);
+    WC->Writer.addDataAccessProfData(std::move(DataAccessProfData));
     return;
   }
 
@@ -786,8 +835,8 @@ loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
   const ProfCorrelatorKind CorrelatorKind = BIDFetcherCorrelatorKind
                                                 ? *BIDFetcherCorrelatorKind
                                                 : ProfCorrelatorKind::NONE;
-  auto ReaderOrErr = InstrProfReader::create(Input.Filename, *FS, Correlator,
-                                             BIDFetcher, CorrelatorKind, Warn);
+  auto ReaderOrErr = InstrProfReader::create(ProfileFile /*ANDRES changed from Input.Filename to ProfileFile*/, *FS, Correlator, //THIS IS THE IMPORTANT LINE!!!!
+                                             BIDFetcher, CorrelatorKind, Warn, Architecture /*ANDRES added this parameter*/);
   if (Error E = ReaderOrErr.takeError()) {
     // Skip the empty profiles by returning silently.
     auto [ErrCode, Msg] = InstrProfError::take(std::move(E));
@@ -1713,6 +1762,28 @@ static void addWeightedInput(WeightedFileVector &WNI, const WeightedFile &WF) {
     return;
   }
 
+  //ANDRES ADDED CODE UPDATED CODE TO HANDLE ARCH SPECIFIC EXECUTABLE
+  StringRef ExecutableName, ProfileFile;
+  if(Filename.contains(':')){
+    std::tie(ExecutableName, ProfileFile) = Filename.split(':');
+
+
+    if(!ExecutableName.empty() && !ProfileFile.empty()){
+      llvm::sys::fs::file_status Status;
+      llvm::sys::fs::status(ProfileFile, Status);
+      if(!llvm::sys::fs::exists(Status)){
+        exitWithErrorCode(make_error_code(errc::no_such_file_or_directory),ProfileFile);
+      }
+      if(llvm::sys::fs::is_regular_file(Status)){
+        WNI.push_back({std::string(Filename), Weight});
+        return;
+      }
+
+      Filename = ProfileFile;
+    }
+  }
+  //ANDRES ADDED CODE
+
   llvm::sys::fs::file_status Status;
   llvm::sys::fs::status(Filename, Status);
   if (!llvm::sys::fs::exists(Status))
@@ -1760,8 +1831,9 @@ static void parseInputFilenamesFile(MemoryBuffer *Buffer,
 
 static int merge_main(StringRef ProgName) {
   WeightedFileVector WeightedInputs;
-  for (StringRef Filename : InputFilenames)
+  for (StringRef Filename : InputFilenames){
     addWeightedInput(WeightedInputs, {std::string(Filename), 1});
+  }
   for (StringRef WeightedFilename : WeightedInputFilenames)
     addWeightedInput(WeightedInputs, parseWeightedFile(WeightedFilename));
 
@@ -3308,6 +3380,18 @@ static int showMemProfProfile(ShowFormat SFormat, raw_fd_ostream &OS) {
 
   auto Reader = std::move(ReaderOrErr.get());
   memprof::AllMemProfData Data = Reader->getAllMemProfData();
+
+  // For v4 and above the summary is serialized in the indexed profile, and can
+  // be accessed from the reader. Earlier versions build the summary below.
+  // The summary is emitted as YAML comments at the start of the output.
+  if (auto *MemProfSum = Reader->getMemProfSummary()) {
+    MemProfSum->printSummaryYaml(OS);
+  } else {
+    memprof::MemProfSummaryBuilder MemProfSumBuilder;
+    for (auto &Pair : Data.HeapProfileRecords)
+      MemProfSumBuilder.addRecord(Pair.Record);
+    MemProfSumBuilder.getSummary()->printSummaryYaml(OS);
+  }
   // Construct yaml::Output with the maximum column width of 80 so that each
   // Frame fits in one line.
   yaml::Output Yout(OS, nullptr, 80);

>From b88e0bc94119daba5e0c8b729eacdc6e72003526 Mon Sep 17 00:00:00 2001
From: Andres Wearden <awearden at hu-awearden-lv.qualcomm.com>
Date: Tue, 1 Jul 2025 09:58:52 -0700
Subject: [PATCH 02/17] saving changes

---
 llvm/include/llvm/ProfileData/InstrProfReader.h | 2 +-
 llvm/lib/ProfileData/InstrProf.cpp              | 2 +-
 llvm/lib/ProfileData/InstrProfReader.cpp        | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/InstrProfReader.h b/llvm/include/llvm/ProfileData/InstrProfReader.h
index d5988ed793fb3..b92253a81502d 100644
--- a/llvm/include/llvm/ProfileData/InstrProfReader.h
+++ b/llvm/include/llvm/ProfileData/InstrProfReader.h
@@ -106,7 +106,7 @@ class InstrProfReader {
   /// Read a single record.
   virtual Error readNextRecord(NamedInstrProfRecord &Record) = 0;
 
-  /// Read a list of binary ids.
+  /// Read a list of biny ids.
   virtual Error readBinaryIds(std::vector<llvm::object::BuildID> &BinaryIds) {
     return success();
   }
diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp
index f2ba250845f67..16d4877f3ccc8 100644
--- a/llvm/lib/ProfileData/InstrProf.cpp
+++ b/llvm/lib/ProfileData/InstrProf.cpp
@@ -608,7 +608,7 @@ Error readAndDecodeStrings(StringRef NameStrings,
     StringRef ArchRef(Architecture); 
     NameStrings.split(Names, getInstrProfNameSeparator());
     for (StringRef &Name : Names)
-      if (Error E = NameCallback(Name.str()+ ":" + ArchRef.str()*/))
+      if (Error E = NameCallback(Name.str()+ ":" + ArchRef.str()))
         return E;
 
     while (P < EndP && *P == 0)
diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp
index 916758dde4fa9..33b62cf5cca5c 100644
--- a/llvm/lib/ProfileData/InstrProfReader.cpp
+++ b/llvm/lib/ProfileData/InstrProfReader.cpp
@@ -556,7 +556,7 @@ Error RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) {
 template <class IntPtrT>
 Error RawInstrProfReader<IntPtrT>::createSymtab(InstrProfSymtab &Symtab) { //STEP 5
   
-  Symtab.setArchitecture(Architecture)
+  Symtab.setArchitecture(Architecture);
   
   if (Error E = Symtab.create(StringRef(NamesStart, NamesEnd - NamesStart),
                               StringRef(VNamesStart, VNamesEnd - VNamesStart)))

>From 7e74608c9beb84778ebdb12e3a145bdfd9273be8 Mon Sep 17 00:00:00 2001
From: Andres Wearden <awearden at hu-awearden-lv.qualcomm.com>
Date: Sat, 5 Jul 2025 12:12:44 -0700
Subject: [PATCH 03/17] saving updates

---
 code_changes.txt                          | 81 +++++++++++++++++++++++
 llvm/include/llvm/ProfileData/InstrProf.h |  6 +-
 llvm/lib/ProfileData/InstrProf.cpp        | 18 +++--
 3 files changed, 98 insertions(+), 7 deletions(-)
 create mode 100644 code_changes.txt

diff --git a/code_changes.txt b/code_changes.txt
new file mode 100644
index 0000000000000..62aa011714912
--- /dev/null
+++ b/code_changes.txt
@@ -0,0 +1,81 @@
+diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h
+index a786aadce6de..eeea25e25fe8 100644
+--- a/llvm/include/llvm/ProfileData/InstrProf.h
++++ b/llvm/include/llvm/ProfileData/InstrProf.h
+@@ -40,6 +40,7 @@
+ #include <cassert>
+ #include <cstddef>
+ #include <cstdint>
++#include <cstdio>
+ #include <cstring>
+ #include <list>
+ #include <memory>
+@@ -643,7 +644,10 @@ public:
+ 
+     // Insert into NameTab so that MD5NameMap (a vector that will be sorted)
+     // won't have duplicated entries in the first place.
+-    auto Ins = NameTab.insert(SymbolName);
++    uint64_t HashValue = IndexedInstrProf::ComputeHash(SymbolName);
++    printf("Hash Value for %.*s: %" PRIu64 "\n", static_cast<int>(SymbolName.size()), SymbolName.data(), HashValue);
++    auto Ins = NameTab.insert(FuncName);
++    printf("mapped value for %" PRIu64 " hash: %.*s\n", HashValue, static_cast<int>(Ins.first->getKey().size()), Ins.first->getKey().data());
+     if (Ins.second) {
+       MD5NameMap.push_back(std::make_pair(
+           IndexedInstrProf::ComputeHash(SymbolName), Ins.first->getKey()));
+diff --git a/llvm/include/llvm/ProfileData/InstrProfReader.h b/llvm/include/llvm/ProfileData/InstrProfReader.h
+index b92253a81502..7bd1bed6b74f 100644
+--- a/llvm/include/llvm/ProfileData/InstrProfReader.h
++++ b/llvm/include/llvm/ProfileData/InstrProfReader.h
+@@ -356,7 +356,8 @@ private:
+   uint64_t CountersDelta;
+   uint64_t BitmapDelta;
+   uint64_t NamesDelta;
+-  const RawInstrProf::ProfileData<IntPtrT> *Data;
++  const RawInstrProf::ProfileData<IntPtrT> *cccccbveifehbfkeciugkvlcugkcgbdhkkkvdtrfbgkn
++  Data;
+   const RawInstrProf::ProfileData<IntPtrT> *DataEnd;
+   const RawInstrProf::VTableProfileData<IntPtrT> *VTableBegin = nullptr;
+   const RawInstrProf::VTableProfileData<IntPtrT> *VTableEnd = nullptr;
+diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp
+index 16d4877f3ccc..ea9e0ea2e129 100644
+--- a/llvm/lib/ProfileData/InstrProf.cpp
++++ b/llvm/lib/ProfileData/InstrProf.cpp
+@@ -555,7 +555,6 @@ Error InstrProfSymtab::addVTableWithName(GlobalVariable &VTable,
+   auto NameToGUIDMap = [&](StringRef Name) -> Error {
+     if (Error E = addSymbolName(Name))
+       return E;
+-
+     bool Inserted = true;
+     std::tie(std::ignore, Inserted) = MD5VTableMap.try_emplace(
+         GlobalValue::getGUIDAssumingExternalLinkage(Name), &VTable);
+@@ -607,10 +606,18 @@ Error readAndDecodeStrings(StringRef NameStrings,
+     SmallVector<StringRef, 0> Names;
+     StringRef ArchRef(Architecture); 
+     NameStrings.split(Names, getInstrProfNameSeparator());
+-    for (StringRef &Name : Names)
+-      if (Error E = NameCallback(Name.str()+ ":" + ArchRef.str()))
+-        return E;
+-
++    printf("=====================READER DATA====================");
++    for (StringRef &Name : Names){
++      std::string ConcHashString = Name.str() + ":" + ArchRef.str();
++      printf("The string %s will get hashed and mapped to %s\n", ConcHashString.c_str(), Name.str().c_str());
++      if(ArchRef.empty()){
++        if (Error E = NameCallback(Name))
++          return E;
++      }else{
++        if (Error E = NameCallback(Name.str() + ":" + ArchRef.str()))
++          return E;
++      }
++    }
+     while (P < EndP && *P == 0)
+       P++;
+   }
+@@ -653,7 +660,6 @@ Error readAndDecodeStrings(StringRef NameStrings,
+     for (StringRef &Name : Names)
+       if (Error E = NameCallback(Name))
+         return E;
+-
+     while (P < EndP && *P == 0)
+       P++;
+   }
diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h
index a786aadce6de1..eeea25e25fe86 100644
--- a/llvm/include/llvm/ProfileData/InstrProf.h
+++ b/llvm/include/llvm/ProfileData/InstrProf.h
@@ -40,6 +40,7 @@
 #include <cassert>
 #include <cstddef>
 #include <cstdint>
+#include <cstdio>
 #include <cstring>
 #include <list>
 #include <memory>
@@ -643,7 +644,10 @@ class InstrProfSymtab {
 
     // Insert into NameTab so that MD5NameMap (a vector that will be sorted)
     // won't have duplicated entries in the first place.
-    auto Ins = NameTab.insert(SymbolName);
+    uint64_t HashValue = IndexedInstrProf::ComputeHash(SymbolName);
+    printf("Hash Value for %.*s: %" PRIu64 "\n", static_cast<int>(SymbolName.size()), SymbolName.data(), HashValue);
+    auto Ins = NameTab.insert(FuncName);
+    printf("mapped value for %" PRIu64 " hash: %.*s\n", HashValue, static_cast<int>(Ins.first->getKey().size()), Ins.first->getKey().data());
     if (Ins.second) {
       MD5NameMap.push_back(std::make_pair(
           IndexedInstrProf::ComputeHash(SymbolName), Ins.first->getKey()));
diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp
index 16d4877f3ccc8..ea9e0ea2e1292 100644
--- a/llvm/lib/ProfileData/InstrProf.cpp
+++ b/llvm/lib/ProfileData/InstrProf.cpp
@@ -555,7 +555,6 @@ Error InstrProfSymtab::addVTableWithName(GlobalVariable &VTable,
   auto NameToGUIDMap = [&](StringRef Name) -> Error {
     if (Error E = addSymbolName(Name))
       return E;
-
     bool Inserted = true;
     std::tie(std::ignore, Inserted) = MD5VTableMap.try_emplace(
         GlobalValue::getGUIDAssumingExternalLinkage(Name), &VTable);
@@ -607,10 +606,18 @@ Error readAndDecodeStrings(StringRef NameStrings,
     SmallVector<StringRef, 0> Names;
     StringRef ArchRef(Architecture); 
     NameStrings.split(Names, getInstrProfNameSeparator());
-    for (StringRef &Name : Names)
-      if (Error E = NameCallback(Name.str()+ ":" + ArchRef.str()))
-        return E;
-
+    printf("=====================READER DATA====================");
+    for (StringRef &Name : Names){
+      std::string ConcHashString = Name.str() + ":" + ArchRef.str();
+      printf("The string %s will get hashed and mapped to %s\n", ConcHashString.c_str(), Name.str().c_str());
+      if(ArchRef.empty()){
+        if (Error E = NameCallback(Name))
+          return E;
+      }else{
+        if (Error E = NameCallback(Name.str() + ":" + ArchRef.str()))
+          return E;
+      }
+    }
     while (P < EndP && *P == 0)
       P++;
   }
@@ -653,7 +660,6 @@ Error readAndDecodeStrings(StringRef NameStrings,
     for (StringRef &Name : Names)
       if (Error E = NameCallback(Name))
         return E;
-
     while (P < EndP && *P == 0)
       P++;
   }

>From 3a398c11a57236a83e0a364718f1b0eaaf7043ef Mon Sep 17 00:00:00 2001
From: Andres Wearden <awearden at hu-awearden-lv.qualcomm.com>
Date: Sat, 5 Jul 2025 23:08:53 -0700
Subject: [PATCH 04/17] added new way of hashing the functions so they are more
 consistent with hashes from .profraw file

---
 llvm/include/llvm/ProfileData/InstrProf.h     | 18 ++++++++---
 .../llvm/ProfileData/InstrProfWriter.h        |  5 +++
 llvm/lib/ProfileData/InstrProf.cpp            |  3 +-
 llvm/lib/ProfileData/InstrProfWriter.cpp      | 32 +++++++++++++++++--
 llvm/tools/llvm-profdata/llvm-profdata.cpp    |  2 +-
 5 files changed, 52 insertions(+), 8 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h
index eeea25e25fe86..e9c21c5fc284b 100644
--- a/llvm/include/llvm/ProfileData/InstrProf.h
+++ b/llvm/include/llvm/ProfileData/InstrProf.h
@@ -644,13 +644,19 @@ class InstrProfSymtab {
 
     // Insert into NameTab so that MD5NameMap (a vector that will be sorted)
     // won't have duplicated entries in the first place.
-    uint64_t HashValue = IndexedInstrProf::ComputeHash(SymbolName);
+    
+    uint64_t HashValue = IndexedInstrProf::ComputeHash(FuncName);
+    std::string HashStr = std::to_string(HashValue);
+    std::string CombinedStr = HashStr + ":" + ArchName.str();
+    llvm::StringRef HashRef(CombinedStr);
+    HashValue = IndexedInstrProf::ComputeHash(HashRef);
+
     printf("Hash Value for %.*s: %" PRIu64 "\n", static_cast<int>(SymbolName.size()), SymbolName.data(), HashValue);
     auto Ins = NameTab.insert(FuncName);
     printf("mapped value for %" PRIu64 " hash: %.*s\n", HashValue, static_cast<int>(Ins.first->getKey().size()), Ins.first->getKey().data());
     if (Ins.second) {
       MD5NameMap.push_back(std::make_pair(
-          IndexedInstrProf::ComputeHash(SymbolName), Ins.first->getKey()));
+          IndexedInstrProf::ComputeHash(HashRef), Ins.first->getKey()));
       Sorted = false;
     }
     return Error::success();
@@ -779,10 +785,14 @@ StringRef InstrProfSymtab::getFuncOrVarNameIfDefined(uint64_t MD5Hash) {
 
 StringRef InstrProfSymtab::getFuncOrVarName(uint64_t MD5Hash) {
   finalizeSymtab();
-  auto Result = llvm::lower_bound(MD5NameMap, MD5Hash,
+  std::string TempMD5HashStr = std::to_string(MD5Hash);
+  std::string CombinedHashStr = TempMD5HashStr + ":" + Architecture;
+  llvm::StringRef CombinedHashRef(CombinedHashStr);
+  uint64_t NewMD5Hash = IndexedInstrProf::ComputeHash(CombinedHashRef);
+  auto Result = llvm::lower_bound(MD5NameMap, NewMD5Hash,
                                   [](const std::pair<uint64_t, StringRef> &LHS,
                                      uint64_t RHS) { return LHS.first < RHS; });
-  if (Result != MD5NameMap.end() && Result->first == MD5Hash)
+  if (Result != MD5NameMap.end() && Result->first == NewMD5Hash)
     return Result->second;
   return StringRef();
 }
diff --git a/llvm/include/llvm/ProfileData/InstrProfWriter.h b/llvm/include/llvm/ProfileData/InstrProfWriter.h
index f339fe2c2a9eb..e281e100bf808 100644
--- a/llvm/include/llvm/ProfileData/InstrProfWriter.h
+++ b/llvm/include/llvm/ProfileData/InstrProfWriter.h
@@ -114,6 +114,11 @@ class InstrProfWriter {
   /// summed. Optionally scale counts by \p Weight.
   LLVM_ABI void addRecord(NamedInstrProfRecord &&I, uint64_t Weight,
                           function_ref<void(Error)> Warn);
+  LLVM_ABI void addRecord(StringRef Name, uint64_t Hash,
+                                InstrProfRecord &&I, uint64_t Weight,
+                                function_ref<void(Error)> Warn, const std::string &Architecture);
+  void addRecord(NamedInstrProfRecord &&I, uint64_t Weight, const std::string &Architecture,
+                                function_ref<void(Error)> Warn);
   void addRecord(NamedInstrProfRecord &&I, function_ref<void(Error)> Warn) {
     addRecord(std::move(I), 1, Warn);
   }
diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp
index ea9e0ea2e1292..c175723bb41c7 100644
--- a/llvm/lib/ProfileData/InstrProf.cpp
+++ b/llvm/lib/ProfileData/InstrProf.cpp
@@ -320,6 +320,8 @@ std::string getPGOFuncName(StringRef Name, GlobalValue::LinkageTypes Linkage,
     else
       NewName = NewName.insert(0, FileName.str() + ":");
   }
+
+  
   return NewName;
 }
 
@@ -606,7 +608,6 @@ Error readAndDecodeStrings(StringRef NameStrings,
     SmallVector<StringRef, 0> Names;
     StringRef ArchRef(Architecture); 
     NameStrings.split(Names, getInstrProfNameSeparator());
-    printf("=====================READER DATA====================");
     for (StringRef &Name : Names){
       std::string ConcHashString = Name.str() + ":" + ArchRef.str();
       printf("The string %s will get hashed and mapped to %s\n", ConcHashString.c_str(), Name.str().c_str());
diff --git a/llvm/lib/ProfileData/InstrProfWriter.cpp b/llvm/lib/ProfileData/InstrProfWriter.cpp
index 7ca26aa138012..4dfeeca00d988 100644
--- a/llvm/lib/ProfileData/InstrProfWriter.cpp
+++ b/llvm/lib/ProfileData/InstrProfWriter.cpp
@@ -153,11 +153,11 @@ void InstrProfWriter::setValueProfDataEndianness(llvm::endianness Endianness) {
 
 void InstrProfWriter::setOutputSparse(bool Sparse) { this->Sparse = Sparse; }
 
-void InstrProfWriter::addRecord(NamedInstrProfRecord &&I, uint64_t Weight,
+void InstrProfWriter::addRecord(NamedInstrProfRecord &&I, uint64_t Weight, const std::string &Architecture,
                                 function_ref<void(Error)> Warn) {
   auto Name = I.Name;
   auto Hash = I.Hash;
-  addRecord(Name, Hash, std::move(I), Weight, Warn);
+  addRecord(Name, Hash, std::move(I), Weight, Warn, Architecture);
 }
 
 void InstrProfWriter::overlapRecord(NamedInstrProfRecord &&Other,
@@ -216,6 +216,34 @@ void InstrProfWriter::addRecord(StringRef Name, uint64_t Hash,
   Dest.sortValueData();
 }
 
+void InstrProfWriter::addRecord(StringRef Name, uint64_t Hash,
+                                InstrProfRecord &&I, uint64_t Weight,
+                                function_ref<void(Error)> Warn, const std::string &Architecture) {
+  auto &ProfileDataMap = FunctionData[Name];
+  std::string HashStr = std::to_string(Hash) + ":" + Architecture;
+  llvm::StringRef HashRef(HashStr);
+  uint64_t NewHash = IndexedInstrProf::ComputeHash(HashRef);
+
+  auto [Where, NewFunc] = ProfileDataMap.try_emplace(NewHash);
+  InstrProfRecord &Dest = Where->second;
+
+  auto MapWarn = [&](instrprof_error E) {
+    Warn(make_error<InstrProfError>(E));
+  };
+
+  if (NewFunc) {
+    // We've never seen a function with this name and hash, add it.
+    Dest = std::move(I);
+    if (Weight > 1)
+      Dest.scale(Weight, 1, MapWarn);
+  } else {
+    // We're updating a function we've seen before.
+    Dest.merge(I, Weight, MapWarn);
+  }
+
+  Dest.sortValueData();
+}
+
 void InstrProfWriter::addMemProfRecord(
     const Function::GUID Id, const memprof::IndexedMemProfRecord &Record) {
   auto NewRecord = Record;
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 2b53b7e77f0a7..3d3fd34a493ab 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -862,7 +862,7 @@ loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
       I.Name = (*Remapper)(I.Name);
     const StringRef FuncName = I.Name;
     bool Reported = false;
-    WC->Writer.addRecord(std::move(I), Input.Weight, [&](Error E) {
+    WC->Writer.addRecord(std::move(I), Input.Weight, Architecture, [&](Error E) {
       if (Reported) {
         consumeError(std::move(E));
         return;

>From 1d6ae59767ab3bae2cd4a3b77781658cf06c6eca Mon Sep 17 00:00:00 2001
From: Andres Wearden <andreswearden5 at gmail.com>
Date: Tue, 8 Jul 2025 08:26:10 -0700
Subject: [PATCH 05/17] saving changes to compare with main branch

---
 .../ProfileData/Coverage/CoverageMapping.h    |  35 +++-
 .../Coverage/CoverageMappingReader.h          |   9 +-
 llvm/include/llvm/ProfileData/InstrProf.h     |  32 +--
 .../llvm/ProfileData/InstrProfReader.h        |   4 +
 .../ProfileData/Coverage/CoverageMapping.cpp  | 189 +++++++++++++++++-
 .../Coverage/CoverageMappingReader.cpp        |  33 +--
 llvm/lib/ProfileData/InstrProf.cpp            |   3 +-
 llvm/lib/ProfileData/InstrProfReader.cpp      |  22 ++
 8 files changed, 280 insertions(+), 47 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index 7d1a85ba528fc..555c7e5f37f2b 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -993,6 +993,7 @@ class CoverageMapping {
   std::vector<FunctionRecord> Functions;
   DenseMap<size_t, SmallVector<unsigned, 0>> FilenameHash2RecordIndices;
   std::vector<std::pair<std::string, uint64_t>> FuncHashMismatches;
+  StringRef Arch;
 
   std::optional<bool> SingleByteCoverage;
 
@@ -1000,10 +1001,16 @@ class CoverageMapping {
 
   // Load coverage records from readers.
   static Error loadFromReaders(
-      ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
-      std::optional<std::reference_wrapper<IndexedInstrProfReader>>
-          &ProfileReader,
-      CoverageMapping &Coverage);
+    ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
+    std::optional<std::reference_wrapper<IndexedInstrProfReader>>
+        &ProfileReader,
+    CoverageMapping &Coverage, StringRef Arch);
+  
+  static Error loadFromReaders(
+    ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
+    std::optional<std::reference_wrapper<IndexedInstrProfReader>>
+        &ProfileReader,
+    CoverageMapping &Coverage);
 
   // Load coverage records from file.
   static Error
@@ -1018,6 +1025,8 @@ class CoverageMapping {
       const CoverageMappingRecord &Record,
       const std::optional<std::reference_wrapper<IndexedInstrProfReader>>
           &ProfileReader);
+  
+  Error loadFunctionRecord(const CoverageMappingRecord &Record, const std::optional<std::reference_wrapper<IndexedInstrProfReader>> &ProfileReader, const std::string &Arch);
 
   /// Look up the indices for function records which are at least partially
   /// defined in the specified file. This is guaranteed to return a superset of
@@ -1027,6 +1036,13 @@ class CoverageMapping {
   getImpreciseRecordIndicesForFilename(StringRef Filename) const;
 
 public:
+
+  const StringRef &getArchitecture() const { return Arch; }
+
+  void setArchitecture(StringRef NewArch){
+    Arch = StringRef(NewArch);
+  }
+
   CoverageMapping(const CoverageMapping &) = delete;
   CoverageMapping &operator=(const CoverageMapping &) = delete;
 
@@ -1234,8 +1250,9 @@ uint64_t getFuncNameRef(const FuncRecordTy *Record) {
 /// a hash.
 template <class FuncRecordTy, llvm::endianness Endian>
 Error getFuncNameViaRef(const FuncRecordTy *Record,
-                        InstrProfSymtab &ProfileNames, StringRef &FuncName) {
+                        InstrProfSymtab &ProfileNames, StringRef &FuncName, StringRef Arch = "") {
   uint64_t NameRef = getFuncNameRef<FuncRecordTy, Endian>(Record);
+  ProfileNames.setArchitecture(Arch.str());
   FuncName = ProfileNames.getFuncOrVarName(NameRef);
   return Error::success();
 }
@@ -1285,7 +1302,7 @@ struct CovMapFunctionRecordV1 {
 
   /// Return the PGO name of the function.
   template <llvm::endianness Endian>
-  Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const {
+  Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName, StringRef Arch = "") const {
     IntPtrT NameRef = getFuncNameRef<Endian>();
     uint32_t NameS = support::endian::byte_swap<uint32_t, Endian>(NameSize);
     FuncName = ProfileNames.getFuncName(NameRef, NameS);
@@ -1334,7 +1351,7 @@ struct CovMapFunctionRecordV2 {
   }
 
   template <llvm::endianness Endian>
-  Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const {
+  Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName, StringRef Arch = "") const {
     return accessors::getFuncNameViaRef<ThisT, Endian>(this, ProfileNames,
                                                        FuncName);
   }
@@ -1378,9 +1395,9 @@ struct CovMapFunctionRecordV3 {
   }
 
   template <llvm::endianness Endian>
-  Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const {
+  Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName, StringRef Arch = "") const {
     return accessors::getFuncNameViaRef<ThisT, Endian>(this, ProfileNames,
-                                                       FuncName);
+                                                       FuncName, Arch);
   }
 
   /// Get the filename set reference.
diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h
index e91ba9147a745..7cf09e29f2145 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h
@@ -39,6 +39,12 @@ struct CoverageMappingRecord {
   ArrayRef<StringRef> Filenames;
   ArrayRef<CounterExpression> Expressions;
   ArrayRef<CounterMappingRegion> MappingRegions;
+  StringRef Arch;
+
+  const StringRef &getArchitecture() const { return Arch; }
+  void setArchitecture(StringRef NewArch){
+    Arch = StringRef(NewArch);
+  }
 };
 
 /// A file format agnostic iterator over coverage mapping data.
@@ -191,6 +197,7 @@ class LLVM_ABI BinaryCoverageReader : public CoverageMappingReader {
   std::vector<StringRef> FunctionsFilenames;
   std::vector<CounterExpression> Expressions;
   std::vector<CounterMappingRegion> MappingRegions;
+  StringRef Arch;
 
   // Used to tie the lifetimes of coverage function records to the lifetime of
   // this BinaryCoverageReader instance. Needed to support the format change in
@@ -223,7 +230,7 @@ class LLVM_ABI BinaryCoverageReader : public CoverageMappingReader {
       StringRef Coverage, FuncRecordsStorage &&FuncRecords,
       CoverageMapCopyStorage &&CoverageMap,
       std::unique_ptr<InstrProfSymtab> ProfileNamesPtr, uint8_t BytesInAddress,
-      llvm::endianness Endian, StringRef CompilationDir = "");
+      llvm::endianness Endian, StringRef CompilationDir = "", StringRef Arch = "");
 
   Error readNextRecord(CoverageMappingRecord &Record) override;
 };
diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h
index e9c21c5fc284b..747853f3af8e9 100644
--- a/llvm/include/llvm/ProfileData/InstrProf.h
+++ b/llvm/include/llvm/ProfileData/InstrProf.h
@@ -636,7 +636,7 @@ class InstrProfSymtab {
   // Map the MD5 of the symbol name to the name.
   Error addSymbolName(StringRef SymbolName) {
     StringRef FuncName;
-    StringRef ArchName;
+    StringRef ArchName = "";
     std::tie(FuncName, ArchName) = SymbolName.split(":");
     if (SymbolName.empty())
       return make_error<InstrProfError>(instrprof_error::malformed,
@@ -644,14 +644,15 @@ class InstrProfSymtab {
 
     // Insert into NameTab so that MD5NameMap (a vector that will be sorted)
     // won't have duplicated entries in the first place.
-    
     uint64_t HashValue = IndexedInstrProf::ComputeHash(FuncName);
-    std::string HashStr = std::to_string(HashValue);
-    std::string CombinedStr = HashStr + ":" + ArchName.str();
-    llvm::StringRef HashRef(CombinedStr);
-    HashValue = IndexedInstrProf::ComputeHash(HashRef);
-
-    printf("Hash Value for %.*s: %" PRIu64 "\n", static_cast<int>(SymbolName.size()), SymbolName.data(), HashValue);
+    llvm::StringRef HashRef(FuncName);
+    if(!ArchName.empty()){
+      std::string HashStr = std::to_string(HashValue);
+      std::string CombinedStr = HashStr + ":" + ArchName.str();
+      HashRef = CombinedStr;
+      HashValue = IndexedInstrProf::ComputeHash(HashRef);
+    }
+    printf("Hash Value for %.*s %" PRIu64 "\n", static_cast<int>(SymbolName.size()), SymbolName.data(), HashValue);
     auto Ins = NameTab.insert(FuncName);
     printf("mapped value for %" PRIu64 " hash: %.*s\n", HashValue, static_cast<int>(Ins.first->getKey().size()), Ins.first->getKey().data());
     if (Ins.second) {
@@ -786,13 +787,14 @@ StringRef InstrProfSymtab::getFuncOrVarNameIfDefined(uint64_t MD5Hash) {
 StringRef InstrProfSymtab::getFuncOrVarName(uint64_t MD5Hash) {
   finalizeSymtab();
   std::string TempMD5HashStr = std::to_string(MD5Hash);
-  std::string CombinedHashStr = TempMD5HashStr + ":" + Architecture;
-  llvm::StringRef CombinedHashRef(CombinedHashStr);
-  uint64_t NewMD5Hash = IndexedInstrProf::ComputeHash(CombinedHashRef);
-  auto Result = llvm::lower_bound(MD5NameMap, NewMD5Hash,
-                                  [](const std::pair<uint64_t, StringRef> &LHS,
-                                     uint64_t RHS) { return LHS.first < RHS; });
-  if (Result != MD5NameMap.end() && Result->first == NewMD5Hash)
+  if(!Architecture.empty()){
+    std::string CombinedHashStr = TempMD5HashStr + ":" + Architecture;
+    llvm::StringRef CombinedHashRef(CombinedHashStr);
+    MD5Hash = IndexedInstrProf::ComputeHash(CombinedHashRef);
+  }
+  auto Result = llvm::lower_bound(MD5NameMap, MD5Hash, [](const std::pair<uint64_t, StringRef> &LHS, uint64_t RHS) { return LHS.first < RHS; });
+  llvm::errs() << "Architecture: " << (!Architecture.empty() ? Architecture : "No Specified Architecture") << ": " << Result->second<< ": " << "Result->first: " << Result->first << " vs. MD5hash: " << MD5Hash << "\n";
+  if (Result != MD5NameMap.end() && Result->first == MD5Hash)
     return Result->second;
   return StringRef();
 }
diff --git a/llvm/include/llvm/ProfileData/InstrProfReader.h b/llvm/include/llvm/ProfileData/InstrProfReader.h
index b92253a81502d..70b54d1fa0fba 100644
--- a/llvm/include/llvm/ProfileData/InstrProfReader.h
+++ b/llvm/include/llvm/ProfileData/InstrProfReader.h
@@ -875,6 +875,10 @@ class LLVM_ABI IndexedInstrProfReader : public InstrProfReader {
   create(const Twine &Path, vfs::FileSystem &FS,
          const Twine &RemappingPath = "");
 
+  static Expected<std::unique_ptr<IndexedInstrProfReader>>
+  create(const Twine &Path, vfs::FileSystem &FS,
+        const std::string &Arch, const Twine &RemappingPath = "");
+
   static Expected<std::unique_ptr<IndexedInstrProfReader>>
   create(std::unique_ptr<MemoryBuffer> Buffer,
          std::unique_ptr<MemoryBuffer> RemappingBuffer = nullptr);
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 429ec5c19f1f8..a034ac7dd2e69 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -821,6 +821,154 @@ class MCDCDecisionRecorder {
 
 } // namespace
 
+Error CoverageMapping::loadFunctionRecord(
+    const CoverageMappingRecord &Record,
+    const std::optional<std::reference_wrapper<IndexedInstrProfReader>>
+        &ProfileReader, const std::string &Arch) {
+  StringRef OrigFuncName = Record.FunctionName;
+  if (OrigFuncName.empty())
+    return make_error<CoverageMapError>(coveragemap_error::malformed,
+                                        "record function name is empty");
+
+  if (Record.Filenames.empty())
+    OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName);
+  else
+    OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName, Record.Filenames[0]);
+
+  CounterMappingContext Ctx(Record.Expressions);
+
+  std::string HashStr = std::to_string(Record.FunctionHash) + ":" + Arch;
+  llvm::StringRef HashRef(HashStr);
+  uint64_t NewHash = IndexedInstrProf::ComputeHash(HashRef);
+
+  std::vector<uint64_t> Counts;
+  if (ProfileReader) {
+    if (Error E = ProfileReader.value().get().getFunctionCounts(
+            Record.FunctionName, NewHash, Counts)) {
+      instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
+      if (IPE == instrprof_error::hash_mismatch) {
+        FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
+                                        NewHash);
+        return Error::success();
+      }
+      if (IPE != instrprof_error::unknown_function)
+        return make_error<InstrProfError>(IPE);
+      Counts.assign(getMaxCounterID(Ctx, Record) + 1, 0);
+    }
+  } else {
+    Counts.assign(getMaxCounterID(Ctx, Record) + 1, 0);
+  }
+  Ctx.setCounts(Counts);
+
+  bool IsVersion11 =
+      ProfileReader && ProfileReader.value().get().getVersion() <
+                           IndexedInstrProf::ProfVersion::Version12;
+
+  BitVector Bitmap;
+  if (ProfileReader) {
+    if (Error E = ProfileReader.value().get().getFunctionBitmap(
+            Record.FunctionName, NewHash, Bitmap)) {
+      instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
+      if (IPE == instrprof_error::hash_mismatch) {
+        FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
+                                        NewHash);
+        return Error::success();
+      }
+      if (IPE != instrprof_error::unknown_function)
+        return make_error<InstrProfError>(IPE);
+      Bitmap = BitVector(getMaxBitmapSize(Record, IsVersion11));
+    }
+  } else {
+    Bitmap = BitVector(getMaxBitmapSize(Record, false));
+  }
+  Ctx.setBitmap(std::move(Bitmap));
+
+  assert(!Record.MappingRegions.empty() && "Function has no regions");
+
+  // This coverage record is a zero region for a function that's unused in
+  // some TU, but used in a different TU. Ignore it. The coverage maps from the
+  // the other TU will either be loaded (providing full region counts) or they
+  // won't (in which case we don't unintuitively report functions as uncovered
+  // when they have non-zero counts in the profile).
+  if (Record.MappingRegions.size() == 1 &&
+      Record.MappingRegions[0].Count.isZero() && Counts[0] > 0)
+    return Error::success();
+
+  MCDCDecisionRecorder MCDCDecisions;
+  FunctionRecord Function(OrigFuncName, Record.Filenames);
+  for (const auto &Region : Record.MappingRegions) {
+    // MCDCDecisionRegion should be handled first since it overlaps with
+    // others inside.
+    if (Region.Kind == CounterMappingRegion::MCDCDecisionRegion) {
+      MCDCDecisions.registerDecision(Region);
+      continue;
+    }
+    Expected<int64_t> ExecutionCount = Ctx.evaluate(Region.Count);
+    if (auto E = ExecutionCount.takeError()) {
+      consumeError(std::move(E));
+      return Error::success();
+    }
+    Expected<int64_t> AltExecutionCount = Ctx.evaluate(Region.FalseCount);
+    if (auto E = AltExecutionCount.takeError()) {
+      consumeError(std::move(E));
+      return Error::success();
+    }
+    Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount);
+
+    // Record ExpansionRegion.
+    if (Region.Kind == CounterMappingRegion::ExpansionRegion) {
+      MCDCDecisions.recordExpansion(Region);
+      continue;
+    }
+
+    // Do nothing unless MCDCBranchRegion.
+    if (Region.Kind != CounterMappingRegion::MCDCBranchRegion)
+      continue;
+
+    auto Result = MCDCDecisions.processBranch(Region);
+    if (!Result) // Any Decision doesn't complete.
+      continue;
+
+    auto MCDCDecision = Result->first;
+    auto &MCDCBranches = Result->second;
+
+    // Since the bitmap identifies the executed test vectors for an MC/DC
+    // DecisionRegion, all of the information is now available to process.
+    // This is where the bulk of the MC/DC progressing takes place.
+    Expected<MCDCRecord> Record =
+        Ctx.evaluateMCDCRegion(*MCDCDecision, MCDCBranches, IsVersion11);
+    if (auto E = Record.takeError()) {
+      consumeError(std::move(E));
+      return Error::success();
+    }
+
+    // Save the MC/DC Record so that it can be visualized later.
+    Function.pushMCDCRecord(std::move(*Record));
+  }
+
+  // Don't create records for (filenames, function) pairs we've already seen.
+  auto FilenamesHash = hash_combine_range(Record.Filenames);
+  if (!RecordProvenance[FilenamesHash].insert(hash_value(OrigFuncName)).second)
+    return Error::success();
+
+  Functions.push_back(std::move(Function));
+
+  // Performance optimization: keep track of the indices of the function records
+  // which correspond to each filename. This can be used to substantially speed
+  // up queries for coverage info in a file.
+  unsigned RecordIndex = Functions.size() - 1;
+  for (StringRef Filename : Record.Filenames) {
+    auto &RecordIndices = FilenameHash2RecordIndices[hash_value(Filename)];
+    // Note that there may be duplicates in the filename set for a function
+    // record, because of e.g. macro expansions in the function in which both
+    // the macro and the function are defined in the same file.
+    if (RecordIndices.empty() || RecordIndices.back() != RecordIndex)
+      RecordIndices.push_back(RecordIndex);
+  }
+
+  return Error::success();
+}
+
 Error CoverageMapping::loadFunctionRecord(
     const CoverageMappingRecord &Record,
     const std::optional<std::reference_wrapper<IndexedInstrProfReader>>
@@ -837,14 +985,18 @@ Error CoverageMapping::loadFunctionRecord(
 
   CounterMappingContext Ctx(Record.Expressions);
 
+  std::string HashStr = std::to_string(Record.FunctionHash) + ":" + Arch.str();
+  llvm::StringRef HashRef(HashStr);
+  uint64_t NewHash = IndexedInstrProf::ComputeHash(HashRef);
+
   std::vector<uint64_t> Counts;
   if (ProfileReader) {
     if (Error E = ProfileReader.value().get().getFunctionCounts(
-            Record.FunctionName, Record.FunctionHash, Counts)) {
+            Record.FunctionName, NewHash, Counts)) {
       instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
       if (IPE == instrprof_error::hash_mismatch) {
         FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
-                                        Record.FunctionHash);
+                                        NewHash);
         return Error::success();
       }
       if (IPE != instrprof_error::unknown_function)
@@ -863,11 +1015,11 @@ Error CoverageMapping::loadFunctionRecord(
   BitVector Bitmap;
   if (ProfileReader) {
     if (Error E = ProfileReader.value().get().getFunctionBitmap(
-            Record.FunctionName, Record.FunctionHash, Bitmap)) {
+            Record.FunctionName, NewHash, Bitmap)) {
       instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
       if (IPE == instrprof_error::hash_mismatch) {
         FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
-                                        Record.FunctionHash);
+                                        NewHash);
         return Error::success();
       }
       if (IPE != instrprof_error::unknown_function)
@@ -989,6 +1141,31 @@ Error CoverageMapping::loadFromReaders(
   return Error::success();
 }
 
+
+Error CoverageMapping::loadFromReaders(
+    ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
+    std::optional<std::reference_wrapper<IndexedInstrProfReader>>
+        &ProfileReader,
+    CoverageMapping &Coverage, StringRef Arch) {
+  
+  Coverage.setArchitecture(Arch);
+  assert(!Coverage.SingleByteCoverage || !ProfileReader ||
+         *Coverage.SingleByteCoverage ==
+             ProfileReader.value().get().hasSingleByteCoverage());
+  Coverage.SingleByteCoverage =
+      !ProfileReader || ProfileReader.value().get().hasSingleByteCoverage();
+  for (const auto &CoverageReader : CoverageReaders) {
+    for (auto RecordOrErr : *CoverageReader) {
+      if (Error E = RecordOrErr.takeError())
+        return E;
+      const auto &Record = *RecordOrErr;
+      if (Error E = Coverage.loadFunctionRecord(Record, ProfileReader))
+        return E;
+    }
+  }
+  return Error::success();
+}
+
 Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
     ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
     std::optional<std::reference_wrapper<IndexedInstrProfReader>>
@@ -1022,6 +1199,8 @@ Error CoverageMapping::loadFromFile(
       CovMappingBufOrErr.get()->getMemBufferRef();
   SmallVector<std::unique_ptr<MemoryBuffer>, 4> Buffers;
 
+
+
   SmallVector<object::BuildIDRef> BinaryIDs;
   auto CoverageReadersOrErr = BinaryCoverageReader::create(
       CovMappingBufRef, Arch, Buffers, CompilationDir,
@@ -1043,7 +1222,7 @@ Error CoverageMapping::loadFromFile(
                        }));
   }
   DataFound |= !Readers.empty();
-  if (Error E = loadFromReaders(Readers, ProfileReader, Coverage))
+  if (Error E = loadFromReaders(Readers, ProfileReader, Coverage, Arch))
     return createFileError(Filename, std::move(E));
   return Error::success();
 }
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
index cdf4412c6477a..aa5b714bbdec8 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
@@ -579,13 +579,13 @@ struct CovMapFuncRecordReader {
   readFunctionRecords(const char *FuncRecBuf, const char *FuncRecBufEnd,
                       std::optional<FilenameRange> OutOfLineFileRange,
                       const char *OutOfLineMappingBuf,
-                      const char *OutOfLineMappingBufEnd) = 0;
+                      const char *OutOfLineMappingBufEnd, StringRef Arch = "") = 0;
 
   template <class IntPtrT, llvm::endianness Endian>
   static Expected<std::unique_ptr<CovMapFuncRecordReader>>
   get(CovMapVersion Version, InstrProfSymtab &P,
       std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, StringRef D,
-      std::vector<std::string> &F);
+      std::vector<std::string> &F, StringRef Arch = "");
 };
 
 // A class for reading coverage mapping function records for a module.
@@ -615,7 +615,7 @@ class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader {
   // not used in the corresponding translation unit.
   Error insertFunctionRecordIfNeeded(const FuncRecordType *CFR,
                                      StringRef Mapping,
-                                     FilenameRange FileRange) {
+                                     FilenameRange FileRange, StringRef Arch = "") {
     ++CovMapNumRecords;
     uint64_t FuncHash = CFR->template getFuncHash<Endian>();
     NameRefType NameRef = CFR->template getFuncNameRef<Endian>();
@@ -623,7 +623,7 @@ class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader {
         FunctionRecords.insert(std::make_pair(NameRef, Records.size()));
     if (InsertResult.second) {
       StringRef FuncName;
-      if (Error Err = CFR->template getFuncName<Endian>(ProfileNames, FuncName))
+      if (Error Err = CFR->template getFuncName<Endian>(ProfileNames, FuncName, Arch))
         return Err;
       if (FuncName.empty())
         return make_error<InstrProfError>(instrprof_error::malformed,
@@ -762,7 +762,7 @@ class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader {
   Error readFunctionRecords(const char *FuncRecBuf, const char *FuncRecBufEnd,
                             std::optional<FilenameRange> OutOfLineFileRange,
                             const char *OutOfLineMappingBuf,
-                            const char *OutOfLineMappingBufEnd) override {
+                            const char *OutOfLineMappingBufEnd, StringRef Arch = "") override {
     auto CFR = reinterpret_cast<const FuncRecordType *>(FuncRecBuf);
     while ((const char *)CFR < FuncRecBufEnd) {
       // Validate the length of the coverage mapping for this function.
@@ -801,7 +801,7 @@ class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader {
           return make_error<CoverageMapError>(
               coveragemap_error::malformed,
               "coverage mapping data is larger than buffer size");
-        if (Error Err = insertFunctionRecordIfNeeded(CFR, Mapping, *FileRange))
+        if (Error Err = insertFunctionRecordIfNeeded(CFR, Mapping, *FileRange, Arch))
           return Err;
       }
 
@@ -817,7 +817,7 @@ template <class IntPtrT, llvm::endianness Endian>
 Expected<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get(
     CovMapVersion Version, InstrProfSymtab &P,
     std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, StringRef D,
-    std::vector<std::string> &F) {
+    std::vector<std::string> &F, StringRef Arch) {
   using namespace coverage;
 
   switch (Version) {
@@ -831,6 +831,7 @@ Expected<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get(
   case CovMapVersion::Version6:
   case CovMapVersion::Version7:
     // Decompress the name data.
+    P.setArchitecture(Arch.str());
     if (Error E = P.create(P.getNameData()))
       return std::move(E);
     if (Version == CovMapVersion::Version2)
@@ -859,7 +860,7 @@ template <typename T, llvm::endianness Endian>
 static Error readCoverageMappingData(
     InstrProfSymtab &ProfileNames, StringRef CovMap, StringRef FuncRecords,
     std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records,
-    StringRef CompilationDir, std::vector<std::string> &Filenames) {
+    StringRef CompilationDir, std::vector<std::string> &Filenames, StringRef Arch = "") {
   using namespace coverage;
 
   // Read the records in the coverage data section.
@@ -870,7 +871,7 @@ static Error readCoverageMappingData(
     return make_error<CoverageMapError>(coveragemap_error::unsupported_version);
   Expected<std::unique_ptr<CovMapFuncRecordReader>> ReaderExpected =
       CovMapFuncRecordReader::get<T, Endian>(Version, ProfileNames, Records,
-                                             CompilationDir, Filenames);
+                                             CompilationDir, Filenames, Arch);
   if (Error E = ReaderExpected.takeError())
     return E;
   auto Reader = std::move(ReaderExpected.get());
@@ -894,7 +895,7 @@ static Error readCoverageMappingData(
   // the records from their dedicated section.
   if (Version >= CovMapVersion::Version4)
     return Reader->readFunctionRecords(FuncRecBuf, FuncRecBufEnd, std::nullopt,
-                                       nullptr, nullptr);
+                                       nullptr, nullptr, Arch);
   return Error::success();
 }
 
@@ -903,7 +904,7 @@ BinaryCoverageReader::createCoverageReaderFromBuffer(
     StringRef Coverage, FuncRecordsStorage &&FuncRecords,
     CoverageMapCopyStorage &&CoverageMap,
     std::unique_ptr<InstrProfSymtab> ProfileNamesPtr, uint8_t BytesInAddress,
-    llvm::endianness Endian, StringRef CompilationDir) {
+    llvm::endianness Endian, StringRef CompilationDir, StringRef Arch) {
   if (ProfileNamesPtr == nullptr)
     return make_error<CoverageMapError>(coveragemap_error::malformed,
                                         "Caller must provide ProfileNames");
@@ -915,22 +916,22 @@ BinaryCoverageReader::createCoverageReaderFromBuffer(
   if (BytesInAddress == 4 && Endian == llvm::endianness::little) {
     if (Error E = readCoverageMappingData<uint32_t, llvm::endianness::little>(
             ProfileNames, Coverage, FuncRecordsRef, Reader->MappingRecords,
-            CompilationDir, Reader->Filenames))
+            CompilationDir, Reader->Filenames, Arch))
       return std::move(E);
   } else if (BytesInAddress == 4 && Endian == llvm::endianness::big) {
     if (Error E = readCoverageMappingData<uint32_t, llvm::endianness::big>(
             ProfileNames, Coverage, FuncRecordsRef, Reader->MappingRecords,
-            CompilationDir, Reader->Filenames))
+            CompilationDir, Reader->Filenames, Arch))
       return std::move(E);
   } else if (BytesInAddress == 8 && Endian == llvm::endianness::little) {
     if (Error E = readCoverageMappingData<uint64_t, llvm::endianness::little>(
             ProfileNames, Coverage, FuncRecordsRef, Reader->MappingRecords,
-            CompilationDir, Reader->Filenames))
+            CompilationDir, Reader->Filenames, Arch))
       return std::move(E);
   } else if (BytesInAddress == 8 && Endian == llvm::endianness::big) {
     if (Error E = readCoverageMappingData<uint64_t, llvm::endianness::big>(
             ProfileNames, Coverage, FuncRecordsRef, Reader->MappingRecords,
-            CompilationDir, Reader->Filenames))
+            CompilationDir, Reader->Filenames, Arch))
       return std::move(E);
   } else
     return make_error<CoverageMapError>(
@@ -1250,7 +1251,7 @@ loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch,
 
   return BinaryCoverageReader::createCoverageReaderFromBuffer(
       CoverageMapping, std::move(FuncRecords), std::move(CoverageMapCopy),
-      std::move(ProfileNames), BytesInAddress, Endian, CompilationDir);
+      std::move(ProfileNames), BytesInAddress, Endian, CompilationDir, Arch);
 }
 
 /// Determine whether \p Arch is invalid or empty, given \p Bin.
diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp
index c175723bb41c7..9998adc5b2343 100644
--- a/llvm/lib/ProfileData/InstrProf.cpp
+++ b/llvm/lib/ProfileData/InstrProf.cpp
@@ -668,7 +668,8 @@ Error readAndDecodeStrings(StringRef NameStrings,
 }
 
 Error InstrProfSymtab::create(StringRef NameStrings) {
-  return readAndDecodeStrings(NameStrings, std::bind(&InstrProfSymtab::addFuncName, this, std::placeholders::_1));
+  const std::string &Architecture = getArchitecture();
+  return readAndDecodeStrings(NameStrings, std::bind(&InstrProfSymtab::addFuncName, this, std::placeholders::_1), Architecture);
 }
 
 Error InstrProfSymtab::create(StringRef FuncNameStrings,
diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp
index 33b62cf5cca5c..33ebcfd3200b2 100644
--- a/llvm/lib/ProfileData/InstrProfReader.cpp
+++ b/llvm/lib/ProfileData/InstrProfReader.cpp
@@ -226,6 +226,28 @@ IndexedInstrProfReader::create(const Twine &Path, vfs::FileSystem &FS,
                                         std::move(RemappingBuffer));
 }
 
+Expected<std::unique_ptr<IndexedInstrProfReader>>
+IndexedInstrProfReader::create(const Twine &Path, vfs::FileSystem &FS,
+                               const std::string &Arch, const Twine &RemappingPath) {
+  // Set up the buffer to read.
+  auto BufferOrError = setupMemoryBuffer(Path, FS);
+  if (Error E = BufferOrError.takeError())
+    return std::move(E);
+
+  // Set up the remapping buffer if requested.
+  std::unique_ptr<MemoryBuffer> RemappingBuffer;
+  std::string RemappingPathStr = RemappingPath.str();
+  if (!RemappingPathStr.empty()) {
+    auto RemappingBufferOrError = setupMemoryBuffer(RemappingPathStr, FS);
+    if (Error E = RemappingBufferOrError.takeError())
+      return std::move(E);
+    RemappingBuffer = std::move(RemappingBufferOrError.get());
+  }
+
+  return IndexedInstrProfReader::create(std::move(BufferOrError.get()),
+                                        std::move(RemappingBuffer));
+}
+
 Expected<std::unique_ptr<IndexedInstrProfReader>>
 IndexedInstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer,
                                std::unique_ptr<MemoryBuffer> RemappingBuffer) {

>From 451e0fd2bbef42ce263e28a0c0d2c84123011c0e Mon Sep 17 00:00:00 2001
From: Andres Wearden <andreswearden5 at gmail.com>
Date: Tue, 8 Jul 2025 13:41:49 -0700
Subject: [PATCH 06/17] fixed bug messing up coremark build, it was getting
 rehashed when hash was inserted into MD5NameMap

---
 llvm/include/llvm/ProfileData/InstrProf.h | 21 ++++++++++++++++-----
 llvm/lib/ProfileData/InstrProf.cpp        |  2 +-
 2 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h
index 747853f3af8e9..19850c418db9d 100644
--- a/llvm/include/llvm/ProfileData/InstrProf.h
+++ b/llvm/include/llvm/ProfileData/InstrProf.h
@@ -636,14 +636,15 @@ class InstrProfSymtab {
   // Map the MD5 of the symbol name to the name.
   Error addSymbolName(StringRef SymbolName) {
     StringRef FuncName;
-    StringRef ArchName = "";
-    std::tie(FuncName, ArchName) = SymbolName.split(":");
+    StringRef ArchName = Architecture;
+    std::tie(FuncName, ArchName) = SymbolName.split("#");
     if (SymbolName.empty())
       return make_error<InstrProfError>(instrprof_error::malformed,
                                         "symbol name is empty");
 
     // Insert into NameTab so that MD5NameMap (a vector that will be sorted)
     // won't have duplicated entries in the first place.
+
     uint64_t HashValue = IndexedInstrProf::ComputeHash(FuncName);
     llvm::StringRef HashRef(FuncName);
     if(!ArchName.empty()){
@@ -652,14 +653,18 @@ class InstrProfSymtab {
       HashRef = CombinedStr;
       HashValue = IndexedInstrProf::ComputeHash(HashRef);
     }
+    llvm::errs() << "FuncName is " << FuncName << " is written in " << ArchName << "\n";
     printf("Hash Value for %.*s %" PRIu64 "\n", static_cast<int>(SymbolName.size()), SymbolName.data(), HashValue);
     auto Ins = NameTab.insert(FuncName);
     printf("mapped value for %" PRIu64 " hash: %.*s\n", HashValue, static_cast<int>(Ins.first->getKey().size()), Ins.first->getKey().data());
     if (Ins.second) {
-      MD5NameMap.push_back(std::make_pair(
-          IndexedInstrProf::ComputeHash(HashRef), Ins.first->getKey()));
+      MD5NameMap.push_back(std::make_pair(HashValue /*IndexedInstrProf::ComputeHash(HashRef)*/, Ins.first->getKey()));
       Sorted = false;
     }
+    llvm::errs() << "Hash values when inside of addSymbolName" << "\n";
+    for(int I = 0; I < int(MD5NameMap.size()); ++I){
+      llvm::errs() << "Hash: " << MD5NameMap[I].first << " Function Name: " << MD5NameMap[I].second << "\n";
+    }
     return Error::success();
   }
 
@@ -787,13 +792,19 @@ StringRef InstrProfSymtab::getFuncOrVarNameIfDefined(uint64_t MD5Hash) {
 StringRef InstrProfSymtab::getFuncOrVarName(uint64_t MD5Hash) {
   finalizeSymtab();
   std::string TempMD5HashStr = std::to_string(MD5Hash);
+  llvm::errs() << "Before: " << MD5Hash << "\n";
   if(!Architecture.empty()){
     std::string CombinedHashStr = TempMD5HashStr + ":" + Architecture;
     llvm::StringRef CombinedHashRef(CombinedHashStr);
     MD5Hash = IndexedInstrProf::ComputeHash(CombinedHashRef);
   }
+  llvm::errs() << "After: " << MD5Hash << "\n";
+  llvm::errs() << "Hash values when inside of getFuncOrVarName" << "\n";
+  for(int I = 0; I < int(MD5NameMap.size()); ++I){
+    llvm::errs() << "Hash: " << MD5NameMap[I].first << " Function Name: " << MD5NameMap[I].second << "\n";
+  }
   auto Result = llvm::lower_bound(MD5NameMap, MD5Hash, [](const std::pair<uint64_t, StringRef> &LHS, uint64_t RHS) { return LHS.first < RHS; });
-  llvm::errs() << "Architecture: " << (!Architecture.empty() ? Architecture : "No Specified Architecture") << ": " << Result->second<< ": " << "Result->first: " << Result->first << " vs. MD5hash: " << MD5Hash << "\n";
+  llvm::errs() << "Architecture: " << (!Architecture.empty() ? Architecture : "No Specified Architecture") << ": " << Result->second << ": " << "Result->first: " << Result->first << " vs. MD5hash: " << MD5Hash << "\n";
   if (Result != MD5NameMap.end() && Result->first == MD5Hash)
     return Result->second;
   return StringRef();
diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp
index 9998adc5b2343..9a75164ebe698 100644
--- a/llvm/lib/ProfileData/InstrProf.cpp
+++ b/llvm/lib/ProfileData/InstrProf.cpp
@@ -615,7 +615,7 @@ Error readAndDecodeStrings(StringRef NameStrings,
         if (Error E = NameCallback(Name))
           return E;
       }else{
-        if (Error E = NameCallback(Name.str() + ":" + ArchRef.str()))
+        if (Error E = NameCallback(Name.str() + "#" + ArchRef.str()))
           return E;
       }
     }

>From 4b25f41035b11ca0230690d1978044f2dc743cca Mon Sep 17 00:00:00 2001
From: Andres Wearden <andreswearden5 at gmail.com>
Date: Fri, 11 Jul 2025 10:25:20 -0700
Subject: [PATCH 07/17] saving changes

---
 llvm/include/llvm/ProfileData/InstrProf.h     |  45 ++-
 .../llvm/ProfileData/InstrProfReader.h        |   8 +-
 .../llvm/ProfileData/InstrProfWriter.h        |  10 +-
 .../ProfileData/Coverage/CoverageMapping.cpp  | 314 +++++++++---------
 llvm/lib/ProfileData/InstrProf.cpp            | 102 +++---
 llvm/lib/ProfileData/InstrProfReader.cpp      |   4 +-
 llvm/lib/ProfileData/InstrProfWriter.cpp      |  56 ++--
 llvm/tools/llvm-cov/CodeCoverage.cpp          |   8 +-
 llvm/tools/llvm-cov/SourceCoverageView.cpp    |  23 +-
 llvm/tools/llvm-cov/SourceCoverageView.h      |   5 +-
 .../tools/llvm-cov/SourceCoverageViewHTML.cpp |  25 ++
 llvm/tools/llvm-cov/SourceCoverageViewHTML.h  |   2 +
 .../tools/llvm-cov/SourceCoverageViewText.cpp |  21 +-
 llvm/tools/llvm-cov/SourceCoverageViewText.h  |   2 +
 llvm/tools/llvm-profdata/llvm-profdata.cpp    |   4 +-
 15 files changed, 342 insertions(+), 287 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h
index 19850c418db9d..98890b5541a8f 100644
--- a/llvm/include/llvm/ProfileData/InstrProf.h
+++ b/llvm/include/llvm/ProfileData/InstrProf.h
@@ -369,9 +369,9 @@ LLVM_ABI bool needsComdatForCounter(const GlobalObject &GV, const Module &M);
 /// InstrProf.h:getInstrProfNameSeparator). This method decodes the string and
 /// calls `NameCallback` for each substring.
 LLVM_ABI Error readAndDecodeStrings(
-    StringRef NameStrings, std::function<Error(StringRef)> NameCallback);
+    StringRef NameStrings, std::function<Error(StringRef)> NameCallback, StringRef Architecture = "");
+
 
-LLVM_ABI Error readAndDecodeStrings(StringRef NameStrings, std::function<Error(StringRef)> NameCallback, const std::string &Architecture);
 /// An enum describing the attributes of an instrumented profile.
 enum class InstrProfKind {
   Unknown = 0x0,
@@ -515,11 +515,11 @@ class InstrProfSymtab {
   LLVM_ABI static StringRef getCanonicalName(StringRef PGOName);
 
   //ANDRES Function
-  const std::string &getArchitecture() {return Architecture;}
-  void setArchitecture(const std::string &Arch) {Architecture = Arch;}
+  StringRef getArchitecture() {return Architecture;}
+  void setArchitecture(StringRef Arch) {Architecture = Arch;}
   //ANDRES Function
 private:
-  std::string Architecture;
+  StringRef Architecture;
   using AddrIntervalMap =
       IntervalMap<uint64_t, uint64_t, 4, IntervalMapHalfOpenInfo<uint64_t>>;
   StringRef Data;
@@ -635,9 +635,9 @@ class InstrProfSymtab {
 
   // Map the MD5 of the symbol name to the name.
   Error addSymbolName(StringRef SymbolName) {
-    StringRef FuncName;
-    StringRef ArchName = Architecture;
-    std::tie(FuncName, ArchName) = SymbolName.split("#");
+    // StringRef FuncName;
+    // StringRef ArchName = Architecture;
+    // std::tie(FuncName, ArchName) = SymbolName.split("#");
     if (SymbolName.empty())
       return make_error<InstrProfError>(instrprof_error::malformed,
                                         "symbol name is empty");
@@ -645,25 +645,20 @@ class InstrProfSymtab {
     // Insert into NameTab so that MD5NameMap (a vector that will be sorted)
     // won't have duplicated entries in the first place.
 
-    uint64_t HashValue = IndexedInstrProf::ComputeHash(FuncName);
-    llvm::StringRef HashRef(FuncName);
-    if(!ArchName.empty()){
+    uint64_t HashValue = IndexedInstrProf::ComputeHash(SymbolName);
+    llvm::StringRef HashRef(SymbolName);
+    if(!Architecture.empty()){
       std::string HashStr = std::to_string(HashValue);
-      std::string CombinedStr = HashStr + ":" + ArchName.str();
+      std::string CombinedStr = HashStr + ":" + Architecture.str();
       HashRef = CombinedStr;
       HashValue = IndexedInstrProf::ComputeHash(HashRef);
     }
-    llvm::errs() << "FuncName is " << FuncName << " is written in " << ArchName << "\n";
-    printf("Hash Value for %.*s %" PRIu64 "\n", static_cast<int>(SymbolName.size()), SymbolName.data(), HashValue);
-    auto Ins = NameTab.insert(FuncName);
-    printf("mapped value for %" PRIu64 " hash: %.*s\n", HashValue, static_cast<int>(Ins.first->getKey().size()), Ins.first->getKey().data());
+    auto Ins = NameTab.insert(SymbolName);
     if (Ins.second) {
       MD5NameMap.push_back(std::make_pair(HashValue /*IndexedInstrProf::ComputeHash(HashRef)*/, Ins.first->getKey()));
       Sorted = false;
     }
-    llvm::errs() << "Hash values when inside of addSymbolName" << "\n";
     for(int I = 0; I < int(MD5NameMap.size()); ++I){
-      llvm::errs() << "Hash: " << MD5NameMap[I].first << " Function Name: " << MD5NameMap[I].second << "\n";
     }
     return Error::success();
   }
@@ -792,19 +787,17 @@ StringRef InstrProfSymtab::getFuncOrVarNameIfDefined(uint64_t MD5Hash) {
 StringRef InstrProfSymtab::getFuncOrVarName(uint64_t MD5Hash) {
   finalizeSymtab();
   std::string TempMD5HashStr = std::to_string(MD5Hash);
-  llvm::errs() << "Before: " << MD5Hash << "\n";
   if(!Architecture.empty()){
-    std::string CombinedHashStr = TempMD5HashStr + ":" + Architecture;
+    std::string CombinedHashStr = TempMD5HashStr + ":" + Architecture.str();
     llvm::StringRef CombinedHashRef(CombinedHashStr);
     MD5Hash = IndexedInstrProf::ComputeHash(CombinedHashRef);
   }
-  llvm::errs() << "After: " << MD5Hash << "\n";
-  llvm::errs() << "Hash values when inside of getFuncOrVarName" << "\n";
-  for(int I = 0; I < int(MD5NameMap.size()); ++I){
-    llvm::errs() << "Hash: " << MD5NameMap[I].first << " Function Name: " << MD5NameMap[I].second << "\n";
-  }
   auto Result = llvm::lower_bound(MD5NameMap, MD5Hash, [](const std::pair<uint64_t, StringRef> &LHS, uint64_t RHS) { return LHS.first < RHS; });
-  llvm::errs() << "Architecture: " << (!Architecture.empty() ? Architecture : "No Specified Architecture") << ": " << Result->second << ": " << "Result->first: " << Result->first << " vs. MD5hash: " << MD5Hash << "\n";
+
+  // for(auto name : MD5NameMap){
+  //   llvm::errs() << "Function Name " << name.second  << " Result->first: " << name.first << "\n";
+  // }
+  // llvm::errs() << "Function Name " << Result->second  << " Result->first: " << Result->first << " vs. " << MD5Hash << "\n";
   if (Result != MD5NameMap.end() && Result->first == MD5Hash)
     return Result->second;
   return StringRef();
diff --git a/llvm/include/llvm/ProfileData/InstrProfReader.h b/llvm/include/llvm/ProfileData/InstrProfReader.h
index 70b54d1fa0fba..e2ed1cb8cf399 100644
--- a/llvm/include/llvm/ProfileData/InstrProfReader.h
+++ b/llvm/include/llvm/ProfileData/InstrProfReader.h
@@ -213,7 +213,7 @@ class InstrProfReader {
       const object::BuildIDFetcher *BIDFetcher = nullptr,
       const InstrProfCorrelator::ProfCorrelatorKind BIDFetcherCorrelatorKind =
           InstrProfCorrelator::ProfCorrelatorKind::NONE,
-      std::function<void(Error)> Warn = nullptr, const std::string &Architecture = "");
+      std::function<void(Error)> Warn = nullptr, StringRef Architecture = "");
 
   LLVM_ABI static Expected<std::unique_ptr<InstrProfReader>> create(
       std::unique_ptr<MemoryBuffer> Buffer,
@@ -221,11 +221,11 @@ class InstrProfReader {
       const object::BuildIDFetcher *BIDFetcher = nullptr,
       const InstrProfCorrelator::ProfCorrelatorKind BIDFetcherCorrelatorKind =
           InstrProfCorrelator::ProfCorrelatorKind::NONE,
-      std::function<void(Error)> Warn = nullptr, const std::string &Architecture = "");
+      std::function<void(Error)> Warn = nullptr, StringRef Architecture = "");
   
-  const std::string &getArchitecture() {return Architecture;}
+  StringRef getArchitecture() {return Architecture;}
 
-  void setArchitecture(const std::string &Arch) {Architecture = Arch;}
+  void setArchitecture(StringRef Arch) {Architecture = Arch;}
   /// \param Weight for raw profiles use this as the temporal profile trace
   ///               weight
   /// \returns a list of temporal profile traces.
diff --git a/llvm/include/llvm/ProfileData/InstrProfWriter.h b/llvm/include/llvm/ProfileData/InstrProfWriter.h
index e281e100bf808..77c93c537f468 100644
--- a/llvm/include/llvm/ProfileData/InstrProfWriter.h
+++ b/llvm/include/llvm/ProfileData/InstrProfWriter.h
@@ -113,12 +113,8 @@ class InstrProfWriter {
   /// for this function and the hash and number of counts match, each counter is
   /// summed. Optionally scale counts by \p Weight.
   LLVM_ABI void addRecord(NamedInstrProfRecord &&I, uint64_t Weight,
-                          function_ref<void(Error)> Warn);
-  LLVM_ABI void addRecord(StringRef Name, uint64_t Hash,
-                                InstrProfRecord &&I, uint64_t Weight,
-                                function_ref<void(Error)> Warn, const std::string &Architecture);
-  void addRecord(NamedInstrProfRecord &&I, uint64_t Weight, const std::string &Architecture,
-                                function_ref<void(Error)> Warn);
+                          function_ref<void(Error)> Warn, StringRef Architecture = "");
+  // void addRecord(NamedInstrProfRecord &&I, uint64_t Weight, function_ref<void(Error)> Warn);
   void addRecord(NamedInstrProfRecord &&I, function_ref<void(Error)> Warn) {
     addRecord(std::move(I), 1, Warn);
   }
@@ -229,7 +225,7 @@ class InstrProfWriter {
 
 private:
   void addRecord(StringRef Name, uint64_t Hash, InstrProfRecord &&I,
-                 uint64_t Weight, function_ref<void(Error)> Warn);
+                 uint64_t Weight, function_ref<void(Error)> Warn, StringRef Architecture = "");
   bool shouldEncodeData(const ProfilingData &PD);
   /// Add \p Trace using reservoir sampling.
   void addTemporalProfileTrace(TemporalProfTraceTy Trace);
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index a034ac7dd2e69..0a391b3d56773 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -821,153 +821,156 @@ class MCDCDecisionRecorder {
 
 } // namespace
 
-Error CoverageMapping::loadFunctionRecord(
-    const CoverageMappingRecord &Record,
-    const std::optional<std::reference_wrapper<IndexedInstrProfReader>>
-        &ProfileReader, const std::string &Arch) {
-  StringRef OrigFuncName = Record.FunctionName;
-  if (OrigFuncName.empty())
-    return make_error<CoverageMapError>(coveragemap_error::malformed,
-                                        "record function name is empty");
-
-  if (Record.Filenames.empty())
-    OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName);
-  else
-    OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName, Record.Filenames[0]);
-
-  CounterMappingContext Ctx(Record.Expressions);
-
-  std::string HashStr = std::to_string(Record.FunctionHash) + ":" + Arch;
-  llvm::StringRef HashRef(HashStr);
-  uint64_t NewHash = IndexedInstrProf::ComputeHash(HashRef);
-
-  std::vector<uint64_t> Counts;
-  if (ProfileReader) {
-    if (Error E = ProfileReader.value().get().getFunctionCounts(
-            Record.FunctionName, NewHash, Counts)) {
-      instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
-      if (IPE == instrprof_error::hash_mismatch) {
-        FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
-                                        NewHash);
-        return Error::success();
-      }
-      if (IPE != instrprof_error::unknown_function)
-        return make_error<InstrProfError>(IPE);
-      Counts.assign(getMaxCounterID(Ctx, Record) + 1, 0);
-    }
-  } else {
-    Counts.assign(getMaxCounterID(Ctx, Record) + 1, 0);
-  }
-  Ctx.setCounts(Counts);
-
-  bool IsVersion11 =
-      ProfileReader && ProfileReader.value().get().getVersion() <
-                           IndexedInstrProf::ProfVersion::Version12;
-
-  BitVector Bitmap;
-  if (ProfileReader) {
-    if (Error E = ProfileReader.value().get().getFunctionBitmap(
-            Record.FunctionName, NewHash, Bitmap)) {
-      instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
-      if (IPE == instrprof_error::hash_mismatch) {
-        FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
-                                        NewHash);
-        return Error::success();
-      }
-      if (IPE != instrprof_error::unknown_function)
-        return make_error<InstrProfError>(IPE);
-      Bitmap = BitVector(getMaxBitmapSize(Record, IsVersion11));
-    }
-  } else {
-    Bitmap = BitVector(getMaxBitmapSize(Record, false));
-  }
-  Ctx.setBitmap(std::move(Bitmap));
-
-  assert(!Record.MappingRegions.empty() && "Function has no regions");
-
-  // This coverage record is a zero region for a function that's unused in
-  // some TU, but used in a different TU. Ignore it. The coverage maps from the
-  // the other TU will either be loaded (providing full region counts) or they
-  // won't (in which case we don't unintuitively report functions as uncovered
-  // when they have non-zero counts in the profile).
-  if (Record.MappingRegions.size() == 1 &&
-      Record.MappingRegions[0].Count.isZero() && Counts[0] > 0)
-    return Error::success();
-
-  MCDCDecisionRecorder MCDCDecisions;
-  FunctionRecord Function(OrigFuncName, Record.Filenames);
-  for (const auto &Region : Record.MappingRegions) {
-    // MCDCDecisionRegion should be handled first since it overlaps with
-    // others inside.
-    if (Region.Kind == CounterMappingRegion::MCDCDecisionRegion) {
-      MCDCDecisions.registerDecision(Region);
-      continue;
-    }
-    Expected<int64_t> ExecutionCount = Ctx.evaluate(Region.Count);
-    if (auto E = ExecutionCount.takeError()) {
-      consumeError(std::move(E));
-      return Error::success();
-    }
-    Expected<int64_t> AltExecutionCount = Ctx.evaluate(Region.FalseCount);
-    if (auto E = AltExecutionCount.takeError()) {
-      consumeError(std::move(E));
-      return Error::success();
-    }
-    Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount);
-
-    // Record ExpansionRegion.
-    if (Region.Kind == CounterMappingRegion::ExpansionRegion) {
-      MCDCDecisions.recordExpansion(Region);
-      continue;
-    }
-
-    // Do nothing unless MCDCBranchRegion.
-    if (Region.Kind != CounterMappingRegion::MCDCBranchRegion)
-      continue;
-
-    auto Result = MCDCDecisions.processBranch(Region);
-    if (!Result) // Any Decision doesn't complete.
-      continue;
-
-    auto MCDCDecision = Result->first;
-    auto &MCDCBranches = Result->second;
-
-    // Since the bitmap identifies the executed test vectors for an MC/DC
-    // DecisionRegion, all of the information is now available to process.
-    // This is where the bulk of the MC/DC progressing takes place.
-    Expected<MCDCRecord> Record =
-        Ctx.evaluateMCDCRegion(*MCDCDecision, MCDCBranches, IsVersion11);
-    if (auto E = Record.takeError()) {
-      consumeError(std::move(E));
-      return Error::success();
-    }
-
-    // Save the MC/DC Record so that it can be visualized later.
-    Function.pushMCDCRecord(std::move(*Record));
-  }
-
-  // Don't create records for (filenames, function) pairs we've already seen.
-  auto FilenamesHash = hash_combine_range(Record.Filenames);
-  if (!RecordProvenance[FilenamesHash].insert(hash_value(OrigFuncName)).second)
-    return Error::success();
-
-  Functions.push_back(std::move(Function));
-
-  // Performance optimization: keep track of the indices of the function records
-  // which correspond to each filename. This can be used to substantially speed
-  // up queries for coverage info in a file.
-  unsigned RecordIndex = Functions.size() - 1;
-  for (StringRef Filename : Record.Filenames) {
-    auto &RecordIndices = FilenameHash2RecordIndices[hash_value(Filename)];
-    // Note that there may be duplicates in the filename set for a function
-    // record, because of e.g. macro expansions in the function in which both
-    // the macro and the function are defined in the same file.
-    if (RecordIndices.empty() || RecordIndices.back() != RecordIndex)
-      RecordIndices.push_back(RecordIndex);
-  }
-
-  return Error::success();
-}
+// Error CoverageMapping::loadFunctionRecord(
+//     const CoverageMappingRecord &Record,
+//     const std::optional<std::reference_wrapper<IndexedInstrProfReader>>
+//         &ProfileReader, StringRef Arch) {
+//   StringRef OrigFuncName = Record.FunctionName;
+//   if (OrigFuncName.empty())
+//     return make_error<CoverageMapError>(coveragemap_error::malformed,
+//                                         "record function name is empty");
+
+//   if (Record.Filenames.empty())
+//     OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName);
+//   else
+//     OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName, Record.Filenames[0]);
+
+//   CounterMappingContext Ctx(Record.Expressions);
+
+//   uint64_t FuncArchHash = Record.FunctionHash;
+//   if(!Arch.empty()){
+//     std::string HashStr = std::to_string(Record.FunctionHash) + ":" + Arch.str();
+//     llvm::StringRef HashRef(HashStr);
+//     FuncArchHash = IndexedInstrProf::ComputeHash(HashRef);
+//   }
+
+//   std::vector<uint64_t> Counts;
+//   if (ProfileReader) {
+//     if (Error E = ProfileReader.value().get().getFunctionCounts(
+//             Record.FunctionName, FuncArchHash, Counts)) {
+//       instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
+//       if (IPE == instrprof_error::hash_mismatch) {
+//         FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
+//                                         FuncArchHash);
+//         return Error::success();
+//       }
+//       if (IPE != instrprof_error::unknown_function)
+//         return make_error<InstrProfError>(IPE);
+//       Counts.assign(getMaxCounterID(Ctx, Record) + 1, 0);
+//     }
+//   } else {
+//     Counts.assign(getMaxCounterID(Ctx, Record) + 1, 0);
+//   }
+//   Ctx.setCounts(Counts);
+
+//   bool IsVersion11 =
+//       ProfileReader && ProfileReader.value().get().getVersion() <
+//                            IndexedInstrProf::ProfVersion::Version12;
+
+//   BitVector Bitmap;
+//   if (ProfileReader) {
+//     if (Error E = ProfileReader.value().get().getFunctionBitmap(
+//             Record.FunctionName, FuncArchHash, Bitmap)) {
+//       instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
+//       if (IPE == instrprof_error::hash_mismatch) {
+//         FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
+//                                         FuncArchHash);
+//         return Error::success();
+//       }
+//       if (IPE != instrprof_error::unknown_function)
+//         return make_error<InstrProfError>(IPE);
+//       Bitmap = BitVector(getMaxBitmapSize(Record, IsVersion11));
+//     }
+//   } else {
+//     Bitmap = BitVector(getMaxBitmapSize(Record, false));
+//   }
+//   Ctx.setBitmap(std::move(Bitmap));
+
+//   assert(!Record.MappingRegions.empty() && "Function has no regions");
+
+//   // This coverage record is a zero region for a function that's unused in
+//   // some TU, but used in a different TU. Ignore it. The coverage maps from the
+//   // the other TU will either be loaded (providing full region counts) or they
+//   // won't (in which case we don't unintuitively report functions as uncovered
+//   // when they have non-zero counts in the profile).
+//   if (Record.MappingRegions.size() == 1 &&
+//       Record.MappingRegions[0].Count.isZero() && Counts[0] > 0)
+//     return Error::success();
+
+//   MCDCDecisionRecorder MCDCDecisions;
+//   FunctionRecord Function(OrigFuncName, Record.Filenames);
+//   for (const auto &Region : Record.MappingRegions) {
+//     // MCDCDecisionRegion should be handled first since it overlaps with
+//     // others inside.
+//     if (Region.Kind == CounterMappingRegion::MCDCDecisionRegion) {
+//       MCDCDecisions.registerDecision(Region);
+//       continue;
+//     }
+//     Expected<int64_t> ExecutionCount = Ctx.evaluate(Region.Count);
+//     if (auto E = ExecutionCount.takeError()) {
+//       consumeError(std::move(E));
+//       return Error::success();
+//     }
+//     Expected<int64_t> AltExecutionCount = Ctx.evaluate(Region.FalseCount);
+//     if (auto E = AltExecutionCount.takeError()) {
+//       consumeError(std::move(E));
+//       return Error::success();
+//     }
+//     Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount);
+
+//     // Record ExpansionRegion.
+//     if (Region.Kind == CounterMappingRegion::ExpansionRegion) {
+//       MCDCDecisions.recordExpansion(Region);
+//       continue;
+//     }
+
+//     // Do nothing unless MCDCBranchRegion.
+//     if (Region.Kind != CounterMappingRegion::MCDCBranchRegion)
+//       continue;
+
+//     auto Result = MCDCDecisions.processBranch(Region);
+//     if (!Result) // Any Decision doesn't complete.
+//       continue;
+
+//     auto MCDCDecision = Result->first;
+//     auto &MCDCBranches = Result->second;
+
+//     // Since the bitmap identifies the executed test vectors for an MC/DC
+//     // DecisionRegion, all of the information is now available to process.
+//     // This is where the bulk of the MC/DC progressing takes place.
+//     Expected<MCDCRecord> Record =
+//         Ctx.evaluateMCDCRegion(*MCDCDecision, MCDCBranches, IsVersion11);
+//     if (auto E = Record.takeError()) {
+//       consumeError(std::move(E));
+//       return Error::success();
+//     }
+
+//     // Save the MC/DC Record so that it can be visualized later.
+//     Function.pushMCDCRecord(std::move(*Record));
+//   }
+
+//   // Don't create records for (filenames, function) pairs we've already seen.
+//   auto FilenamesHash = hash_combine_range(Record.Filenames);
+//   if (!RecordProvenance[FilenamesHash].insert(hash_value(OrigFuncName)).second)
+//     return Error::success();
+
+//   Functions.push_back(std::move(Function));
+
+//   // Performance optimization: keep track of the indices of the function records
+//   // which correspond to each filename. This can be used to substantially speed
+//   // up queries for coverage info in a file.
+//   unsigned RecordIndex = Functions.size() - 1;
+//   for (StringRef Filename : Record.Filenames) {
+//     auto &RecordIndices = FilenameHash2RecordIndices[hash_value(Filename)];
+//     // Note that there may be duplicates in the filename set for a function
+//     // record, because of e.g. macro expansions in the function in which both
+//     // the macro and the function are defined in the same file.
+//     if (RecordIndices.empty() || RecordIndices.back() != RecordIndex)
+//       RecordIndices.push_back(RecordIndex);
+//   }
+
+//   return Error::success();
+// }
 
 Error CoverageMapping::loadFunctionRecord(
     const CoverageMappingRecord &Record,
@@ -985,18 +988,21 @@ Error CoverageMapping::loadFunctionRecord(
 
   CounterMappingContext Ctx(Record.Expressions);
 
-  std::string HashStr = std::to_string(Record.FunctionHash) + ":" + Arch.str();
-  llvm::StringRef HashRef(HashStr);
-  uint64_t NewHash = IndexedInstrProf::ComputeHash(HashRef);
+  uint64_t FuncArchHash = Record.FunctionHash;
+  if(!Arch.empty()){
+    std::string HashStr = std::to_string(Record.FunctionHash) + ":" + Arch.str();
+    llvm::StringRef HashRef(HashStr);
+    FuncArchHash = IndexedInstrProf::ComputeHash(HashRef);
+  }
 
   std::vector<uint64_t> Counts;
   if (ProfileReader) {
     if (Error E = ProfileReader.value().get().getFunctionCounts(
-            Record.FunctionName, NewHash, Counts)) {
+            Record.FunctionName, FuncArchHash, Counts)) {
       instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
       if (IPE == instrprof_error::hash_mismatch) {
         FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
-                                        NewHash);
+                                        FuncArchHash);
         return Error::success();
       }
       if (IPE != instrprof_error::unknown_function)
@@ -1015,11 +1021,11 @@ Error CoverageMapping::loadFunctionRecord(
   BitVector Bitmap;
   if (ProfileReader) {
     if (Error E = ProfileReader.value().get().getFunctionBitmap(
-            Record.FunctionName, NewHash, Bitmap)) {
+            Record.FunctionName, FuncArchHash, Bitmap)) {
       instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
       if (IPE == instrprof_error::hash_mismatch) {
         FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
-                                        NewHash);
+                                        FuncArchHash);
         return Error::success();
       }
       if (IPE != instrprof_error::unknown_function)
diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp
index 9a75164ebe698..8fda78bd26802 100644
--- a/llvm/lib/ProfileData/InstrProf.cpp
+++ b/llvm/lib/ProfileData/InstrProf.cpp
@@ -574,59 +574,51 @@ Error InstrProfSymtab::addVTableWithName(GlobalVariable &VTable,
   return Error::success();
 }
 
-Error readAndDecodeStrings(StringRef NameStrings,
-                           std::function<Error(StringRef)> NameCallback, const std::string &Architecture) {
-  const uint8_t *P = NameStrings.bytes_begin();
-  const uint8_t *EndP = NameStrings.bytes_end();
-  while (P < EndP) {
-    uint32_t N;
-    uint64_t UncompressedSize = decodeULEB128(P, &N);
-    P += N;
-    uint64_t CompressedSize = decodeULEB128(P, &N);
-    P += N;
-    const bool IsCompressed = (CompressedSize != 0);
-    SmallVector<uint8_t, 128> UncompressedNameStrings;
-    StringRef NameStrings;
-    if (IsCompressed) {
-      if (!llvm::compression::zlib::isAvailable())
-        return make_error<InstrProfError>(instrprof_error::zlib_unavailable);
-
-      if (Error E = compression::zlib::decompress(ArrayRef(P, CompressedSize),
-                                                  UncompressedNameStrings,
-                                                  UncompressedSize)) {
-        consumeError(std::move(E));
-        return make_error<InstrProfError>(instrprof_error::uncompress_failed);
-      }
-      P += CompressedSize;
-      NameStrings = toStringRef(UncompressedNameStrings);
-    } else {
-      NameStrings =
-          StringRef(reinterpret_cast<const char *>(P), UncompressedSize);
-      P += UncompressedSize;
-    }
-    // Now parse the name strings.
-    SmallVector<StringRef, 0> Names;
-    StringRef ArchRef(Architecture); 
-    NameStrings.split(Names, getInstrProfNameSeparator());
-    for (StringRef &Name : Names){
-      std::string ConcHashString = Name.str() + ":" + ArchRef.str();
-      printf("The string %s will get hashed and mapped to %s\n", ConcHashString.c_str(), Name.str().c_str());
-      if(ArchRef.empty()){
-        if (Error E = NameCallback(Name))
-          return E;
-      }else{
-        if (Error E = NameCallback(Name.str() + "#" + ArchRef.str()))
-          return E;
-      }
-    }
-    while (P < EndP && *P == 0)
-      P++;
-  }
-  return Error::success();
-}
+// Error readAndDecodeStrings(StringRef NameStrings,
+//                            std::function<Error(StringRef)> NameCallback, const std::string &Architecture) {
+//   const uint8_t *P = NameStrings.bytes_begin();
+//   const uint8_t *EndP = NameStrings.bytes_end();
+//   while (P < EndP) {
+//     uint32_t N;
+//     uint64_t UncompressedSize = decodeULEB128(P, &N);
+//     P += N;
+//     uint64_t CompressedSize = decodeULEB128(P, &N);
+//     P += N;
+//     const bool IsCompressed = (CompressedSize != 0);
+//     SmallVector<uint8_t, 128> UncompressedNameStrings;
+//     StringRef NameStrings;
+//     if (IsCompressed) {
+//       if (!llvm::compression::zlib::isAvailable())
+//         return make_error<InstrProfError>(instrprof_error::zlib_unavailable);
+
+//       if (Error E = compression::zlib::decompress(ArrayRef(P, CompressedSize),
+//                                                   UncompressedNameStrings,
+//                                                   UncompressedSize)) {
+//         consumeError(std::move(E));
+//         return make_error<InstrProfError>(instrprof_error::uncompress_failed);
+//       }
+//       P += CompressedSize;
+//       NameStrings = toStringRef(UncompressedNameStrings);
+//     } else {
+//       NameStrings =
+//           StringRef(reinterpret_cast<const char *>(P), UncompressedSize);
+//       P += UncompressedSize;
+//     }
+//     // Now parse the name strings.
+//     SmallVector<StringRef, 0> Names;
+//     NameStrings.split(Names, getInstrProfNameSeparator());
+//     for (StringRef &Name : Names){
+//       if (Error E = NameCallback(Name))
+//         return E;
+//     }
+//     while (P < EndP && *P == 0)
+//       P++;
+//   }
+//   return Error::success();
+// }
 
 Error readAndDecodeStrings(StringRef NameStrings,
-                           std::function<Error(StringRef)> NameCallback) {
+                           std::function<Error(StringRef)> NameCallback, StringRef Architecture) {
   const uint8_t *P = NameStrings.bytes_begin();
   const uint8_t *EndP = NameStrings.bytes_end();
   while (P < EndP) {
@@ -668,19 +660,19 @@ Error readAndDecodeStrings(StringRef NameStrings,
 }
 
 Error InstrProfSymtab::create(StringRef NameStrings) {
-  const std::string &Architecture = getArchitecture();
+  StringRef Architecture = getArchitecture();
   return readAndDecodeStrings(NameStrings, std::bind(&InstrProfSymtab::addFuncName, this, std::placeholders::_1), Architecture);
 }
 
 Error InstrProfSymtab::create(StringRef FuncNameStrings,
                               StringRef VTableNameStrings) {
-  const std::string &Architecture = getArchitecture();                                
-  if (Error E = readAndDecodeStrings(FuncNameStrings, std::bind(&InstrProfSymtab::addFuncName, this, std::placeholders::_1), Architecture))
+  // const std::string &Architecture = getArchitecture();                                
+  if (Error E = readAndDecodeStrings(FuncNameStrings, std::bind(&InstrProfSymtab::addFuncName, this, std::placeholders::_1)))
     return E;
 
   return readAndDecodeStrings(
       VTableNameStrings,
-      std::bind(&InstrProfSymtab::addVTableName, this, std::placeholders::_1), Architecture);
+      std::bind(&InstrProfSymtab::addVTableName, this, std::placeholders::_1));
 }
 
 Error InstrProfSymtab::initVTableNamesFromCompressedStrings(
diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp
index 33ebcfd3200b2..b8a1397f323b2 100644
--- a/llvm/lib/ProfileData/InstrProfReader.cpp
+++ b/llvm/lib/ProfileData/InstrProfReader.cpp
@@ -160,7 +160,7 @@ Expected<std::unique_ptr<InstrProfReader>> InstrProfReader::create( //STEP 1
     const object::BuildIDFetcher *BIDFetcher,
     const InstrProfCorrelator::ProfCorrelatorKind BIDFetcherCorrelatorKind,
     std::function<void(Error)> Warn, 
-    const std::string &Architecture) {
+    StringRef Architecture) {
   // Set up the buffer to read.
   auto BufferOrError = setupMemoryBuffer(Path, FS);
   if (Error E = BufferOrError.takeError())
@@ -173,7 +173,7 @@ Expected<std::unique_ptr<InstrProfReader>> InstrProfReader::create(
     std::unique_ptr<MemoryBuffer> Buffer, const InstrProfCorrelator *Correlator,
     const object::BuildIDFetcher *BIDFetcher,
     const InstrProfCorrelator::ProfCorrelatorKind BIDFetcherCorrelatorKind,
-    std::function<void(Error)> Warn, const std::string &Architecture) {
+    std::function<void(Error)> Warn, StringRef Architecture) {
   if (Buffer->getBufferSize() == 0)
     return make_error<InstrProfError>(instrprof_error::empty_raw_profile);
 
diff --git a/llvm/lib/ProfileData/InstrProfWriter.cpp b/llvm/lib/ProfileData/InstrProfWriter.cpp
index 4dfeeca00d988..1c5c82b3c5193 100644
--- a/llvm/lib/ProfileData/InstrProfWriter.cpp
+++ b/llvm/lib/ProfileData/InstrProfWriter.cpp
@@ -153,8 +153,8 @@ void InstrProfWriter::setValueProfDataEndianness(llvm::endianness Endianness) {
 
 void InstrProfWriter::setOutputSparse(bool Sparse) { this->Sparse = Sparse; }
 
-void InstrProfWriter::addRecord(NamedInstrProfRecord &&I, uint64_t Weight, const std::string &Architecture,
-                                function_ref<void(Error)> Warn) {
+void InstrProfWriter::addRecord(NamedInstrProfRecord &&I, uint64_t Weight,
+                                function_ref<void(Error)> Warn, StringRef Architecture) {
   auto Name = I.Name;
   auto Hash = I.Hash;
   addRecord(Name, Hash, std::move(I), Weight, Warn, Architecture);
@@ -191,40 +191,42 @@ void InstrProfWriter::overlapRecord(NamedInstrProfRecord &&Other,
   Dest.overlap(Other, Overlap, FuncLevelOverlap, ValueCutoff);
 }
 
-void InstrProfWriter::addRecord(StringRef Name, uint64_t Hash,
-                                InstrProfRecord &&I, uint64_t Weight,
-                                function_ref<void(Error)> Warn) {
-  auto &ProfileDataMap = FunctionData[Name];
+// void InstrProfWriter::addRecord(StringRef Name, uint64_t Hash,
+//                                 InstrProfRecord &&I, uint64_t Weight,
+//                                 function_ref<void(Error)> Warn) {
+//   auto &ProfileDataMap = FunctionData[Name];
 
-  auto [Where, NewFunc] = ProfileDataMap.try_emplace(Hash);
-  InstrProfRecord &Dest = Where->second;
+//   auto [Where, NewFunc] = ProfileDataMap.try_emplace(Hash);
+//   InstrProfRecord &Dest = Where->second;
 
-  auto MapWarn = [&](instrprof_error E) {
-    Warn(make_error<InstrProfError>(E));
-  };
+//   auto MapWarn = [&](instrprof_error E) {
+//     Warn(make_error<InstrProfError>(E));
+//   };
 
-  if (NewFunc) {
-    // We've never seen a function with this name and hash, add it.
-    Dest = std::move(I);
-    if (Weight > 1)
-      Dest.scale(Weight, 1, MapWarn);
-  } else {
-    // We're updating a function we've seen before.
-    Dest.merge(I, Weight, MapWarn);
-  }
+//   if (NewFunc) {
+//     // We've never seen a function with this name and hash, add it.
+//     Dest = std::move(I);
+//     if (Weight > 1)
+//       Dest.scale(Weight, 1, MapWarn);
+//   } else {
+//     // We're updating a function we've seen before.
+//     Dest.merge(I, Weight, MapWarn);
+//   }
 
-  Dest.sortValueData();
-}
+//   Dest.sortValueData();
+// }
 
 void InstrProfWriter::addRecord(StringRef Name, uint64_t Hash,
                                 InstrProfRecord &&I, uint64_t Weight,
-                                function_ref<void(Error)> Warn, const std::string &Architecture) {
+                                function_ref<void(Error)> Warn, StringRef Architecture) {
   auto &ProfileDataMap = FunctionData[Name];
-  std::string HashStr = std::to_string(Hash) + ":" + Architecture;
-  llvm::StringRef HashRef(HashStr);
-  uint64_t NewHash = IndexedInstrProf::ComputeHash(HashRef);
+  if(!Architecture.empty()){
+    std::string HashStr = std::to_string(Hash) + ":" + Architecture.str();
+    llvm::StringRef HashRef(HashStr);
+    Hash = IndexedInstrProf::ComputeHash(HashRef);
+  }
 
-  auto [Where, NewFunc] = ProfileDataMap.try_emplace(NewHash);
+  auto [Where, NewFunc] = ProfileDataMap.try_emplace(Hash);
   InstrProfRecord &Dest = Where->second;
 
   auto MapWarn = [&](instrprof_error E) {
diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp
index 6c66858c4de8c..a90bcef7eaf7d 100644
--- a/llvm/tools/llvm-cov/CodeCoverage.cpp
+++ b/llvm/tools/llvm-cov/CodeCoverage.cpp
@@ -114,7 +114,7 @@ class CodeCoverageTool {
 
   /// Create the main source view of a particular source file.
   std::unique_ptr<SourceCoverageView>
-  createSourceFileView(StringRef SourceFile, const CoverageMapping &Coverage);
+  createSourceFileView(StringRef SourceFile, const CoverageMapping &Coverage, std::vector<StringRef> Arches);
 
   /// Load the coverage mapping data. Return nullptr if an error occurred.
   std::unique_ptr<CoverageMapping> load();
@@ -391,7 +391,7 @@ CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
 
 std::unique_ptr<SourceCoverageView>
 CodeCoverageTool::createSourceFileView(StringRef SourceFile,
-                                       const CoverageMapping &Coverage) {
+                                       const CoverageMapping &Coverage, std::vector<StringRef> Arches) {
   auto SourceBuffer = getSourceFile(SourceFile);
   if (!SourceBuffer)
     return nullptr;
@@ -633,7 +633,7 @@ void CodeCoverageTool::writeSourceFileView(StringRef SourceFile,
                                            CoverageMapping *Coverage,
                                            CoveragePrinter *Printer,
                                            bool ShowFilenames) {
-  auto View = createSourceFileView(SourceFile, *Coverage);
+  auto View = createSourceFileView(SourceFile, *Coverage, CoverageArches);
   if (!View) {
     warning("The file '" + SourceFile + "' isn't covered.");
     return;
@@ -648,7 +648,7 @@ void CodeCoverageTool::writeSourceFileView(StringRef SourceFile,
 
   View->print(*OS.get(), /*Wholefile=*/true,
               /*ShowSourceName=*/ShowFilenames,
-              /*ShowTitle=*/ViewOpts.hasOutputDirectory());
+              /*ShowTitle=*/ViewOpts.hasOutputDirectory(), SourceFile);
   Printer->closeViewFile(std::move(OS));
 }
 
diff --git a/llvm/tools/llvm-cov/SourceCoverageView.cpp b/llvm/tools/llvm-cov/SourceCoverageView.cpp
index dfecddfaf4143..810e2c6024584 100644
--- a/llvm/tools/llvm-cov/SourceCoverageView.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageView.cpp
@@ -15,9 +15,11 @@
 #include "SourceCoverageViewText.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/ProfileData/Coverage/CoverageMapping.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/LineIterator.h"
 #include "llvm/Support/Path.h"
+#include <vector>
 
 using namespace llvm;
 
@@ -192,7 +194,7 @@ void SourceCoverageView::addInstantiation(
 
 void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
                                bool ShowSourceName, bool ShowTitle,
-                               unsigned ViewDepth) {
+                               unsigned ViewDepth, StringRef SourceFile) {
   if (ShowTitle)
     renderTitle(OS, "Coverage Report");
 
@@ -222,9 +224,25 @@ void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
   auto StartSegment = CoverageInfo.begin();
   auto EndSegment = CoverageInfo.end();
   LineCoverageIterator LCI{CoverageInfo, 1};
+  // LineCoverageIterator LCIInit{CoverageInfo, 1};
   LineCoverageIterator LCIEnd = LCI.getEnd();
-
   unsigned FirstLine = StartSegment != EndSegment ? StartSegment->Line : 0;
+  
+  // // Determine the number of lines in the file
+  // unsigned NumLines = 0;
+  // for (line_iterator LI(File, /*SkipBlanks=*/false); !LI.is_at_eof(); ++LI)
+  //   ++NumLines;
+  // // Resize the outer vector to hold one entry per line
+  // std::vector<std::vector<LineCoverageStats>> LineArchStats;
+  // LineArchStats.resize(CoverageArches.size()); // +1 in case line numbers are 1-based
+  // for (line_iterator LI(File, /*SkipBlanks=*/false); !LI.is_at_eof(); ++LI, ++LCIInit) {
+  //   unsigned LineNo = LCIInit->getLine();
+  //   if (LineNo >= LineArchStats.size()){
+  //     LineArchStats.resize(LineNo + 1); // Ensure enough space
+  //   }
+  //   LineArchStats[LineNo].push_back(*LCIInit); // Store the LineCoverageStats
+  // }
+
   for (line_iterator LI(File, /*SkipBlanks=*/false); !LI.is_at_eof();
        ++LI, ++LCI) {
     // If we aren't rendering the whole file, we need to filter out the prologue
@@ -242,6 +260,7 @@ void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
 
     if (getOptions().ShowLineStats)
       renderLineCoverageColumn(OS, *LCI);
+      // renderArchLineCoverageColumn(OS, *LCI, LineArchStats);
 
     // If there are expansion subviews, we want to highlight the first one.
     unsigned ExpansionColumn = 0;
diff --git a/llvm/tools/llvm-cov/SourceCoverageView.h b/llvm/tools/llvm-cov/SourceCoverageView.h
index cff32b756ee32..df83e8ca37279 100644
--- a/llvm/tools/llvm-cov/SourceCoverageView.h
+++ b/llvm/tools/llvm-cov/SourceCoverageView.h
@@ -224,6 +224,9 @@ class SourceCoverageView {
   /// Render the line's execution count column.
   virtual void renderLineCoverageColumn(raw_ostream &OS,
                                         const LineCoverageStats &Line) = 0;
+                                
+  virtual void renderArchLineCoverageColumn(raw_ostream &OS, const LineCoverageStats &Line, std::vector<std::vector<LineCoverageStats>> LineArchStats) = 0;
+
 
   /// Render the line number column.
   virtual void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo) = 0;
@@ -319,7 +322,7 @@ class SourceCoverageView {
   /// Print the code coverage information for a specific portion of a
   /// source file to the output stream.
   void print(raw_ostream &OS, bool WholeFile, bool ShowSourceName,
-             bool ShowTitle, unsigned ViewDepth = 0);
+             bool ShowTitle, unsigned ViewDepth = 0, StringRef CoverageArches = "");
 };
 
 } // namespace llvm
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
index c94d3853fc014..d4dec5e699a58 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
@@ -1062,6 +1062,31 @@ void SourceCoverageViewHTML::renderLineCoverageColumn(
   OS << tag("td", Count, CoverageClass);
 }
 
+void SourceCoverageViewHTML::renderArchLineCoverageColumn(
+    raw_ostream &OS,
+    const LineCoverageStats &Line,
+    std::vector<std::vector<LineCoverageStats>> LineArchStats) {
+  
+  std::string CellContent;
+
+  if (Line.isMapped()) {
+    unsigned LineNo = Line.getLine();
+    for (const auto &ArchStats : LineArchStats[LineNo]) {
+      CellContent += formatBinaryCount(ArchStats.getExecutionCount()) + "/";
+    }
+    if (!CellContent.empty())
+      CellContent.pop_back(); // Remove trailing '/'
+  }
+
+  std::string CoverageClass =
+      (Line.getExecutionCount() > 0)
+          ? "covered-line"
+          : (Line.isMapped() ? "uncovered-line" : "skipped-line");
+
+  OS << tag("td", tag("pre", CellContent), CoverageClass);
+}
+
+
 void SourceCoverageViewHTML::renderLineNumberColumn(raw_ostream &OS,
                                                     unsigned LineNo) {
   std::string LineNoStr = utostr(uint64_t(LineNo));
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewHTML.h b/llvm/tools/llvm-cov/SourceCoverageViewHTML.h
index 9b7391d0043ec..37098273510e0 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewHTML.h
+++ b/llvm/tools/llvm-cov/SourceCoverageViewHTML.h
@@ -99,6 +99,8 @@ class SourceCoverageViewHTML : public SourceCoverageView {
   void renderLineCoverageColumn(raw_ostream &OS,
                                 const LineCoverageStats &Line) override;
 
+  void renderArchLineCoverageColumn(raw_ostream &OS, const LineCoverageStats &Line, std::vector<std::vector<LineCoverageStats>> LineArchStats) override;
+
   void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo) override;
 
   void renderRegionMarkers(raw_ostream &OS, const LineCoverageStats &Line,
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
index df8eb1d871878..45a8dcf76010f 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
@@ -14,6 +14,7 @@
 #include "CoverageReport.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/ProfileData/Coverage/CoverageMapping.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/Path.h"
@@ -218,9 +219,23 @@ void SourceCoverageViewText::renderLineCoverageColumn(
   }
   std::string C = formatBinaryCount(Line.getExecutionCount());
   OS.indent(LineCoverageColumnWidth - C.size());
-  colored_ostream(OS, raw_ostream::MAGENTA,
-                  Line.hasMultipleRegions() && getOptions().Colors)
-      << C;
+  colored_ostream(OS, raw_ostream::MAGENTA, Line.hasMultipleRegions() && getOptions().Colors) << C;
+  OS << '|';
+}
+
+void SourceCoverageViewText::renderArchLineCoverageColumn(
+    raw_ostream &OS, const LineCoverageStats &Line, std::vector<std::vector<LineCoverageStats>> LineArchStats) {
+  if (!Line.isMapped()) {
+    OS.indent(LineCoverageColumnWidth) << '|';
+    return;
+  }
+  std::string C = "";
+  for(LineCoverageStats Counts : LineArchStats[Line.getLine()]){
+    C += formatBinaryCount(Counts.getExecutionCount()) + "/";
+  }
+  // std::string C = formatBinaryCount(Line.getExecutionCount());
+  OS.indent(LineCoverageColumnWidth - C.size());
+  colored_ostream(OS, raw_ostream::MAGENTA, Line.hasMultipleRegions() && getOptions().Colors) << C;
   OS << '|';
 }
 
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewText.h b/llvm/tools/llvm-cov/SourceCoverageViewText.h
index 25a161b096200..3841aad607324 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewText.h
+++ b/llvm/tools/llvm-cov/SourceCoverageViewText.h
@@ -85,6 +85,8 @@ class SourceCoverageViewText : public SourceCoverageView {
 
   void renderLineCoverageColumn(raw_ostream &OS,
                                 const LineCoverageStats &Line) override;
+  
+  void renderArchLineCoverageColumn(raw_ostream &OS, const LineCoverageStats &Line, std::vector<std::vector<LineCoverageStats>> LineArchStats) override;
 
   void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo) override;
 
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 3d3fd34a493ab..8aa7f23a3398d 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -862,7 +862,7 @@ loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
       I.Name = (*Remapper)(I.Name);
     const StringRef FuncName = I.Name;
     bool Reported = false;
-    WC->Writer.addRecord(std::move(I), Input.Weight, Architecture, [&](Error E) {
+    WC->Writer.addRecord(std::move(I), Input.Weight, [&](Error E) {
       if (Reported) {
         consumeError(std::move(E));
         return;
@@ -874,7 +874,7 @@ loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
       bool firstTime = WC->WriterErrorCodes.insert(ErrCode).second;
       handleMergeWriterError(make_error<InstrProfError>(ErrCode, Msg),
                              Input.Filename, FuncName, firstTime);
-    });
+    }, Architecture);
   }
 
   if (KeepVTableSymbols) {

>From e88c4ea0698e8918f9be7bed150ef647a694f42f Mon Sep 17 00:00:00 2001
From: Andres Wearden <andreswearden5 at gmail.com>
Date: Sun, 20 Jul 2025 20:38:16 -0700
Subject: [PATCH 08/17] committing to save updates

---
 .../ProfileData/Coverage/CoverageMapping.h    | 30 ++++++---
 llvm/include/llvm/ProfileData/InstrProf.h     |  4 +-
 .../ProfileData/Coverage/CoverageMapping.cpp  | 66 ++++++++++++++-----
 .../Coverage/CoverageMappingReader.cpp        |  3 +-
 llvm/lib/ProfileData/InstrProfWriter.cpp      | 37 ++++++++++-
 llvm/tools/llvm-cov/CodeCoverage.cpp          | 30 ++++++++-
 .../tools/llvm-cov/SourceCoverageViewText.cpp |  3 +
 llvm/tools/llvm-profdata/llvm-profdata.cpp    |  1 +
 8 files changed, 141 insertions(+), 33 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index 555c7e5f37f2b..0487a96ce4ae8 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -19,6 +19,7 @@
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/iterator.h"
 #include "llvm/ADT/iterator_range.h"
@@ -375,6 +376,7 @@ struct CountedRegion : public CounterMappingRegion {
   uint64_t FalseExecutionCount;
   bool TrueFolded;
   bool FalseFolded;
+  StringRef ObjectFilename;
 
   CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount)
       : CounterMappingRegion(R), ExecutionCount(ExecutionCount),
@@ -385,6 +387,12 @@ struct CountedRegion : public CounterMappingRegion {
       : CounterMappingRegion(R), ExecutionCount(ExecutionCount),
         FalseExecutionCount(FalseExecutionCount), TrueFolded(false),
         FalseFolded(false) {}
+  
+  CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount,
+          uint64_t FalseExecutionCount, StringRef ObjectFilename)
+: CounterMappingRegion(R), ExecutionCount(ExecutionCount),
+  FalseExecutionCount(FalseExecutionCount), TrueFolded(false),
+  FalseFolded(false), ObjectFilename(ObjectFilename) {}
 };
 
 /// MCDC Record grouping all information together.
@@ -731,9 +739,11 @@ struct FunctionRecord {
   std::vector<MCDCRecord> MCDCRecords;
   /// The number of times this function was executed.
   uint64_t ExecutionCount = 0;
+  /// The executable this function was compiled in
+  StringRef ObjectFilename;
 
-  FunctionRecord(StringRef Name, ArrayRef<StringRef> Filenames)
-      : Name(Name), Filenames(Filenames.begin(), Filenames.end()) {}
+  FunctionRecord(StringRef Name, ArrayRef<StringRef> Filenames, StringRef ObjectFilename = "")
+      : Name(Name), Filenames(Filenames.begin(), Filenames.end()), ObjectFilename(ObjectFilename) {}
 
   FunctionRecord(FunctionRecord &&FR) = default;
   FunctionRecord &operator=(FunctionRecord &&) = default;
@@ -752,9 +762,10 @@ struct FunctionRecord {
       CountedBranchRegions.back().FalseFolded = Region.FalseCount.isZero();
       return;
     }
-    if (CountedRegions.empty())
+    if (CountedRegions.empty()){
       ExecutionCount = Count;
-    CountedRegions.emplace_back(Region, Count, FalseCount);
+    }
+    CountedRegions.emplace_back(Region, Count, FalseCount, ObjectFilename);
   }
 };
 
@@ -994,6 +1005,9 @@ class CoverageMapping {
   DenseMap<size_t, SmallVector<unsigned, 0>> FilenameHash2RecordIndices;
   std::vector<std::pair<std::string, uint64_t>> FuncHashMismatches;
   StringRef Arch;
+  DenseMap<std::pair<size_t, hash_code>, unsigned> RecordIndices;
+
+  std::map<std::pair<std::string, std::string>, std::vector<uint64_t>> AggregatedCounts;
 
   std::optional<bool> SingleByteCoverage;
 
@@ -1004,7 +1018,7 @@ class CoverageMapping {
     ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
     std::optional<std::reference_wrapper<IndexedInstrProfReader>>
         &ProfileReader,
-    CoverageMapping &Coverage, StringRef Arch);
+    CoverageMapping &Coverage, StringRef Arch, StringRef ObjectFilename = "");
   
   static Error loadFromReaders(
     ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
@@ -1018,15 +1032,15 @@ class CoverageMapping {
                std::optional<std::reference_wrapper<IndexedInstrProfReader>>
                    &ProfileReader,
                CoverageMapping &Coverage, bool &DataFound,
-               SmallVectorImpl<object::BuildID> *FoundBinaryIDs = nullptr);
+               SmallVectorImpl<object::BuildID> *FoundBinaryIDs = nullptr, StringRef ObjectFilename = "");
 
   /// Add a function record corresponding to \p Record.
   Error loadFunctionRecord(
       const CoverageMappingRecord &Record,
       const std::optional<std::reference_wrapper<IndexedInstrProfReader>>
-          &ProfileReader);
+          &ProfileReader, StringRef ObjectFilename = "");
   
-  Error loadFunctionRecord(const CoverageMappingRecord &Record, const std::optional<std::reference_wrapper<IndexedInstrProfReader>> &ProfileReader, const std::string &Arch);
+  Error loadFunctionRecord(const CoverageMappingRecord &Record, const std::optional<std::reference_wrapper<IndexedInstrProfReader>> &ProfileReader, const std::string &Arch, StringRef ObjectFilename = "");
 
   /// Look up the indices for function records which are at least partially
   /// defined in the specified file. This is guaranteed to return a superset of
diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h
index 98890b5541a8f..21a58ce1f14ce 100644
--- a/llvm/include/llvm/ProfileData/InstrProf.h
+++ b/llvm/include/llvm/ProfileData/InstrProf.h
@@ -635,9 +635,6 @@ class InstrProfSymtab {
 
   // Map the MD5 of the symbol name to the name.
   Error addSymbolName(StringRef SymbolName) {
-    // StringRef FuncName;
-    // StringRef ArchName = Architecture;
-    // std::tie(FuncName, ArchName) = SymbolName.split("#");
     if (SymbolName.empty())
       return make_error<InstrProfError>(instrprof_error::malformed,
                                         "symbol name is empty");
@@ -1075,6 +1072,7 @@ struct InstrProfRecord {
 struct NamedInstrProfRecord : InstrProfRecord {
   StringRef Name;
   uint64_t Hash;
+  StringRef Filename;
 
   // We reserve this bit as the flag for context sensitive profile record.
   static const int CS_FLAG_IN_FUNC_HASH = 60;
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 0a391b3d56773..3dcbbbb1aaa5b 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -40,6 +40,7 @@
 #include <stack>
 #include <string>
 #include <system_error>
+#include <unordered_map>
 #include <utility>
 #include <vector>
 
@@ -975,7 +976,7 @@ class MCDCDecisionRecorder {
 Error CoverageMapping::loadFunctionRecord(
     const CoverageMappingRecord &Record,
     const std::optional<std::reference_wrapper<IndexedInstrProfReader>>
-        &ProfileReader) {
+        &ProfileReader, StringRef ObjectFilename) {
   StringRef OrigFuncName = Record.FunctionName;
   if (OrigFuncName.empty())
     return make_error<CoverageMapError>(coveragemap_error::malformed,
@@ -997,12 +998,10 @@ Error CoverageMapping::loadFunctionRecord(
 
   std::vector<uint64_t> Counts;
   if (ProfileReader) {
-    if (Error E = ProfileReader.value().get().getFunctionCounts(
-            Record.FunctionName, FuncArchHash, Counts)) {
+    if (Error E = ProfileReader.value().get().getFunctionCounts(Record.FunctionName, FuncArchHash, Counts)) {
       instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
       if (IPE == instrprof_error::hash_mismatch) {
-        FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
-                                        FuncArchHash);
+        FuncHashMismatches.emplace_back(std::string(Record.FunctionName), FuncArchHash);
         return Error::success();
       }
       if (IPE != instrprof_error::unknown_function)
@@ -1035,6 +1034,7 @@ Error CoverageMapping::loadFunctionRecord(
   } else {
     Bitmap = BitVector(getMaxBitmapSize(Record, false));
   }
+
   Ctx.setBitmap(std::move(Bitmap));
 
   assert(!Record.MappingRegions.empty() && "Function has no regions");
@@ -1049,7 +1049,7 @@ Error CoverageMapping::loadFunctionRecord(
     return Error::success();
 
   MCDCDecisionRecorder MCDCDecisions;
-  FunctionRecord Function(OrigFuncName, Record.Filenames);
+  FunctionRecord Function(OrigFuncName, Record.Filenames, ObjectFilename);
   for (const auto &Region : Record.MappingRegions) {
     // MCDCDecisionRegion should be handled first since it overlaps with
     // others inside.
@@ -1102,9 +1102,9 @@ Error CoverageMapping::loadFunctionRecord(
 
   // Don't create records for (filenames, function) pairs we've already seen.
   auto FilenamesHash = hash_combine_range(Record.Filenames);
-  if (!RecordProvenance[FilenamesHash].insert(hash_value(OrigFuncName)).second)
+  if (!RecordProvenance[FilenamesHash].insert(FuncArchHash).second){
     return Error::success();
-
+  }
   Functions.push_back(std::move(Function));
 
   // Performance optimization: keep track of the indices of the function records
@@ -1152,7 +1152,7 @@ Error CoverageMapping::loadFromReaders(
     ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
     std::optional<std::reference_wrapper<IndexedInstrProfReader>>
         &ProfileReader,
-    CoverageMapping &Coverage, StringRef Arch) {
+    CoverageMapping &Coverage, StringRef Arch, StringRef ObjectFilename) {
   
   Coverage.setArchitecture(Arch);
   assert(!Coverage.SingleByteCoverage || !ProfileReader ||
@@ -1165,7 +1165,7 @@ Error CoverageMapping::loadFromReaders(
       if (Error E = RecordOrErr.takeError())
         return E;
       const auto &Record = *RecordOrErr;
-      if (Error E = Coverage.loadFunctionRecord(Record, ProfileReader))
+      if (Error E = Coverage.loadFunctionRecord(Record, ProfileReader, ObjectFilename))
         return E;
     }
   }
@@ -1196,7 +1196,7 @@ Error CoverageMapping::loadFromFile(
     std::optional<std::reference_wrapper<IndexedInstrProfReader>>
         &ProfileReader,
     CoverageMapping &Coverage, bool &DataFound,
-    SmallVectorImpl<object::BuildID> *FoundBinaryIDs) {
+    SmallVectorImpl<object::BuildID> *FoundBinaryIDs, StringRef ObjectFilename) {
   auto CovMappingBufOrErr = MemoryBuffer::getFileOrSTDIN(
       Filename, /*IsText=*/false, /*RequiresNullTerminator=*/false);
   if (std::error_code EC = CovMappingBufOrErr.getError())
@@ -1228,7 +1228,7 @@ Error CoverageMapping::loadFromFile(
                        }));
   }
   DataFound |= !Readers.empty();
-  if (Error E = loadFromReaders(Readers, ProfileReader, Coverage, Arch))
+  if (Error E = loadFromReaders(Readers, ProfileReader, Coverage, Arch, ObjectFilename))
     return createFileError(Filename, std::move(E));
   return Error::success();
 }
@@ -1262,14 +1262,20 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
     return Arches[Idx];
   };
 
+  //I beleive there is an error in this area of code, it's iterating through all arch's of the object files
+  // but its only filling *Coverage with last architecture it gets to
+
   SmallVector<object::BuildID> FoundBinaryIDs;
   for (const auto &File : llvm::enumerate(ObjectFilenames)) {
     if (Error E = loadFromFile(File.value(), GetArch(File.index()),
                                CompilationDir, ProfileReaderRef, *Coverage,
-                               DataFound, &FoundBinaryIDs))
+                               DataFound, &FoundBinaryIDs, ObjectFilenames[File.index()]))
       return std::move(E);
   }
 
+  //I beleive there is an error in this area of code, it's iterating through all arch's of the object files
+  // but its only filling *Coverage with last architecture it gets to
+
   if (BIDFetcher) {
     std::vector<object::BuildID> ProfileBinaryIDs;
     if (ProfileReader)
@@ -1508,19 +1514,24 @@ class SegmentBuilder {
   }
 
   /// Combine counts of regions which cover the same area.
+  //[(3:12, 10:1), (4:1, 6:7), (6:7, 8:1)]
   static ArrayRef<CountedRegion>
   combineRegions(MutableArrayRef<CountedRegion> Regions) {
     if (Regions.empty())
       return Regions;
+
+    
     auto Active = Regions.begin();
     auto End = Regions.end();
     for (auto I = Regions.begin() + 1; I != End; ++I) {
-      if (Active->startLoc() != I->startLoc() ||
-          Active->endLoc() != I->endLoc()) {
+      if (Active->startLoc() != I->startLoc() || Active->endLoc() != I->endLoc()) {
         // Shift to the next region.
         ++Active;
-        if (Active != I)
+        if (Active != I){
           *Active = *I;
+          // Active->ExecutionCount = 1;
+          // Active->Kind = CounterMappingRegion::CodeRegion;
+        }
         continue;
       }
       // Merge duplicate region.
@@ -1549,6 +1560,29 @@ class SegmentBuilder {
     SegmentBuilder Builder(Segments);
 
     sortNestedRegions(Regions);
+
+    for(auto *I = Regions.begin(); I != Regions.end(); ++I){
+      bool FoundMatchInOtherBinary = false;
+      for(auto *J = I + 1; J != Regions.end(); ++J){
+        if(I->ObjectFilename != J->ObjectFilename &&
+            J->Kind == CounterMappingRegion::SkippedRegion 
+            && I->Kind != CounterMappingRegion::SkippedRegion &&
+            J->startLoc() >= I->startLoc() && J->endLoc() <= I->endLoc()){
+          for(auto *K = J + 1; K != Regions.end(); ++K){
+            if(K->ObjectFilename == I->ObjectFilename &&
+              J->startLoc() == K->startLoc() && J->endLoc() == K->endLoc()){
+              FoundMatchInOtherBinary = true;
+            }
+          }
+          if(!FoundMatchInOtherBinary){
+            J->Kind = I->Kind;
+            J->ExecutionCount = I->ExecutionCount;
+          }
+        }
+      }
+    }
+    
+
     ArrayRef<CountedRegion> CombinedRegions = combineRegions(Regions);
 
     LLVM_DEBUG({
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
index aa5b714bbdec8..1c79ffab66b05 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
@@ -288,7 +288,7 @@ Error RawCoverageMappingReader::readMappingRegionsSubArray(
           // Don't do anything when we have a code region with a zero counter.
           break;
         case CounterMappingRegion::SkippedRegion:
-          Kind = CounterMappingRegion::SkippedRegion;
+          Kind = CounterMappingRegion::SkippedRegion; //if you change this to "CodeRegion, then all skipped regions have counter of 0"
           break;
         case CounterMappingRegion::BranchRegion:
           // For a Branch Region, read two successive counters.
@@ -381,7 +381,6 @@ Error RawCoverageMappingReader::readMappingRegionsSubArray(
         CounterMappingContext(Expressions).dump(C, dbgs());
       dbgs() << "\n";
     });
-
     auto CMR = CounterMappingRegion(
         C, C2, InferredFileID, ExpandedFileID, LineStart, ColumnStart,
         LineStart + NumLines, ColumnEnd, Kind, Params);
diff --git a/llvm/lib/ProfileData/InstrProfWriter.cpp b/llvm/lib/ProfileData/InstrProfWriter.cpp
index 1c5c82b3c5193..d911ce6a6ee68 100644
--- a/llvm/lib/ProfileData/InstrProfWriter.cpp
+++ b/llvm/lib/ProfileData/InstrProfWriter.cpp
@@ -15,7 +15,11 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/bit.h"
+#include "llvm/DebugInfo/DIContext.h"
 #include "llvm/IR/ProfileSummary.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/ProfileData/Coverage/CoverageMapping.h"
 #include "llvm/ProfileData/DataAccessProf.h"
 #include "llvm/ProfileData/IndexedMemProfData.h"
 #include "llvm/ProfileData/InstrProf.h"
@@ -216,16 +220,47 @@ void InstrProfWriter::overlapRecord(NamedInstrProfRecord &&Other,
 //   Dest.sortValueData();
 // }
 
+
+
+// #include "llvm/DebugInfo/DWARF/DWARFContext.h"
+
+
+#include <llvm/Support/raw_ostream.h>
+#include <llvm/Support/MemoryBuffer.h>
+#include <llvm/Support/SHA1.h>
+#include <array>
+
+StringRef hashSourceFile(llvm::StringRef FilePath) {
+    auto FileOrErr = llvm::MemoryBuffer::getFile(FilePath);
+    if (!FileOrErr) {
+        llvm::errs() << "Error reading file: " << FilePath << "\n";
+        return "";
+    }
+
+    const auto &Buffer = *FileOrErr.get();
+    llvm::SHA1 Hasher;
+    Hasher.update(Buffer.getBuffer());
+
+    std::array<uint8_t, 20> Hash = Hasher.final();
+    
+    std::string HexStr = llvm::toHex(llvm::ArrayRef<uint8_t>(Hash));
+    llvm::StringRef HashRef(HexStr);
+    return HashRef;
+}
+
+
+
 void InstrProfWriter::addRecord(StringRef Name, uint64_t Hash,
                                 InstrProfRecord &&I, uint64_t Weight,
                                 function_ref<void(Error)> Warn, StringRef Architecture) {
   auto &ProfileDataMap = FunctionData[Name];
+  StringRef SHAHash = hashSourceFile(Architecture);
+  llvm::errs() << "SHA Hashing: " << SHAHash << "\n";
   if(!Architecture.empty()){
     std::string HashStr = std::to_string(Hash) + ":" + Architecture.str();
     llvm::StringRef HashRef(HashStr);
     Hash = IndexedInstrProf::ComputeHash(HashRef);
   }
-
   auto [Where, NewFunc] = ProfileDataMap.try_emplace(Hash);
   InstrProfRecord &Dest = Where->second;
 
diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp
index a90bcef7eaf7d..9885c2ac36df2 100644
--- a/llvm/tools/llvm-cov/CodeCoverage.cpp
+++ b/llvm/tools/llvm-cov/CodeCoverage.cpp
@@ -46,6 +46,7 @@
 #include <functional>
 #include <map>
 #include <optional>
+#include <string>
 #include <system_error>
 
 using namespace llvm;
@@ -297,8 +298,7 @@ CodeCoverageTool::getSourceFile(StringRef SourceFile) {
     error(EC.message(), SourceFile);
     return EC;
   }
-  LoadedSourceFiles.emplace_back(std::string(SourceFile),
-                                 std::move(Buffer.get()));
+  LoadedSourceFiles.emplace_back(std::string(SourceFile), std::move(Buffer.get()));
   return *LoadedSourceFiles.back().second;
 }
 
@@ -310,6 +310,7 @@ void CodeCoverageTool::attachExpansionSubViews(
   for (const auto &Expansion : Expansions) {
     auto ExpansionCoverage = Coverage.getCoverageForExpansion(Expansion);
     if (ExpansionCoverage.empty())
+    
       continue;
     auto SourceBuffer = getSourceFile(ExpansionCoverage.getFilename());
     if (!SourceBuffer)
@@ -454,6 +455,27 @@ static bool modifiedTimeGT(StringRef LHS, StringRef RHS) {
   return LHSTime > RHSTime;
 }
 
+// void mergeExecutionCounts(CoverageMapping &Coverage){
+//   std::map<std::string, std::vector<const FunctionRecord*>> functionGroups;
+
+//   for(const auto &Function : Coverage.getCoveredFunctions()){
+//     if(Function.CountedRegions.empty()) continue;
+//     const auto &MainRegion = Function.CountedRegions.front();
+//     const std::string Key = Function.Name + ":" + std::to_string(MainRegion.LineStart) + ":" + std::to_string(MainRegion.ColumnStart) + ":" + (Function.Filenames.empty() ? "" : std::string(Function.Filenames[0]));
+//     functionGroups[Key].push_back(&Function);
+//     llvm::errs() << Key << "\n";
+//   }
+
+//   for(auto &Group : functionGroups){
+//     if(Group.second.size() > 1){
+//       uint64_t TotalCount = 0;
+//       for(auto *Func : Group.second){
+//         TotalCount += Func->ExecutionCount;
+//       }
+//     }
+//   }
+// }
+
 std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
   if (PGOFilename) {
     for (StringRef ObjectFilename : ObjectFilenames)
@@ -483,6 +505,8 @@ std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
     }
   }
 
+  // mergeExecutionCounts(*Coverage);
+
   remapPathNames(*Coverage);
 
   if (!SourceFiles.empty())
@@ -648,7 +672,7 @@ void CodeCoverageTool::writeSourceFileView(StringRef SourceFile,
 
   View->print(*OS.get(), /*Wholefile=*/true,
               /*ShowSourceName=*/ShowFilenames,
-              /*ShowTitle=*/ViewOpts.hasOutputDirectory(), SourceFile);
+              /*ShowTitle=*/ViewOpts.hasOutputDirectory());
   Printer->closeViewFile(std::move(OS));
 }
 
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
index 45a8dcf76010f..f8b366ac3b3b6 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
@@ -218,6 +218,9 @@ void SourceCoverageViewText::renderLineCoverageColumn(
     return;
   }
   std::string C = formatBinaryCount(Line.getExecutionCount());
+  if(C == "2"){
+    llvm::errs() << C << "\n";
+  }
   OS.indent(LineCoverageColumnWidth - C.size());
   colored_ostream(OS, raw_ostream::MAGENTA, Line.hasMultipleRegions() && getOptions().Colors) << C;
   OS << '|';
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 8aa7f23a3398d..900d105c66e55 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -743,6 +743,7 @@ loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
       consumeError(ArchOrError.takeError());
       Architecture = "unknown";
     }
+    // Architecture = ExeRef;
   }
   //ANDRES CODE
 

>From 76967333cb824f0dc9be1ff6a3505f6c112b751f Mon Sep 17 00:00:00 2001
From: Andres Wearden <andreswearden5 at gmail.com>
Date: Mon, 21 Jul 2025 12:45:24 -0700
Subject: [PATCH 09/17] merging works, just need to fix llvm-lit tests and
 merging errors on same arch

---
 .../ProfileData/Coverage/CoverageMapping.h    |  1 +
 .../ProfileData/Coverage/CoverageMapping.cpp  | 32 +++++++++++++++++--
 llvm/lib/ProfileData/InstrProfWriter.cpp      |  3 +-
 .../tools/llvm-cov/SourceCoverageViewText.cpp |  3 --
 4 files changed, 32 insertions(+), 7 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index 0487a96ce4ae8..118f4e1fd662a 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -1006,6 +1006,7 @@ class CoverageMapping {
   std::vector<std::pair<std::string, uint64_t>> FuncHashMismatches;
   StringRef Arch;
   DenseMap<std::pair<size_t, hash_code>, unsigned> RecordIndices;
+  uint64_t Counter = 0;
 
   std::map<std::pair<std::string, std::string>, std::vector<uint64_t>> AggregatedCounts;
 
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 3dcbbbb1aaa5b..c38df7c41f940 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -1100,11 +1100,39 @@ Error CoverageMapping::loadFunctionRecord(
     Function.pushMCDCRecord(std::move(*Record));
   }
 
-  // Don't create records for (filenames, function) pairs we've already seen.
+  //CHANGES MADE HERE
   auto FilenamesHash = hash_combine_range(Record.Filenames);
-  if (!RecordProvenance[FilenamesHash].insert(FuncArchHash).second){
+  std::string HashStr = OrigFuncName.str(); /*+ ":" + Arch.str();*/
+  if(!Arch.empty()){
+    HashStr += ":" + Arch.str();
+    // auto LogicalFuncKey = std::make_pair(FilenamesHash, hash_value(OrigFuncName));
+    // auto It = RecordIndices.find(LogicalFuncKey);
+    // std::vector<llvm::coverage::CountedRegion> RegionsToAdd;
+
+    // if (It != RecordIndices.end()) {
+    //   auto &ExistingFunction = Functions[It->second];
+
+    //   for (const auto &NewRegion : Function.CountedRegions) {
+    //     for (auto &ExistingRegion : ExistingFunction.CountedRegions) {
+    //       if((NewRegion.ObjectFilename != ExistingRegion.ObjectFilename) &&
+    //         (NewRegion.startLoc() >= ExistingRegion.startLoc()) &&
+    //           (NewRegion.endLoc() <= ExistingRegion.endLoc())){
+    //           RegionsToAdd.push_back(NewRegion);
+    //       }
+    //     }
+    //   }
+    //   ExistingFunction.CountedRegions.insert(ExistingFunction.CountedRegions.end(), RegionsToAdd.begin(), RegionsToAdd.end());
+    // }
+    // RecordIndices[LogicalFuncKey] = Functions.size();
+  }
+  //CHANGES MADE HERE
+
+  // Don't create records for (filenames, function) pairs we've already seen.
+  StringRef HashStrRef(HashStr);
+  if (!RecordProvenance[FilenamesHash].insert(hash_value(HashStrRef)).second){
     return Error::success();
   }
+
   Functions.push_back(std::move(Function));
 
   // Performance optimization: keep track of the indices of the function records
diff --git a/llvm/lib/ProfileData/InstrProfWriter.cpp b/llvm/lib/ProfileData/InstrProfWriter.cpp
index d911ce6a6ee68..4e7cb302afc01 100644
--- a/llvm/lib/ProfileData/InstrProfWriter.cpp
+++ b/llvm/lib/ProfileData/InstrProfWriter.cpp
@@ -254,8 +254,7 @@ void InstrProfWriter::addRecord(StringRef Name, uint64_t Hash,
                                 InstrProfRecord &&I, uint64_t Weight,
                                 function_ref<void(Error)> Warn, StringRef Architecture) {
   auto &ProfileDataMap = FunctionData[Name];
-  StringRef SHAHash = hashSourceFile(Architecture);
-  llvm::errs() << "SHA Hashing: " << SHAHash << "\n";
+  // StringRef SHAHash = hashSourceFile(Architecture);
   if(!Architecture.empty()){
     std::string HashStr = std::to_string(Hash) + ":" + Architecture.str();
     llvm::StringRef HashRef(HashStr);
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
index f8b366ac3b3b6..45a8dcf76010f 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
@@ -218,9 +218,6 @@ void SourceCoverageViewText::renderLineCoverageColumn(
     return;
   }
   std::string C = formatBinaryCount(Line.getExecutionCount());
-  if(C == "2"){
-    llvm::errs() << C << "\n";
-  }
   OS.indent(LineCoverageColumnWidth - C.size());
   colored_ostream(OS, raw_ostream::MAGENTA, Line.hasMultipleRegions() && getOptions().Colors) << C;
   OS << '|';

>From 41d03b02a2fe8cabde2a6237219eb3d171a97e7c Mon Sep 17 00:00:00 2001
From: Andres Wearden <andreswearden5 at gmail.com>
Date: Tue, 22 Jul 2025 13:43:40 -0700
Subject: [PATCH 10/17] changed from hashing arches to hashing executables in
 llvm-profdata and llvm-cov

---
 .../ProfileData/Coverage/CoverageMapping.h    | 13 ++--
 .../ProfileData/Coverage/CoverageMapping.cpp  | 60 ++++++++++---------
 llvm/tools/llvm-cov/CodeCoverage.cpp          |  8 ++-
 llvm/tools/llvm-cov/CoverageViewOptions.h     |  1 +
 .../tools/llvm-cov/SourceCoverageViewText.cpp |  6 +-
 llvm/tools/llvm-profdata/llvm-profdata.cpp    |  2 +-
 6 files changed, 49 insertions(+), 41 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index 118f4e1fd662a..8ed62cfcdfc25 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -1019,7 +1019,7 @@ class CoverageMapping {
     ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
     std::optional<std::reference_wrapper<IndexedInstrProfReader>>
         &ProfileReader,
-    CoverageMapping &Coverage, StringRef Arch, StringRef ObjectFilename = "");
+    CoverageMapping &Coverage, StringRef Arch, StringRef ObjectFilename = "", bool ShowArchExecutables = false);
   
   static Error loadFromReaders(
     ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
@@ -1033,15 +1033,18 @@ class CoverageMapping {
                std::optional<std::reference_wrapper<IndexedInstrProfReader>>
                    &ProfileReader,
                CoverageMapping &Coverage, bool &DataFound,
-               SmallVectorImpl<object::BuildID> *FoundBinaryIDs = nullptr, StringRef ObjectFilename = "");
+               SmallVectorImpl<object::BuildID> *FoundBinaryIDs = nullptr, StringRef ObjectFilename = "", 
+                bool ShowArchExecutables = false);
 
   /// Add a function record corresponding to \p Record.
   Error loadFunctionRecord(
       const CoverageMappingRecord &Record,
       const std::optional<std::reference_wrapper<IndexedInstrProfReader>>
-          &ProfileReader, StringRef ObjectFilename = "");
+          &ProfileReader, StringRef ObjectFilename = "", bool ShowArchExecutables = false);
   
-  Error loadFunctionRecord(const CoverageMappingRecord &Record, const std::optional<std::reference_wrapper<IndexedInstrProfReader>> &ProfileReader, const std::string &Arch, StringRef ObjectFilename = "");
+  Error loadFunctionRecord(const CoverageMappingRecord &Record, 
+    const std::optional<std::reference_wrapper<IndexedInstrProfReader>> &ProfileReader, 
+    const std::string &Arch, StringRef ObjectFilename = "");
 
   /// Look up the indices for function records which are at least partially
   /// defined in the specified file. This is guaranteed to return a superset of
@@ -1075,7 +1078,7 @@ class CoverageMapping {
        std::optional<StringRef> ProfileFilename, vfs::FileSystem &FS,
        ArrayRef<StringRef> Arches = {}, StringRef CompilationDir = "",
        const object::BuildIDFetcher *BIDFetcher = nullptr,
-       bool CheckBinaryIDs = false);
+       bool CheckBinaryIDs = false, bool ShowArchExecutables = false);
 
   /// The number of functions that couldn't have their profiles mapped.
   ///
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index c38df7c41f940..1f7e057d58b1e 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -976,7 +976,7 @@ class MCDCDecisionRecorder {
 Error CoverageMapping::loadFunctionRecord(
     const CoverageMappingRecord &Record,
     const std::optional<std::reference_wrapper<IndexedInstrProfReader>>
-        &ProfileReader, StringRef ObjectFilename) {
+        &ProfileReader, StringRef ObjectFilename, bool ShowArchExecutables) {
   StringRef OrigFuncName = Record.FunctionName;
   if (OrigFuncName.empty())
     return make_error<CoverageMapError>(coveragemap_error::malformed,
@@ -991,7 +991,7 @@ Error CoverageMapping::loadFunctionRecord(
 
   uint64_t FuncArchHash = Record.FunctionHash;
   if(!Arch.empty()){
-    std::string HashStr = std::to_string(Record.FunctionHash) + ":" + Arch.str();
+    std::string HashStr = std::to_string(Record.FunctionHash) + ":" + ObjectFilename.str();
     llvm::StringRef HashRef(HashStr);
     FuncArchHash = IndexedInstrProf::ComputeHash(HashRef);
   }
@@ -1102,28 +1102,29 @@ Error CoverageMapping::loadFunctionRecord(
 
   //CHANGES MADE HERE
   auto FilenamesHash = hash_combine_range(Record.Filenames);
-  std::string HashStr = OrigFuncName.str(); /*+ ":" + Arch.str();*/
-  if(!Arch.empty()){
+  std::string HashStr = OrigFuncName.str();
+  if(ShowArchExecutables){
     HashStr += ":" + Arch.str();
-    // auto LogicalFuncKey = std::make_pair(FilenamesHash, hash_value(OrigFuncName));
-    // auto It = RecordIndices.find(LogicalFuncKey);
-    // std::vector<llvm::coverage::CountedRegion> RegionsToAdd;
-
-    // if (It != RecordIndices.end()) {
-    //   auto &ExistingFunction = Functions[It->second];
-
-    //   for (const auto &NewRegion : Function.CountedRegions) {
-    //     for (auto &ExistingRegion : ExistingFunction.CountedRegions) {
-    //       if((NewRegion.ObjectFilename != ExistingRegion.ObjectFilename) &&
-    //         (NewRegion.startLoc() >= ExistingRegion.startLoc()) &&
-    //           (NewRegion.endLoc() <= ExistingRegion.endLoc())){
-    //           RegionsToAdd.push_back(NewRegion);
-    //       }
-    //     }
-    //   }
-    //   ExistingFunction.CountedRegions.insert(ExistingFunction.CountedRegions.end(), RegionsToAdd.begin(), RegionsToAdd.end());
-    // }
-    // RecordIndices[LogicalFuncKey] = Functions.size();
+  }else{
+    auto LogicalFuncKey = std::make_pair(FilenamesHash, hash_value(OrigFuncName));
+    auto It = RecordIndices.find(LogicalFuncKey);
+    std::vector<llvm::coverage::CountedRegion> RegionsToAdd;
+
+    if (It != RecordIndices.end()) {
+      auto &ExistingFunction = Functions[It->second];
+
+      for (const auto &NewRegion : Function.CountedRegions) {
+        for (auto &ExistingRegion : ExistingFunction.CountedRegions) {
+          if((NewRegion.ObjectFilename != ExistingRegion.ObjectFilename) &&
+            (NewRegion.startLoc() >= ExistingRegion.startLoc()) &&
+              (NewRegion.endLoc() <= ExistingRegion.endLoc())){
+              RegionsToAdd.push_back(NewRegion);
+          }
+        }
+      }
+      ExistingFunction.CountedRegions.insert(ExistingFunction.CountedRegions.end(), RegionsToAdd.begin(), RegionsToAdd.end());
+    }
+    RecordIndices[LogicalFuncKey] = Functions.size();
   }
   //CHANGES MADE HERE
 
@@ -1180,7 +1181,7 @@ Error CoverageMapping::loadFromReaders(
     ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
     std::optional<std::reference_wrapper<IndexedInstrProfReader>>
         &ProfileReader,
-    CoverageMapping &Coverage, StringRef Arch, StringRef ObjectFilename) {
+    CoverageMapping &Coverage, StringRef Arch, StringRef ObjectFilename, bool ShowArchExecutables) {
   
   Coverage.setArchitecture(Arch);
   assert(!Coverage.SingleByteCoverage || !ProfileReader ||
@@ -1193,7 +1194,7 @@ Error CoverageMapping::loadFromReaders(
       if (Error E = RecordOrErr.takeError())
         return E;
       const auto &Record = *RecordOrErr;
-      if (Error E = Coverage.loadFunctionRecord(Record, ProfileReader, ObjectFilename))
+      if (Error E = Coverage.loadFunctionRecord(Record, ProfileReader, ObjectFilename, ShowArchExecutables))
         return E;
     }
   }
@@ -1224,7 +1225,7 @@ Error CoverageMapping::loadFromFile(
     std::optional<std::reference_wrapper<IndexedInstrProfReader>>
         &ProfileReader,
     CoverageMapping &Coverage, bool &DataFound,
-    SmallVectorImpl<object::BuildID> *FoundBinaryIDs, StringRef ObjectFilename) {
+    SmallVectorImpl<object::BuildID> *FoundBinaryIDs, StringRef ObjectFilename, bool ShowArchExecutables) {
   auto CovMappingBufOrErr = MemoryBuffer::getFileOrSTDIN(
       Filename, /*IsText=*/false, /*RequiresNullTerminator=*/false);
   if (std::error_code EC = CovMappingBufOrErr.getError())
@@ -1256,7 +1257,7 @@ Error CoverageMapping::loadFromFile(
                        }));
   }
   DataFound |= !Readers.empty();
-  if (Error E = loadFromReaders(Readers, ProfileReader, Coverage, Arch, ObjectFilename))
+  if (Error E = loadFromReaders(Readers, ProfileReader, Coverage, Arch, ObjectFilename, ShowArchExecutables))
     return createFileError(Filename, std::move(E));
   return Error::success();
 }
@@ -1265,7 +1266,7 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
     ArrayRef<StringRef> ObjectFilenames,
     std::optional<StringRef> ProfileFilename, vfs::FileSystem &FS,
     ArrayRef<StringRef> Arches, StringRef CompilationDir,
-    const object::BuildIDFetcher *BIDFetcher, bool CheckBinaryIDs) {
+    const object::BuildIDFetcher *BIDFetcher, bool CheckBinaryIDs, bool ShowArchExecutables) {
   std::unique_ptr<IndexedInstrProfReader> ProfileReader;
   if (ProfileFilename) {
     auto ProfileReaderOrErr =
@@ -1297,7 +1298,8 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
   for (const auto &File : llvm::enumerate(ObjectFilenames)) {
     if (Error E = loadFromFile(File.value(), GetArch(File.index()),
                                CompilationDir, ProfileReaderRef, *Coverage,
-                               DataFound, &FoundBinaryIDs, ObjectFilenames[File.index()]))
+                               DataFound, &FoundBinaryIDs, ObjectFilenames[File.index()], 
+                               ShowArchExecutables))
       return std::move(E);
   }
 
diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp
index 9885c2ac36df2..93d4f03032ac8 100644
--- a/llvm/tools/llvm-cov/CodeCoverage.cpp
+++ b/llvm/tools/llvm-cov/CodeCoverage.cpp
@@ -486,7 +486,8 @@ std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
   auto FS = vfs::getRealFileSystem();
   auto CoverageOrErr = CoverageMapping::load(
       ObjectFilenames, PGOFilename, *FS, CoverageArches,
-      ViewOpts.CompilationDirectory, BIDFetcher.get(), CheckBinaryIDs);
+      ViewOpts.CompilationDirectory, BIDFetcher.get(), CheckBinaryIDs, 
+      ViewOpts.ShowArchExecutables);
   if (Error E = CoverageOrErr.takeError()) {
     error("failed to load coverage: " + toString(std::move(E)));
     return nullptr;
@@ -824,6 +825,10 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
   cl::opt<bool> CheckBinaryIDs(
       "check-binary-ids", cl::desc("Fail if an object couldn't be found for a "
                                    "binary ID in the profile"));
+  cl::opt<bool> ShowArchExecutables(
+    "show-arch-executables",
+    cl::desc("Show coverage per architecture and the associated executable slice"),
+    cl::init(false));
 
   auto commandLineParser = [&, this](int argc, const char **argv) -> int {
     cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
@@ -990,6 +995,7 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
     ViewOpts.ExportSummaryOnly = SummaryOnly;
     ViewOpts.NumThreads = NumThreads;
     ViewOpts.CompilationDirectory = CompilationDirectory;
+    ViewOpts.ShowArchExecutables = ShowArchExecutables;
 
     return 0;
   };
diff --git a/llvm/tools/llvm-cov/CoverageViewOptions.h b/llvm/tools/llvm-cov/CoverageViewOptions.h
index 1f6ad570f86f2..6129bcfb59757 100644
--- a/llvm/tools/llvm-cov/CoverageViewOptions.h
+++ b/llvm/tools/llvm-cov/CoverageViewOptions.h
@@ -47,6 +47,7 @@ struct CoverageViewOptions {
   bool SkipFunctions;
   bool SkipBranches;
   bool BinaryCounters;
+  bool ShowArchExecutables;
   OutputFormat Format;
   BranchOutputType ShowBranches;
   std::string ShowOutputDirectory;
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
index 45a8dcf76010f..9471f7529e104 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
@@ -229,11 +229,7 @@ void SourceCoverageViewText::renderArchLineCoverageColumn(
     OS.indent(LineCoverageColumnWidth) << '|';
     return;
   }
-  std::string C = "";
-  for(LineCoverageStats Counts : LineArchStats[Line.getLine()]){
-    C += formatBinaryCount(Counts.getExecutionCount()) + "/";
-  }
-  // std::string C = formatBinaryCount(Line.getExecutionCount());
+  std::string C = formatBinaryCount(Line.getExecutionCount());
   OS.indent(LineCoverageColumnWidth - C.size());
   colored_ostream(OS, raw_ostream::MAGENTA, Line.hasMultipleRegions() && getOptions().Colors) << C;
   OS << '|';
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 900d105c66e55..1f74d80cf58d9 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -743,7 +743,7 @@ loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
       consumeError(ArchOrError.takeError());
       Architecture = "unknown";
     }
-    // Architecture = ExeRef;
+    Architecture = ExeRef;
   }
   //ANDRES CODE
 

>From 6cdb2e1e3e61db5f523b43a56c25673cf7431614 Mon Sep 17 00:00:00 2001
From: Andres Wearden <andreswearden5 at gmail.com>
Date: Wed, 23 Jul 2025 14:17:43 -0700
Subject: [PATCH 11/17] updating repository

---
 .../ProfileData/Coverage/CoverageMapping.cpp  | 23 ++---
 llvm/tools/llvm-profdata/llvm-profdata.cpp    | 85 ++++++++++---------
 2 files changed, 58 insertions(+), 50 deletions(-)

diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 1f7e057d58b1e..cf24a85771878 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -40,7 +40,7 @@
 #include <stack>
 #include <string>
 #include <system_error>
-#include <unordered_map>
+#include <unordered_set>
 #include <utility>
 #include <vector>
 
@@ -1113,24 +1113,27 @@ Error CoverageMapping::loadFunctionRecord(
     if (It != RecordIndices.end()) {
       auto &ExistingFunction = Functions[It->second];
 
+      // Step 1: Build a set of existing ObjectFilenames
+      std::unordered_set<std::string> ExistingFilenames;
+      for (const auto &ExistingRegion : ExistingFunction.CountedRegions) {
+        ExistingFilenames.insert(ExistingRegion.ObjectFilename.str());
+      }
+
+      // Step 2: Only add NewRegions with unique ObjectFilenames
       for (const auto &NewRegion : Function.CountedRegions) {
-        for (auto &ExistingRegion : ExistingFunction.CountedRegions) {
-          if((NewRegion.ObjectFilename != ExistingRegion.ObjectFilename) &&
-            (NewRegion.startLoc() >= ExistingRegion.startLoc()) &&
-              (NewRegion.endLoc() <= ExistingRegion.endLoc())){
-              RegionsToAdd.push_back(NewRegion);
-          }
+        if (ExistingFilenames.find(NewRegion.ObjectFilename.str()) == ExistingFilenames.end()) {
+          ExistingFunction.CountedRegions.push_back(NewRegion);
         }
+        
       }
-      ExistingFunction.CountedRegions.insert(ExistingFunction.CountedRegions.end(), RegionsToAdd.begin(), RegionsToAdd.end());
     }
     RecordIndices[LogicalFuncKey] = Functions.size();
   }
   //CHANGES MADE HERE
 
   // Don't create records for (filenames, function) pairs we've already seen.
-  StringRef HashStrRef(HashStr);
-  if (!RecordProvenance[FilenamesHash].insert(hash_value(HashStrRef)).second){
+  StringRef Hash(HashStr);
+  if (!RecordProvenance[FilenamesHash].insert(hash_value(Hash)).second){
     return Error::success();
   }
 
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 1f74d80cf58d9..4dbdce3a1ab5b 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -199,6 +199,11 @@ static cl::opt<std::string> RemappingFile("remapping-file",
                                           cl::desc("Symbol remapping file"));
 static cl::alias RemappingFileA("r", cl::desc("Alias for --remapping-file"),
                                 cl::aliasopt(RemappingFile));
+static cl::list<std::string> ObjectAwareHashing("object-aware-hashing", 
+                                cl::desc("Includes the object file name when hashing function names "
+                                              "and control flow hashes, allowing functions from different "
+                                              "binaries to be distinguished"), 
+                                cl::sub(MergeSubcommand));
 static cl::opt<bool>
     UseMD5("use-md5", cl::init(false), cl::Hidden,
            cl::desc("Choose to use MD5 to represent string in name table (only "
@@ -690,32 +695,32 @@ static void overlapInput(const std::string &BaseFilename,
   }
 }
 
-//ANDRES FUNCTION
-Expected<std::string> getArchitectureFromExecutable(StringRef ExecutablePath){
-  ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrError = MemoryBuffer::getFile(ExecutablePath);
-  if(!BufferOrError){
-    return createStringError(BufferOrError.getError(), "Failed to load input file");
-  }
+// //ANDRES FUNCTION
+// Expected<std::string> getArchitectureFromExecutable(StringRef ExecutablePath){
+//   ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrError = MemoryBuffer::getFile(ExecutablePath);
+//   if(!BufferOrError){
+//     return createStringError(BufferOrError.getError(), "Failed to load input file");
+//   }
 
-  Expected<std::unique_ptr<object::ObjectFile>> ObjectOrError = object::ObjectFile::createObjectFile(BufferOrError.get()->getMemBufferRef());
-  if(!ObjectOrError){
-    return ObjectOrError.takeError();
-  }
+//   Expected<std::unique_ptr<object::ObjectFile>> ObjectOrError = object::ObjectFile::createObjectFile(BufferOrError.get()->getMemBufferRef());
+//   if(!ObjectOrError){
+//     return ObjectOrError.takeError();
+//   }
 
-  std::unique_ptr<llvm::object::ObjectFile> &Object = ObjectOrError.get();
+//   std::unique_ptr<llvm::object::ObjectFile> &Object = ObjectOrError.get();
 
-  StringRef ArchStr = Object->getArch() != Triple::UnknownArch ? Triple::getArchTypeName(Object->getArch()) : "unknown";
+//   StringRef ArchStr = Object->getArch() != Triple::UnknownArch ? Triple::getArchTypeName(Object->getArch()) : "unknown";
 
-  return ArchStr.str();
-}
-//ANDRES FUNCTION
+//   return ArchStr.str();
+// }
+// //ANDRES FUNCTION
 
 /// Load an input into a writer context.
 static void
 loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
           const InstrProfCorrelator *Correlator, const StringRef ProfiledBinary,
           WriterContext *WC, const object::BuildIDFetcher *BIDFetcher = nullptr,
-          const ProfCorrelatorKind *BIDFetcherCorrelatorKind = nullptr) {
+          const ProfCorrelatorKind *BIDFetcherCorrelatorKind = nullptr, StringRef ObjectFilename = "") {
   std::unique_lock<std::mutex> CtxGuard{WC->Lock};
 
   // Copy the filename, because llvm::ThreadPool copied the input "const
@@ -726,24 +731,24 @@ loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
   //ANDRES CODE
   std::string ExecutableName;
   std::string ProfileFile = Input.Filename;
-  std::string Architecture = "";
+  std::string ObjectFilename = "";
 
   StringRef FilenameRef = Filename;
-  if(FilenameRef.contains(':')){
-    StringRef ExeRef, ProfRef;
-    std::tie(ExeRef, ProfRef) = FilenameRef.split(':');
-    if(!ExeRef.empty() && !ProfRef.empty()){
-      ExecutableName = ExeRef.str();
-      ProfileFile = ProfRef.str();
-    }
-    Expected<std::string> ArchOrError = getArchitectureFromExecutable(ExeRef);
-    if(ArchOrError){
-      Architecture = std::move(ArchOrError.get());
-    }else{
-      consumeError(ArchOrError.takeError());
-      Architecture = "unknown";
-    }
-    Architecture = ExeRef;
+  if(!ObjectFilename.empty()){
+    // StringRef ExeRef, ProfRef;
+    // std::tie(ExeRef, ProfRef) = FilenameRef.split(':');
+    // if(!ExeRef.empty() && !ProfRef.empty()){
+    ObjectFilename = ObjectFilename.data();
+      // ProfileFile = ProfRef.str();
+    // }
+    // Expected<std::string> ArchOrError = getArchitectureFromExecutable(ExeRef);
+    // if(ArchOrError){
+    //   Architecture = std::move(ArchOrError.get());
+    // }else{
+    //   consumeError(ArchOrError.takeError());
+    //   Architecture = "unknown";
+    // }
+    // ObjectFilename = ExeRef;
   }
   //ANDRES CODE
 
@@ -837,7 +842,7 @@ loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
                                                 ? *BIDFetcherCorrelatorKind
                                                 : ProfCorrelatorKind::NONE;
   auto ReaderOrErr = InstrProfReader::create(ProfileFile /*ANDRES changed from Input.Filename to ProfileFile*/, *FS, Correlator, //THIS IS THE IMPORTANT LINE!!!!
-                                             BIDFetcher, CorrelatorKind, Warn, Architecture /*ANDRES added this parameter*/);
+                                             BIDFetcher, CorrelatorKind, Warn, ObjectFilename /*ANDRES added this parameter*/);
   if (Error E = ReaderOrErr.takeError()) {
     // Skip the empty profiles by returning silently.
     auto [ErrCode, Msg] = InstrProfError::take(std::move(E));
@@ -875,7 +880,7 @@ loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
       bool firstTime = WC->WriterErrorCodes.insert(ErrCode).second;
       handleMergeWriterError(make_error<InstrProfError>(ErrCode, Msg),
                              Input.Filename, FuncName, firstTime);
-    }, Architecture);
+    }, ObjectFilename);
   }
 
   if (KeepVTableSymbols) {
@@ -1084,18 +1089,18 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs,
         MaxTraceLength));
 
   if (NumThreads == 1) {
-    for (const auto &Input : Inputs)
-      loadInput(Input, Remapper, Correlator.get(), ProfiledBinary,
-                Contexts[0].get(), BIDFetcher.get(), &BIDFetcherCorrelateKind);
+    for (int I = 0; I < int(Inputs.size()); ++I)
+      loadInput(Inputs[I], Remapper, Correlator.get(), ProfiledBinary,
+                Contexts[0].get(), BIDFetcher.get(), &BIDFetcherCorrelateKind, !ObjectAwareHashing.empty() ? ObjectAwareHashing[I] : "");
   } else {
     DefaultThreadPool Pool(hardware_concurrency(NumThreads));
 
     // Load the inputs in parallel (N/NumThreads serial steps).
     unsigned Ctx = 0;
-    for (const auto &Input : Inputs) {
-      Pool.async(loadInput, Input, Remapper, Correlator.get(), ProfiledBinary,
+    for (int I = 0; I < int(Inputs.size()); ++I) {
+      Pool.async(loadInput, Inputs[I], Remapper, Correlator.get(), ProfiledBinary,
                  Contexts[Ctx].get(), BIDFetcher.get(),
-                 &BIDFetcherCorrelateKind);
+                 &BIDFetcherCorrelateKind, !ObjectAwareHashing[I].empty() ? ObjectAwareHashing[I] : "");
       Ctx = (Ctx + 1) % NumThreads;
     }
     Pool.wait();

>From bea56b993df209fb593b4dfc0504fcb3e168352c Mon Sep 17 00:00:00 2001
From: Andres Wearden <andreswearden5 at gmail.com>
Date: Wed, 23 Jul 2025 20:23:16 -0700
Subject: [PATCH 12/17] updated compiler error

---
 llvm/tools/llvm-profdata/llvm-profdata.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 4dbdce3a1ab5b..194c59fb7e8c4 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -720,7 +720,7 @@ static void
 loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
           const InstrProfCorrelator *Correlator, const StringRef ProfiledBinary,
           WriterContext *WC, const object::BuildIDFetcher *BIDFetcher = nullptr,
-          const ProfCorrelatorKind *BIDFetcherCorrelatorKind = nullptr, StringRef ObjectFilename = "") {
+          const ProfCorrelatorKind *BIDFetcherCorrelatorKind = nullptr, StringRef ObjectAwareHashing = "") {
   std::unique_lock<std::mutex> CtxGuard{WC->Lock};
 
   // Copy the filename, because llvm::ThreadPool copied the input "const
@@ -738,7 +738,7 @@ loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
     // StringRef ExeRef, ProfRef;
     // std::tie(ExeRef, ProfRef) = FilenameRef.split(':');
     // if(!ExeRef.empty() && !ProfRef.empty()){
-    ObjectFilename = ObjectFilename.data();
+    ObjectFilename = ObjectAwareHashing.data();
       // ProfileFile = ProfRef.str();
     // }
     // Expected<std::string> ArchOrError = getArchitectureFromExecutable(ExeRef);

>From ebcd68ebbc4f5d7cfa440b652e5a60cd8948c725 Mon Sep 17 00:00:00 2001
From: Andres Wearden <andreswearden5 at gmail.com>
Date: Mon, 28 Jul 2025 01:32:19 -0700
Subject: [PATCH 13/17] fixed issues with time complexity and region counts

---
 .../ProfileData/Coverage/CoverageMapping.h    |  16 +-
 .../ProfileData/Coverage/CoverageMapping.cpp  | 142 ++++++++++++++++--
 llvm/tools/llvm-cov/CodeCoverage.cpp          |   3 +-
 .../llvm-profdata-cross-arch/CMakeLists.txt   |  35 -----
 .../ELFSymbolReader.cpp                       |  90 -----------
 .../ELFSymbolReader.h                         |  31 ----
 .../llvm-profdata-cross-arch.cpp              | 112 --------------
 llvm/tools/llvm-profdata/llvm-profdata.cpp    |   4 +-
 8 files changed, 147 insertions(+), 286 deletions(-)
 delete mode 100644 llvm/tools/llvm-profdata-cross-arch/CMakeLists.txt
 delete mode 100644 llvm/tools/llvm-profdata-cross-arch/ELFSymbolReader.cpp
 delete mode 100644 llvm/tools/llvm-profdata-cross-arch/ELFSymbolReader.h
 delete mode 100644 llvm/tools/llvm-profdata-cross-arch/llvm-profdata-cross-arch.cpp

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index 8ed62cfcdfc25..a91bbde99066d 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -748,6 +748,16 @@ struct FunctionRecord {
   FunctionRecord(FunctionRecord &&FR) = default;
   FunctionRecord &operator=(FunctionRecord &&) = default;
 
+  FunctionRecord(const FunctionRecord &FR)
+    : Name(FR.Name),
+      Filenames(FR.Filenames),
+      CountedRegions(FR.CountedRegions),
+      CountedBranchRegions(FR.CountedBranchRegions),
+      MCDCRecords(FR.MCDCRecords),
+      ExecutionCount(FR.ExecutionCount),
+      ObjectFilename(FR.ObjectFilename) {}
+
+
   void pushMCDCRecord(MCDCRecord &&Record) {
     MCDCRecords.push_back(std::move(Record));
   }
@@ -1006,7 +1016,9 @@ class CoverageMapping {
   std::vector<std::pair<std::string, uint64_t>> FuncHashMismatches;
   StringRef Arch;
   DenseMap<std::pair<size_t, hash_code>, unsigned> RecordIndices;
-  uint64_t Counter = 0;
+  uint64_t DebugCount = 0;
+  std::vector<FunctionRecord> AllFunctionRegions;
+
 
   std::map<std::pair<std::string, std::string>, std::vector<uint64_t>> AggregatedCounts;
 
@@ -1103,7 +1115,7 @@ class CoverageMapping {
   /// The given filename must be the name as recorded in the coverage
   /// information. That is, only names returned from getUniqueSourceFiles will
   /// yield a result.
-  LLVM_ABI CoverageData getCoverageForFile(StringRef Filename) const;
+  LLVM_ABI CoverageData getCoverageForFile(StringRef Filename, bool ShowArchExecutables = false) const;
 
   /// Get the coverage for a particular function.
   LLVM_ABI CoverageData
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index cf24a85771878..6248c202ec6ff 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -14,6 +14,7 @@
 #include "llvm/ProfileData/Coverage/CoverageMapping.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallBitVector.h"
 #include "llvm/ADT/SmallVector.h"
@@ -23,10 +24,12 @@
 #include "llvm/ProfileData/Coverage/CoverageMappingReader.h"
 #include "llvm/ProfileData/InstrProfReader.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/Support/DebugCounter.h"
 #include "llvm/Support/Errc.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/ScopedPrinter.h"
 #include "llvm/Support/VirtualFileSystem.h"
 #include "llvm/Support/raw_ostream.h"
 #include <algorithm>
@@ -1106,39 +1109,74 @@ Error CoverageMapping::loadFunctionRecord(
   if(ShowArchExecutables){
     HashStr += ":" + Arch.str();
   }else{
+    //THIS ALGORITHM NEEDS TO BE FIXED!!!
     auto LogicalFuncKey = std::make_pair(FilenamesHash, hash_value(OrigFuncName));
     auto It = RecordIndices.find(LogicalFuncKey);
-    std::vector<llvm::coverage::CountedRegion> RegionsToAdd;
 
     if (It != RecordIndices.end()) {
       auto &ExistingFunction = Functions[It->second];
 
-      // Step 1: Build a set of existing ObjectFilenames
-      std::unordered_set<std::string> ExistingFilenames;
-      for (const auto &ExistingRegion : ExistingFunction.CountedRegions) {
-        ExistingFilenames.insert(ExistingRegion.ObjectFilename.str());
+
+      // Create a map of existing regions for efficient lookup.
+      // The key uniquely identifies the source region.
+      using RegionKey = std::tuple<unsigned, unsigned, unsigned, unsigned, unsigned>;
+      std::map<RegionKey, CountedRegion *> ExistingRegionsMap;
+      for (auto &ExistingRegion : ExistingFunction.CountedRegions) {
+        RegionKey Key = {ExistingRegion.FileID, ExistingRegion.LineStart,
+                         ExistingRegion.ColumnStart, ExistingRegion.LineEnd,
+                         ExistingRegion.ColumnEnd};
+        ExistingRegionsMap[Key] = &ExistingRegion;
+      }
+
+      for (auto NewRegion : Function.CountedRegions) {
+        AllFunctionRegions[It->second].CountedRegions.push_back(NewRegion);
       }
 
-      // Step 2: Only add NewRegions with unique ObjectFilenames
+      // Merge the new regions into the existing function's regions.
       for (const auto &NewRegion : Function.CountedRegions) {
-        if (ExistingFilenames.find(NewRegion.ObjectFilename.str()) == ExistingFilenames.end()) {
+        RegionKey Key = {NewRegion.FileID, NewRegion.LineStart,
+                         NewRegion.ColumnStart, NewRegion.LineEnd,
+                         NewRegion.ColumnEnd};
+        auto MapIt = ExistingRegionsMap.find(Key);
+        if (MapIt != ExistingRegionsMap.end()) {
+          // Region already exists, merge counts by taking the max.
+          CountedRegion *ExistingRegion = MapIt->second;
+          // llvm::errs() << "EXECUTION COUNTS BEFORE: " +  to_string(ExistingRegion->ExecutionCount) << "\n";
+          // llvm::errs() << "(" << ExistingRegion->LineStart << ", " << ExistingRegion->LineEnd << ")" << "\n";
+          ExistingRegion->ExecutionCount += NewRegion.ExecutionCount;
+          // llvm::errs() << "EXECUTION COUNTS AFTER: " +  to_string(ExistingRegion->ExecutionCount) << "\n";
+          // DebugCount++;
+        } else {
+          // llvm::errs() << "ENTERS ELSE STATEMENT HERE" << "\n";
+          // llvm::errs() << "(" << NewRegion.LineStart << ", " << NewRegion.LineEnd << ")" << "\n";
           ExistingFunction.CountedRegions.push_back(NewRegion);
         }
-        
       }
+      // Since we modified an existing function, we don't add a new one.
+      // We just need to make sure we don't add the new 'Function' object later.
+      // The logic below this block needs to be adjusted to handle this.
+      return Error::success();
     }
-    RecordIndices[LogicalFuncKey] = Functions.size();
+    // llvm::errs() << "ENTERS ELSE STATEMENT HERE" << "\n";
+    RecordIndices.insert({LogicalFuncKey, Functions.size()});
+    //THIS ALGORITHM NEEDS TO BE FIXED!!!
   }
   //CHANGES MADE HERE
 
+  // if(DebugCount == 29){
+  //   llvm::errs() << "ENTERS ELSE STATEMENT HERE" << "\n";
+  // }
+
+
+
   // Don't create records for (filenames, function) pairs we've already seen.
   StringRef Hash(HashStr);
   if (!RecordProvenance[FilenamesHash].insert(hash_value(Hash)).second){
     return Error::success();
   }
 
+  AllFunctionRegions.push_back(Function);
   Functions.push_back(std::move(Function));
-
   // Performance optimization: keep track of the indices of the function records
   // which correspond to each filename. This can be used to substantially speed
   // up queries for coverage info in a file.
@@ -1594,6 +1632,59 @@ class SegmentBuilder {
 
     sortNestedRegions(Regions);
 
+    // // This map is used to efficiently check for the existence of a specific region
+    // // from a specific binary, which is the purpose of the innermost loop in the
+    // // original code.
+    // // Key: A tuple uniquely identifying a region's location and its binary of origin.
+    // // Value: A boolean indicating if the region is NOT a SkippedRegion.
+    // using RegionKey = std::tuple<LineColPair, LineColPair, StringRef>;
+    // std::map<RegionKey, bool> RegionExistenceMap;
+    // for (const auto &R : Regions) {
+    //   RegionKey Key = {R.startLoc(), R.endLoc(), R.ObjectFilename};
+    //   // Only insert if it's a more "valid" region than what might already be there.
+    //   if (R.Kind != CounterMappingRegion::SkippedRegion)
+    //     RegionExistenceMap[Key] = true;
+    //   else
+    //     RegionExistenceMap.try_emplace(Key, false);
+    // }
+
+    // for (auto &I : Regions) {
+    //   // We are only interested in patching SkippedRegions.
+    //   if (I.Kind != CounterMappingRegion::SkippedRegion)
+    //     continue;
+
+    //   for (auto &J : Regions) {
+    //     // Find a non-skipped region 'J' from a different binary that contains 'I'.
+    //     if (I.ObjectFilename == J.ObjectFilename ||
+    //         J.Kind == CounterMappingRegion::SkippedRegion ||
+    //         !(I.startLoc() >= J.startLoc() && I.endLoc() <= J.endLoc())) {
+    //       continue;
+    //     }
+
+    //     // Check if a non-skipped region already exists at I's exact location
+    //     // coming from J's binary. This replaces the O(N) inner loop.
+    //     RegionKey KeyToFind = {I.startLoc(), I.endLoc(), J.ObjectFilename};
+    //     auto It = RegionExistenceMap.find(KeyToFind);
+
+    //     // If no region from J's binary exists at I's location, or if it does
+    //     // but it's a SkippedRegion, we can patch I with J's data.
+    //     if (It == RegionExistenceMap.end() || It->second == false) {
+    //       I.Kind = J.Kind;
+    //       I.ExecutionCount = J.ExecutionCount;
+    //       // We found a patch, no need to check other containing regions.
+    //       break;
+    //     }
+    //   }
+    // }
+
+    // llvm::errs() << "START HERE" << "\n";
+    // for(auto *I = Regions.begin(); I != Regions.end(); ++I){
+    //   llvm::errs() << "(" << to_string(I->startLoc().first) << ", " << to_string(I->endLoc().first) << ")" << "\n";
+    //   llvm::errs() << "Execution Count: " << I->ExecutionCount << "\n";
+    // }
+    // llvm::errs() << "END HERE" << "\n";
+
+
     for(auto *I = Regions.begin(); I != Regions.end(); ++I){
       bool FoundMatchInOtherBinary = false;
       for(auto *J = I + 1; J != Regions.end(); ++J){
@@ -1601,6 +1692,7 @@ class SegmentBuilder {
             J->Kind == CounterMappingRegion::SkippedRegion 
             && I->Kind != CounterMappingRegion::SkippedRegion &&
             J->startLoc() >= I->startLoc() && J->endLoc() <= I->endLoc()){
+          // llvm::errs() << "(" << to_string(J->startLoc().first) << ", " << to_string(J->endLoc().first) << ")" << "\n";
           for(auto *K = J + 1; K != Regions.end(); ++K){
             if(K->ObjectFilename == I->ObjectFilename &&
               J->startLoc() == K->startLoc() && J->endLoc() == K->endLoc()){
@@ -1614,6 +1706,13 @@ class SegmentBuilder {
         }
       }
     }
+
+    // llvm::errs() << "START HERE" << "\n";
+    // for(auto *I = Regions.begin(); I != Regions.end(); ++I){
+    //   llvm::errs() << "(" << to_string(I->startLoc().first) << ", " << to_string(I->endLoc().first) << ")" << "\n";
+    //   llvm::errs() << "Execution Count: " << I->ExecutionCount << "\n";
+    // }
+    // llvm::errs() << "END HERE" << "\n";
     
 
     ArrayRef<CountedRegion> CombinedRegions = combineRegions(Regions);
@@ -1671,9 +1770,15 @@ static SmallBitVector gatherFileIDs(StringRef SourceFile,
 static std::optional<unsigned>
 findMainViewFileID(const FunctionRecord &Function) {
   SmallBitVector IsNotExpandedFile(Function.Filenames.size(), true);
-  for (const auto &CR : Function.CountedRegions)
+  uint64_t counter = 0;
+  for (const auto &CR : Function.CountedRegions){
+    // counter++;
+    // if(counter == 245){
+    //   llvm::errs() << counter << "\n";
+    // }
     if (CR.Kind == CounterMappingRegion::ExpansionRegion)
       IsNotExpandedFile[CR.ExpandedFileID] = false;
+  }
   int I = IsNotExpandedFile.find_first();
   if (I == -1)
     return std::nullopt;
@@ -1695,17 +1800,26 @@ static bool isExpansion(const CountedRegion &R, unsigned FileID) {
   return R.Kind == CounterMappingRegion::ExpansionRegion && R.FileID == FileID;
 }
 
-CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const {
+CoverageData CoverageMapping::getCoverageForFile(StringRef Filename, bool ShowArchExecutables) const {
   assert(SingleByteCoverage);
   CoverageData FileCoverage(*SingleByteCoverage, Filename);
   std::vector<CountedRegion> Regions;
 
   // Look up the function records in the given file. Due to hash collisions on
   // the filename, we may get back some records that are not in the file.
+  // DenseSet<CountedRegion> DeDuplicationSet;
   ArrayRef<unsigned> RecordIndices =
       getImpreciseRecordIndicesForFilename(Filename);
+  // for (unsigned RecordIndex : RecordIndices) {
+  //   const FunctionRecord &Function = AllFunctionRegions[RecordIndex];
+  //   for(const auto &I : Function.CountedRegions){
+  //     llvm::errs() << "(" << to_string(I.startLoc().first) << ", " << to_string(I.endLoc().first) << ")" << "\n";
+  //   }
+  // }
+  // ArrayRef<unsigned> RecordIndices =
+  //     getImpreciseRecordIndicesForFilename(Filename);
   for (unsigned RecordIndex : RecordIndices) {
-    const FunctionRecord &Function = Functions[RecordIndex];
+    const FunctionRecord &Function = ShowArchExecutables ? Functions[RecordIndex] : AllFunctionRegions[RecordIndex];
     auto MainFileID = findMainViewFileID(Filename, Function);
     auto FileIDs = gatherFileIDs(Filename, Function);
     for (const auto &CR : Function.CountedRegions)
@@ -1724,6 +1838,8 @@ CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const {
         FileCoverage.MCDCRecords.push_back(MR);
   }
 
+
+
   LLVM_DEBUG(dbgs() << "Emitting segments for file: " << Filename << "\n");
   FileCoverage.Segments = SegmentBuilder::buildSegments(Regions);
 
diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp
index 93d4f03032ac8..1feb1f8402d38 100644
--- a/llvm/tools/llvm-cov/CodeCoverage.cpp
+++ b/llvm/tools/llvm-cov/CodeCoverage.cpp
@@ -29,6 +29,7 @@
 #include "llvm/ProfileData/Coverage/CoverageMapping.h"
 #include "llvm/ProfileData/InstrProfReader.h"
 #include "llvm/Support/CommandLine.h"
+#include "llvm/Support/DebugCounter.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/MemoryBuffer.h"
@@ -396,7 +397,7 @@ CodeCoverageTool::createSourceFileView(StringRef SourceFile,
   auto SourceBuffer = getSourceFile(SourceFile);
   if (!SourceBuffer)
     return nullptr;
-  auto FileCoverage = Coverage.getCoverageForFile(SourceFile);
+  auto FileCoverage = Coverage.getCoverageForFile(SourceFile, ViewOpts.ShowArchExecutables);
   if (FileCoverage.empty())
     return nullptr;
 
diff --git a/llvm/tools/llvm-profdata-cross-arch/CMakeLists.txt b/llvm/tools/llvm-profdata-cross-arch/CMakeLists.txt
deleted file mode 100644
index b37f76db883b5..0000000000000
--- a/llvm/tools/llvm-profdata-cross-arch/CMakeLists.txt
+++ /dev/null
@@ -1,35 +0,0 @@
-cmake_minimum_required(VERSION 3.13)
-project(llvm-profdata-cross-arch)
-
-set(CMAKE_CXX_STANDARD 17)
-set(CMAKE_CXX_STANDARD_REQUIRED ON)
-
-# Find LLVM package
-find_package(LLVM REQUIRED CONFIG)
-
-message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
-message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
-
-# Set LLVM include and library directories
-include_directories(${LLVM_INCLUDE_DIRS})
-link_directories(${LLVM_LIBRARY_DIRS})
-add_definitions(${LLVM_DEFINITIONS})
-
-# Define the source files
-set(SOURCES
-    ELFSymbolReader.cpp
-    llvm-profdata-cross-arch.cpp
-)
-
-# Add the executable
-add_executable(llvm-profdata-cross-arch ${SOURCES})
-
-# Link against LLVM libraries
-llvm_map_components_to_libnames(llvm_libs
-    Core
-    Support
-    Object
-    Demangle
-)
-
-target_link_libraries(llvm-profdata-cross-arch ${llvm_libs})
diff --git a/llvm/tools/llvm-profdata-cross-arch/ELFSymbolReader.cpp b/llvm/tools/llvm-profdata-cross-arch/ELFSymbolReader.cpp
deleted file mode 100644
index 61076f4e72073..0000000000000
--- a/llvm/tools/llvm-profdata-cross-arch/ELFSymbolReader.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-#include "ELFSymbolReader.h"
-#include "llvm/Object/Binary.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Object/ELFObjectFile.h"
-#include "llvm/Support/Casting.h"
-#include "llvm/Object/ObjectFile.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Demangle/Demangle.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/TargetSelect.h"
-
-
-using namespace llvm;
-using namespace llvm::object;
-
-Expected<std::vector<FunctionSymbol>> ELFSymbolReader::readSymbols(StringRef File){
-    Expected<OwningBinary<Binary>> BinOrErr = createBinary(File);
-    if(!BinOrErr){
-        return BinOrErr.takeError();
-    }
-
-    const ELFObjectFileBase *Obj = dyn_cast<ELFObjectFileBase>(BinOrErr->getBinary());
-    if(!Obj){
-        return createStringError(inconvertibleErrorCode(), "Not an ELF");
-    }
-
-    std::vector<FunctionSymbol> Syms;
-
-    for(const SymbolRef &Sym : Obj->symbols()){
-        if(!(cantFail(Sym.getType()) & SymbolRef::ST_Function)){
-            continue;
-        }
-        if(cantFail(Sym.getFlags()) & SymbolRef::SF_Undefined){
-            continue;
-        }
-        Expected<StringRef> NameOrErr = Sym.getName();
-        if(!NameOrErr){
-            consumeError(NameOrErr.takeError());
-            continue;
-        }
-        StringRef FuncNameRef = *NameOrErr;
-        if(FuncNameRef.starts_with("__")){
-            continue;
-        }
-        
-        // Skip symbols not in executable sections (e.g., not in .text)
-        Expected<section_iterator> SecOrErr = Sym.getSection();
-        if (!SecOrErr || *SecOrErr == Obj->section_end()){
-            continue;
-        }
-        StringRef SectionName;
-        if (Expected<StringRef> NameOrErr = (*SecOrErr)->getName()) {
-            SectionName = *NameOrErr;
-            if (!SectionName.equals_insensitive(".text")){
-                continue;
-            }
-        } else {
-            consumeError(NameOrErr.takeError());
-            continue;
-        }
-
-
-        uint64_t Addr = cantFail(Sym.getAddress());
-        StringRef NameRef = cantFail(Sym.getName());
-
-        FunctionSymbol FS;
-        FS.Address = Addr;
-        FS.Name = NameRef.str();
-        FS.DemangledName = llvm::demangle(FS.Name);
-        Syms.push_back(std::move(FS));
-    }
-    return Syms;
-}
-
-Expected<std::string> ELFSymbolReader::detectArchitecture(StringRef File){
-    Expected<OwningBinary<Binary>> BinOrErr = createBinary(File);
-    if(!BinOrErr){
-        return BinOrErr.takeError();
-    }
-    
-    const ELFObjectFileBase *Obj = dyn_cast<ELFObjectFileBase>(BinOrErr->getBinary());
-    if(!Obj){
-        return createStringError(inconvertibleErrorCode(), "Not an ELF");
-    }
-    return std::string(Triple::getArchTypeName(Obj->getArch()));
-}
-
-std::string ELFSymbolReader::demangleName(StringRef N){
-    return llvm::demangle(N.str());
-}
\ No newline at end of file
diff --git a/llvm/tools/llvm-profdata-cross-arch/ELFSymbolReader.h b/llvm/tools/llvm-profdata-cross-arch/ELFSymbolReader.h
deleted file mode 100644
index 99f88498d3d41..0000000000000
--- a/llvm/tools/llvm-profdata-cross-arch/ELFSymbolReader.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#pragma once
-
-#include "llvm/Object/ELF.h"
-#include "llvm/Object/ObjectFile.h"
-#include "llvm/Support/Error.h"
-#include <string>
-#include <vector>
-
-namespace llvm {
-
-    struct FunctionSymbol {
-        uint64_t Address;
-        std::string Name;
-        std::string DemangledName;
-    };
-
-    class ELFSymbolReader {
-        public:
-            //Expected datatype is an llvm data type that will either have the type specified in the <> or contain an error message explaining why the error occurred.
-            static Expected<std::vector<FunctionSymbol>> readSymbols(StringRef Filename);
-
-            static Expected<std::string> detectArchitecture(StringRef Filename);
-
-            static std::string demangleName(StringRef MangledName);
-    };
-
-} // namespace llvm
-
-
-
-
diff --git a/llvm/tools/llvm-profdata-cross-arch/llvm-profdata-cross-arch.cpp b/llvm/tools/llvm-profdata-cross-arch/llvm-profdata-cross-arch.cpp
deleted file mode 100644
index cbb904cc90161..0000000000000
--- a/llvm/tools/llvm-profdata-cross-arch/llvm-profdata-cross-arch.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-#include "ELFSymbolReader.h"
-#include "llvm/IR/Function.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/raw_ostream.h"
-
-#include <string>
-#include <utility>
-#include <vector>
-
-using namespace llvm;
-
-static cl::SubCommand AnalyzeSymbolsSubcommand("analyze-symbols", "Analyze symbols in ELF files for cross-arch profiling");
-static cl::SubCommand AnalyzeProfrawSubcommand("analyze-profraw", "Used to analyze mappings between source code and coverage data");
-
-static cl::list<std::string> ELFFiles(cl::Positional, cl::sub(AnalyzeSymbolsSubcommand), cl::desc("<elf-files>"), cl::OneOrMore);
-static cl::list<std::string> ProfrawFiles(cl::Positional, cl::sub(AnalyzeProfrawSubcommand), cl::desc("<profraw-files>"), cl::OneOrMore);
-
-static void findAndPrintMatches(const std::vector<std::vector<FunctionSymbol>> &AllSymbols, const std::vector<std::string> &Architectures) {
-    const std::vector<FunctionSymbol> &Symbols1 = AllSymbols[0];
-    const std::vector<FunctionSymbol> &Symbols2 = AllSymbols[1];
-
-    std::vector<std::pair<FunctionSymbol, FunctionSymbol>> Matches;
-
-    for (const FunctionSymbol &Sym1 : Symbols1) {
-        for (const FunctionSymbol &Sym2 : Symbols2) {
-            if (Sym1.Name == Sym2.Name) {
-                Matches.push_back({Sym1, Sym2});
-                continue;
-            }
-
-            if (!Sym1.DemangledName.empty() && !Sym2.DemangledName.empty() && Sym1.DemangledName == Sym2.DemangledName) {
-                Matches.push_back({Sym1, Sym2});
-                continue;
-            }
-        }
-    }
-
-    outs() << "Potential matches found: " << Matches.size() << "\n";
-    for (const auto &Match : Matches) {
-        if (Match.first.DemangledName == Match.second.DemangledName) {
-            outs() << " " << Match.first.DemangledName << " <-> " << Match.second.DemangledName << " (demangled match)\n";
-        } else {
-            outs() << " " << Match.first.Name << " <-> " << Match.second.Name << " (exact match)\n";
-        }
-    }
-
-    outs() << "\n" << Architectures[0] << "-only functions: " << (Symbols1.size() - Matches.size()) << "\n";
-    outs() << Architectures[1] << "-only functions: " << (Symbols2.size() - Matches.size()) << "\n";
-
-    if (!Matches.empty()) {
-        outs() << "\nSUCCESS: Found " << Matches.size() << " functions that exist in both architectures!\n";
-    } else {
-        outs() << "\nWARNING: No matching functions found between architectures.\n";
-    }
-}
-
-static int analyzeSymbols_main(StringRef ProgName) {
-    outs() << "=== Symbol Analysis ==\n\n";
-    std::vector<std::vector<FunctionSymbol>> AllSymbols;
-    std::vector<std::string> Architectures;
-
-    for (const std::string &Filename : ELFFiles) {
-        Expected<std::string> ArchOrErr = ELFSymbolReader::detectArchitecture(Filename);
-        if (!ArchOrErr) {
-            errs() << "Error detecting architecture for " << Filename << ": " << toString(ArchOrErr.takeError()) << "\n";
-            continue;
-        }
-
-        Expected<std::vector<FunctionSymbol>> SymbolsOrErr = ELFSymbolReader::readSymbols(Filename);
-        if (!SymbolsOrErr) {
-            errs() << "Error reading symbols from " << Filename << ": " << toString(SymbolsOrErr.takeError()) << "\n";
-            continue;
-        }
-
-        std::string Arch = ArchOrErr.get();
-        std::vector<FunctionSymbol> Symbols = SymbolsOrErr.get();
-
-        outs() << "File: " << Filename << "\n";
-        outs() << "Architecture: " << Arch << "\n";
-        outs() << "Functions found: " << Symbols.size() << "\n";
-
-        for (const FunctionSymbol &Symbol : Symbols) {
-            outs() << " 0x" << format("%08x", Symbol.Address) << ": " << Symbol.Name;
-            if (Symbol.DemangledName != Symbol.Name) {
-                outs() << " (" << Symbol.DemangledName << ")";
-            }
-            outs() << "\n";
-        }
-        outs() << "\n";
-
-        AllSymbols.push_back(std::move(Symbols));
-        Architectures.push_back(std::move(Arch));
-    }
-
-    if (AllSymbols.size() >= 2) {
-        outs() << "=== Cross-Architecture Analysis ==\n";
-        findAndPrintMatches(AllSymbols, Architectures);
-    }
-
-    return 0;
-}
-
-int main(int argc, const char *argv[]) {
-    cl::ParseCommandLineOptions(argc, argv, "LLVM cross-architecture profile analysis\n");
-    if (AnalyzeSymbolsSubcommand) {
-        return analyzeSymbols_main(argv[0]);
-    }
-
-    cl::PrintHelpMessage();
-    return 1;
-}
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 194c59fb7e8c4..7f4a0df458201 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -731,10 +731,10 @@ loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
   //ANDRES CODE
   std::string ExecutableName;
   std::string ProfileFile = Input.Filename;
-  std::string ObjectFilename = "";
+  StringRef ObjectFilename = "";
 
   StringRef FilenameRef = Filename;
-  if(!ObjectFilename.empty()){
+  if(!ObjectAwareHashing.empty()){
     // StringRef ExeRef, ProfRef;
     // std::tie(ExeRef, ProfRef) = FilenameRef.split(':');
     // if(!ExeRef.empty() && !ProfRef.empty()){

>From 035dd724ba23af8044b1a2d9ce37f78d540a58c4 Mon Sep 17 00:00:00 2001
From: Andres Wearden <andreswearden5 at gmail.com>
Date: Tue, 29 Jul 2025 18:44:18 -0700
Subject: [PATCH 14/17] llvm-lit test cases pass

---
 .../ProfileData/Coverage/CoverageMapping.h    |  18 +--
 .../Coverage/CoverageMappingReader.h          |   9 +-
 llvm/include/llvm/ProfileData/InstrProf.h     |  34 +++---
 .../llvm/ProfileData/InstrProfReader.h        |  14 +--
 .../llvm/ProfileData/InstrProfWriter.h        |   4 +-
 .../ProfileData/Coverage/CoverageMapping.cpp  | 110 +++---------------
 .../Coverage/CoverageMappingReader.cpp        |  40 +++----
 llvm/lib/ProfileData/InstrProf.cpp            |   6 +-
 llvm/lib/ProfileData/InstrProfReader.cpp      |  12 +-
 llvm/lib/ProfileData/InstrProfWriter.cpp      |  10 +-
 .../universal_bin_wrapping_archives.test      |   2 +-
 llvm/tools/llvm-cov/CodeCoverage.cpp          |  10 +-
 llvm/tools/llvm-cov/CoverageViewOptions.h     |   1 +
 13 files changed, 100 insertions(+), 170 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index a91bbde99066d..cb3b7c60ba981 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -1031,7 +1031,7 @@ class CoverageMapping {
     ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
     std::optional<std::reference_wrapper<IndexedInstrProfReader>>
         &ProfileReader,
-    CoverageMapping &Coverage, StringRef Arch, StringRef ObjectFilename = "", bool ShowArchExecutables = false);
+    CoverageMapping &Coverage, StringRef Arch, StringRef ObjectFilename = "", bool ShowArchExecutables = false, bool MergeBinaryCoverage = false);
   
   static Error loadFromReaders(
     ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
@@ -1046,13 +1046,13 @@ class CoverageMapping {
                    &ProfileReader,
                CoverageMapping &Coverage, bool &DataFound,
                SmallVectorImpl<object::BuildID> *FoundBinaryIDs = nullptr, StringRef ObjectFilename = "", 
-                bool ShowArchExecutables = false);
+                bool ShowArchExecutables = false, bool MergeBinaryCoverage = false);
 
   /// Add a function record corresponding to \p Record.
   Error loadFunctionRecord(
       const CoverageMappingRecord &Record,
       const std::optional<std::reference_wrapper<IndexedInstrProfReader>>
-          &ProfileReader, StringRef ObjectFilename = "", bool ShowArchExecutables = false);
+          &ProfileReader, StringRef ObjectFilename = "", bool ShowArchExecutables = false, bool MergeBinaryCoverage = false);
   
   Error loadFunctionRecord(const CoverageMappingRecord &Record, 
     const std::optional<std::reference_wrapper<IndexedInstrProfReader>> &ProfileReader, 
@@ -1090,7 +1090,7 @@ class CoverageMapping {
        std::optional<StringRef> ProfileFilename, vfs::FileSystem &FS,
        ArrayRef<StringRef> Arches = {}, StringRef CompilationDir = "",
        const object::BuildIDFetcher *BIDFetcher = nullptr,
-       bool CheckBinaryIDs = false, bool ShowArchExecutables = false);
+       bool CheckBinaryIDs = false, bool ShowArchExecutables = false, bool MergeBinaryCoverage = false);
 
   /// The number of functions that couldn't have their profiles mapped.
   ///
@@ -1115,7 +1115,7 @@ class CoverageMapping {
   /// The given filename must be the name as recorded in the coverage
   /// information. That is, only names returned from getUniqueSourceFiles will
   /// yield a result.
-  LLVM_ABI CoverageData getCoverageForFile(StringRef Filename, bool ShowArchExecutables = false) const;
+  LLVM_ABI CoverageData getCoverageForFile(StringRef Filename, bool ShowArchExecutables = false, bool MergeBinaryCoverage = false) const;
 
   /// Get the coverage for a particular function.
   LLVM_ABI CoverageData
@@ -1280,9 +1280,9 @@ uint64_t getFuncNameRef(const FuncRecordTy *Record) {
 /// a hash.
 template <class FuncRecordTy, llvm::endianness Endian>
 Error getFuncNameViaRef(const FuncRecordTy *Record,
-                        InstrProfSymtab &ProfileNames, StringRef &FuncName, StringRef Arch = "") {
+                        InstrProfSymtab &ProfileNames, StringRef &FuncName, StringRef ObjectFilename = "") {
   uint64_t NameRef = getFuncNameRef<FuncRecordTy, Endian>(Record);
-  ProfileNames.setArchitecture(Arch.str());
+  ProfileNames.setObjectFilename(ObjectFilename);
   FuncName = ProfileNames.getFuncOrVarName(NameRef);
   return Error::success();
 }
@@ -1425,9 +1425,9 @@ struct CovMapFunctionRecordV3 {
   }
 
   template <llvm::endianness Endian>
-  Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName, StringRef Arch = "") const {
+  Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName, StringRef ObjectFilename = "") const {
     return accessors::getFuncNameViaRef<ThisT, Endian>(this, ProfileNames,
-                                                       FuncName, Arch);
+                                                       FuncName, ObjectFilename);
   }
 
   /// Get the filename set reference.
diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h
index 7cf09e29f2145..45f2f86dc75a3 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h
@@ -40,11 +40,16 @@ struct CoverageMappingRecord {
   ArrayRef<CounterExpression> Expressions;
   ArrayRef<CounterMappingRegion> MappingRegions;
   StringRef Arch;
+  StringRef ObjectFilename;
 
   const StringRef &getArchitecture() const { return Arch; }
   void setArchitecture(StringRef NewArch){
     Arch = StringRef(NewArch);
   }
+  const StringRef &getObjectFilename() const { return ObjectFilename; }
+  void setObjectFilename(StringRef ObjectFilename){
+    this->ObjectFilename = StringRef(ObjectFilename);
+  }
 };
 
 /// A file format agnostic iterator over coverage mapping data.
@@ -223,14 +228,14 @@ class LLVM_ABI BinaryCoverageReader : public CoverageMappingReader {
   create(MemoryBufferRef ObjectBuffer, StringRef Arch,
          SmallVectorImpl<std::unique_ptr<MemoryBuffer>> &ObjectFileBuffers,
          StringRef CompilationDir = "",
-         SmallVectorImpl<object::BuildIDRef> *BinaryIDs = nullptr);
+         SmallVectorImpl<object::BuildIDRef> *BinaryIDs = nullptr, StringRef ObjectFilename = "");
 
   static Expected<std::unique_ptr<BinaryCoverageReader>>
   createCoverageReaderFromBuffer(
       StringRef Coverage, FuncRecordsStorage &&FuncRecords,
       CoverageMapCopyStorage &&CoverageMap,
       std::unique_ptr<InstrProfSymtab> ProfileNamesPtr, uint8_t BytesInAddress,
-      llvm::endianness Endian, StringRef CompilationDir = "", StringRef Arch = "");
+      llvm::endianness Endian, StringRef CompilationDir = "", StringRef Arch = "", StringRef ObjectFilename = "");
 
   Error readNextRecord(CoverageMappingRecord &Record) override;
 };
diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h
index 21a58ce1f14ce..c41c8323bf5fb 100644
--- a/llvm/include/llvm/ProfileData/InstrProf.h
+++ b/llvm/include/llvm/ProfileData/InstrProf.h
@@ -369,7 +369,7 @@ LLVM_ABI bool needsComdatForCounter(const GlobalObject &GV, const Module &M);
 /// InstrProf.h:getInstrProfNameSeparator). This method decodes the string and
 /// calls `NameCallback` for each substring.
 LLVM_ABI Error readAndDecodeStrings(
-    StringRef NameStrings, std::function<Error(StringRef)> NameCallback, StringRef Architecture = "");
+    StringRef NameStrings, std::function<Error(StringRef)> NameCallback, StringRef ObjectFilename = "");
 
 
 /// An enum describing the attributes of an instrumented profile.
@@ -513,12 +513,14 @@ class InstrProfSymtab {
   // suffixes that begins with "." except ".__uniq." are stripped.
   // FIXME: Unify this with `FunctionSamples::getCanonicalFnName`.
   LLVM_ABI static StringRef getCanonicalName(StringRef PGOName);
-
   //ANDRES Function
+  StringRef getObjectFilename() {return ObjectFilename;}
+  void setObjectFilename(StringRef ObjectFilename) {this->ObjectFilename = ObjectFilename;}
   StringRef getArchitecture() {return Architecture;}
-  void setArchitecture(StringRef Arch) {Architecture = Arch;}
+  void setArchitecture(StringRef Architecture) {this->Architecture = Architecture;}
   //ANDRES Function
 private:
+  StringRef ObjectFilename;
   StringRef Architecture;
   using AddrIntervalMap =
       IntervalMap<uint64_t, uint64_t, 4, IntervalMapHalfOpenInfo<uint64_t>>;
@@ -643,11 +645,12 @@ class InstrProfSymtab {
     // won't have duplicated entries in the first place.
 
     uint64_t HashValue = IndexedInstrProf::ComputeHash(SymbolName);
-    llvm::StringRef HashRef(SymbolName);
-    if(!Architecture.empty()){
-      std::string HashStr = std::to_string(HashValue);
-      std::string CombinedStr = HashStr + ":" + Architecture.str();
-      HashRef = CombinedStr;
+    std::string HashStr(std::to_string(HashValue));
+    // llvm::errs() << "HELLLOOOOOOOOO" << "\n";
+    if(!ObjectFilename.empty()){
+      std::string CombinedStr = HashStr + ":" + ObjectFilename.str();
+      llvm::errs() << CombinedStr << "\n";
+      StringRef HashRef = CombinedStr;
       HashValue = IndexedInstrProf::ComputeHash(HashRef);
     }
     auto Ins = NameTab.insert(SymbolName);
@@ -655,8 +658,6 @@ class InstrProfSymtab {
       MD5NameMap.push_back(std::make_pair(HashValue /*IndexedInstrProf::ComputeHash(HashRef)*/, Ins.first->getKey()));
       Sorted = false;
     }
-    for(int I = 0; I < int(MD5NameMap.size()); ++I){
-    }
     return Error::success();
   }
 
@@ -784,19 +785,20 @@ StringRef InstrProfSymtab::getFuncOrVarNameIfDefined(uint64_t MD5Hash) {
 StringRef InstrProfSymtab::getFuncOrVarName(uint64_t MD5Hash) {
   finalizeSymtab();
   std::string TempMD5HashStr = std::to_string(MD5Hash);
-  if(!Architecture.empty()){
-    std::string CombinedHashStr = TempMD5HashStr + ":" + Architecture.str();
+  if(!ObjectFilename.empty()){
+    std::string CombinedHashStr = TempMD5HashStr + ":" + ObjectFilename.str();
     llvm::StringRef CombinedHashRef(CombinedHashStr);
     MD5Hash = IndexedInstrProf::ComputeHash(CombinedHashRef);
   }
   auto Result = llvm::lower_bound(MD5NameMap, MD5Hash, [](const std::pair<uint64_t, StringRef> &LHS, uint64_t RHS) { return LHS.first < RHS; });
 
-  // for(auto name : MD5NameMap){
-  //   llvm::errs() << "Function Name " << name.second  << " Result->first: " << name.first << "\n";
-  // }
-  // llvm::errs() << "Function Name " << Result->second  << " Result->first: " << Result->first << " vs. " << MD5Hash << "\n";
+  for(auto name : MD5NameMap){
+    llvm::errs() << "Function Name " << name.second  << " Result->first: " << name.first << "\n";
+  }
+  llvm::errs() << "Function Name " << Result->second  << " Result->first: " << Result->first << " vs. " << MD5Hash << "\n";
   if (Result != MD5NameMap.end() && Result->first == MD5Hash)
     return Result->second;
+  llvm::errs() << "MISMATCH HERE" << "\n";
   return StringRef();
 }
 
diff --git a/llvm/include/llvm/ProfileData/InstrProfReader.h b/llvm/include/llvm/ProfileData/InstrProfReader.h
index e2ed1cb8cf399..db80731037887 100644
--- a/llvm/include/llvm/ProfileData/InstrProfReader.h
+++ b/llvm/include/llvm/ProfileData/InstrProfReader.h
@@ -162,8 +162,8 @@ class InstrProfReader {
   LLVM_ABI void accumulateCounts(CountSumOrPercent &Sum, bool IsCS);
 
 protected:
-  //ANDRES Storing Architecture Information as a string
-  std::string Architecture;
+  //ANDRES Storing ObjectFilename Information as a string
+  std::string ObjectFilename;
 
   std::unique_ptr<InstrProfSymtab> Symtab;
   /// A list of temporal profile traces.
@@ -213,7 +213,7 @@ class InstrProfReader {
       const object::BuildIDFetcher *BIDFetcher = nullptr,
       const InstrProfCorrelator::ProfCorrelatorKind BIDFetcherCorrelatorKind =
           InstrProfCorrelator::ProfCorrelatorKind::NONE,
-      std::function<void(Error)> Warn = nullptr, StringRef Architecture = "");
+      std::function<void(Error)> Warn = nullptr, StringRef ObjectFilename = "");
 
   LLVM_ABI static Expected<std::unique_ptr<InstrProfReader>> create(
       std::unique_ptr<MemoryBuffer> Buffer,
@@ -221,11 +221,11 @@ class InstrProfReader {
       const object::BuildIDFetcher *BIDFetcher = nullptr,
       const InstrProfCorrelator::ProfCorrelatorKind BIDFetcherCorrelatorKind =
           InstrProfCorrelator::ProfCorrelatorKind::NONE,
-      std::function<void(Error)> Warn = nullptr, StringRef Architecture = "");
+      std::function<void(Error)> Warn = nullptr, StringRef ObjectFilename = "");
   
-  StringRef getArchitecture() {return Architecture;}
+  StringRef getObjectFilename() {return ObjectFilename;}
 
-  void setArchitecture(StringRef Arch) {Architecture = Arch;}
+  void setObjectFilename(StringRef ObjectFilename) {this->ObjectFilename = ObjectFilename;}
   /// \param Weight for raw profiles use this as the temporal profile trace
   ///               weight
   /// \returns a list of temporal profile traces.
@@ -877,7 +877,7 @@ class LLVM_ABI IndexedInstrProfReader : public InstrProfReader {
 
   static Expected<std::unique_ptr<IndexedInstrProfReader>>
   create(const Twine &Path, vfs::FileSystem &FS,
-        const std::string &Arch, const Twine &RemappingPath = "");
+        const std::string &ObjectFilename, const Twine &RemappingPath = "");
 
   static Expected<std::unique_ptr<IndexedInstrProfReader>>
   create(std::unique_ptr<MemoryBuffer> Buffer,
diff --git a/llvm/include/llvm/ProfileData/InstrProfWriter.h b/llvm/include/llvm/ProfileData/InstrProfWriter.h
index 77c93c537f468..5ba07991f0f48 100644
--- a/llvm/include/llvm/ProfileData/InstrProfWriter.h
+++ b/llvm/include/llvm/ProfileData/InstrProfWriter.h
@@ -113,7 +113,7 @@ class InstrProfWriter {
   /// for this function and the hash and number of counts match, each counter is
   /// summed. Optionally scale counts by \p Weight.
   LLVM_ABI void addRecord(NamedInstrProfRecord &&I, uint64_t Weight,
-                          function_ref<void(Error)> Warn, StringRef Architecture = "");
+                          function_ref<void(Error)> Warn, StringRef ObjectFilename = "");
   // void addRecord(NamedInstrProfRecord &&I, uint64_t Weight, function_ref<void(Error)> Warn);
   void addRecord(NamedInstrProfRecord &&I, function_ref<void(Error)> Warn) {
     addRecord(std::move(I), 1, Warn);
@@ -225,7 +225,7 @@ class InstrProfWriter {
 
 private:
   void addRecord(StringRef Name, uint64_t Hash, InstrProfRecord &&I,
-                 uint64_t Weight, function_ref<void(Error)> Warn, StringRef Architecture = "");
+                 uint64_t Weight, function_ref<void(Error)> Warn, StringRef ObjectFilename = "");
   bool shouldEncodeData(const ProfilingData &PD);
   /// Add \p Trace using reservoir sampling.
   void addTemporalProfileTrace(TemporalProfTraceTy Trace);
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 6248c202ec6ff..cac35b29e8aec 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -979,7 +979,7 @@ class MCDCDecisionRecorder {
 Error CoverageMapping::loadFunctionRecord(
     const CoverageMappingRecord &Record,
     const std::optional<std::reference_wrapper<IndexedInstrProfReader>>
-        &ProfileReader, StringRef ObjectFilename, bool ShowArchExecutables) {
+        &ProfileReader, StringRef ObjectFilename, bool ShowArchExecutables, bool MergeBinaryCoverage) {
   StringRef OrigFuncName = Record.FunctionName;
   if (OrigFuncName.empty())
     return make_error<CoverageMapError>(coveragemap_error::malformed,
@@ -993,12 +993,11 @@ Error CoverageMapping::loadFunctionRecord(
   CounterMappingContext Ctx(Record.Expressions);
 
   uint64_t FuncArchHash = Record.FunctionHash;
-  if(!Arch.empty()){
+  if(!ObjectFilename.empty() && MergeBinaryCoverage){
     std::string HashStr = std::to_string(Record.FunctionHash) + ":" + ObjectFilename.str();
     llvm::StringRef HashRef(HashStr);
     FuncArchHash = IndexedInstrProf::ComputeHash(HashRef);
   }
-
   std::vector<uint64_t> Counts;
   if (ProfileReader) {
     if (Error E = ProfileReader.value().get().getFunctionCounts(Record.FunctionName, FuncArchHash, Counts)) {
@@ -1103,20 +1102,15 @@ Error CoverageMapping::loadFunctionRecord(
     Function.pushMCDCRecord(std::move(*Record));
   }
 
-  //CHANGES MADE HERE
   auto FilenamesHash = hash_combine_range(Record.Filenames);
   std::string HashStr = OrigFuncName.str();
   if(ShowArchExecutables){
     HashStr += ":" + Arch.str();
   }else{
-    //THIS ALGORITHM NEEDS TO BE FIXED!!!
     auto LogicalFuncKey = std::make_pair(FilenamesHash, hash_value(OrigFuncName));
     auto It = RecordIndices.find(LogicalFuncKey);
-
     if (It != RecordIndices.end()) {
       auto &ExistingFunction = Functions[It->second];
-
-
       // Create a map of existing regions for efficient lookup.
       // The key uniquely identifies the source region.
       using RegionKey = std::tuple<unsigned, unsigned, unsigned, unsigned, unsigned>;
@@ -1127,11 +1121,9 @@ Error CoverageMapping::loadFunctionRecord(
                          ExistingRegion.ColumnEnd};
         ExistingRegionsMap[Key] = &ExistingRegion;
       }
-
       for (auto NewRegion : Function.CountedRegions) {
         AllFunctionRegions[It->second].CountedRegions.push_back(NewRegion);
       }
-
       // Merge the new regions into the existing function's regions.
       for (const auto &NewRegion : Function.CountedRegions) {
         RegionKey Key = {NewRegion.FileID, NewRegion.LineStart,
@@ -1141,14 +1133,8 @@ Error CoverageMapping::loadFunctionRecord(
         if (MapIt != ExistingRegionsMap.end()) {
           // Region already exists, merge counts by taking the max.
           CountedRegion *ExistingRegion = MapIt->second;
-          // llvm::errs() << "EXECUTION COUNTS BEFORE: " +  to_string(ExistingRegion->ExecutionCount) << "\n";
-          // llvm::errs() << "(" << ExistingRegion->LineStart << ", " << ExistingRegion->LineEnd << ")" << "\n";
           ExistingRegion->ExecutionCount += NewRegion.ExecutionCount;
-          // llvm::errs() << "EXECUTION COUNTS AFTER: " +  to_string(ExistingRegion->ExecutionCount) << "\n";
-          // DebugCount++;
         } else {
-          // llvm::errs() << "ENTERS ELSE STATEMENT HERE" << "\n";
-          // llvm::errs() << "(" << NewRegion.LineStart << ", " << NewRegion.LineEnd << ")" << "\n";
           ExistingFunction.CountedRegions.push_back(NewRegion);
         }
       }
@@ -1157,18 +1143,8 @@ Error CoverageMapping::loadFunctionRecord(
       // The logic below this block needs to be adjusted to handle this.
       return Error::success();
     }
-    // llvm::errs() << "ENTERS ELSE STATEMENT HERE" << "\n";
     RecordIndices.insert({LogicalFuncKey, Functions.size()});
-    //THIS ALGORITHM NEEDS TO BE FIXED!!!
   }
-  //CHANGES MADE HERE
-
-  // if(DebugCount == 29){
-  //   llvm::errs() << "ENTERS ELSE STATEMENT HERE" << "\n";
-  // }
-
-
-
   // Don't create records for (filenames, function) pairs we've already seen.
   StringRef Hash(HashStr);
   if (!RecordProvenance[FilenamesHash].insert(hash_value(Hash)).second){
@@ -1222,9 +1198,9 @@ Error CoverageMapping::loadFromReaders(
     ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
     std::optional<std::reference_wrapper<IndexedInstrProfReader>>
         &ProfileReader,
-    CoverageMapping &Coverage, StringRef Arch, StringRef ObjectFilename, bool ShowArchExecutables) {
+    CoverageMapping &Coverage, StringRef Arch, StringRef ObjectFilename, bool ShowArchExecutables, bool MergeBinaryCoverage) {
   
-  Coverage.setArchitecture(Arch);
+  // Coverage.setArchitecture(Arch);
   assert(!Coverage.SingleByteCoverage || !ProfileReader ||
          *Coverage.SingleByteCoverage ==
              ProfileReader.value().get().hasSingleByteCoverage());
@@ -1235,7 +1211,7 @@ Error CoverageMapping::loadFromReaders(
       if (Error E = RecordOrErr.takeError())
         return E;
       const auto &Record = *RecordOrErr;
-      if (Error E = Coverage.loadFunctionRecord(Record, ProfileReader, ObjectFilename, ShowArchExecutables))
+      if (Error E = Coverage.loadFunctionRecord(Record, ProfileReader, ObjectFilename, ShowArchExecutables, MergeBinaryCoverage))
         return E;
     }
   }
@@ -1266,7 +1242,7 @@ Error CoverageMapping::loadFromFile(
     std::optional<std::reference_wrapper<IndexedInstrProfReader>>
         &ProfileReader,
     CoverageMapping &Coverage, bool &DataFound,
-    SmallVectorImpl<object::BuildID> *FoundBinaryIDs, StringRef ObjectFilename, bool ShowArchExecutables) {
+    SmallVectorImpl<object::BuildID> *FoundBinaryIDs, StringRef ObjectFilename, bool ShowArchExecutables, bool MergeBinaryCoverage) {
   auto CovMappingBufOrErr = MemoryBuffer::getFileOrSTDIN(
       Filename, /*IsText=*/false, /*RequiresNullTerminator=*/false);
   if (std::error_code EC = CovMappingBufOrErr.getError())
@@ -1280,7 +1256,7 @@ Error CoverageMapping::loadFromFile(
   SmallVector<object::BuildIDRef> BinaryIDs;
   auto CoverageReadersOrErr = BinaryCoverageReader::create(
       CovMappingBufRef, Arch, Buffers, CompilationDir,
-      FoundBinaryIDs ? &BinaryIDs : nullptr);
+      FoundBinaryIDs ? &BinaryIDs : nullptr, ObjectFilename);
   if (Error E = CoverageReadersOrErr.takeError()) {
     E = handleMaybeNoDataFoundError(std::move(E));
     if (E)
@@ -1298,7 +1274,7 @@ Error CoverageMapping::loadFromFile(
                        }));
   }
   DataFound |= !Readers.empty();
-  if (Error E = loadFromReaders(Readers, ProfileReader, Coverage, Arch, ObjectFilename, ShowArchExecutables))
+  if (Error E = loadFromReaders(Readers, ProfileReader, Coverage, Arch, ObjectFilename, ShowArchExecutables, MergeBinaryCoverage))
     return createFileError(Filename, std::move(E));
   return Error::success();
 }
@@ -1307,7 +1283,7 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
     ArrayRef<StringRef> ObjectFilenames,
     std::optional<StringRef> ProfileFilename, vfs::FileSystem &FS,
     ArrayRef<StringRef> Arches, StringRef CompilationDir,
-    const object::BuildIDFetcher *BIDFetcher, bool CheckBinaryIDs, bool ShowArchExecutables) {
+    const object::BuildIDFetcher *BIDFetcher, bool CheckBinaryIDs, bool ShowArchExecutables, bool MergeBinaryCoverage) {
   std::unique_ptr<IndexedInstrProfReader> ProfileReader;
   if (ProfileFilename) {
     auto ProfileReaderOrErr =
@@ -1339,8 +1315,8 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
   for (const auto &File : llvm::enumerate(ObjectFilenames)) {
     if (Error E = loadFromFile(File.value(), GetArch(File.index()),
                                CompilationDir, ProfileReaderRef, *Coverage,
-                               DataFound, &FoundBinaryIDs, ObjectFilenames[File.index()], 
-                               ShowArchExecutables))
+                               DataFound, &FoundBinaryIDs, MergeBinaryCoverage ? ObjectFilenames[File.index()] : "", 
+                               ShowArchExecutables, MergeBinaryCoverage))
       return std::move(E);
   }
 
@@ -1632,59 +1608,6 @@ class SegmentBuilder {
 
     sortNestedRegions(Regions);
 
-    // // This map is used to efficiently check for the existence of a specific region
-    // // from a specific binary, which is the purpose of the innermost loop in the
-    // // original code.
-    // // Key: A tuple uniquely identifying a region's location and its binary of origin.
-    // // Value: A boolean indicating if the region is NOT a SkippedRegion.
-    // using RegionKey = std::tuple<LineColPair, LineColPair, StringRef>;
-    // std::map<RegionKey, bool> RegionExistenceMap;
-    // for (const auto &R : Regions) {
-    //   RegionKey Key = {R.startLoc(), R.endLoc(), R.ObjectFilename};
-    //   // Only insert if it's a more "valid" region than what might already be there.
-    //   if (R.Kind != CounterMappingRegion::SkippedRegion)
-    //     RegionExistenceMap[Key] = true;
-    //   else
-    //     RegionExistenceMap.try_emplace(Key, false);
-    // }
-
-    // for (auto &I : Regions) {
-    //   // We are only interested in patching SkippedRegions.
-    //   if (I.Kind != CounterMappingRegion::SkippedRegion)
-    //     continue;
-
-    //   for (auto &J : Regions) {
-    //     // Find a non-skipped region 'J' from a different binary that contains 'I'.
-    //     if (I.ObjectFilename == J.ObjectFilename ||
-    //         J.Kind == CounterMappingRegion::SkippedRegion ||
-    //         !(I.startLoc() >= J.startLoc() && I.endLoc() <= J.endLoc())) {
-    //       continue;
-    //     }
-
-    //     // Check if a non-skipped region already exists at I's exact location
-    //     // coming from J's binary. This replaces the O(N) inner loop.
-    //     RegionKey KeyToFind = {I.startLoc(), I.endLoc(), J.ObjectFilename};
-    //     auto It = RegionExistenceMap.find(KeyToFind);
-
-    //     // If no region from J's binary exists at I's location, or if it does
-    //     // but it's a SkippedRegion, we can patch I with J's data.
-    //     if (It == RegionExistenceMap.end() || It->second == false) {
-    //       I.Kind = J.Kind;
-    //       I.ExecutionCount = J.ExecutionCount;
-    //       // We found a patch, no need to check other containing regions.
-    //       break;
-    //     }
-    //   }
-    // }
-
-    // llvm::errs() << "START HERE" << "\n";
-    // for(auto *I = Regions.begin(); I != Regions.end(); ++I){
-    //   llvm::errs() << "(" << to_string(I->startLoc().first) << ", " << to_string(I->endLoc().first) << ")" << "\n";
-    //   llvm::errs() << "Execution Count: " << I->ExecutionCount << "\n";
-    // }
-    // llvm::errs() << "END HERE" << "\n";
-
-
     for(auto *I = Regions.begin(); I != Regions.end(); ++I){
       bool FoundMatchInOtherBinary = false;
       for(auto *J = I + 1; J != Regions.end(); ++J){
@@ -1706,13 +1629,6 @@ class SegmentBuilder {
         }
       }
     }
-
-    // llvm::errs() << "START HERE" << "\n";
-    // for(auto *I = Regions.begin(); I != Regions.end(); ++I){
-    //   llvm::errs() << "(" << to_string(I->startLoc().first) << ", " << to_string(I->endLoc().first) << ")" << "\n";
-    //   llvm::errs() << "Execution Count: " << I->ExecutionCount << "\n";
-    // }
-    // llvm::errs() << "END HERE" << "\n";
     
 
     ArrayRef<CountedRegion> CombinedRegions = combineRegions(Regions);
@@ -1800,7 +1716,7 @@ static bool isExpansion(const CountedRegion &R, unsigned FileID) {
   return R.Kind == CounterMappingRegion::ExpansionRegion && R.FileID == FileID;
 }
 
-CoverageData CoverageMapping::getCoverageForFile(StringRef Filename, bool ShowArchExecutables) const {
+CoverageData CoverageMapping::getCoverageForFile(StringRef Filename, bool ShowArchExecutables, bool MergeBinaryCoverage) const {
   assert(SingleByteCoverage);
   CoverageData FileCoverage(*SingleByteCoverage, Filename);
   std::vector<CountedRegion> Regions;
@@ -1819,7 +1735,7 @@ CoverageData CoverageMapping::getCoverageForFile(StringRef Filename, bool ShowAr
   // ArrayRef<unsigned> RecordIndices =
   //     getImpreciseRecordIndicesForFilename(Filename);
   for (unsigned RecordIndex : RecordIndices) {
-    const FunctionRecord &Function = ShowArchExecutables ? Functions[RecordIndex] : AllFunctionRegions[RecordIndex];
+    const FunctionRecord &Function = !MergeBinaryCoverage ? Functions[RecordIndex] : AllFunctionRegions[RecordIndex];
     auto MainFileID = findMainViewFileID(Filename, Function);
     auto FileIDs = gatherFileIDs(Filename, Function);
     for (const auto &CR : Function.CountedRegions)
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
index 1c79ffab66b05..aaf11e451cc26 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
@@ -578,13 +578,13 @@ struct CovMapFuncRecordReader {
   readFunctionRecords(const char *FuncRecBuf, const char *FuncRecBufEnd,
                       std::optional<FilenameRange> OutOfLineFileRange,
                       const char *OutOfLineMappingBuf,
-                      const char *OutOfLineMappingBufEnd, StringRef Arch = "") = 0;
+                      const char *OutOfLineMappingBufEnd, StringRef Arch = "", StringRef ObjectFilename = "") = 0;
 
   template <class IntPtrT, llvm::endianness Endian>
   static Expected<std::unique_ptr<CovMapFuncRecordReader>>
   get(CovMapVersion Version, InstrProfSymtab &P,
       std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, StringRef D,
-      std::vector<std::string> &F, StringRef Arch = "");
+      std::vector<std::string> &F, StringRef Arch = "", StringRef ObjectFilename = "");
 };
 
 // A class for reading coverage mapping function records for a module.
@@ -614,7 +614,7 @@ class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader {
   // not used in the corresponding translation unit.
   Error insertFunctionRecordIfNeeded(const FuncRecordType *CFR,
                                      StringRef Mapping,
-                                     FilenameRange FileRange, StringRef Arch = "") {
+                                     FilenameRange FileRange, StringRef Arch = "", StringRef ObjectFilename = "") {
     ++CovMapNumRecords;
     uint64_t FuncHash = CFR->template getFuncHash<Endian>();
     NameRefType NameRef = CFR->template getFuncNameRef<Endian>();
@@ -622,7 +622,7 @@ class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader {
         FunctionRecords.insert(std::make_pair(NameRef, Records.size()));
     if (InsertResult.second) {
       StringRef FuncName;
-      if (Error Err = CFR->template getFuncName<Endian>(ProfileNames, FuncName, Arch))
+      if (Error Err = CFR->template getFuncName<Endian>(ProfileNames, FuncName, ObjectFilename))
         return Err;
       if (FuncName.empty())
         return make_error<InstrProfError>(instrprof_error::malformed,
@@ -761,7 +761,7 @@ class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader {
   Error readFunctionRecords(const char *FuncRecBuf, const char *FuncRecBufEnd,
                             std::optional<FilenameRange> OutOfLineFileRange,
                             const char *OutOfLineMappingBuf,
-                            const char *OutOfLineMappingBufEnd, StringRef Arch = "") override {
+                            const char *OutOfLineMappingBufEnd, StringRef Arch = "", StringRef ObjectFilename = "") override {
     auto CFR = reinterpret_cast<const FuncRecordType *>(FuncRecBuf);
     while ((const char *)CFR < FuncRecBufEnd) {
       // Validate the length of the coverage mapping for this function.
@@ -800,7 +800,7 @@ class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader {
           return make_error<CoverageMapError>(
               coveragemap_error::malformed,
               "coverage mapping data is larger than buffer size");
-        if (Error Err = insertFunctionRecordIfNeeded(CFR, Mapping, *FileRange, Arch))
+        if (Error Err = insertFunctionRecordIfNeeded(CFR, Mapping, *FileRange, Arch, ObjectFilename))
           return Err;
       }
 
@@ -816,7 +816,7 @@ template <class IntPtrT, llvm::endianness Endian>
 Expected<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get(
     CovMapVersion Version, InstrProfSymtab &P,
     std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, StringRef D,
-    std::vector<std::string> &F, StringRef Arch) {
+    std::vector<std::string> &F, StringRef Arch, StringRef ObjectFilename) {
   using namespace coverage;
 
   switch (Version) {
@@ -829,8 +829,8 @@ Expected<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get(
   case CovMapVersion::Version5:
   case CovMapVersion::Version6:
   case CovMapVersion::Version7:
+    P.setObjectFilename(ObjectFilename);
     // Decompress the name data.
-    P.setArchitecture(Arch.str());
     if (Error E = P.create(P.getNameData()))
       return std::move(E);
     if (Version == CovMapVersion::Version2)
@@ -859,7 +859,7 @@ template <typename T, llvm::endianness Endian>
 static Error readCoverageMappingData(
     InstrProfSymtab &ProfileNames, StringRef CovMap, StringRef FuncRecords,
     std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records,
-    StringRef CompilationDir, std::vector<std::string> &Filenames, StringRef Arch = "") {
+    StringRef CompilationDir, std::vector<std::string> &Filenames, StringRef Arch = "", StringRef ObjectFilename = "") {
   using namespace coverage;
 
   // Read the records in the coverage data section.
@@ -870,7 +870,7 @@ static Error readCoverageMappingData(
     return make_error<CoverageMapError>(coveragemap_error::unsupported_version);
   Expected<std::unique_ptr<CovMapFuncRecordReader>> ReaderExpected =
       CovMapFuncRecordReader::get<T, Endian>(Version, ProfileNames, Records,
-                                             CompilationDir, Filenames, Arch);
+                                             CompilationDir, Filenames, Arch, ObjectFilename);
   if (Error E = ReaderExpected.takeError())
     return E;
   auto Reader = std::move(ReaderExpected.get());
@@ -894,7 +894,7 @@ static Error readCoverageMappingData(
   // the records from their dedicated section.
   if (Version >= CovMapVersion::Version4)
     return Reader->readFunctionRecords(FuncRecBuf, FuncRecBufEnd, std::nullopt,
-                                       nullptr, nullptr, Arch);
+                                       nullptr, nullptr, Arch, ObjectFilename);
   return Error::success();
 }
 
@@ -903,7 +903,7 @@ BinaryCoverageReader::createCoverageReaderFromBuffer(
     StringRef Coverage, FuncRecordsStorage &&FuncRecords,
     CoverageMapCopyStorage &&CoverageMap,
     std::unique_ptr<InstrProfSymtab> ProfileNamesPtr, uint8_t BytesInAddress,
-    llvm::endianness Endian, StringRef CompilationDir, StringRef Arch) {
+    llvm::endianness Endian, StringRef CompilationDir, StringRef Arch, StringRef ObjectFilename) {
   if (ProfileNamesPtr == nullptr)
     return make_error<CoverageMapError>(coveragemap_error::malformed,
                                         "Caller must provide ProfileNames");
@@ -915,22 +915,22 @@ BinaryCoverageReader::createCoverageReaderFromBuffer(
   if (BytesInAddress == 4 && Endian == llvm::endianness::little) {
     if (Error E = readCoverageMappingData<uint32_t, llvm::endianness::little>(
             ProfileNames, Coverage, FuncRecordsRef, Reader->MappingRecords,
-            CompilationDir, Reader->Filenames, Arch))
+            CompilationDir, Reader->Filenames, Arch, ObjectFilename))
       return std::move(E);
   } else if (BytesInAddress == 4 && Endian == llvm::endianness::big) {
     if (Error E = readCoverageMappingData<uint32_t, llvm::endianness::big>(
             ProfileNames, Coverage, FuncRecordsRef, Reader->MappingRecords,
-            CompilationDir, Reader->Filenames, Arch))
+            CompilationDir, Reader->Filenames, Arch, ObjectFilename))
       return std::move(E);
   } else if (BytesInAddress == 8 && Endian == llvm::endianness::little) {
     if (Error E = readCoverageMappingData<uint64_t, llvm::endianness::little>(
             ProfileNames, Coverage, FuncRecordsRef, Reader->MappingRecords,
-            CompilationDir, Reader->Filenames, Arch))
+            CompilationDir, Reader->Filenames, Arch, ObjectFilename))
       return std::move(E);
   } else if (BytesInAddress == 8 && Endian == llvm::endianness::big) {
     if (Error E = readCoverageMappingData<uint64_t, llvm::endianness::big>(
             ProfileNames, Coverage, FuncRecordsRef, Reader->MappingRecords,
-            CompilationDir, Reader->Filenames, Arch))
+            CompilationDir, Reader->Filenames, Arch,ObjectFilename))
       return std::move(E);
   } else
     return make_error<CoverageMapError>(
@@ -1137,7 +1137,7 @@ lookupAllocatableSection(ObjectFile &OF, InstrProfSectKind IPSK) {
 static Expected<std::unique_ptr<BinaryCoverageReader>>
 loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch,
                  StringRef CompilationDir = "",
-                 object::BuildIDRef *BinaryID = nullptr) {
+                 object::BuildIDRef *BinaryID = nullptr, StringRef ObjectFilename = "") {
   std::unique_ptr<ObjectFile> OF;
   if (auto *Universal = dyn_cast<MachOUniversalBinary>(Bin.get())) {
     // If we have a universal binary, try to look up the object for the
@@ -1250,7 +1250,7 @@ loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch,
 
   return BinaryCoverageReader::createCoverageReaderFromBuffer(
       CoverageMapping, std::move(FuncRecords), std::move(CoverageMapCopy),
-      std::move(ProfileNames), BytesInAddress, Endian, CompilationDir, Arch);
+      std::move(ProfileNames), BytesInAddress, Endian, CompilationDir, Arch, ObjectFilename);
 }
 
 /// Determine whether \p Arch is invalid or empty, given \p Bin.
@@ -1270,7 +1270,7 @@ Expected<std::vector<std::unique_ptr<BinaryCoverageReader>>>
 BinaryCoverageReader::create(
     MemoryBufferRef ObjectBuffer, StringRef Arch,
     SmallVectorImpl<std::unique_ptr<MemoryBuffer>> &ObjectFileBuffers,
-    StringRef CompilationDir, SmallVectorImpl<object::BuildIDRef> *BinaryIDs) {
+    StringRef CompilationDir, SmallVectorImpl<object::BuildIDRef> *BinaryIDs, StringRef ObjectFilename) {
   std::vector<std::unique_ptr<BinaryCoverageReader>> Readers;
 
   if (ObjectBuffer.getBuffer().size() > sizeof(TestingFormatMagic)) {
@@ -1350,7 +1350,7 @@ BinaryCoverageReader::create(
 
   object::BuildIDRef BinaryID;
   auto ReaderOrErr = loadBinaryFormat(std::move(Bin), Arch, CompilationDir,
-                                      BinaryIDs ? &BinaryID : nullptr);
+                                      BinaryIDs ? &BinaryID : nullptr, ObjectFilename);
   if (!ReaderOrErr)
     return ReaderOrErr.takeError();
   Readers.push_back(std::move(ReaderOrErr.get()));
diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp
index 8fda78bd26802..404e5177980d6 100644
--- a/llvm/lib/ProfileData/InstrProf.cpp
+++ b/llvm/lib/ProfileData/InstrProf.cpp
@@ -618,7 +618,7 @@ Error InstrProfSymtab::addVTableWithName(GlobalVariable &VTable,
 // }
 
 Error readAndDecodeStrings(StringRef NameStrings,
-                           std::function<Error(StringRef)> NameCallback, StringRef Architecture) {
+                           std::function<Error(StringRef)> NameCallback, StringRef ObjectFilename) {
   const uint8_t *P = NameStrings.bytes_begin();
   const uint8_t *EndP = NameStrings.bytes_end();
   while (P < EndP) {
@@ -660,8 +660,8 @@ Error readAndDecodeStrings(StringRef NameStrings,
 }
 
 Error InstrProfSymtab::create(StringRef NameStrings) {
-  StringRef Architecture = getArchitecture();
-  return readAndDecodeStrings(NameStrings, std::bind(&InstrProfSymtab::addFuncName, this, std::placeholders::_1), Architecture);
+  StringRef ObjectFilename = getObjectFilename();
+  return readAndDecodeStrings(NameStrings, std::bind(&InstrProfSymtab::addFuncName, this, std::placeholders::_1), ObjectFilename);
 }
 
 Error InstrProfSymtab::create(StringRef FuncNameStrings,
diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp
index b8a1397f323b2..d4f70ecb247a0 100644
--- a/llvm/lib/ProfileData/InstrProfReader.cpp
+++ b/llvm/lib/ProfileData/InstrProfReader.cpp
@@ -160,20 +160,20 @@ Expected<std::unique_ptr<InstrProfReader>> InstrProfReader::create( //STEP 1
     const object::BuildIDFetcher *BIDFetcher,
     const InstrProfCorrelator::ProfCorrelatorKind BIDFetcherCorrelatorKind,
     std::function<void(Error)> Warn, 
-    StringRef Architecture) {
+    StringRef ObjectFilename) {
   // Set up the buffer to read.
   auto BufferOrError = setupMemoryBuffer(Path, FS);
   if (Error E = BufferOrError.takeError())
     return std::move(E);
   return InstrProfReader::create(std::move(BufferOrError.get()), Correlator,
-                                 BIDFetcher, BIDFetcherCorrelatorKind, Warn, Architecture);
+                                 BIDFetcher, BIDFetcherCorrelatorKind, Warn, ObjectFilename);
 }
 
 Expected<std::unique_ptr<InstrProfReader>> InstrProfReader::create(
     std::unique_ptr<MemoryBuffer> Buffer, const InstrProfCorrelator *Correlator,
     const object::BuildIDFetcher *BIDFetcher,
     const InstrProfCorrelator::ProfCorrelatorKind BIDFetcherCorrelatorKind,
-    std::function<void(Error)> Warn, StringRef Architecture) {
+    std::function<void(Error)> Warn, StringRef ObjectFilename) {
   if (Buffer->getBufferSize() == 0)
     return make_error<InstrProfError>(instrprof_error::empty_raw_profile);
 
@@ -197,7 +197,7 @@ Expected<std::unique_ptr<InstrProfReader>> InstrProfReader::create(
   // Initialize the reader and return the result.
 
   if(Result){
-    Result->setArchitecture(Architecture);
+    Result->setObjectFilename(ObjectFilename);
   }
   if (Error E = initializeReader(*Result))
     return std::move(E);
@@ -228,7 +228,7 @@ IndexedInstrProfReader::create(const Twine &Path, vfs::FileSystem &FS,
 
 Expected<std::unique_ptr<IndexedInstrProfReader>>
 IndexedInstrProfReader::create(const Twine &Path, vfs::FileSystem &FS,
-                               const std::string &Arch, const Twine &RemappingPath) {
+                               const std::string &ObjectFilename, const Twine &RemappingPath) {
   // Set up the buffer to read.
   auto BufferOrError = setupMemoryBuffer(Path, FS);
   if (Error E = BufferOrError.takeError())
@@ -578,7 +578,7 @@ Error RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) {
 template <class IntPtrT>
 Error RawInstrProfReader<IntPtrT>::createSymtab(InstrProfSymtab &Symtab) { //STEP 5
   
-  Symtab.setArchitecture(Architecture);
+  Symtab.setObjectFilename(ObjectFilename);
   
   if (Error E = Symtab.create(StringRef(NamesStart, NamesEnd - NamesStart),
                               StringRef(VNamesStart, VNamesEnd - VNamesStart)))
diff --git a/llvm/lib/ProfileData/InstrProfWriter.cpp b/llvm/lib/ProfileData/InstrProfWriter.cpp
index 4e7cb302afc01..2c18a5c7825ad 100644
--- a/llvm/lib/ProfileData/InstrProfWriter.cpp
+++ b/llvm/lib/ProfileData/InstrProfWriter.cpp
@@ -158,10 +158,10 @@ void InstrProfWriter::setValueProfDataEndianness(llvm::endianness Endianness) {
 void InstrProfWriter::setOutputSparse(bool Sparse) { this->Sparse = Sparse; }
 
 void InstrProfWriter::addRecord(NamedInstrProfRecord &&I, uint64_t Weight,
-                                function_ref<void(Error)> Warn, StringRef Architecture) {
+                                function_ref<void(Error)> Warn, StringRef ObjectFilename) {
   auto Name = I.Name;
   auto Hash = I.Hash;
-  addRecord(Name, Hash, std::move(I), Weight, Warn, Architecture);
+  addRecord(Name, Hash, std::move(I), Weight, Warn, ObjectFilename);
 }
 
 void InstrProfWriter::overlapRecord(NamedInstrProfRecord &&Other,
@@ -252,11 +252,11 @@ StringRef hashSourceFile(llvm::StringRef FilePath) {
 
 void InstrProfWriter::addRecord(StringRef Name, uint64_t Hash,
                                 InstrProfRecord &&I, uint64_t Weight,
-                                function_ref<void(Error)> Warn, StringRef Architecture) {
+                                function_ref<void(Error)> Warn, StringRef ObjectFilename) {
   auto &ProfileDataMap = FunctionData[Name];
   // StringRef SHAHash = hashSourceFile(Architecture);
-  if(!Architecture.empty()){
-    std::string HashStr = std::to_string(Hash) + ":" + Architecture.str();
+  if(!ObjectFilename.empty()){
+    std::string HashStr = std::to_string(Hash) + ":" + ObjectFilename.str();
     llvm::StringRef HashRef(HashStr);
     Hash = IndexedInstrProf::ComputeHash(HashRef);
   }
diff --git a/llvm/test/tools/llvm-cov/universal_bin_wrapping_archives.test b/llvm/test/tools/llvm-cov/universal_bin_wrapping_archives.test
index 903dae45002ec..342edce47368b 100644
--- a/llvm/test/tools/llvm-cov/universal_bin_wrapping_archives.test
+++ b/llvm/test/tools/llvm-cov/universal_bin_wrapping_archives.test
@@ -4,7 +4,7 @@ MachO universal binaries.
 ---
 Steps to re-generate these files on macOS:
 
-clang -fprofile-instr-generate -fcoverage-mapping -c obj1.c -o obj1_32.o -arch i386
+clang -fprofile-instr-generate -fcoverage-mapping -c obj1.c -o obj1_32.o -arch=i386
 clang -fprofile-instr-generate -fcoverage-mapping -c obj2.c -o obj2_32.o -arch i386
 clang -fprofile-instr-generate -fcoverage-mapping -c obj1.c -o obj1_64.o -arch x86_64
 clang -fprofile-instr-generate -fcoverage-mapping -c obj2.c -o obj2_64.o -arch x86_64
diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp
index 1feb1f8402d38..bc273f554043e 100644
--- a/llvm/tools/llvm-cov/CodeCoverage.cpp
+++ b/llvm/tools/llvm-cov/CodeCoverage.cpp
@@ -397,7 +397,7 @@ CodeCoverageTool::createSourceFileView(StringRef SourceFile,
   auto SourceBuffer = getSourceFile(SourceFile);
   if (!SourceBuffer)
     return nullptr;
-  auto FileCoverage = Coverage.getCoverageForFile(SourceFile, ViewOpts.ShowArchExecutables);
+  auto FileCoverage = Coverage.getCoverageForFile(SourceFile, ViewOpts.ShowArchExecutables, ViewOpts.MergeBinaryCoverage);
   if (FileCoverage.empty())
     return nullptr;
 
@@ -488,7 +488,7 @@ std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
   auto CoverageOrErr = CoverageMapping::load(
       ObjectFilenames, PGOFilename, *FS, CoverageArches,
       ViewOpts.CompilationDirectory, BIDFetcher.get(), CheckBinaryIDs, 
-      ViewOpts.ShowArchExecutables);
+      ViewOpts.ShowArchExecutables, ViewOpts.MergeBinaryCoverage);
   if (Error E = CoverageOrErr.takeError()) {
     error("failed to load coverage: " + toString(std::move(E)));
     return nullptr;
@@ -830,6 +830,11 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
     "show-arch-executables",
     cl::desc("Show coverage per architecture and the associated executable slice"),
     cl::init(false));
+  
+  cl::opt<bool> MergeBinaryCoverage(
+    "merge-binary-coverage",
+    cl::desc("Enable merging of coverage profiles from binaries compiled for different architectures"),
+    cl::init(false));
 
   auto commandLineParser = [&, this](int argc, const char **argv) -> int {
     cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
@@ -997,6 +1002,7 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
     ViewOpts.NumThreads = NumThreads;
     ViewOpts.CompilationDirectory = CompilationDirectory;
     ViewOpts.ShowArchExecutables = ShowArchExecutables;
+    ViewOpts.MergeBinaryCoverage = MergeBinaryCoverage;
 
     return 0;
   };
diff --git a/llvm/tools/llvm-cov/CoverageViewOptions.h b/llvm/tools/llvm-cov/CoverageViewOptions.h
index 6129bcfb59757..ec99220558ca2 100644
--- a/llvm/tools/llvm-cov/CoverageViewOptions.h
+++ b/llvm/tools/llvm-cov/CoverageViewOptions.h
@@ -48,6 +48,7 @@ struct CoverageViewOptions {
   bool SkipBranches;
   bool BinaryCounters;
   bool ShowArchExecutables;
+  bool MergeBinaryCoverage;
   OutputFormat Format;
   BranchOutputType ShowBranches;
   std::string ShowOutputDirectory;

>From d9006f25a1b2dc7a481f0fc62db1dd1dfe5ff70b Mon Sep 17 00:00:00 2001
From: Andres Wearden <andreswearden5 at gmail.com>
Date: Wed, 30 Jul 2025 09:45:49 -0700
Subject: [PATCH 15/17] commit to push final changes

---
 llvm/include/llvm/ProfileData/InstrProf.h     |  14 +-
 .../llvm/ProfileData/InstrProfReader.h        |   2 +-
 .../ProfileData/Coverage/CoverageMapping.cpp  | 178 +-----------------
 llvm/lib/ProfileData/InstrProf.cpp            |  46 +----
 llvm/lib/ProfileData/InstrProfReader.cpp      |  10 +-
 llvm/lib/ProfileData/InstrProfWriter.cpp      |  55 +-----
 llvm/tools/llvm-profdata/llvm-profdata.cpp    |  62 +-----
 7 files changed, 17 insertions(+), 350 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h
index c41c8323bf5fb..99c3df6a2e834 100644
--- a/llvm/include/llvm/ProfileData/InstrProf.h
+++ b/llvm/include/llvm/ProfileData/InstrProf.h
@@ -513,12 +513,12 @@ class InstrProfSymtab {
   // suffixes that begins with "." except ".__uniq." are stripped.
   // FIXME: Unify this with `FunctionSamples::getCanonicalFnName`.
   LLVM_ABI static StringRef getCanonicalName(StringRef PGOName);
-  //ANDRES Function
+
   StringRef getObjectFilename() {return ObjectFilename;}
   void setObjectFilename(StringRef ObjectFilename) {this->ObjectFilename = ObjectFilename;}
   StringRef getArchitecture() {return Architecture;}
   void setArchitecture(StringRef Architecture) {this->Architecture = Architecture;}
-  //ANDRES Function
+
 private:
   StringRef ObjectFilename;
   StringRef Architecture;
@@ -646,16 +646,15 @@ class InstrProfSymtab {
 
     uint64_t HashValue = IndexedInstrProf::ComputeHash(SymbolName);
     std::string HashStr(std::to_string(HashValue));
-    // llvm::errs() << "HELLLOOOOOOOOO" << "\n";
+    //if ObjectFilename is not empty from the --object-aware-hashing flag, add ObjectFilename to hash context
     if(!ObjectFilename.empty()){
       std::string CombinedStr = HashStr + ":" + ObjectFilename.str();
-      llvm::errs() << CombinedStr << "\n";
       StringRef HashRef = CombinedStr;
       HashValue = IndexedInstrProf::ComputeHash(HashRef);
     }
     auto Ins = NameTab.insert(SymbolName);
     if (Ins.second) {
-      MD5NameMap.push_back(std::make_pair(HashValue /*IndexedInstrProf::ComputeHash(HashRef)*/, Ins.first->getKey()));
+      MD5NameMap.push_back(std::make_pair(HashValue, Ins.first->getKey()));
       Sorted = false;
     }
     return Error::success();
@@ -792,13 +791,8 @@ StringRef InstrProfSymtab::getFuncOrVarName(uint64_t MD5Hash) {
   }
   auto Result = llvm::lower_bound(MD5NameMap, MD5Hash, [](const std::pair<uint64_t, StringRef> &LHS, uint64_t RHS) { return LHS.first < RHS; });
 
-  for(auto name : MD5NameMap){
-    llvm::errs() << "Function Name " << name.second  << " Result->first: " << name.first << "\n";
-  }
-  llvm::errs() << "Function Name " << Result->second  << " Result->first: " << Result->first << " vs. " << MD5Hash << "\n";
   if (Result != MD5NameMap.end() && Result->first == MD5Hash)
     return Result->second;
-  llvm::errs() << "MISMATCH HERE" << "\n";
   return StringRef();
 }
 
diff --git a/llvm/include/llvm/ProfileData/InstrProfReader.h b/llvm/include/llvm/ProfileData/InstrProfReader.h
index db80731037887..230c7e3233e58 100644
--- a/llvm/include/llvm/ProfileData/InstrProfReader.h
+++ b/llvm/include/llvm/ProfileData/InstrProfReader.h
@@ -162,7 +162,7 @@ class InstrProfReader {
   LLVM_ABI void accumulateCounts(CountSumOrPercent &Sum, bool IsCS);
 
 protected:
-  //ANDRES Storing ObjectFilename Information as a string
+  //Storing ObjectFilename Information as a string
   std::string ObjectFilename;
 
   std::unique_ptr<InstrProfSymtab> Symtab;
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index cac35b29e8aec..aaab6081e8bc4 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -825,157 +825,6 @@ class MCDCDecisionRecorder {
 
 } // namespace
 
-// Error CoverageMapping::loadFunctionRecord(
-//     const CoverageMappingRecord &Record,
-//     const std::optional<std::reference_wrapper<IndexedInstrProfReader>>
-//         &ProfileReader, StringRef Arch) {
-//   StringRef OrigFuncName = Record.FunctionName;
-//   if (OrigFuncName.empty())
-//     return make_error<CoverageMapError>(coveragemap_error::malformed,
-//                                         "record function name is empty");
-
-//   if (Record.Filenames.empty())
-//     OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName);
-//   else
-//     OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName, Record.Filenames[0]);
-
-//   CounterMappingContext Ctx(Record.Expressions);
-
-//   uint64_t FuncArchHash = Record.FunctionHash;
-//   if(!Arch.empty()){
-//     std::string HashStr = std::to_string(Record.FunctionHash) + ":" + Arch.str();
-//     llvm::StringRef HashRef(HashStr);
-//     FuncArchHash = IndexedInstrProf::ComputeHash(HashRef);
-//   }
-
-//   std::vector<uint64_t> Counts;
-//   if (ProfileReader) {
-//     if (Error E = ProfileReader.value().get().getFunctionCounts(
-//             Record.FunctionName, FuncArchHash, Counts)) {
-//       instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
-//       if (IPE == instrprof_error::hash_mismatch) {
-//         FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
-//                                         FuncArchHash);
-//         return Error::success();
-//       }
-//       if (IPE != instrprof_error::unknown_function)
-//         return make_error<InstrProfError>(IPE);
-//       Counts.assign(getMaxCounterID(Ctx, Record) + 1, 0);
-//     }
-//   } else {
-//     Counts.assign(getMaxCounterID(Ctx, Record) + 1, 0);
-//   }
-//   Ctx.setCounts(Counts);
-
-//   bool IsVersion11 =
-//       ProfileReader && ProfileReader.value().get().getVersion() <
-//                            IndexedInstrProf::ProfVersion::Version12;
-
-//   BitVector Bitmap;
-//   if (ProfileReader) {
-//     if (Error E = ProfileReader.value().get().getFunctionBitmap(
-//             Record.FunctionName, FuncArchHash, Bitmap)) {
-//       instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
-//       if (IPE == instrprof_error::hash_mismatch) {
-//         FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
-//                                         FuncArchHash);
-//         return Error::success();
-//       }
-//       if (IPE != instrprof_error::unknown_function)
-//         return make_error<InstrProfError>(IPE);
-//       Bitmap = BitVector(getMaxBitmapSize(Record, IsVersion11));
-//     }
-//   } else {
-//     Bitmap = BitVector(getMaxBitmapSize(Record, false));
-//   }
-//   Ctx.setBitmap(std::move(Bitmap));
-
-//   assert(!Record.MappingRegions.empty() && "Function has no regions");
-
-//   // This coverage record is a zero region for a function that's unused in
-//   // some TU, but used in a different TU. Ignore it. The coverage maps from the
-//   // the other TU will either be loaded (providing full region counts) or they
-//   // won't (in which case we don't unintuitively report functions as uncovered
-//   // when they have non-zero counts in the profile).
-//   if (Record.MappingRegions.size() == 1 &&
-//       Record.MappingRegions[0].Count.isZero() && Counts[0] > 0)
-//     return Error::success();
-
-//   MCDCDecisionRecorder MCDCDecisions;
-//   FunctionRecord Function(OrigFuncName, Record.Filenames);
-//   for (const auto &Region : Record.MappingRegions) {
-//     // MCDCDecisionRegion should be handled first since it overlaps with
-//     // others inside.
-//     if (Region.Kind == CounterMappingRegion::MCDCDecisionRegion) {
-//       MCDCDecisions.registerDecision(Region);
-//       continue;
-//     }
-//     Expected<int64_t> ExecutionCount = Ctx.evaluate(Region.Count);
-//     if (auto E = ExecutionCount.takeError()) {
-//       consumeError(std::move(E));
-//       return Error::success();
-//     }
-//     Expected<int64_t> AltExecutionCount = Ctx.evaluate(Region.FalseCount);
-//     if (auto E = AltExecutionCount.takeError()) {
-//       consumeError(std::move(E));
-//       return Error::success();
-//     }
-//     Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount);
-
-//     // Record ExpansionRegion.
-//     if (Region.Kind == CounterMappingRegion::ExpansionRegion) {
-//       MCDCDecisions.recordExpansion(Region);
-//       continue;
-//     }
-
-//     // Do nothing unless MCDCBranchRegion.
-//     if (Region.Kind != CounterMappingRegion::MCDCBranchRegion)
-//       continue;
-
-//     auto Result = MCDCDecisions.processBranch(Region);
-//     if (!Result) // Any Decision doesn't complete.
-//       continue;
-
-//     auto MCDCDecision = Result->first;
-//     auto &MCDCBranches = Result->second;
-
-//     // Since the bitmap identifies the executed test vectors for an MC/DC
-//     // DecisionRegion, all of the information is now available to process.
-//     // This is where the bulk of the MC/DC progressing takes place.
-//     Expected<MCDCRecord> Record =
-//         Ctx.evaluateMCDCRegion(*MCDCDecision, MCDCBranches, IsVersion11);
-//     if (auto E = Record.takeError()) {
-//       consumeError(std::move(E));
-//       return Error::success();
-//     }
-
-//     // Save the MC/DC Record so that it can be visualized later.
-//     Function.pushMCDCRecord(std::move(*Record));
-//   }
-
-//   // Don't create records for (filenames, function) pairs we've already seen.
-//   auto FilenamesHash = hash_combine_range(Record.Filenames);
-//   if (!RecordProvenance[FilenamesHash].insert(hash_value(OrigFuncName)).second)
-//     return Error::success();
-
-//   Functions.push_back(std::move(Function));
-
-//   // Performance optimization: keep track of the indices of the function records
-//   // which correspond to each filename. This can be used to substantially speed
-//   // up queries for coverage info in a file.
-//   unsigned RecordIndex = Functions.size() - 1;
-//   for (StringRef Filename : Record.Filenames) {
-//     auto &RecordIndices = FilenameHash2RecordIndices[hash_value(Filename)];
-//     // Note that there may be duplicates in the filename set for a function
-//     // record, because of e.g. macro expansions in the function in which both
-//     // the macro and the function are defined in the same file.
-//     if (RecordIndices.empty() || RecordIndices.back() != RecordIndex)
-//       RecordIndices.push_back(RecordIndex);
-//   }
-
-//   return Error::success();
-// }
-
 Error CoverageMapping::loadFunctionRecord(
     const CoverageMappingRecord &Record,
     const std::optional<std::reference_wrapper<IndexedInstrProfReader>>
@@ -1200,7 +1049,6 @@ Error CoverageMapping::loadFromReaders(
         &ProfileReader,
     CoverageMapping &Coverage, StringRef Arch, StringRef ObjectFilename, bool ShowArchExecutables, bool MergeBinaryCoverage) {
   
-  // Coverage.setArchitecture(Arch);
   assert(!Coverage.SingleByteCoverage || !ProfileReader ||
          *Coverage.SingleByteCoverage ==
              ProfileReader.value().get().hasSingleByteCoverage());
@@ -1308,9 +1156,6 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
     return Arches[Idx];
   };
 
-  //I beleive there is an error in this area of code, it's iterating through all arch's of the object files
-  // but its only filling *Coverage with last architecture it gets to
-
   SmallVector<object::BuildID> FoundBinaryIDs;
   for (const auto &File : llvm::enumerate(ObjectFilenames)) {
     if (Error E = loadFromFile(File.value(), GetArch(File.index()),
@@ -1320,9 +1165,6 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
       return std::move(E);
   }
 
-  //I beleive there is an error in this area of code, it's iterating through all arch's of the object files
-  // but its only filling *Coverage with last architecture it gets to
-
   if (BIDFetcher) {
     std::vector<object::BuildID> ProfileBinaryIDs;
     if (ProfileReader)
@@ -1561,7 +1403,6 @@ class SegmentBuilder {
   }
 
   /// Combine counts of regions which cover the same area.
-  //[(3:12, 10:1), (4:1, 6:7), (6:7, 8:1)]
   static ArrayRef<CountedRegion>
   combineRegions(MutableArrayRef<CountedRegion> Regions) {
     if (Regions.empty())
@@ -1576,8 +1417,6 @@ class SegmentBuilder {
         ++Active;
         if (Active != I){
           *Active = *I;
-          // Active->ExecutionCount = 1;
-          // Active->Kind = CounterMappingRegion::CodeRegion;
         }
         continue;
       }
@@ -1608,6 +1447,9 @@ class SegmentBuilder {
 
     sortNestedRegions(Regions);
 
+    
+    //check to see if a skipped region from executable A is within a CodeRegion from executable B,
+    //promote to CodeRegion if skipped region does not show up on any other executable.
     for(auto *I = Regions.begin(); I != Regions.end(); ++I){
       bool FoundMatchInOtherBinary = false;
       for(auto *J = I + 1; J != Regions.end(); ++J){
@@ -1615,7 +1457,6 @@ class SegmentBuilder {
             J->Kind == CounterMappingRegion::SkippedRegion 
             && I->Kind != CounterMappingRegion::SkippedRegion &&
             J->startLoc() >= I->startLoc() && J->endLoc() <= I->endLoc()){
-          // llvm::errs() << "(" << to_string(J->startLoc().first) << ", " << to_string(J->endLoc().first) << ")" << "\n";
           for(auto *K = J + 1; K != Regions.end(); ++K){
             if(K->ObjectFilename == I->ObjectFilename &&
               J->startLoc() == K->startLoc() && J->endLoc() == K->endLoc()){
@@ -1686,12 +1527,7 @@ static SmallBitVector gatherFileIDs(StringRef SourceFile,
 static std::optional<unsigned>
 findMainViewFileID(const FunctionRecord &Function) {
   SmallBitVector IsNotExpandedFile(Function.Filenames.size(), true);
-  uint64_t counter = 0;
   for (const auto &CR : Function.CountedRegions){
-    // counter++;
-    // if(counter == 245){
-    //   llvm::errs() << counter << "\n";
-    // }
     if (CR.Kind == CounterMappingRegion::ExpansionRegion)
       IsNotExpandedFile[CR.ExpandedFileID] = false;
   }
@@ -1726,14 +1562,6 @@ CoverageData CoverageMapping::getCoverageForFile(StringRef Filename, bool ShowAr
   // DenseSet<CountedRegion> DeDuplicationSet;
   ArrayRef<unsigned> RecordIndices =
       getImpreciseRecordIndicesForFilename(Filename);
-  // for (unsigned RecordIndex : RecordIndices) {
-  //   const FunctionRecord &Function = AllFunctionRegions[RecordIndex];
-  //   for(const auto &I : Function.CountedRegions){
-  //     llvm::errs() << "(" << to_string(I.startLoc().first) << ", " << to_string(I.endLoc().first) << ")" << "\n";
-  //   }
-  // }
-  // ArrayRef<unsigned> RecordIndices =
-  //     getImpreciseRecordIndicesForFilename(Filename);
   for (unsigned RecordIndex : RecordIndices) {
     const FunctionRecord &Function = !MergeBinaryCoverage ? Functions[RecordIndex] : AllFunctionRegions[RecordIndex];
     auto MainFileID = findMainViewFileID(Filename, Function);
diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp
index 404e5177980d6..2910ca8486b63 100644
--- a/llvm/lib/ProfileData/InstrProf.cpp
+++ b/llvm/lib/ProfileData/InstrProf.cpp
@@ -574,49 +574,6 @@ Error InstrProfSymtab::addVTableWithName(GlobalVariable &VTable,
   return Error::success();
 }
 
-// Error readAndDecodeStrings(StringRef NameStrings,
-//                            std::function<Error(StringRef)> NameCallback, const std::string &Architecture) {
-//   const uint8_t *P = NameStrings.bytes_begin();
-//   const uint8_t *EndP = NameStrings.bytes_end();
-//   while (P < EndP) {
-//     uint32_t N;
-//     uint64_t UncompressedSize = decodeULEB128(P, &N);
-//     P += N;
-//     uint64_t CompressedSize = decodeULEB128(P, &N);
-//     P += N;
-//     const bool IsCompressed = (CompressedSize != 0);
-//     SmallVector<uint8_t, 128> UncompressedNameStrings;
-//     StringRef NameStrings;
-//     if (IsCompressed) {
-//       if (!llvm::compression::zlib::isAvailable())
-//         return make_error<InstrProfError>(instrprof_error::zlib_unavailable);
-
-//       if (Error E = compression::zlib::decompress(ArrayRef(P, CompressedSize),
-//                                                   UncompressedNameStrings,
-//                                                   UncompressedSize)) {
-//         consumeError(std::move(E));
-//         return make_error<InstrProfError>(instrprof_error::uncompress_failed);
-//       }
-//       P += CompressedSize;
-//       NameStrings = toStringRef(UncompressedNameStrings);
-//     } else {
-//       NameStrings =
-//           StringRef(reinterpret_cast<const char *>(P), UncompressedSize);
-//       P += UncompressedSize;
-//     }
-//     // Now parse the name strings.
-//     SmallVector<StringRef, 0> Names;
-//     NameStrings.split(Names, getInstrProfNameSeparator());
-//     for (StringRef &Name : Names){
-//       if (Error E = NameCallback(Name))
-//         return E;
-//     }
-//     while (P < EndP && *P == 0)
-//       P++;
-//   }
-//   return Error::success();
-// }
-
 Error readAndDecodeStrings(StringRef NameStrings,
                            std::function<Error(StringRef)> NameCallback, StringRef ObjectFilename) {
   const uint8_t *P = NameStrings.bytes_begin();
@@ -665,8 +622,7 @@ Error InstrProfSymtab::create(StringRef NameStrings) {
 }
 
 Error InstrProfSymtab::create(StringRef FuncNameStrings,
-                              StringRef VTableNameStrings) {
-  // const std::string &Architecture = getArchitecture();                                
+                              StringRef VTableNameStrings) {                          
   if (Error E = readAndDecodeStrings(FuncNameStrings, std::bind(&InstrProfSymtab::addFuncName, this, std::placeholders::_1)))
     return E;
 
diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp
index d4f70ecb247a0..a13c557d8f923 100644
--- a/llvm/lib/ProfileData/InstrProfReader.cpp
+++ b/llvm/lib/ProfileData/InstrProfReader.cpp
@@ -154,7 +154,7 @@ static void printBinaryIdsInternal(raw_ostream &OS,
   }
 }
 
-Expected<std::unique_ptr<InstrProfReader>> InstrProfReader::create( //STEP 1
+Expected<std::unique_ptr<InstrProfReader>> InstrProfReader::create(
     const Twine &Path, vfs::FileSystem &FS,
     const InstrProfCorrelator *Correlator,
     const object::BuildIDFetcher *BIDFetcher,
@@ -196,6 +196,7 @@ Expected<std::unique_ptr<InstrProfReader>> InstrProfReader::create(
 
   // Initialize the reader and return the result.
 
+  //Pass the ObjectFilename to Result
   if(Result){
     Result->setObjectFilename(ObjectFilename);
   }
@@ -536,7 +537,7 @@ bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) {
 }
 
 template <class IntPtrT>
-Error RawInstrProfReader<IntPtrT>::readHeader() { //STEP 2
+Error RawInstrProfReader<IntPtrT>::readHeader() {
   if (!hasFormat(*DataBuffer))
     return error(instrprof_error::bad_magic);
   if (DataBuffer->getBufferSize() < sizeof(RawInstrProf::Header))
@@ -576,8 +577,7 @@ Error RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) {
 }
 
 template <class IntPtrT>
-Error RawInstrProfReader<IntPtrT>::createSymtab(InstrProfSymtab &Symtab) { //STEP 5
-  
+Error RawInstrProfReader<IntPtrT>::createSymtab(InstrProfSymtab &Symtab) {
   Symtab.setObjectFilename(ObjectFilename);
   
   if (Error E = Symtab.create(StringRef(NamesStart, NamesEnd - NamesStart),
@@ -610,7 +610,7 @@ Error RawInstrProfReader<IntPtrT>::createSymtab(InstrProfSymtab &Symtab) { //STE
 template <class IntPtrT>
 Error RawInstrProfReader<IntPtrT>::readHeader(
     const RawInstrProf::Header &Header) {
-  Version = swap(Header.Version); //STEP 4
+  Version = swap(Header.Version);
   if (GET_VERSION(Version) != RawInstrProf::Version)
     return error(instrprof_error::raw_profile_version_mismatch,
                  ("Profile uses raw profile format version = " +
diff --git a/llvm/lib/ProfileData/InstrProfWriter.cpp b/llvm/lib/ProfileData/InstrProfWriter.cpp
index 2c18a5c7825ad..5d42d5c24346f 100644
--- a/llvm/lib/ProfileData/InstrProfWriter.cpp
+++ b/llvm/lib/ProfileData/InstrProfWriter.cpp
@@ -195,66 +195,13 @@ void InstrProfWriter::overlapRecord(NamedInstrProfRecord &&Other,
   Dest.overlap(Other, Overlap, FuncLevelOverlap, ValueCutoff);
 }
 
-// void InstrProfWriter::addRecord(StringRef Name, uint64_t Hash,
-//                                 InstrProfRecord &&I, uint64_t Weight,
-//                                 function_ref<void(Error)> Warn) {
-//   auto &ProfileDataMap = FunctionData[Name];
-
-//   auto [Where, NewFunc] = ProfileDataMap.try_emplace(Hash);
-//   InstrProfRecord &Dest = Where->second;
-
-//   auto MapWarn = [&](instrprof_error E) {
-//     Warn(make_error<InstrProfError>(E));
-//   };
-
-//   if (NewFunc) {
-//     // We've never seen a function with this name and hash, add it.
-//     Dest = std::move(I);
-//     if (Weight > 1)
-//       Dest.scale(Weight, 1, MapWarn);
-//   } else {
-//     // We're updating a function we've seen before.
-//     Dest.merge(I, Weight, MapWarn);
-//   }
-
-//   Dest.sortValueData();
-// }
-
-
-
-// #include "llvm/DebugInfo/DWARF/DWARFContext.h"
-
-
-#include <llvm/Support/raw_ostream.h>
-#include <llvm/Support/MemoryBuffer.h>
-#include <llvm/Support/SHA1.h>
-#include <array>
-
-StringRef hashSourceFile(llvm::StringRef FilePath) {
-    auto FileOrErr = llvm::MemoryBuffer::getFile(FilePath);
-    if (!FileOrErr) {
-        llvm::errs() << "Error reading file: " << FilePath << "\n";
-        return "";
-    }
-
-    const auto &Buffer = *FileOrErr.get();
-    llvm::SHA1 Hasher;
-    Hasher.update(Buffer.getBuffer());
-
-    std::array<uint8_t, 20> Hash = Hasher.final();
-    
-    std::string HexStr = llvm::toHex(llvm::ArrayRef<uint8_t>(Hash));
-    llvm::StringRef HashRef(HexStr);
-    return HashRef;
-}
-
 
 
 void InstrProfWriter::addRecord(StringRef Name, uint64_t Hash,
                                 InstrProfRecord &&I, uint64_t Weight,
                                 function_ref<void(Error)> Warn, StringRef ObjectFilename) {
   auto &ProfileDataMap = FunctionData[Name];
-  // StringRef SHAHash = hashSourceFile(Architecture);
+  //add objectFilename to hash value if --object-aware-hashing is used
   if(!ObjectFilename.empty()){
     std::string HashStr = std::to_string(Hash) + ":" + ObjectFilename.str();
     llvm::StringRef HashRef(HashStr);
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 7f4a0df458201..e24cba8f532bd 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -695,26 +695,6 @@ static void overlapInput(const std::string &BaseFilename,
   }
 }
 
-// //ANDRES FUNCTION
-// Expected<std::string> getArchitectureFromExecutable(StringRef ExecutablePath){
-//   ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrError = MemoryBuffer::getFile(ExecutablePath);
-//   if(!BufferOrError){
-//     return createStringError(BufferOrError.getError(), "Failed to load input file");
-//   }
-
-//   Expected<std::unique_ptr<object::ObjectFile>> ObjectOrError = object::ObjectFile::createObjectFile(BufferOrError.get()->getMemBufferRef());
-//   if(!ObjectOrError){
-//     return ObjectOrError.takeError();
-//   }
-
-//   std::unique_ptr<llvm::object::ObjectFile> &Object = ObjectOrError.get();
-
-//   StringRef ArchStr = Object->getArch() != Triple::UnknownArch ? Triple::getArchTypeName(Object->getArch()) : "unknown";
-
-//   return ArchStr.str();
-// }
-// //ANDRES FUNCTION
-
 /// Load an input into a writer context.
 static void
 loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
@@ -727,30 +707,14 @@ loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
   // WeightedFile &" by value, making a reference to the filename within it
   // invalid outside of this packaged task.
   std::string Filename = Input.Filename;
-
-  //ANDRES CODE
   std::string ExecutableName;
   std::string ProfileFile = Input.Filename;
   StringRef ObjectFilename = "";
 
   StringRef FilenameRef = Filename;
   if(!ObjectAwareHashing.empty()){
-    // StringRef ExeRef, ProfRef;
-    // std::tie(ExeRef, ProfRef) = FilenameRef.split(':');
-    // if(!ExeRef.empty() && !ProfRef.empty()){
     ObjectFilename = ObjectAwareHashing.data();
-      // ProfileFile = ProfRef.str();
-    // }
-    // Expected<std::string> ArchOrError = getArchitectureFromExecutable(ExeRef);
-    // if(ArchOrError){
-    //   Architecture = std::move(ArchOrError.get());
-    // }else{
-    //   consumeError(ArchOrError.takeError());
-    //   Architecture = "unknown";
-    // }
-    // ObjectFilename = ExeRef;
   }
-  //ANDRES CODE
 
 
   using ::llvm::memprof::RawMemProfReader;
@@ -841,8 +805,8 @@ loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
   const ProfCorrelatorKind CorrelatorKind = BIDFetcherCorrelatorKind
                                                 ? *BIDFetcherCorrelatorKind
                                                 : ProfCorrelatorKind::NONE;
-  auto ReaderOrErr = InstrProfReader::create(ProfileFile /*ANDRES changed from Input.Filename to ProfileFile*/, *FS, Correlator, //THIS IS THE IMPORTANT LINE!!!!
-                                             BIDFetcher, CorrelatorKind, Warn, ObjectFilename /*ANDRES added this parameter*/);
+  auto ReaderOrErr = InstrProfReader::create(ProfileFile, *FS, Correlator,
+                                             BIDFetcher, CorrelatorKind, Warn, ObjectFilename);
   if (Error E = ReaderOrErr.takeError()) {
     // Skip the empty profiles by returning silently.
     auto [ErrCode, Msg] = InstrProfError::take(std::move(E));
@@ -1771,28 +1735,6 @@ static void addWeightedInput(WeightedFileVector &WNI, const WeightedFile &WF) {
     return;
   }
 
-  //ANDRES ADDED CODE UPDATED CODE TO HANDLE ARCH SPECIFIC EXECUTABLE
-  StringRef ExecutableName, ProfileFile;
-  if(Filename.contains(':')){
-    std::tie(ExecutableName, ProfileFile) = Filename.split(':');
-
-
-    if(!ExecutableName.empty() && !ProfileFile.empty()){
-      llvm::sys::fs::file_status Status;
-      llvm::sys::fs::status(ProfileFile, Status);
-      if(!llvm::sys::fs::exists(Status)){
-        exitWithErrorCode(make_error_code(errc::no_such_file_or_directory),ProfileFile);
-      }
-      if(llvm::sys::fs::is_regular_file(Status)){
-        WNI.push_back({std::string(Filename), Weight});
-        return;
-      }
-
-      Filename = ProfileFile;
-    }
-  }
-  //ANDRES ADDED CODE
-
   llvm::sys::fs::file_status Status;
   llvm::sys::fs::status(Filename, Status);
   if (!llvm::sys::fs::exists(Status))

>From e8a2c1a967faf89b2a69e8aa409ea64dfc3d80a6 Mon Sep 17 00:00:00 2001
From: Andres Wearden <andreswearden5 at gmail.com>
Date: Fri, 1 Aug 2025 10:21:18 -0700
Subject: [PATCH 16/17] added three llvm-lit tests, testing the
 --merge-binary-coverage flag and the --show-arch-executables flag

---
 .../ProfileData/Coverage/CoverageMapping.h    |  7 ++
 llvm/include/llvm/ProfileData/InstrProf.h     |  3 +-
 .../llvm/ProfileData/InstrProfReader.h        |  2 +-
 .../ProfileData/Coverage/CoverageMapping.cpp  | 28 +++----
 llvm/lib/ProfileData/InstrProf.cpp            |  2 +-
 llvm/lib/ProfileData/InstrProfReader.cpp      |  8 +-
 llvm/lib/ProfileData/InstrProfWriter.cpp      |  4 +-
 llvm/test/tools/llvm-cov/Inputs/fb.c          |  5 ++
 llvm/test/tools/llvm-cov/Inputs/mypg.c        |  2 +
 llvm/test/tools/llvm-cov/Inputs/myprogram.c   |  8 ++
 .../merge-binary-coverage-multi-file.c        | 39 ++++++++++
 .../tools/llvm-cov/merge-binary-coverage.c    | 61 ++++++++++++++++
 .../tools/llvm-cov/merge-show-arch-exec.c     | 73 +++++++++++++++++++
 llvm/tools/llvm-cov/CodeCoverage.cpp          | 48 ++++--------
 llvm/tools/llvm-cov/SourceCoverageView.cpp    | 42 +++++------
 llvm/tools/llvm-cov/SourceCoverageView.h      | 26 +++++--
 .../tools/llvm-cov/SourceCoverageViewHTML.cpp | 59 ++++++++-------
 llvm/tools/llvm-cov/SourceCoverageViewHTML.h  | 10 +--
 .../tools/llvm-cov/SourceCoverageViewText.cpp | 48 ++++++++----
 llvm/tools/llvm-cov/SourceCoverageViewText.h  | 10 +--
 llvm/tools/llvm-profdata/llvm-profdata.cpp    | 10 +--
 21 files changed, 349 insertions(+), 146 deletions(-)
 create mode 100644 llvm/test/tools/llvm-cov/Inputs/fb.c
 create mode 100644 llvm/test/tools/llvm-cov/Inputs/mypg.c
 create mode 100644 llvm/test/tools/llvm-cov/Inputs/myprogram.c
 create mode 100644 llvm/test/tools/llvm-cov/merge-binary-coverage-multi-file.c
 create mode 100644 llvm/test/tools/llvm-cov/merge-binary-coverage.c
 create mode 100644 llvm/test/tools/llvm-cov/merge-show-arch-exec.c

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index cb3b7c60ba981..5c4eece59e2e2 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -1018,6 +1018,7 @@ class CoverageMapping {
   DenseMap<std::pair<size_t, hash_code>, unsigned> RecordIndices;
   uint64_t DebugCount = 0;
   std::vector<FunctionRecord> AllFunctionRegions;
+  StringRef ObjectFilename;
 
 
   std::map<std::pair<std::string, std::string>, std::vector<uint64_t>> AggregatedCounts;
@@ -1073,6 +1074,12 @@ class CoverageMapping {
     Arch = StringRef(NewArch);
   }
 
+  void setObjectFilename(StringRef ObjectFilename){
+    this->ObjectFilename = StringRef(ObjectFilename);
+  }
+
+  const StringRef &getObjectFilename() const { return this->ObjectFilename; }
+
   CoverageMapping(const CoverageMapping &) = delete;
   CoverageMapping &operator=(const CoverageMapping &) = delete;
 
diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h
index 99c3df6a2e834..2cbe412fed75c 100644
--- a/llvm/include/llvm/ProfileData/InstrProf.h
+++ b/llvm/include/llvm/ProfileData/InstrProf.h
@@ -646,7 +646,8 @@ class InstrProfSymtab {
 
     uint64_t HashValue = IndexedInstrProf::ComputeHash(SymbolName);
     std::string HashStr(std::to_string(HashValue));
-    //if ObjectFilename is not empty from the --object-aware-hashing flag, add ObjectFilename to hash context
+    // if ObjectFilename is not empty from the --object-aware-hashing flag, add
+    // ObjectFilename to hash context
     if(!ObjectFilename.empty()){
       std::string CombinedStr = HashStr + ":" + ObjectFilename.str();
       StringRef HashRef = CombinedStr;
diff --git a/llvm/include/llvm/ProfileData/InstrProfReader.h b/llvm/include/llvm/ProfileData/InstrProfReader.h
index 230c7e3233e58..24bb3f384a394 100644
--- a/llvm/include/llvm/ProfileData/InstrProfReader.h
+++ b/llvm/include/llvm/ProfileData/InstrProfReader.h
@@ -162,7 +162,7 @@ class InstrProfReader {
   LLVM_ABI void accumulateCounts(CountSumOrPercent &Sum, bool IsCS);
 
 protected:
-  //Storing ObjectFilename Information as a string
+  // Storing ObjectFilename Information as a string
   std::string ObjectFilename;
 
   std::unique_ptr<InstrProfSymtab> Symtab;
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index aaab6081e8bc4..4880582f79f8d 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -32,6 +32,7 @@
 #include "llvm/Support/ScopedPrinter.h"
 #include "llvm/Support/VirtualFileSystem.h"
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/Object/ObjectFile.h"
 #include <algorithm>
 #include <cassert>
 #include <cmath>
@@ -825,6 +826,7 @@ class MCDCDecisionRecorder {
 
 } // namespace
 
+
 Error CoverageMapping::loadFunctionRecord(
     const CoverageMappingRecord &Record,
     const std::optional<std::reference_wrapper<IndexedInstrProfReader>>
@@ -954,13 +956,13 @@ Error CoverageMapping::loadFunctionRecord(
   auto FilenamesHash = hash_combine_range(Record.Filenames);
   std::string HashStr = OrigFuncName.str();
   if(ShowArchExecutables){
-    HashStr += ":" + Arch.str();
+    HashStr += ":" + ObjectFilename.str();
   }else{
     auto LogicalFuncKey = std::make_pair(FilenamesHash, hash_value(OrigFuncName));
     auto It = RecordIndices.find(LogicalFuncKey);
     if (It != RecordIndices.end()) {
       auto &ExistingFunction = Functions[It->second];
-      // Create a map of existing regions for efficient lookup.
+      // Create a map of existing regions for lookup.
       // The key uniquely identifies the source region.
       using RegionKey = std::tuple<unsigned, unsigned, unsigned, unsigned, unsigned>;
       std::map<RegionKey, CountedRegion *> ExistingRegionsMap;
@@ -987,9 +989,7 @@ Error CoverageMapping::loadFunctionRecord(
           ExistingFunction.CountedRegions.push_back(NewRegion);
         }
       }
-      // Since we modified an existing function, we don't add a new one.
-      // We just need to make sure we don't add the new 'Function' object later.
-      // The logic below this block needs to be adjusted to handle this.
+
       return Error::success();
     }
     RecordIndices.insert({LogicalFuncKey, Functions.size()});
@@ -1048,7 +1048,7 @@ Error CoverageMapping::loadFromReaders(
     std::optional<std::reference_wrapper<IndexedInstrProfReader>>
         &ProfileReader,
     CoverageMapping &Coverage, StringRef Arch, StringRef ObjectFilename, bool ShowArchExecutables, bool MergeBinaryCoverage) {
-  
+
   assert(!Coverage.SingleByteCoverage || !ProfileReader ||
          *Coverage.SingleByteCoverage ==
              ProfileReader.value().get().hasSingleByteCoverage());
@@ -1447,16 +1447,16 @@ class SegmentBuilder {
 
     sortNestedRegions(Regions);
 
-    
-    //check to see if a skipped region from executable A is within a CodeRegion from executable B,
-    //promote to CodeRegion if skipped region does not show up on any other executable.
+    // check to see if a skipped region from executable A is within a CodeRegion
+    // from executable B, promote to CodeRegion if skipped region does not show
+    // up on any other executable.
     for(auto *I = Regions.begin(); I != Regions.end(); ++I){
       bool FoundMatchInOtherBinary = false;
       for(auto *J = I + 1; J != Regions.end(); ++J){
-        if(I->ObjectFilename != J->ObjectFilename &&
-            J->Kind == CounterMappingRegion::SkippedRegion 
-            && I->Kind != CounterMappingRegion::SkippedRegion &&
-            J->startLoc() >= I->startLoc() && J->endLoc() <= I->endLoc()){
+        if (I->ObjectFilename != J->ObjectFilename &&
+            J->Kind == CounterMappingRegion::SkippedRegion &&
+            I->Kind != CounterMappingRegion::SkippedRegion &&
+            J->startLoc() >= I->startLoc() && J->endLoc() <= I->endLoc()) {
           for(auto *K = J + 1; K != Regions.end(); ++K){
             if(K->ObjectFilename == I->ObjectFilename &&
               J->startLoc() == K->startLoc() && J->endLoc() == K->endLoc()){
@@ -1527,7 +1527,7 @@ static SmallBitVector gatherFileIDs(StringRef SourceFile,
 static std::optional<unsigned>
 findMainViewFileID(const FunctionRecord &Function) {
   SmallBitVector IsNotExpandedFile(Function.Filenames.size(), true);
-  for (const auto &CR : Function.CountedRegions){
+  for (const auto &CR : Function.CountedRegions) {
     if (CR.Kind == CounterMappingRegion::ExpansionRegion)
       IsNotExpandedFile[CR.ExpandedFileID] = false;
   }
diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp
index 2910ca8486b63..07122e4736486 100644
--- a/llvm/lib/ProfileData/InstrProf.cpp
+++ b/llvm/lib/ProfileData/InstrProf.cpp
@@ -622,7 +622,7 @@ Error InstrProfSymtab::create(StringRef NameStrings) {
 }
 
 Error InstrProfSymtab::create(StringRef FuncNameStrings,
-                              StringRef VTableNameStrings) {                          
+                              StringRef VTableNameStrings) {
   if (Error E = readAndDecodeStrings(FuncNameStrings, std::bind(&InstrProfSymtab::addFuncName, this, std::placeholders::_1)))
     return E;
 
diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp
index a13c557d8f923..875fe57765088 100644
--- a/llvm/lib/ProfileData/InstrProfReader.cpp
+++ b/llvm/lib/ProfileData/InstrProfReader.cpp
@@ -159,8 +159,7 @@ Expected<std::unique_ptr<InstrProfReader>> InstrProfReader::create(
     const InstrProfCorrelator *Correlator,
     const object::BuildIDFetcher *BIDFetcher,
     const InstrProfCorrelator::ProfCorrelatorKind BIDFetcherCorrelatorKind,
-    std::function<void(Error)> Warn, 
-    StringRef ObjectFilename) {
+    std::function<void(Error)> Warn, StringRef ObjectFilename) {
   // Set up the buffer to read.
   auto BufferOrError = setupMemoryBuffer(Path, FS);
   if (Error E = BufferOrError.takeError())
@@ -196,7 +195,7 @@ Expected<std::unique_ptr<InstrProfReader>> InstrProfReader::create(
 
   // Initialize the reader and return the result.
 
-  //Pass the ObjectFilename to Result
+  // Pass the ObjectFilename to Result
   if(Result){
     Result->setObjectFilename(ObjectFilename);
   }
@@ -536,8 +535,7 @@ bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) {
          llvm::byteswap(RawInstrProf::getMagic<IntPtrT>()) == Magic;
 }
 
-template <class IntPtrT>
-Error RawInstrProfReader<IntPtrT>::readHeader() {
+template <class IntPtrT> Error RawInstrProfReader<IntPtrT>::readHeader() {
   if (!hasFormat(*DataBuffer))
     return error(instrprof_error::bad_magic);
   if (DataBuffer->getBufferSize() < sizeof(RawInstrProf::Header))
diff --git a/llvm/lib/ProfileData/InstrProfWriter.cpp b/llvm/lib/ProfileData/InstrProfWriter.cpp
index 5d42d5c24346f..c5644d1cb56e3 100644
--- a/llvm/lib/ProfileData/InstrProfWriter.cpp
+++ b/llvm/lib/ProfileData/InstrProfWriter.cpp
@@ -195,13 +195,11 @@ void InstrProfWriter::overlapRecord(NamedInstrProfRecord &&Other,
   Dest.overlap(Other, Overlap, FuncLevelOverlap, ValueCutoff);
 }
 
-
-
 void InstrProfWriter::addRecord(StringRef Name, uint64_t Hash,
                                 InstrProfRecord &&I, uint64_t Weight,
                                 function_ref<void(Error)> Warn, StringRef ObjectFilename) {
   auto &ProfileDataMap = FunctionData[Name];
-  //add objectFilename to hash value if --object-aware-hashing is used
+  // add objectFilename to hash value if --object-aware-hashing is used
   if(!ObjectFilename.empty()){
     std::string HashStr = std::to_string(Hash) + ":" + ObjectFilename.str();
     llvm::StringRef HashRef(HashStr);
diff --git a/llvm/test/tools/llvm-cov/Inputs/fb.c b/llvm/test/tools/llvm-cov/Inputs/fb.c
new file mode 100644
index 0000000000000..428cbfd163a72
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/fb.c
@@ -0,0 +1,5 @@
+int foo() { return 0; }
+
+int bar() { return 0; }
+
+int bun() { return 0; }
diff --git a/llvm/test/tools/llvm-cov/Inputs/mypg.c b/llvm/test/tools/llvm-cov/Inputs/mypg.c
new file mode 100644
index 0000000000000..2fcea0fce9546
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/mypg.c
@@ -0,0 +1,2 @@
+int baz() { return 0; }
+int main() { return 1; }
diff --git a/llvm/test/tools/llvm-cov/Inputs/myprogram.c b/llvm/test/tools/llvm-cov/Inputs/myprogram.c
new file mode 100644
index 0000000000000..863b2baa017f6
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/myprogram.c
@@ -0,0 +1,8 @@
+extern int foo();
+extern int bar();
+extern int bun();
+
+
+int main() {
+  return foo() + bar() + bun();
+}
diff --git a/llvm/test/tools/llvm-cov/merge-binary-coverage-multi-file.c b/llvm/test/tools/llvm-cov/merge-binary-coverage-multi-file.c
new file mode 100644
index 0000000000000..74945ab84bb36
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/merge-binary-coverage-multi-file.c
@@ -0,0 +1,39 @@
+// RUN: clang -O0 -fprofile-instr-generate -fcoverage-mapping \
+// RUN:        %S/Inputs/myprogram.c %S/Inputs/fb.c -o %t.hex
+// RUN: env LLVM_PROFILE_FILE=%t.hex.profraw 
+// RUN: %t.hex
+//
+//---------------- build & run the “x86” variant ------------------------------//
+// RUN: clang -O0 -fprofile-instr-generate -fcoverage-mapping \
+// RUN:        %S/Inputs/mypg.c %S/Inputs/fb.c -o %t.x86
+// RUN: env LLVM_PROFILE_FILE=%t.x86.profraw 
+// RUN: %t.x86 || true
+//
+//---------------- merge the raw profiles ------------------------------------//
+// RUN: llvm-profdata merge --object-aware-hashing=%t.x86 %t.x86.profraw \
+// RUN:                     --object-aware-hashing=%t.hex %t.hex.profraw \
+// RUN:                     -o %t.profdata
+//
+//---------------- show unified coverage & check -----------------------------//
+// RUN: llvm-cov show -instr-profile=%t.profdata --object=%t.x86 --object=%t.hex --merge-binary-coverage | FileCheck %s
+//
+// CHECK-LABEL: {{.*fb\.c}}:
+// CHECK:     1|      1|int foo() { return 0; }
+// CHECK:     2|       |
+// CHECK:     3|      1|int bar() { return 0; }
+// CHECK:     4|       |
+// CHECK:     5|      1|int bun() { return 0; }
+//
+// CHECK-LABEL: {{.*mypg\.c}}:
+// CHECK:     1|      0|int baz() { return 0; }
+// CHECK:     2|      1|int main() { return 1; }
+//
+// CHECK-LABEL: {{.*myprogram\.c}}:
+// CHECK:     1|       |extern int foo();
+// CHECK:     2|       |extern int bar();
+// CHECK:     3|       |extern int bun();
+// CHECK:     4|       |
+// CHECK:     5|       |
+// CHECK:     6|      1|int main()
+// CHECK:     7|      1|  return foo() + bar() + bun();
+// CHECK:     8|      1|}
diff --git a/llvm/test/tools/llvm-cov/merge-binary-coverage.c b/llvm/test/tools/llvm-cov/merge-binary-coverage.c
new file mode 100644
index 0000000000000..23dce6c30f2dc
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/merge-binary-coverage.c
@@ -0,0 +1,61 @@
+// RUN: clang -O0 -fprofile-instr-generate -fcoverage-mapping -DTOGGLE %s \
+// RUN:       -o %t.toggle
+// RUN: env LLVM_PROFILE_FILE=%t.toggle.profraw 
+// RUN: %t.toggle
+// RUN: cp default.profraw %t.toggle.profraw
+
+//------------------ build & run variant WITHOUT TOGGLE ----------------------//
+// RUN: clang -O0 -fprofile-instr-generate -fcoverage-mapping %s \
+// RUN:       -o %t.notoggle
+// RUN: env LLVM_PROFILE_FILE=%t.notoggle.profraw 
+// RUN: %t.notoggle
+
+//------------------ merge profiles & show coverage --------------------------//
+// RUN: llvm-profdata merge --object-aware-hashing=%t.notoggle %t.notoggle.profraw\
+// RUN:     --object-aware-hashing=%t.toggle   %t.toggle.profraw \
+// RUN:     -o %t.profdata
+//
+// RUN: llvm-cov show -instr-profile=%t.profdata                     \
+// RUN:       --object=%t.toggle --object=%t.notoggle                \
+// RUN:       --merge-binary-coverage                                \
+// RUN:   | FileCheck %s
+
+/* Expected unified coverage table:
+
+ 1|      2|int main() {
+ 2|      2|  int a = 1;
+ 3|      2|  int b = 2;
+ 4|      2|  int res = 0;
+ 5|      2|#if defined(TOGGLE)
+ 6|      1|    res = a + b;
+ 7|      1|#else
+ 8|      1|    res = b - a;
+ 9|      1|#endif
+10|      2|  return 0;
+11|      2|}
+*/
+
+// CHECK-LABEL: {{^ *1\|}}
+// CHECK: 1|      2|int main()
+// CHECK: 2|      2|int a = 1;
+// CHECK: 3|      2|int b = 2;
+// CHECK: 4|      2|int res = 0;
+// CHECK: 5|      2|#if defined(TOGGLE)
+// CHECK: 6|      1|    res = a + b;
+// CHECK: 7|      1|#else
+// CHECK: 8|      1|    res = b - a;
+// CHECK: 9|      1|#endif
+// CHECK: 10|      2|    return 0;
+// CHECK: 11|      2|}
+
+int main() {
+  int a = 1;
+  int b = 2;
+  int res = 0;
+#if defined(TOGGLE)
+  res = a + b;
+#else
+  res = b - a;
+#endif
+  return 0;
+}
\ No newline at end of file
diff --git a/llvm/test/tools/llvm-cov/merge-show-arch-exec.c b/llvm/test/tools/llvm-cov/merge-show-arch-exec.c
new file mode 100644
index 0000000000000..aae3570042d10
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/merge-show-arch-exec.c
@@ -0,0 +1,73 @@
+// RUN: clang -O0 -fprofile-instr-generate -fcoverage-mapping -DTOGGLE %s \
+// RUN:       -o %t.toggle
+// RUN: %t.toggle
+// RUN: cp default.profraw %t.toggle.profraw
+
+//------------------ build & run variant WITHOUT TOGGLE ----------------------//
+// RUN: clang -O0 -fprofile-instr-generate -fcoverage-mapping %s \
+// RUN:       -o %t.notoggle
+// RUN: %t.notoggle
+// RUN: cp default.profraw %t.notoggle.profraw 
+
+//------------------ merge profiles & show coverage --------------------------//
+// RUN: llvm-profdata merge --object-aware-hashing=%t.notoggle %t.notoggle.profraw\
+// RUN:     --object-aware-hashing=%t.toggle   %t.toggle.profraw \
+// RUN:     -o %t.profdata
+//
+// RUN: llvm-cov show -instr-profile=%t.profdata --object=%t.toggle --object=%t.notoggle --merge-binary-coverage --show-arch-executables | FileCheck %s
+
+// CHECK:       |    2|      2|int a = 1;
+// CHECK:       |    3|      2|int b = 2;
+// CHECK:       |    4|      2|int res = 0;
+// CHECK:       |    5|      2|#if defined\(TOGGLE\)
+// CHECK:       |    6|      1|    res = a \+ b;
+// CHECK:       |    7|      1|#else
+// CHECK:       |    8|      1|    res = b - a;
+// CHECK:       |    9|      1|#endif
+// CHECK:       |   10|      2|    return 0;
+// CHECK:       |   11|      2|}
+// CHECK:       |  ------------------
+// CHECK:       |  | main:
+// CHECK:       |  |    -x86_64
+// CHECK:       |  |    -merge-ifdef.toggle:
+// CHECK:       |  |    1|      1|int main\(\) {
+// CHECK:       |  |    2|      1|int a = 1;
+// CHECK:       |  |    3|      1|int b = 2;
+// CHECK:       |  |    4|      1|int res = 0;
+// CHECK:       |  |    5|      1|#if defined\(TOGGLE\)
+// CHECK:       |  |    6|      1|    res = a \+ b;
+// CHECK:       |  |    7|       |#else
+// CHECK:       |  |    8|       |    res = b - a;
+// CHECK:       |  |    9|       |#endif
+// CHECK:       |  |   10|      1|    return 0;
+// CHECK:       |  |   11|      1|}
+// CHECK:       |  ------------------
+// CHECK:       |  | main:
+// CHECK:       |  |    -x86_64
+// CHECK:       |  |    -merge-ifdef.notoggle:
+// CHECK:       |  |    1|      1|int main\(\) {
+// CHECK:       |  |    2|      1|int a = 1;
+// CHECK:       |  |    3|      1|int b = 2;
+// CHECK:       |  |    4|      1|int res = 0;
+// CHECK:       |  |    5|       |#if defined\(TOGGLE\)
+// CHECK:       |  |    6|       |    res = a \+ b;
+// CHECK:       |  |    7|       |#else
+// CHECK:       |  |    8|      1|    res = b - a;
+// CHECK:       |  |    9|      1|#endif
+// CHECK:       |  |   10|      1|    return 0;
+// CHECK:       |  |   11|      1|}
+// CHECK:       |  ------------------
+
+
+
+int main() {
+  int a = 1;
+  int b = 2;
+  int res = 0;
+#if defined(TOGGLE)
+  res = a + b;
+#else
+  res = b - a;
+#endif
+  return 0;
+}
\ No newline at end of file
diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp
index bc273f554043e..a157a3069e349 100644
--- a/llvm/tools/llvm-cov/CodeCoverage.cpp
+++ b/llvm/tools/llvm-cov/CodeCoverage.cpp
@@ -116,7 +116,7 @@ class CodeCoverageTool {
 
   /// Create the main source view of a particular source file.
   std::unique_ptr<SourceCoverageView>
-  createSourceFileView(StringRef SourceFile, const CoverageMapping &Coverage, std::vector<StringRef> Arches);
+  createSourceFileView(StringRef SourceFile, const CoverageMapping &Coverage, std::vector<StringRef> Arches, std::vector<StringRef> ObjectFilenames = {});
 
   /// Load the coverage mapping data. Return nullptr if an error occurred.
   std::unique_ptr<CoverageMapping> load();
@@ -131,9 +131,10 @@ class CodeCoverageTool {
   /// If a demangler is available, demangle all symbol names.
   void demangleSymbols(const CoverageMapping &Coverage);
 
-  /// Write out a source file view to the filesystem.
   void writeSourceFileView(StringRef SourceFile, CoverageMapping *Coverage,
-                           CoveragePrinter *Printer, bool ShowFilenames);
+                            CoveragePrinter *Printer, bool ShowFilenames, 
+                            std::vector<StringRef> ObjectFilenames);
+
 
   typedef llvm::function_ref<int(int, const char **)> CommandLineParserType;
 
@@ -393,7 +394,7 @@ CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
 
 std::unique_ptr<SourceCoverageView>
 CodeCoverageTool::createSourceFileView(StringRef SourceFile,
-                                       const CoverageMapping &Coverage, std::vector<StringRef> Arches) {
+                                       const CoverageMapping &Coverage, std::vector<StringRef> Arches, std::vector<StringRef>ObjectFilenames) {
   auto SourceBuffer = getSourceFile(SourceFile);
   if (!SourceBuffer)
     return nullptr;
@@ -405,7 +406,7 @@ CodeCoverageTool::createSourceFileView(StringRef SourceFile,
   auto Expansions = FileCoverage.getExpansions();
   auto MCDCRecords = FileCoverage.getMCDCRecords();
   auto View = SourceCoverageView::create(SourceFile, SourceBuffer.get(),
-                                         ViewOpts, std::move(FileCoverage));
+                                         ViewOpts, std::move(FileCoverage), ObjectFilenames);
   attachExpansionSubViews(*View, Expansions, Coverage);
   attachBranchSubViews(*View, Branches);
   attachMCDCSubViews(*View, MCDCRecords);
@@ -456,27 +457,6 @@ static bool modifiedTimeGT(StringRef LHS, StringRef RHS) {
   return LHSTime > RHSTime;
 }
 
-// void mergeExecutionCounts(CoverageMapping &Coverage){
-//   std::map<std::string, std::vector<const FunctionRecord*>> functionGroups;
-
-//   for(const auto &Function : Coverage.getCoveredFunctions()){
-//     if(Function.CountedRegions.empty()) continue;
-//     const auto &MainRegion = Function.CountedRegions.front();
-//     const std::string Key = Function.Name + ":" + std::to_string(MainRegion.LineStart) + ":" + std::to_string(MainRegion.ColumnStart) + ":" + (Function.Filenames.empty() ? "" : std::string(Function.Filenames[0]));
-//     functionGroups[Key].push_back(&Function);
-//     llvm::errs() << Key << "\n";
-//   }
-
-//   for(auto &Group : functionGroups){
-//     if(Group.second.size() > 1){
-//       uint64_t TotalCount = 0;
-//       for(auto *Func : Group.second){
-//         TotalCount += Func->ExecutionCount;
-//       }
-//     }
-//   }
-// }
-
 std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
   if (PGOFilename) {
     for (StringRef ObjectFilename : ObjectFilenames)
@@ -506,9 +486,6 @@ std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
                << '\n';
     }
   }
-
-  // mergeExecutionCounts(*Coverage);
-
   remapPathNames(*Coverage);
 
   if (!SourceFiles.empty())
@@ -658,8 +635,9 @@ void CodeCoverageTool::demangleSymbols(const CoverageMapping &Coverage) {
 void CodeCoverageTool::writeSourceFileView(StringRef SourceFile,
                                            CoverageMapping *Coverage,
                                            CoveragePrinter *Printer,
-                                           bool ShowFilenames) {
-  auto View = createSourceFileView(SourceFile, *Coverage, CoverageArches);
+                                           bool ShowFilenames, 
+                                           std::vector<StringRef> ObjectFilenames) {
+  auto View = createSourceFileView(SourceFile, *Coverage, CoverageArches, ObjectFilenames);
   if (!View) {
     warning("The file '" + SourceFile + "' isn't covered.");
     return;
@@ -674,7 +652,7 @@ void CodeCoverageTool::writeSourceFileView(StringRef SourceFile,
 
   View->print(*OS.get(), /*Wholefile=*/true,
               /*ShowSourceName=*/ShowFilenames,
-              /*ShowTitle=*/ViewOpts.hasOutputDirectory());
+              /*ShowTitle=*/ViewOpts.hasOutputDirectory(), ViewOpts.ShowArchExecutables);
   Printer->closeViewFile(std::move(OS));
 }
 
@@ -1262,13 +1240,13 @@ int CodeCoverageTool::doShow(int argc, const char **argv,
   if (!ViewOpts.hasOutputDirectory() || S.ThreadsRequested == 1) {
     for (const std::string &SourceFile : SourceFiles)
       writeSourceFileView(SourceFile, Coverage.get(), Printer.get(),
-                          ShowFilenames);
+                          ShowFilenames, ObjectFilenames);
   } else {
     // In -output-dir mode, it's safe to use multiple threads to print files.
     DefaultThreadPool Pool(S);
     for (const std::string &SourceFile : SourceFiles)
-      Pool.async(&CodeCoverageTool::writeSourceFileView, this, SourceFile,
-                 Coverage.get(), Printer.get(), ShowFilenames);
+      Pool.async(static_cast<void (CodeCoverageTool::*)(StringRef, CoverageMapping *, CoveragePrinter *, bool, std::vector<StringRef>)>(&CodeCoverageTool::writeSourceFileView), this, SourceFile,
+                 Coverage.get(), Printer.get(), ShowFilenames, ObjectFilenames);
     Pool.wait();
   }
 
diff --git a/llvm/tools/llvm-cov/SourceCoverageView.cpp b/llvm/tools/llvm-cov/SourceCoverageView.cpp
index 810e2c6024584..084c601601c73 100644
--- a/llvm/tools/llvm-cov/SourceCoverageView.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageView.cpp
@@ -11,6 +11,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "SourceCoverageView.h"
+#include "CoverageViewOptions.h"
 #include "SourceCoverageViewHTML.h"
 #include "SourceCoverageViewText.h"
 #include "llvm/ADT/SmallString.h"
@@ -147,14 +148,14 @@ bool SourceCoverageView::hasSubViews() const {
 std::unique_ptr<SourceCoverageView>
 SourceCoverageView::create(StringRef SourceName, const MemoryBuffer &File,
                            const CoverageViewOptions &Options,
-                           CoverageData &&CoverageInfo) {
+                           CoverageData &&CoverageInfo, std::vector<StringRef> ObjectFilenames) {
   switch (Options.Format) {
   case CoverageViewOptions::OutputFormat::Text:
     return std::make_unique<SourceCoverageViewText>(
-        SourceName, File, Options, std::move(CoverageInfo));
+        SourceName, File, Options, std::move(CoverageInfo), ObjectFilenames);
   case CoverageViewOptions::OutputFormat::HTML:
     return std::make_unique<SourceCoverageViewHTML>(
-        SourceName, File, Options, std::move(CoverageInfo));
+        SourceName, File, Options, std::move(CoverageInfo), ObjectFilenames);
   case CoverageViewOptions::OutputFormat::Lcov:
     // Unreachable because CodeCoverage.cpp should terminate with an error
     // before we get here.
@@ -194,14 +195,19 @@ void SourceCoverageView::addInstantiation(
 
 void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
                                bool ShowSourceName, bool ShowTitle,
-                               unsigned ViewDepth, StringRef SourceFile) {
+                               unsigned ViewDepth, StringRef ObjectFilename) {
   if (ShowTitle)
     renderTitle(OS, "Coverage Report");
 
   renderViewHeader(OS);
 
-  if (ShowSourceName)
+  if (ShowSourceName){
     renderSourceName(OS, WholeFile);
+    if(!ObjectFilename.empty()){
+      renderArchandObj(OS, ObjectFilename);
+    }
+  }
+
 
   renderTableHeader(OS, ViewDepth);
 
@@ -224,25 +230,8 @@ void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
   auto StartSegment = CoverageInfo.begin();
   auto EndSegment = CoverageInfo.end();
   LineCoverageIterator LCI{CoverageInfo, 1};
-  // LineCoverageIterator LCIInit{CoverageInfo, 1};
   LineCoverageIterator LCIEnd = LCI.getEnd();
   unsigned FirstLine = StartSegment != EndSegment ? StartSegment->Line : 0;
-  
-  // // Determine the number of lines in the file
-  // unsigned NumLines = 0;
-  // for (line_iterator LI(File, /*SkipBlanks=*/false); !LI.is_at_eof(); ++LI)
-  //   ++NumLines;
-  // // Resize the outer vector to hold one entry per line
-  // std::vector<std::vector<LineCoverageStats>> LineArchStats;
-  // LineArchStats.resize(CoverageArches.size()); // +1 in case line numbers are 1-based
-  // for (line_iterator LI(File, /*SkipBlanks=*/false); !LI.is_at_eof(); ++LI, ++LCIInit) {
-  //   unsigned LineNo = LCIInit->getLine();
-  //   if (LineNo >= LineArchStats.size()){
-  //     LineArchStats.resize(LineNo + 1); // Ensure enough space
-  //   }
-  //   LineArchStats[LineNo].push_back(*LCIInit); // Store the LineCoverageStats
-  // }
-
   for (line_iterator LI(File, /*SkipBlanks=*/false); !LI.is_at_eof();
        ++LI, ++LCI) {
     // If we aren't rendering the whole file, we need to filter out the prologue
@@ -260,7 +249,6 @@ void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
 
     if (getOptions().ShowLineStats)
       renderLineCoverageColumn(OS, *LCI);
-      // renderArchLineCoverageColumn(OS, *LCI, LineArchStats);
 
     // If there are expansion subviews, we want to highlight the first one.
     unsigned ExpansionColumn = 0;
@@ -294,8 +282,14 @@ void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
       RenderedSubView = true;
     }
     for (; NextISV != EndISV && NextISV->Line == LI.line_number(); ++NextISV) {
+      //ANDRES FIX HERE, ADD MAP FROM STRINGREF TO OBJECT FILE INDEX NEED TO PASS IN ObjectFilenames ARRAY INSTEAD OF ObjectFilename
       renderViewDivider(OS, ViewDepth + 1);
-      renderInstantiationView(OS, *NextISV, ViewDepth + 1);
+      renderInstantiationView(OS, *NextISV, ViewDepth + 1, ObjectFilenames[FunctionNameToObjectFile[NextISV->FunctionName]]);
+      if(FunctionNameToObjectFile.find(NextISV->FunctionName) == FunctionNameToObjectFile.end()){
+        FunctionNameToObjectFile[NextISV->FunctionName] = 0;
+      }else{
+        FunctionNameToObjectFile[NextISV->FunctionName] += (FunctionNameToObjectFile[NextISV->FunctionName] + 1) % ObjectFilenames.size();
+      }
       RenderedSubView = true;
     }
     for (; NextBRV != EndBRV && NextBRV->Line == LI.line_number(); ++NextBRV) {
diff --git a/llvm/tools/llvm-cov/SourceCoverageView.h b/llvm/tools/llvm-cov/SourceCoverageView.h
index df83e8ca37279..11794b708ef00 100644
--- a/llvm/tools/llvm-cov/SourceCoverageView.h
+++ b/llvm/tools/llvm-cov/SourceCoverageView.h
@@ -15,6 +15,7 @@
 
 #include "CoverageViewOptions.h"
 #include "CoverageSummaryInfo.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ProfileData/Coverage/CoverageMapping.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include <vector>
@@ -182,6 +183,11 @@ class SourceCoverageView {
 
   bool BinaryCounters;
 
+  //Contains the object file path
+  std::vector<StringRef> ObjectFilenames;
+
+  DenseMap<StringRef, uint64_t> FunctionNameToObjectFile;
+
   /// Get the first uncovered line number for the source file.
   unsigned getFirstUncoveredLineNo();
 
@@ -207,6 +213,11 @@ class SourceCoverageView {
   /// Render the source name for the view.
   virtual void renderSourceName(raw_ostream &OS, bool WholeFile) = 0;
 
+  /// Render the Architecture for the view.
+  virtual void renderArchandObj(raw_ostream &OS, StringRef ObjectFilename) = 0;
+
+  /// Render the Object name for the view.
+
   /// Render the line prefix at the given \p ViewDepth.
   virtual void renderLinePrefix(raw_ostream &OS, unsigned ViewDepth) = 0;
 
@@ -224,9 +235,6 @@ class SourceCoverageView {
   /// Render the line's execution count column.
   virtual void renderLineCoverageColumn(raw_ostream &OS,
                                         const LineCoverageStats &Line) = 0;
-                                
-  virtual void renderArchLineCoverageColumn(raw_ostream &OS, const LineCoverageStats &Line, std::vector<std::vector<LineCoverageStats>> LineArchStats) = 0;
-
 
   /// Render the line number column.
   virtual void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo) = 0;
@@ -248,7 +256,7 @@ class SourceCoverageView {
 
   /// Render an instantiation view and any nested views.
   virtual void renderInstantiationView(raw_ostream &OS, InstantiationView &ISV,
-                                       unsigned ViewDepth) = 0;
+                                       unsigned ViewDepth, StringRef ObjectFilename) = 0;
 
   /// Render a branch view and any nested views.
   virtual void renderBranchView(raw_ostream &OS, BranchView &BRV,
@@ -287,16 +295,18 @@ class SourceCoverageView {
 
   SourceCoverageView(StringRef SourceName, const MemoryBuffer &File,
                      const CoverageViewOptions &Options,
-                     CoverageData &&CoverageInfo)
+                     CoverageData &&CoverageInfo, std::vector<StringRef> ObjectFilenames)
       : SourceName(SourceName), File(File), Options(Options),
         CoverageInfo(std::move(CoverageInfo)),
         BinaryCounters(Options.BinaryCounters ||
-                       CoverageInfo.getSingleByteCoverage()) {}
+        CoverageInfo.getSingleByteCoverage()),
+        ObjectFilenames(ObjectFilenames) {}
+
 
 public:
   static std::unique_ptr<SourceCoverageView>
   create(StringRef SourceName, const MemoryBuffer &File,
-         const CoverageViewOptions &Options, CoverageData &&CoverageInfo);
+         const CoverageViewOptions &Options, CoverageData &&CoverageInfo, std::vector<StringRef> ObjectFilenames = {});
 
   virtual ~SourceCoverageView() {}
 
@@ -322,7 +332,7 @@ class SourceCoverageView {
   /// Print the code coverage information for a specific portion of a
   /// source file to the output stream.
   void print(raw_ostream &OS, bool WholeFile, bool ShowSourceName,
-             bool ShowTitle, unsigned ViewDepth = 0, StringRef CoverageArches = "");
+             bool ShowTitle, unsigned ViewDepth = 0, StringRef ObjectFilename = "");
 };
 
 } // namespace llvm
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
index d4dec5e699a58..c4aecd3dbac71 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
@@ -17,6 +17,7 @@
 #include "llvm/Support/Format.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/ThreadPool.h"
+#include "llvm/Object/ObjectFile.h"
 #include <optional>
 
 using namespace llvm;
@@ -907,6 +908,36 @@ void SourceCoverageViewHTML::renderSourceName(raw_ostream &OS, bool WholeFile) {
      << EndSourceNameDiv;
 }
 
+static Expected<std::string> getArchitectureFromExecutable(StringRef ExecutablePath){
+  ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrError = MemoryBuffer::getFile(ExecutablePath);
+  if(!BufferOrError){
+    return createStringError(BufferOrError.getError(), "Failed to load input file");
+  }
+
+  Expected<std::unique_ptr<object::ObjectFile>> ObjectOrError = object::ObjectFile::createObjectFile(BufferOrError.get()->getMemBufferRef());
+  if(!ObjectOrError){
+    return ObjectOrError.takeError();
+  }
+
+  std::unique_ptr<llvm::object::ObjectFile> &Object = ObjectOrError.get();
+
+  StringRef ArchStr = Object->getArch() != Triple::UnknownArch ? Triple::getArchTypeName(Object->getArch()) : "unknown";
+
+  return ArchStr.str();
+}
+
+void SourceCoverageViewHTML::renderArchandObj(raw_ostream &OS, StringRef ObjectFilename) {
+  Expected<std::string> ArchOrErr = getArchitectureFromExecutable(ObjectFilename);
+    if (!ArchOrErr) {
+      // Handle the error
+      logAllUnhandledErrors(ArchOrErr.takeError(), llvm::errs(), "Error extracting architecture: ");
+      return;
+    }
+    // Use the value
+  StringRef Arch = *ArchOrErr;
+  OS << tag("pre", escape("\t-" + Arch.str() + "\n" + "\t-" + ObjectFilename.str(), getOptions()));
+}
+
 void SourceCoverageViewHTML::renderLinePrefix(raw_ostream &OS, unsigned) {
   OS << "<tr>";
 }
@@ -1062,30 +1093,6 @@ void SourceCoverageViewHTML::renderLineCoverageColumn(
   OS << tag("td", Count, CoverageClass);
 }
 
-void SourceCoverageViewHTML::renderArchLineCoverageColumn(
-    raw_ostream &OS,
-    const LineCoverageStats &Line,
-    std::vector<std::vector<LineCoverageStats>> LineArchStats) {
-  
-  std::string CellContent;
-
-  if (Line.isMapped()) {
-    unsigned LineNo = Line.getLine();
-    for (const auto &ArchStats : LineArchStats[LineNo]) {
-      CellContent += formatBinaryCount(ArchStats.getExecutionCount()) + "/";
-    }
-    if (!CellContent.empty())
-      CellContent.pop_back(); // Remove trailing '/'
-  }
-
-  std::string CoverageClass =
-      (Line.getExecutionCount() > 0)
-          ? "covered-line"
-          : (Line.isMapped() ? "uncovered-line" : "skipped-line");
-
-  OS << tag("td", tag("pre", CellContent), CoverageClass);
-}
-
 
 void SourceCoverageViewHTML::renderLineNumberColumn(raw_ostream &OS,
                                                     unsigned LineNo) {
@@ -1220,7 +1227,7 @@ void SourceCoverageViewHTML::renderMCDCView(raw_ostream &OS, MCDCView &MRV,
 
 void SourceCoverageViewHTML::renderInstantiationView(raw_ostream &OS,
                                                      InstantiationView &ISV,
-                                                     unsigned ViewDepth) {
+                                                     unsigned ViewDepth, StringRef ObjectFilename) {
   OS << BeginExpansionDiv;
   if (!ISV.View)
     OS << BeginSourceNameDiv
@@ -1230,7 +1237,7 @@ void SourceCoverageViewHTML::renderInstantiationView(raw_ostream &OS,
        << EndSourceNameDiv;
   else
     ISV.View->print(OS, /*WholeFile=*/false, /*ShowSourceName=*/true,
-                    /*ShowTitle=*/false, ViewDepth);
+                    /*ShowTitle=*/false, ViewDepth, ObjectFilename);
   OS << EndExpansionDiv;
 }
 
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewHTML.h b/llvm/tools/llvm-cov/SourceCoverageViewHTML.h
index 37098273510e0..92cbe6c16d23d 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewHTML.h
+++ b/llvm/tools/llvm-cov/SourceCoverageViewHTML.h
@@ -71,6 +71,8 @@ class SourceCoverageViewHTML : public SourceCoverageView {
 
   void renderSourceName(raw_ostream &OS, bool WholeFile) override;
 
+  void renderArchandObj(raw_ostream &OS, StringRef ObjectFilename) override;
+
   void renderLinePrefix(raw_ostream &OS, unsigned ViewDepth) override;
 
   void renderLineSuffix(raw_ostream &OS, unsigned ViewDepth) override;
@@ -94,13 +96,11 @@ class SourceCoverageViewHTML : public SourceCoverageView {
                       unsigned ViewDepth) override;
 
   void renderInstantiationView(raw_ostream &OS, InstantiationView &ISV,
-                               unsigned ViewDepth) override;
+                               unsigned ViewDepth, StringRef ObjectFilenames) override;
 
   void renderLineCoverageColumn(raw_ostream &OS,
                                 const LineCoverageStats &Line) override;
 
-  void renderArchLineCoverageColumn(raw_ostream &OS, const LineCoverageStats &Line, std::vector<std::vector<LineCoverageStats>> LineArchStats) override;
-
   void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo) override;
 
   void renderRegionMarkers(raw_ostream &OS, const LineCoverageStats &Line,
@@ -113,8 +113,8 @@ class SourceCoverageViewHTML : public SourceCoverageView {
 public:
   SourceCoverageViewHTML(StringRef SourceName, const MemoryBuffer &File,
                          const CoverageViewOptions &Options,
-                         coverage::CoverageData &&CoverageInfo)
-      : SourceCoverageView(SourceName, File, Options, std::move(CoverageInfo)) {
+                         coverage::CoverageData &&CoverageInfo, std::vector<StringRef> ObjectFilenames)
+      : SourceCoverageView(SourceName, File, Options, std::move(CoverageInfo), ObjectFilenames) {
   }
 };
 
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
index 9471f7529e104..e70fb6cf4e292 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
@@ -18,6 +18,7 @@
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/Path.h"
+#include "llvm/Object/ObjectFile.h"
 #include <optional>
 
 using namespace llvm;
@@ -140,6 +141,38 @@ void SourceCoverageViewText::renderSourceName(raw_ostream &OS, bool WholeFile) {
                                                       << ":\n";
 }
 
+static Expected<std::string> getArchitectureFromExecutable(StringRef ExecutablePath){
+  ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrError = MemoryBuffer::getFile(ExecutablePath);
+  if(!BufferOrError){
+    return createStringError(BufferOrError.getError(), "Failed to load input file");
+  }
+
+  Expected<std::unique_ptr<object::ObjectFile>> ObjectOrError = object::ObjectFile::createObjectFile(BufferOrError.get()->getMemBufferRef());
+  if(!ObjectOrError){
+    return ObjectOrError.takeError();
+  }
+
+  std::unique_ptr<llvm::object::ObjectFile> &Object = ObjectOrError.get();
+
+  StringRef ArchStr = Object->getArch() != Triple::UnknownArch ? Triple::getArchTypeName(Object->getArch()) : "unknown";
+
+  return ArchStr.str();
+}
+
+void SourceCoverageViewText::renderArchandObj(raw_ostream &OS, StringRef ObjectFilename) {
+  Expected<std::string> ArchOrErr = getArchitectureFromExecutable(ObjectFilename);
+    if (!ArchOrErr) {
+      // Handle the error
+      logAllUnhandledErrors(ArchOrErr.takeError(), llvm::errs(), "Error extracting architecture: ");
+      return;
+    }
+    // Use the value
+  StringRef Arch = *ArchOrErr;
+  getOptions().colored_ostream(OS, raw_ostream::CYAN) << "\t-" + Arch + "\n" + "\t-" + ObjectFilename
+                                                      << ":\n";
+}
+
+
 void SourceCoverageViewText::renderLinePrefix(raw_ostream &OS,
                                               unsigned ViewDepth) {
   for (unsigned I = 0; I < ViewDepth; ++I)
@@ -223,17 +256,6 @@ void SourceCoverageViewText::renderLineCoverageColumn(
   OS << '|';
 }
 
-void SourceCoverageViewText::renderArchLineCoverageColumn(
-    raw_ostream &OS, const LineCoverageStats &Line, std::vector<std::vector<LineCoverageStats>> LineArchStats) {
-  if (!Line.isMapped()) {
-    OS.indent(LineCoverageColumnWidth) << '|';
-    return;
-  }
-  std::string C = formatBinaryCount(Line.getExecutionCount());
-  OS.indent(LineCoverageColumnWidth - C.size());
-  colored_ostream(OS, raw_ostream::MAGENTA, Line.hasMultipleRegions() && getOptions().Colors) << C;
-  OS << '|';
-}
 
 void SourceCoverageViewText::renderLineNumberColumn(raw_ostream &OS,
                                                     unsigned LineNo) {
@@ -400,7 +422,7 @@ void SourceCoverageViewText::renderMCDCView(raw_ostream &OS, MCDCView &MRV,
 
 void SourceCoverageViewText::renderInstantiationView(raw_ostream &OS,
                                                      InstantiationView &ISV,
-                                                     unsigned ViewDepth) {
+                                                     unsigned ViewDepth, StringRef ObjectFilename) {
   renderLinePrefix(OS, ViewDepth);
   OS << ' ';
   if (!ISV.View)
@@ -408,7 +430,7 @@ void SourceCoverageViewText::renderInstantiationView(raw_ostream &OS,
         << "Unexecuted instantiation: " << ISV.FunctionName << "\n";
   else
     ISV.View->print(OS, /*WholeFile=*/false, /*ShowSourceName=*/true,
-                    /*ShowTitle=*/false, ViewDepth);
+                    /*ShowTitle=*/false, ViewDepth, ObjectFilename);
 }
 
 void SourceCoverageViewText::renderTitle(raw_ostream &OS, StringRef Title) {
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewText.h b/llvm/tools/llvm-cov/SourceCoverageViewText.h
index 3841aad607324..7f7131e1eb324 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewText.h
+++ b/llvm/tools/llvm-cov/SourceCoverageViewText.h
@@ -58,6 +58,8 @@ class SourceCoverageViewText : public SourceCoverageView {
 
   void renderSourceName(raw_ostream &OS, bool WholeFile) override;
 
+  void renderArchandObj(raw_ostream &OS, StringRef ObjectFilename) override;
+
   void renderLinePrefix(raw_ostream &OS, unsigned ViewDepth) override;
 
   void renderLineSuffix(raw_ostream &OS, unsigned ViewDepth) override;
@@ -81,13 +83,11 @@ class SourceCoverageViewText : public SourceCoverageView {
                       unsigned ViewDepth) override;
 
   void renderInstantiationView(raw_ostream &OS, InstantiationView &ISV,
-                               unsigned ViewDepth) override;
+                               unsigned ViewDepth, StringRef ObjectFilenames) override;
 
   void renderLineCoverageColumn(raw_ostream &OS,
                                 const LineCoverageStats &Line) override;
   
-  void renderArchLineCoverageColumn(raw_ostream &OS, const LineCoverageStats &Line, std::vector<std::vector<LineCoverageStats>> LineArchStats) override;
-
   void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo) override;
 
   void renderRegionMarkers(raw_ostream &OS, const LineCoverageStats &Line,
@@ -100,8 +100,8 @@ class SourceCoverageViewText : public SourceCoverageView {
 public:
   SourceCoverageViewText(StringRef SourceName, const MemoryBuffer &File,
                          const CoverageViewOptions &Options,
-                         CoverageData &&CoverageInfo)
-      : SourceCoverageView(SourceName, File, Options, std::move(CoverageInfo)) {
+                         CoverageData &&CoverageInfo, std::vector<StringRef> ObjectFilenames)
+      : SourceCoverageView(SourceName, File, Options, std::move(CoverageInfo), ObjectFilenames) {
   }
 };
 
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index e24cba8f532bd..aa0a90aaa7afd 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -712,11 +712,10 @@ loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
   StringRef ObjectFilename = "";
 
   StringRef FilenameRef = Filename;
-  if(!ObjectAwareHashing.empty()){
+  if (!ObjectAwareHashing.empty()) {
     ObjectFilename = ObjectAwareHashing.data();
   }
 
-
   using ::llvm::memprof::RawMemProfReader;
   if (RawMemProfReader::hasFormat(ProfileFile)) {
     auto ReaderOrErr = RawMemProfReader::create(ProfileFile, ProfiledBinary);
@@ -805,8 +804,9 @@ loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
   const ProfCorrelatorKind CorrelatorKind = BIDFetcherCorrelatorKind
                                                 ? *BIDFetcherCorrelatorKind
                                                 : ProfCorrelatorKind::NONE;
-  auto ReaderOrErr = InstrProfReader::create(ProfileFile, *FS, Correlator,
-                                             BIDFetcher, CorrelatorKind, Warn, ObjectFilename);
+  auto ReaderOrErr =
+      InstrProfReader::create(ProfileFile, *FS, Correlator, BIDFetcher,
+                              CorrelatorKind, Warn, ObjectFilename);
   if (Error E = ReaderOrErr.takeError()) {
     // Skip the empty profiles by returning silently.
     auto [ErrCode, Msg] = InstrProfError::take(std::move(E));
@@ -1064,7 +1064,7 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs,
     for (int I = 0; I < int(Inputs.size()); ++I) {
       Pool.async(loadInput, Inputs[I], Remapper, Correlator.get(), ProfiledBinary,
                  Contexts[Ctx].get(), BIDFetcher.get(),
-                 &BIDFetcherCorrelateKind, !ObjectAwareHashing[I].empty() ? ObjectAwareHashing[I] : "");
+                 &BIDFetcherCorrelateKind, !ObjectAwareHashing.empty() ? ObjectAwareHashing[I] : "");
       Ctx = (Ctx + 1) % NumThreads;
     }
     Pool.wait();

>From 33ed3662da65f1141f0bd57aa03b77f189a15f60 Mon Sep 17 00:00:00 2001
From: Andres Wearden <andreswearden5 at gmail.com>
Date: Fri, 1 Aug 2025 10:41:13 -0700
Subject: [PATCH 17/17] changed some of the llvm-lit file names to make more
 sense

---
 .../Inputs/{fb.c => merge-same-func-bin1-2.c} |  0
 .../{myprogram.c => merge-same-func-bin1.c}   |  0
 .../Inputs/{mypg.c => merge-same-func-bin2.c} |  0
 ...ulti-file.c => merge-same-func-diff-bin.c} | 21 +++++++++----------
 .../tools/llvm-cov/merge-show-arch-exec.c     |  1 +
 5 files changed, 11 insertions(+), 11 deletions(-)
 rename llvm/test/tools/llvm-cov/Inputs/{fb.c => merge-same-func-bin1-2.c} (100%)
 rename llvm/test/tools/llvm-cov/Inputs/{myprogram.c => merge-same-func-bin1.c} (100%)
 rename llvm/test/tools/llvm-cov/Inputs/{mypg.c => merge-same-func-bin2.c} (100%)
 rename llvm/test/tools/llvm-cov/{merge-binary-coverage-multi-file.c => merge-same-func-diff-bin.c} (76%)

diff --git a/llvm/test/tools/llvm-cov/Inputs/fb.c b/llvm/test/tools/llvm-cov/Inputs/merge-same-func-bin1-2.c
similarity index 100%
rename from llvm/test/tools/llvm-cov/Inputs/fb.c
rename to llvm/test/tools/llvm-cov/Inputs/merge-same-func-bin1-2.c
diff --git a/llvm/test/tools/llvm-cov/Inputs/myprogram.c b/llvm/test/tools/llvm-cov/Inputs/merge-same-func-bin1.c
similarity index 100%
rename from llvm/test/tools/llvm-cov/Inputs/myprogram.c
rename to llvm/test/tools/llvm-cov/Inputs/merge-same-func-bin1.c
diff --git a/llvm/test/tools/llvm-cov/Inputs/mypg.c b/llvm/test/tools/llvm-cov/Inputs/merge-same-func-bin2.c
similarity index 100%
rename from llvm/test/tools/llvm-cov/Inputs/mypg.c
rename to llvm/test/tools/llvm-cov/Inputs/merge-same-func-bin2.c
diff --git a/llvm/test/tools/llvm-cov/merge-binary-coverage-multi-file.c b/llvm/test/tools/llvm-cov/merge-same-func-diff-bin.c
similarity index 76%
rename from llvm/test/tools/llvm-cov/merge-binary-coverage-multi-file.c
rename to llvm/test/tools/llvm-cov/merge-same-func-diff-bin.c
index 74945ab84bb36..6132254b0ac17 100644
--- a/llvm/test/tools/llvm-cov/merge-binary-coverage-multi-file.c
+++ b/llvm/test/tools/llvm-cov/merge-same-func-diff-bin.c
@@ -1,14 +1,13 @@
 // RUN: clang -O0 -fprofile-instr-generate -fcoverage-mapping \
-// RUN:        %S/Inputs/myprogram.c %S/Inputs/fb.c -o %t.hex
-// RUN: env LLVM_PROFILE_FILE=%t.hex.profraw 
+// RUN:        %S/Inputs/merge-same-func-bin1.c %S/Inputs/merge-same-func-bin1-2.c -o %t.hex
 // RUN: %t.hex
+// RUN: cp default.profraw %t.hex.profraw 
 //
 //---------------- build & run the “x86” variant ------------------------------//
 // RUN: clang -O0 -fprofile-instr-generate -fcoverage-mapping \
-// RUN:        %S/Inputs/mypg.c %S/Inputs/fb.c -o %t.x86
-// RUN: env LLVM_PROFILE_FILE=%t.x86.profraw 
+// RUN:        %S/Inputs/merge-same-func-bin2.c %S/Inputs/merge-same-func-bin1-2.c -o %t.x86
 // RUN: %t.x86 || true
-//
+// RUN: cp default.profraw %t.x86.profraw  
 //---------------- merge the raw profiles ------------------------------------//
 // RUN: llvm-profdata merge --object-aware-hashing=%t.x86 %t.x86.profraw \
 // RUN:                     --object-aware-hashing=%t.hex %t.hex.profraw \
@@ -17,18 +16,14 @@
 //---------------- show unified coverage & check -----------------------------//
 // RUN: llvm-cov show -instr-profile=%t.profdata --object=%t.x86 --object=%t.hex --merge-binary-coverage | FileCheck %s
 //
-// CHECK-LABEL: {{.*fb\.c}}:
+// CHECK-LABEL: {{.*merge-same-func-bin1-2\.c}}:
 // CHECK:     1|      1|int foo() { return 0; }
 // CHECK:     2|       |
 // CHECK:     3|      1|int bar() { return 0; }
 // CHECK:     4|       |
 // CHECK:     5|      1|int bun() { return 0; }
 //
-// CHECK-LABEL: {{.*mypg\.c}}:
-// CHECK:     1|      0|int baz() { return 0; }
-// CHECK:     2|      1|int main() { return 1; }
-//
-// CHECK-LABEL: {{.*myprogram\.c}}:
+// CHECK-LABEL: {{.*merge-same-func-bin1\.c}}:
 // CHECK:     1|       |extern int foo();
 // CHECK:     2|       |extern int bar();
 // CHECK:     3|       |extern int bun();
@@ -37,3 +32,7 @@
 // CHECK:     6|      1|int main()
 // CHECK:     7|      1|  return foo() + bar() + bun();
 // CHECK:     8|      1|}
+//
+// CHECK-LABEL: {{.*merge-same-func-bin2\.c}}:
+// CHECK:     1|      0|int baz() { return 0; }
+// CHECK:     2|      1|int main() { return 1; }
diff --git a/llvm/test/tools/llvm-cov/merge-show-arch-exec.c b/llvm/test/tools/llvm-cov/merge-show-arch-exec.c
index aae3570042d10..967d5f2604311 100644
--- a/llvm/test/tools/llvm-cov/merge-show-arch-exec.c
+++ b/llvm/test/tools/llvm-cov/merge-show-arch-exec.c
@@ -16,6 +16,7 @@
 //
 // RUN: llvm-cov show -instr-profile=%t.profdata --object=%t.toggle --object=%t.notoggle --merge-binary-coverage --show-arch-executables | FileCheck %s
 
+// CHECK:       |    1|      2|int main() {
 // CHECK:       |    2|      2|int a = 1;
 // CHECK:       |    3|      2|int b = 2;
 // CHECK:       |    4|      2|int res = 0;



More information about the llvm-commits mailing list