xref: /llvm-project/llvm/include/llvm/ProfileData/FunctionId.h (revision ef0e0adccd94ffdb10546491ef2719669754d3c9)
1*ef0e0adcSWilliam Junda Huang //===--- FunctionId.h - Sample profile function object ----------*- C++ -*-===//
2*ef0e0adcSWilliam Junda Huang //
3*ef0e0adcSWilliam Junda Huang // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*ef0e0adcSWilliam Junda Huang // See https://llvm.org/LICENSE.txt for license information.
5*ef0e0adcSWilliam Junda Huang // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*ef0e0adcSWilliam Junda Huang //
7*ef0e0adcSWilliam Junda Huang //===----------------------------------------------------------------------===//
8*ef0e0adcSWilliam Junda Huang ///
9*ef0e0adcSWilliam Junda Huang /// \file
10*ef0e0adcSWilliam Junda Huang ///
11*ef0e0adcSWilliam Junda Huang /// Defines FunctionId class.
12*ef0e0adcSWilliam Junda Huang ///
13*ef0e0adcSWilliam Junda Huang //===----------------------------------------------------------------------===//
14*ef0e0adcSWilliam Junda Huang 
15*ef0e0adcSWilliam Junda Huang #ifndef LLVM_PROFILEDATA_FUNCTIONID_H
16*ef0e0adcSWilliam Junda Huang #define LLVM_PROFILEDATA_FUNCTIONID_H
17*ef0e0adcSWilliam Junda Huang 
18*ef0e0adcSWilliam Junda Huang #include "llvm/ADT/DenseMapInfo.h"
19*ef0e0adcSWilliam Junda Huang #include "llvm/ADT/Hashing.h"
20*ef0e0adcSWilliam Junda Huang #include "llvm/ADT/StringRef.h"
21*ef0e0adcSWilliam Junda Huang #include "llvm/Support/MD5.h"
22*ef0e0adcSWilliam Junda Huang #include "llvm/Support/raw_ostream.h"
23*ef0e0adcSWilliam Junda Huang #include <cstdint>
24*ef0e0adcSWilliam Junda Huang 
25*ef0e0adcSWilliam Junda Huang namespace llvm {
26*ef0e0adcSWilliam Junda Huang namespace sampleprof {
27*ef0e0adcSWilliam Junda Huang 
28*ef0e0adcSWilliam Junda Huang /// This class represents a function that is read from a sample profile. It
29*ef0e0adcSWilliam Junda Huang /// comes with two forms: a string or a hash code. The latter form is the 64-bit
30*ef0e0adcSWilliam Junda Huang /// MD5 of the function name for efficient storage supported by ExtBinary
31*ef0e0adcSWilliam Junda Huang /// profile format, and when reading the profile, this class can represent it
32*ef0e0adcSWilliam Junda Huang /// without converting it to a string first.
33*ef0e0adcSWilliam Junda Huang /// When representing a hash code, we utilize the LengthOrHashCode field to
34*ef0e0adcSWilliam Junda Huang /// store it, and Name is set to null. When representing a string, it is same as
35*ef0e0adcSWilliam Junda Huang /// StringRef.
36*ef0e0adcSWilliam Junda Huang class FunctionId {
37*ef0e0adcSWilliam Junda Huang 
38*ef0e0adcSWilliam Junda Huang   const char *Data = nullptr;
39*ef0e0adcSWilliam Junda Huang 
40*ef0e0adcSWilliam Junda Huang   // Use uint64_t instead of size_t so that it can also hold a MD5 value on
41*ef0e0adcSWilliam Junda Huang   // 32-bit system.
42*ef0e0adcSWilliam Junda Huang   uint64_t LengthOrHashCode = 0;
43*ef0e0adcSWilliam Junda Huang 
44*ef0e0adcSWilliam Junda Huang   /// Extension to memcmp to handle hash code representation. If both are hash
45*ef0e0adcSWilliam Junda Huang   /// values, Lhs and Rhs are both null, function returns 0 (and needs an extra
46*ef0e0adcSWilliam Junda Huang   /// comparison using getIntValue). If only one is hash code, it is considered
47*ef0e0adcSWilliam Junda Huang   /// less than the StringRef one. Otherwise perform normal string comparison.
compareMemory(const char * Lhs,const char * Rhs,uint64_t Length)48*ef0e0adcSWilliam Junda Huang   static int compareMemory(const char *Lhs, const char *Rhs, uint64_t Length) {
49*ef0e0adcSWilliam Junda Huang     if (Lhs == Rhs)
50*ef0e0adcSWilliam Junda Huang       return 0;
51*ef0e0adcSWilliam Junda Huang     if (!Lhs)
52*ef0e0adcSWilliam Junda Huang       return -1;
53*ef0e0adcSWilliam Junda Huang     if (!Rhs)
54*ef0e0adcSWilliam Junda Huang       return 1;
55*ef0e0adcSWilliam Junda Huang     return ::memcmp(Lhs, Rhs, (size_t)Length);
56*ef0e0adcSWilliam Junda Huang   }
57*ef0e0adcSWilliam Junda Huang 
58*ef0e0adcSWilliam Junda Huang public:
59*ef0e0adcSWilliam Junda Huang   FunctionId() = default;
60*ef0e0adcSWilliam Junda Huang 
61*ef0e0adcSWilliam Junda Huang   /// Constructor from a StringRef.
FunctionId(StringRef Str)62*ef0e0adcSWilliam Junda Huang   explicit FunctionId(StringRef Str)
63*ef0e0adcSWilliam Junda Huang       : Data(Str.data()), LengthOrHashCode(Str.size()) {
64*ef0e0adcSWilliam Junda Huang   }
65*ef0e0adcSWilliam Junda Huang 
66*ef0e0adcSWilliam Junda Huang   /// Constructor from a hash code.
FunctionId(uint64_t HashCode)67*ef0e0adcSWilliam Junda Huang   explicit FunctionId(uint64_t HashCode)
68*ef0e0adcSWilliam Junda Huang       : LengthOrHashCode(HashCode) {
69*ef0e0adcSWilliam Junda Huang     assert(HashCode != 0);
70*ef0e0adcSWilliam Junda Huang   }
71*ef0e0adcSWilliam Junda Huang 
72*ef0e0adcSWilliam Junda Huang   /// Check for equality. Similar to StringRef::equals, but will also cover for
73*ef0e0adcSWilliam Junda Huang   /// the case where one or both are hash codes. Comparing their int values are
74*ef0e0adcSWilliam Junda Huang   /// sufficient. A hash code FunctionId is considered not equal to a StringRef
75*ef0e0adcSWilliam Junda Huang   /// FunctionId regardless of actual contents.
equals(const FunctionId & Other)76*ef0e0adcSWilliam Junda Huang   bool equals(const FunctionId &Other) const {
77*ef0e0adcSWilliam Junda Huang     return LengthOrHashCode == Other.LengthOrHashCode &&
78*ef0e0adcSWilliam Junda Huang            compareMemory(Data, Other.Data, LengthOrHashCode) == 0;
79*ef0e0adcSWilliam Junda Huang   }
80*ef0e0adcSWilliam Junda Huang 
81*ef0e0adcSWilliam Junda Huang   /// Total order comparison. If both FunctionId are StringRef, this is the same
82*ef0e0adcSWilliam Junda Huang   /// as StringRef::compare. If one of them is StringRef, it is considered
83*ef0e0adcSWilliam Junda Huang   /// greater than the hash code FunctionId. Otherwise this is the the same
84*ef0e0adcSWilliam Junda Huang   /// as comparing their int values.
compare(const FunctionId & Other)85*ef0e0adcSWilliam Junda Huang   int compare(const FunctionId &Other) const {
86*ef0e0adcSWilliam Junda Huang     auto Res = compareMemory(
87*ef0e0adcSWilliam Junda Huang         Data, Other.Data, std::min(LengthOrHashCode, Other.LengthOrHashCode));
88*ef0e0adcSWilliam Junda Huang     if (Res != 0)
89*ef0e0adcSWilliam Junda Huang       return Res;
90*ef0e0adcSWilliam Junda Huang     if (LengthOrHashCode == Other.LengthOrHashCode)
91*ef0e0adcSWilliam Junda Huang       return 0;
92*ef0e0adcSWilliam Junda Huang     return LengthOrHashCode < Other.LengthOrHashCode ? -1 : 1;
93*ef0e0adcSWilliam Junda Huang   }
94*ef0e0adcSWilliam Junda Huang 
95*ef0e0adcSWilliam Junda Huang   /// Convert to a string, usually for output purpose. Use caution on return
96*ef0e0adcSWilliam Junda Huang   /// value's lifetime when converting to StringRef.
str()97*ef0e0adcSWilliam Junda Huang   std::string str() const {
98*ef0e0adcSWilliam Junda Huang     if (Data)
99*ef0e0adcSWilliam Junda Huang       return std::string(Data, LengthOrHashCode);
100*ef0e0adcSWilliam Junda Huang     if (LengthOrHashCode != 0)
101*ef0e0adcSWilliam Junda Huang       return std::to_string(LengthOrHashCode);
102*ef0e0adcSWilliam Junda Huang     return std::string();
103*ef0e0adcSWilliam Junda Huang   }
104*ef0e0adcSWilliam Junda Huang 
105*ef0e0adcSWilliam Junda Huang   /// Convert to StringRef. This is only allowed when it is known this object is
106*ef0e0adcSWilliam Junda Huang   /// representing a StringRef, not a hash code. Calling this function on a hash
107*ef0e0adcSWilliam Junda Huang   /// code is considered an error.
stringRef()108*ef0e0adcSWilliam Junda Huang   StringRef stringRef() const {
109*ef0e0adcSWilliam Junda Huang     if (Data)
110*ef0e0adcSWilliam Junda Huang       return StringRef(Data, LengthOrHashCode);
111*ef0e0adcSWilliam Junda Huang     assert(LengthOrHashCode == 0 &&
112*ef0e0adcSWilliam Junda Huang            "Cannot convert MD5 FunctionId to StringRef");
113*ef0e0adcSWilliam Junda Huang     return StringRef();
114*ef0e0adcSWilliam Junda Huang   }
115*ef0e0adcSWilliam Junda Huang 
116*ef0e0adcSWilliam Junda Huang   friend raw_ostream &operator<<(raw_ostream &OS, const FunctionId &Obj);
117*ef0e0adcSWilliam Junda Huang 
118*ef0e0adcSWilliam Junda Huang   /// Get hash code of this object. Returns this object's hash code if it is
119*ef0e0adcSWilliam Junda Huang   /// already representing one, otherwise returns the MD5 of its string content.
120*ef0e0adcSWilliam Junda Huang   /// Note that it is not the same as std::hash because we want to keep the
121*ef0e0adcSWilliam Junda Huang   /// consistency that the same sample profile function in string form or MD5
122*ef0e0adcSWilliam Junda Huang   /// form has the same hash code.
getHashCode()123*ef0e0adcSWilliam Junda Huang   uint64_t getHashCode() const {
124*ef0e0adcSWilliam Junda Huang     if (Data)
125*ef0e0adcSWilliam Junda Huang       return MD5Hash(StringRef(Data, LengthOrHashCode));
126*ef0e0adcSWilliam Junda Huang     return LengthOrHashCode;
127*ef0e0adcSWilliam Junda Huang   }
128*ef0e0adcSWilliam Junda Huang 
empty()129*ef0e0adcSWilliam Junda Huang   bool empty() const { return LengthOrHashCode == 0; }
130*ef0e0adcSWilliam Junda Huang 
131*ef0e0adcSWilliam Junda Huang   /// Check if this object represents a StringRef, or a hash code.
isStringRef()132*ef0e0adcSWilliam Junda Huang   bool isStringRef() const { return Data != nullptr; }
133*ef0e0adcSWilliam Junda Huang };
134*ef0e0adcSWilliam Junda Huang 
135*ef0e0adcSWilliam Junda Huang inline bool operator==(const FunctionId &LHS, const FunctionId &RHS) {
136*ef0e0adcSWilliam Junda Huang   return LHS.equals(RHS);
137*ef0e0adcSWilliam Junda Huang }
138*ef0e0adcSWilliam Junda Huang 
139*ef0e0adcSWilliam Junda Huang inline bool operator!=(const FunctionId &LHS, const FunctionId &RHS) {
140*ef0e0adcSWilliam Junda Huang   return !LHS.equals(RHS);
141*ef0e0adcSWilliam Junda Huang }
142*ef0e0adcSWilliam Junda Huang 
143*ef0e0adcSWilliam Junda Huang inline bool operator<(const FunctionId &LHS, const FunctionId &RHS) {
144*ef0e0adcSWilliam Junda Huang   return LHS.compare(RHS) < 0;
145*ef0e0adcSWilliam Junda Huang }
146*ef0e0adcSWilliam Junda Huang 
147*ef0e0adcSWilliam Junda Huang inline bool operator<=(const FunctionId &LHS, const FunctionId &RHS) {
148*ef0e0adcSWilliam Junda Huang   return LHS.compare(RHS) <= 0;
149*ef0e0adcSWilliam Junda Huang }
150*ef0e0adcSWilliam Junda Huang 
151*ef0e0adcSWilliam Junda Huang inline bool operator>(const FunctionId &LHS, const FunctionId &RHS) {
152*ef0e0adcSWilliam Junda Huang   return LHS.compare(RHS) > 0;
153*ef0e0adcSWilliam Junda Huang }
154*ef0e0adcSWilliam Junda Huang 
155*ef0e0adcSWilliam Junda Huang inline bool operator>=(const FunctionId &LHS, const FunctionId &RHS) {
156*ef0e0adcSWilliam Junda Huang   return LHS.compare(RHS) >= 0;
157*ef0e0adcSWilliam Junda Huang }
158*ef0e0adcSWilliam Junda Huang 
159*ef0e0adcSWilliam Junda Huang inline raw_ostream &operator<<(raw_ostream &OS, const FunctionId &Obj) {
160*ef0e0adcSWilliam Junda Huang   if (Obj.Data)
161*ef0e0adcSWilliam Junda Huang     return OS << StringRef(Obj.Data, Obj.LengthOrHashCode);
162*ef0e0adcSWilliam Junda Huang   if (Obj.LengthOrHashCode != 0)
163*ef0e0adcSWilliam Junda Huang     return OS << Obj.LengthOrHashCode;
164*ef0e0adcSWilliam Junda Huang   return OS;
165*ef0e0adcSWilliam Junda Huang }
166*ef0e0adcSWilliam Junda Huang 
MD5Hash(const FunctionId & Obj)167*ef0e0adcSWilliam Junda Huang inline uint64_t MD5Hash(const FunctionId &Obj) {
168*ef0e0adcSWilliam Junda Huang   return Obj.getHashCode();
169*ef0e0adcSWilliam Junda Huang }
170*ef0e0adcSWilliam Junda Huang 
hash_value(const FunctionId & Obj)171*ef0e0adcSWilliam Junda Huang inline uint64_t hash_value(const FunctionId &Obj) {
172*ef0e0adcSWilliam Junda Huang   return Obj.getHashCode();
173*ef0e0adcSWilliam Junda Huang }
174*ef0e0adcSWilliam Junda Huang 
175*ef0e0adcSWilliam Junda Huang } // end namespace sampleprof
176*ef0e0adcSWilliam Junda Huang 
177*ef0e0adcSWilliam Junda Huang /// Template specialization for FunctionId so that it can be used in LLVM map
178*ef0e0adcSWilliam Junda Huang /// containers.
179*ef0e0adcSWilliam Junda Huang template <> struct DenseMapInfo<sampleprof::FunctionId, void> {
180*ef0e0adcSWilliam Junda Huang 
181*ef0e0adcSWilliam Junda Huang   static inline sampleprof::FunctionId getEmptyKey() {
182*ef0e0adcSWilliam Junda Huang     return sampleprof::FunctionId(~0ULL);
183*ef0e0adcSWilliam Junda Huang   }
184*ef0e0adcSWilliam Junda Huang 
185*ef0e0adcSWilliam Junda Huang   static inline sampleprof::FunctionId getTombstoneKey() {
186*ef0e0adcSWilliam Junda Huang     return sampleprof::FunctionId(~1ULL);
187*ef0e0adcSWilliam Junda Huang   }
188*ef0e0adcSWilliam Junda Huang 
189*ef0e0adcSWilliam Junda Huang   static unsigned getHashValue(const sampleprof::FunctionId &Val) {
190*ef0e0adcSWilliam Junda Huang     return Val.getHashCode();
191*ef0e0adcSWilliam Junda Huang   }
192*ef0e0adcSWilliam Junda Huang 
193*ef0e0adcSWilliam Junda Huang   static bool isEqual(const sampleprof::FunctionId &LHS,
194*ef0e0adcSWilliam Junda Huang                       const sampleprof::FunctionId &RHS) {
195*ef0e0adcSWilliam Junda Huang     return LHS == RHS;
196*ef0e0adcSWilliam Junda Huang   }
197*ef0e0adcSWilliam Junda Huang };
198*ef0e0adcSWilliam Junda Huang 
199*ef0e0adcSWilliam Junda Huang } // end namespace llvm
200*ef0e0adcSWilliam Junda Huang 
201*ef0e0adcSWilliam Junda Huang namespace std {
202*ef0e0adcSWilliam Junda Huang 
203*ef0e0adcSWilliam Junda Huang /// Template specialization for FunctionId so that it can be used in STL
204*ef0e0adcSWilliam Junda Huang /// containers.
205*ef0e0adcSWilliam Junda Huang template <> struct hash<llvm::sampleprof::FunctionId> {
206*ef0e0adcSWilliam Junda Huang   size_t operator()(const llvm::sampleprof::FunctionId &Val) const {
207*ef0e0adcSWilliam Junda Huang     return Val.getHashCode();
208*ef0e0adcSWilliam Junda Huang   }
209*ef0e0adcSWilliam Junda Huang };
210*ef0e0adcSWilliam Junda Huang 
211*ef0e0adcSWilliam Junda Huang } // end namespace std
212*ef0e0adcSWilliam Junda Huang 
213*ef0e0adcSWilliam Junda Huang #endif // LLVM_PROFILEDATA_FUNCTIONID_H
214