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