[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:04:27 PDT 2025
https://github.com/awearden updated https://github.com/llvm/llvm-project/pull/151771
>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