Skip to content

Commit f099207

Browse files
committed
Rebase with main
1 parent 70fd123 commit f099207

19 files changed

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

0 commit comments

Comments
 (0)