| //===--- FunctionId.h - Sample profile function object ----------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| /// |
| /// \file |
| /// |
| /// Defines FunctionId class. |
| /// |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_PROFILEDATA_FUNCTIONID_H |
| #define LLVM_PROFILEDATA_FUNCTIONID_H |
| |
| #include "llvm/ADT/DenseMapInfo.h" |
| #include "llvm/ADT/Hashing.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/Support/MD5.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include <cstdint> |
| |
| namespace llvm { |
| namespace sampleprof { |
| |
| /// This class represents a function that is read from a sample profile. It |
| /// comes with two forms: a string or a hash code. The latter form is the 64-bit |
| /// MD5 of the function name for efficient storage supported by ExtBinary |
| /// profile format, and when reading the profile, this class can represent it |
| /// without converting it to a string first. |
| /// When representing a hash code, we utilize the LengthOrHashCode field to |
| /// store it, and Name is set to null. When representing a string, it is same as |
| /// StringRef. |
| class FunctionId { |
| |
| const char *Data = nullptr; |
| |
| // Use uint64_t instead of size_t so that it can also hold a MD5 value on |
| // 32-bit system. |
| uint64_t LengthOrHashCode = 0; |
| |
| /// Extension to memcmp to handle hash code representation. If both are hash |
| /// values, Lhs and Rhs are both null, function returns 0 (and needs an extra |
| /// comparison using getIntValue). If only one is hash code, it is considered |
| /// less than the StringRef one. Otherwise perform normal string comparison. |
| static int compareMemory(const char *Lhs, const char *Rhs, uint64_t Length) { |
| if (Lhs == Rhs) |
| return 0; |
| if (!Lhs) |
| return -1; |
| if (!Rhs) |
| return 1; |
| return ::memcmp(Lhs, Rhs, (size_t)Length); |
| } |
| |
| public: |
| FunctionId() = default; |
| |
| /// Constructor from a StringRef. |
| explicit FunctionId(StringRef Str) |
| : Data(Str.data()), LengthOrHashCode(Str.size()) { |
| } |
| |
| /// Constructor from a hash code. |
| explicit FunctionId(uint64_t HashCode) |
| : LengthOrHashCode(HashCode) { |
| assert(HashCode != 0); |
| } |
| |
| /// Check for equality. Similar to StringRef::equals, but will also cover for |
| /// the case where one or both are hash codes. Comparing their int values are |
| /// sufficient. A hash code FunctionId is considered not equal to a StringRef |
| /// FunctionId regardless of actual contents. |
| bool equals(const FunctionId &Other) const { |
| return LengthOrHashCode == Other.LengthOrHashCode && |
| compareMemory(Data, Other.Data, LengthOrHashCode) == 0; |
| } |
| |
| /// Total order comparison. If both FunctionId are StringRef, this is the same |
| /// as StringRef::compare. If one of them is StringRef, it is considered |
| /// greater than the hash code FunctionId. Otherwise this is the the same |
| /// as comparing their int values. |
| int compare(const FunctionId &Other) const { |
| auto Res = compareMemory( |
| Data, Other.Data, std::min(LengthOrHashCode, Other.LengthOrHashCode)); |
| if (Res != 0) |
| return Res; |
| if (LengthOrHashCode == Other.LengthOrHashCode) |
| return 0; |
| return LengthOrHashCode < Other.LengthOrHashCode ? -1 : 1; |
| } |
| |
| /// Convert to a string, usually for output purpose. Use caution on return |
| /// value's lifetime when converting to StringRef. |
| std::string str() const { |
| if (Data) |
| return std::string(Data, LengthOrHashCode); |
| if (LengthOrHashCode != 0) |
| return std::to_string(LengthOrHashCode); |
| return std::string(); |
| } |
| |
| /// Convert to StringRef. This is only allowed when it is known this object is |
| /// representing a StringRef, not a hash code. Calling this function on a hash |
| /// code is considered an error. |
| StringRef stringRef() const { |
| if (Data) |
| return StringRef(Data, LengthOrHashCode); |
| assert(LengthOrHashCode == 0 && |
| "Cannot convert MD5 FunctionId to StringRef"); |
| return StringRef(); |
| } |
| |
| friend raw_ostream &operator<<(raw_ostream &OS, const FunctionId &Obj); |
| |
| /// Get hash code of this object. Returns this object's hash code if it is |
| /// already representing one, otherwise returns the MD5 of its string content. |
| /// Note that it is not the same as std::hash because we want to keep the |
| /// consistency that the same sample profile function in string form or MD5 |
| /// form has the same hash code. |
| uint64_t getHashCode() const { |
| if (Data) |
| return MD5Hash(StringRef(Data, LengthOrHashCode)); |
| return LengthOrHashCode; |
| } |
| |
| bool empty() const { return LengthOrHashCode == 0; } |
| |
| /// Check if this object represents a StringRef, or a hash code. |
| bool isStringRef() const { return Data != nullptr; } |
| }; |
| |
| inline bool operator==(const FunctionId &LHS, const FunctionId &RHS) { |
| return LHS.equals(RHS); |
| } |
| |
| inline bool operator!=(const FunctionId &LHS, const FunctionId &RHS) { |
| return !LHS.equals(RHS); |
| } |
| |
| inline bool operator<(const FunctionId &LHS, const FunctionId &RHS) { |
| return LHS.compare(RHS) < 0; |
| } |
| |
| inline bool operator<=(const FunctionId &LHS, const FunctionId &RHS) { |
| return LHS.compare(RHS) <= 0; |
| } |
| |
| inline bool operator>(const FunctionId &LHS, const FunctionId &RHS) { |
| return LHS.compare(RHS) > 0; |
| } |
| |
| inline bool operator>=(const FunctionId &LHS, const FunctionId &RHS) { |
| return LHS.compare(RHS) >= 0; |
| } |
| |
| inline raw_ostream &operator<<(raw_ostream &OS, const FunctionId &Obj) { |
| if (Obj.Data) |
| return OS << StringRef(Obj.Data, Obj.LengthOrHashCode); |
| if (Obj.LengthOrHashCode != 0) |
| return OS << Obj.LengthOrHashCode; |
| return OS; |
| } |
| |
| inline uint64_t MD5Hash(const FunctionId &Obj) { |
| return Obj.getHashCode(); |
| } |
| |
| inline uint64_t hash_value(const FunctionId &Obj) { |
| return Obj.getHashCode(); |
| } |
| |
| } // end namespace sampleprof |
| |
| /// Template specialization for FunctionId so that it can be used in LLVM map |
| /// containers. |
| template <> struct DenseMapInfo<sampleprof::FunctionId, void> { |
| |
| static inline sampleprof::FunctionId getEmptyKey() { |
| return sampleprof::FunctionId(~0ULL); |
| } |
| |
| static inline sampleprof::FunctionId getTombstoneKey() { |
| return sampleprof::FunctionId(~1ULL); |
| } |
| |
| static unsigned getHashValue(const sampleprof::FunctionId &Val) { |
| return Val.getHashCode(); |
| } |
| |
| static bool isEqual(const sampleprof::FunctionId &LHS, |
| const sampleprof::FunctionId &RHS) { |
| return LHS == RHS; |
| } |
| }; |
| |
| } // end namespace llvm |
| |
| namespace std { |
| |
| /// Template specialization for FunctionId so that it can be used in STL |
| /// containers. |
| template <> struct hash<llvm::sampleprof::FunctionId> { |
| size_t operator()(const llvm::sampleprof::FunctionId &Val) const { |
| return Val.getHashCode(); |
| } |
| }; |
| |
| } // end namespace std |
| |
| #endif // LLVM_PROFILEDATA_FUNCTIONID_H |