Skip to content

Commit 92dac9f

Browse files
committed
Merge with main
1 parent d343529 commit 92dac9f

22 files changed

+797
-513
lines changed
Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
//===--- FunctionId.h - Sample profile function object ----------*- 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+
/// \file
10+
///
11+
/// Defines FunctionId class.
12+
///
13+
//===----------------------------------------------------------------------===//
14+
15+
#ifndef LLVM_PROFILEDATA_FUNCTIONID_H
16+
#define LLVM_PROFILEDATA_FUNCTIONID_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 that is read from a sample profile. It
29+
/// comes with two forms: a string or a hash code. The latter form is the 64-bit
30+
/// MD5 of the function name for efficient storage supported by ExtBinary
31+
/// profile format, and when reading the profile, this class can represent it
32+
/// without converting it to a string first.
33+
/// When representing a hash code, we utilize the LengthOrHashCode field to
34+
/// store it, and Name is set to null. When representing a string, it is same as
35+
/// StringRef.
36+
class FunctionId {
37+
38+
const char *Data = nullptr;
39+
40+
// Use uint64_t instead of size_t so that it can also hold a MD5 value on
41+
// 32-bit system.
42+
uint64_t LengthOrHashCode = 0;
43+
44+
/// Extension to memcmp to handle hash code representation. If both are hash
45+
/// values, Lhs and Rhs are both null, function returns 0 (and needs an extra
46+
/// comparison using getIntValue). If only one is hash code, it is considered
47+
/// less than the StringRef one. Otherwise perform normal string comparison.
48+
static int compareMemory(const char *Lhs, const char *Rhs, uint64_t Length) {
49+
if (Lhs == Rhs)
50+
return 0;
51+
if (!Lhs)
52+
return -1;
53+
if (!Rhs)
54+
return 1;
55+
return ::memcmp(Lhs, Rhs, (size_t)Length);
56+
}
57+
58+
public:
59+
FunctionId() = default;
60+
61+
/// Constructor from a StringRef.
62+
explicit FunctionId(StringRef Str)
63+
: Data(Str.data()), LengthOrHashCode(Str.size()) {
64+
}
65+
66+
/// Constructor from a hash code.
67+
explicit FunctionId(uint64_t HashCode)
68+
: LengthOrHashCode(HashCode) {
69+
assert(HashCode != 0);
70+
}
71+
72+
/// Check for equality. Similar to StringRef::equals, but will also cover for
73+
/// the case where one or both are hash codes. Comparing their int values are
74+
/// sufficient. A hash code FunctionId is considered not equal to a StringRef
75+
/// FunctionId regardless of actual contents.
76+
bool equals(const FunctionId &Other) const {
77+
return LengthOrHashCode == Other.LengthOrHashCode &&
78+
compareMemory(Data, Other.Data, LengthOrHashCode) == 0;
79+
}
80+
81+
/// Total order comparison. If both FunctionId are StringRef, this is the same
82+
/// as StringRef::compare. If one of them is StringRef, it is considered
83+
/// greater than the hash code FunctionId. Otherwise this is the the same
84+
/// as comparing their int values.
85+
int compare(const FunctionId &Other) const {
86+
auto Res = compareMemory(
87+
Data, Other.Data, std::min(LengthOrHashCode, Other.LengthOrHashCode));
88+
if (Res != 0)
89+
return Res;
90+
if (LengthOrHashCode == Other.LengthOrHashCode)
91+
return 0;
92+
return LengthOrHashCode < Other.LengthOrHashCode ? -1 : 1;
93+
}
94+
95+
/// Convert to a string, usually for output purpose. Use caution on return
96+
/// value's lifetime when converting to StringRef.
97+
std::string str() const {
98+
if (Data)
99+
return std::string(Data, LengthOrHashCode);
100+
if (LengthOrHashCode != 0)
101+
return std::to_string(LengthOrHashCode);
102+
return std::string();
103+
}
104+
105+
/// Convert to StringRef. This is only allowed when it is known this object is
106+
/// representing a StringRef, not a hash code. Calling this function on a hash
107+
/// code is considered an error.
108+
StringRef stringRef() const {
109+
if (Data)
110+
return StringRef(Data, LengthOrHashCode);
111+
assert(LengthOrHashCode == 0 &&
112+
"Cannot convert MD5 FunctionId to StringRef");
113+
return StringRef();
114+
}
115+
116+
friend raw_ostream &operator<<(raw_ostream &OS, const FunctionId &Obj);
117+
118+
/// Get hash code of this object. Returns this object's hash code if it is
119+
/// already representing one, otherwise returns the MD5 of its string content.
120+
/// Note that it is not the same as std::hash because we want to keep the
121+
/// consistency that the same sample profile function in string form or MD5
122+
/// form has the same hash code.
123+
uint64_t getHashCode() const {
124+
if (Data)
125+
return MD5Hash(StringRef(Data, LengthOrHashCode));
126+
return LengthOrHashCode;
127+
}
128+
129+
bool empty() const { return LengthOrHashCode == 0; }
130+
131+
/// Check if this object represents a StringRef, or a hash code.
132+
bool isStringRef() const { return Data != nullptr; }
133+
};
134+
135+
inline bool operator==(const FunctionId &LHS, const FunctionId &RHS) {
136+
return LHS.equals(RHS);
137+
}
138+
139+
inline bool operator!=(const FunctionId &LHS, const FunctionId &RHS) {
140+
return !LHS.equals(RHS);
141+
}
142+
143+
inline bool operator<(const FunctionId &LHS, const FunctionId &RHS) {
144+
return LHS.compare(RHS) < 0;
145+
}
146+
147+
inline bool operator<=(const FunctionId &LHS, const FunctionId &RHS) {
148+
return LHS.compare(RHS) <= 0;
149+
}
150+
151+
inline bool operator>(const FunctionId &LHS, const FunctionId &RHS) {
152+
return LHS.compare(RHS) > 0;
153+
}
154+
155+
inline bool operator>=(const FunctionId &LHS, const FunctionId &RHS) {
156+
return LHS.compare(RHS) >= 0;
157+
}
158+
159+
inline raw_ostream &operator<<(raw_ostream &OS, const FunctionId &Obj) {
160+
if (Obj.Data)
161+
return OS << StringRef(Obj.Data, Obj.LengthOrHashCode);
162+
if (Obj.LengthOrHashCode != 0)
163+
return OS << Obj.LengthOrHashCode;
164+
return OS;
165+
}
166+
167+
inline uint64_t MD5Hash(const FunctionId &Obj) {
168+
return Obj.getHashCode();
169+
}
170+
171+
inline uint64_t hash_value(const FunctionId &Obj) {
172+
return Obj.getHashCode();
173+
}
174+
175+
} // end namespace sampleprof
176+
177+
/// Template specialization for FunctionId so that it can be used in LLVM map
178+
/// containers.
179+
template <> struct DenseMapInfo<sampleprof::FunctionId, void> {
180+
181+
static inline sampleprof::FunctionId getEmptyKey() {
182+
return sampleprof::FunctionId(~0ULL);
183+
}
184+
185+
static inline sampleprof::FunctionId getTombstoneKey() {
186+
return sampleprof::FunctionId(~1ULL);
187+
}
188+
189+
static unsigned getHashValue(const sampleprof::FunctionId &Val) {
190+
return Val.getHashCode();
191+
}
192+
193+
static bool isEqual(const sampleprof::FunctionId &LHS,
194+
const sampleprof::FunctionId &RHS) {
195+
return LHS == RHS;
196+
}
197+
};
198+
199+
} // end namespace llvm
200+
201+
namespace std {
202+
203+
/// Template specialization for FunctionId so that it can be used in STL
204+
/// containers.
205+
template <> struct hash<llvm::sampleprof::FunctionId> {
206+
size_t operator()(const llvm::sampleprof::FunctionId &Val) const {
207+
return Val.getHashCode();
208+
}
209+
};
210+
211+
} // end namespace std
212+
213+
#endif // LLVM_PROFILEDATA_FUNCTIONID_H
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
//===--- HashKeyMap.h - Wrapper for maps using hash value key ---*- 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+
/// \file
10+
///
11+
/// Defines HashKeyMap template.
12+
///
13+
//===----------------------------------------------------------------------===//
14+
15+
#ifndef LLVM_PROFILEDATA_HASHKEYMAP_H
16+
#define LLVM_PROFILEDATA_HASHKEYMAP_H
17+
18+
#include "llvm/ADT/Hashing.h"
19+
#include <iterator>
20+
#include <utility>
21+
22+
namespace llvm {
23+
24+
namespace sampleprof {
25+
26+
/// This class is a wrapper to associative container MapT<KeyT, ValueT> using
27+
/// the hash value of the original key as the new key. This greatly improves the
28+
/// performance of insert and query operations especially when hash values of
29+
/// keys are available a priori, and reduces memory usage if KeyT has a large
30+
/// size.
31+
/// All keys with the same hash value are considered equivalent (i.e. hash
32+
/// collision is silently ignored). Given such feature this class should only be
33+
/// used where it does not affect compilation correctness, for example, when
34+
/// loading a sample profile. The original key is not stored, so if the user
35+
/// needs to preserve it, it should be stored in the mapped type.
36+
/// Assuming the hashing algorithm is uniform, we use the formula
37+
/// 1 - Permute(n, k) / n ^ k where n is the universe size and k is number of
38+
/// elements chosen at random to calculate the probability of collision. With
39+
/// 1,000,000 entries the probability is negligible:
40+
/// 1 - (2^64)!/((2^64-1000000)!*(2^64)^1000000) ~= 3*10^-8.
41+
/// Source: https://en.wikipedia.org/wiki/Birthday_problem
42+
///
43+
/// \param MapT The underlying associative container type.
44+
/// \param KeyT The original key type, which requires the implementation of
45+
/// llvm::hash_value(KeyT).
46+
/// \param ValueT The original mapped type, which has the same requirement as
47+
/// the underlying container.
48+
/// \param MapTArgs Additional template parameters passed to the underlying
49+
/// container.
50+
template <template <typename, typename, typename...> typename MapT,
51+
typename KeyT, typename ValueT, typename... MapTArgs>
52+
class HashKeyMap :
53+
public MapT<decltype(hash_value(KeyT())), ValueT, MapTArgs...> {
54+
public:
55+
using base_type = MapT<decltype(hash_value(KeyT())), ValueT, MapTArgs...>;
56+
using key_type = decltype(hash_value(KeyT()));
57+
using original_key_type = KeyT;
58+
using mapped_type = ValueT;
59+
using value_type = typename base_type::value_type;
60+
61+
using iterator = typename base_type::iterator;
62+
using const_iterator = typename base_type::const_iterator;
63+
64+
template <typename... Ts>
65+
std::pair<iterator, bool> try_emplace(const key_type &Hash,
66+
const original_key_type &Key,
67+
Ts &&...Args) {
68+
assert(Hash == hash_value(Key));
69+
return base_type::try_emplace(Hash, std::forward<Ts>(Args)...);
70+
}
71+
72+
template <typename... Ts>
73+
std::pair<iterator, bool> try_emplace(const original_key_type &Key,
74+
Ts &&...Args) {
75+
return try_emplace(hash_value(Key), Key, std::forward<Ts>(Args)...);
76+
}
77+
78+
template <typename... Ts> std::pair<iterator, bool> emplace(Ts &&...Args) {
79+
return try_emplace(std::forward<Ts>(Args)...);
80+
}
81+
82+
mapped_type &operator[](const original_key_type &Key) {
83+
return try_emplace(Key, mapped_type()).first->second;
84+
}
85+
86+
iterator find(const original_key_type &Key) {
87+
auto It = base_type::find(hash_value(Key));
88+
if (It != base_type::end())
89+
return It;
90+
return base_type::end();
91+
}
92+
93+
const_iterator find(const original_key_type &Key) const {
94+
auto It = base_type::find(hash_value(Key));
95+
if (It != base_type::end())
96+
return It;
97+
return base_type::end();
98+
}
99+
100+
mapped_type lookup(const original_key_type &Key) const {
101+
auto It = base_type::find(hash_value(Key));
102+
if (It != base_type::end())
103+
return It->second;
104+
return mapped_type();
105+
}
106+
107+
size_t count(const original_key_type &Key) const {
108+
return base_type::count(hash_value(Key));
109+
}
110+
111+
size_t erase(const original_key_type &Ctx) {
112+
auto It = find(Ctx);
113+
if (It != base_type::end()) {
114+
base_type::erase(It);
115+
return 1;
116+
}
117+
return 0;
118+
}
119+
120+
iterator erase(const_iterator It) {
121+
return base_type::erase(It);
122+
}
123+
};
124+
125+
}
126+
127+
}
128+
129+
#endif // LLVM_PROFILEDATA_HASHKEYMAP_H

0 commit comments

Comments
 (0)