Skip to content

Commit 4635922

Browse files
melverdvbuka
authored andcommitted
[AllocToken] Refactor stateless token calculation into Support (llvm#163633)
Refactor the stateless (hash-based) token calculation logic out of the `AllocToken` pass and into `llvm/Support/AllocToken.h`. This helps with making the token calculation logic available to other parts of the codebase, which will be necessary for frontend implementation of `__builtin_infer_alloc_token` to perform constexpr evaluation. The `AllocTokenMode` enum and a new `AllocTokenMetadata` struct are moved into a shared header. The `getAllocTokenHash()` function now provides the source of truth for calculating token IDs for `TypeHash` and `TypeHashPointerSplit` modes.
1 parent cdc3e48 commit 4635922

File tree

5 files changed

+128
-39
lines changed

5 files changed

+128
-39
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//===- llvm/Support/AllocToken.h - Allocation Token Calculation -----*- 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+
// Definition of AllocToken modes and shared calculation of stateless token IDs.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_SUPPORT_ALLOCTOKEN_H
14+
#define LLVM_SUPPORT_ALLOCTOKEN_H
15+
16+
#include "llvm/ADT/SmallString.h"
17+
#include <cstdint>
18+
#include <optional>
19+
20+
namespace llvm {
21+
22+
/// Modes for generating allocation token IDs.
23+
enum class AllocTokenMode {
24+
/// Incrementally increasing token ID.
25+
Increment,
26+
27+
/// Simple mode that returns a statically-assigned random token ID.
28+
Random,
29+
30+
/// Token ID based on allocated type hash.
31+
TypeHash,
32+
33+
/// Token ID based on allocated type hash, where the top half ID-space is
34+
/// reserved for types that contain pointers and the bottom half for types
35+
/// that do not contain pointers.
36+
TypeHashPointerSplit,
37+
};
38+
39+
/// Metadata about an allocation used to generate a token ID.
40+
struct AllocTokenMetadata {
41+
SmallString<64> TypeName;
42+
bool ContainsPointer;
43+
};
44+
45+
/// Calculates stable allocation token ID. Returns std::nullopt for stateful
46+
/// modes that are only available in the AllocToken pass.
47+
///
48+
/// \param Mode The token generation mode.
49+
/// \param Metadata The metadata about the allocation.
50+
/// \param MaxTokens The maximum number of tokens (must not be 0)
51+
/// \return The calculated allocation token ID, or std::nullopt.
52+
LLVM_ABI std::optional<uint64_t>
53+
getAllocToken(AllocTokenMode Mode, const AllocTokenMetadata &Metadata,
54+
uint64_t MaxTokens);
55+
56+
} // end namespace llvm
57+
58+
#endif // LLVM_SUPPORT_ALLOCTOKEN_H

llvm/lib/Support/AllocToken.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//===- AllocToken.cpp - Allocation Token Calculation ----------------------===//
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+
// Definition of AllocToken modes and shared calculation of stateless token IDs.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "llvm/Support/AllocToken.h"
14+
#include "llvm/Support/ErrorHandling.h"
15+
#include "llvm/Support/SipHash.h"
16+
17+
using namespace llvm;
18+
19+
static uint64_t getStableHash(const AllocTokenMetadata &Metadata,
20+
uint64_t MaxTokens) {
21+
return getStableSipHash(Metadata.TypeName) % MaxTokens;
22+
}
23+
24+
std::optional<uint64_t> llvm::getAllocToken(AllocTokenMode Mode,
25+
const AllocTokenMetadata &Metadata,
26+
uint64_t MaxTokens) {
27+
assert(MaxTokens && "Must provide non-zero max tokens");
28+
29+
switch (Mode) {
30+
case AllocTokenMode::Increment:
31+
case AllocTokenMode::Random:
32+
// Stateful modes cannot be implemented as a pure function.
33+
return std::nullopt;
34+
35+
case AllocTokenMode::TypeHash:
36+
return getStableHash(Metadata, MaxTokens);
37+
38+
case AllocTokenMode::TypeHashPointerSplit: {
39+
if (MaxTokens == 1)
40+
return 0;
41+
const uint64_t HalfTokens = MaxTokens / 2;
42+
uint64_t Hash = getStableHash(Metadata, HalfTokens);
43+
if (Metadata.ContainsPointer)
44+
Hash += HalfTokens;
45+
return Hash;
46+
}
47+
}
48+
49+
llvm_unreachable("");
50+
}

llvm/lib/Support/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ add_llvm_component_library(LLVMSupport
149149
AArch64BuildAttributes.cpp
150150
ARMAttributeParser.cpp
151151
ARMWinEH.cpp
152+
AllocToken.cpp
152153
Allocator.cpp
153154
AutoConvert.cpp
154155
Base64.cpp

llvm/lib/Transforms/Instrumentation/AllocToken.cpp

Lines changed: 18 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "llvm/IR/Module.h"
3737
#include "llvm/IR/PassManager.h"
3838
#include "llvm/IR/Type.h"
39+
#include "llvm/Support/AllocToken.h"
3940
#include "llvm/Support/Casting.h"
4041
#include "llvm/Support/CommandLine.h"
4142
#include "llvm/Support/Compiler.h"
@@ -54,29 +55,12 @@
5455
#include <variant>
5556

5657
using namespace llvm;
58+
using TokenMode = AllocTokenMode;
5759

5860
#define DEBUG_TYPE "alloc-token"
5961

6062
namespace {
6163

62-
//===--- Constants --------------------------------------------------------===//
63-
64-
enum class TokenMode : unsigned {
65-
/// Incrementally increasing token ID.
66-
Increment = 0,
67-
68-
/// Simple mode that returns a statically-assigned random token ID.
69-
Random = 1,
70-
71-
/// Token ID based on allocated type hash.
72-
TypeHash = 2,
73-
74-
/// Token ID based on allocated type hash, where the top half ID-space is
75-
/// reserved for types that contain pointers and the bottom half for types
76-
/// that do not contain pointers.
77-
TypeHashPointerSplit = 3,
78-
};
79-
8064
//===--- Command-line options ---------------------------------------------===//
8165

8266
cl::opt<TokenMode> ClMode(
@@ -217,22 +201,19 @@ class TypeHashMode : public ModeBase {
217201
using ModeBase::ModeBase;
218202

219203
uint64_t operator()(const CallBase &CB, OptimizationRemarkEmitter &ORE) {
220-
const auto [N, H] = getHash(CB, ORE);
221-
return N ? boundedToken(H) : H;
222-
}
223204

224-
protected:
225-
std::pair<MDNode *, uint64_t> getHash(const CallBase &CB,
226-
OptimizationRemarkEmitter &ORE) {
227205
if (MDNode *N = getAllocTokenMetadata(CB)) {
228206
MDString *S = cast<MDString>(N->getOperand(0));
229-
return {N, getStableSipHash(S->getString())};
207+
AllocTokenMetadata Metadata{S->getString(), containsPointer(N)};
208+
if (auto Token = getAllocToken(TokenMode::TypeHash, Metadata, MaxTokens))
209+
return *Token;
230210
}
231211
// Fallback.
232212
remarkNoMetadata(CB, ORE);
233-
return {nullptr, ClFallbackToken};
213+
return ClFallbackToken;
234214
}
235215

216+
protected:
236217
/// Remark that there was no precise type information.
237218
static void remarkNoMetadata(const CallBase &CB,
238219
OptimizationRemarkEmitter &ORE) {
@@ -253,20 +234,18 @@ class TypeHashPointerSplitMode : public TypeHashMode {
253234
using TypeHashMode::TypeHashMode;
254235

255236
uint64_t operator()(const CallBase &CB, OptimizationRemarkEmitter &ORE) {
256-
if (MaxTokens == 1)
257-
return 0;
258-
const uint64_t HalfTokens = MaxTokens / 2;
259-
const auto [N, H] = getHash(CB, ORE);
260-
if (!N) {
261-
// Pick the fallback token (ClFallbackToken), which by default is 0,
262-
// meaning it'll fall into the pointer-less bucket. Override by setting
263-
// -alloc-token-fallback if that is the wrong choice.
264-
return H;
237+
if (MDNode *N = getAllocTokenMetadata(CB)) {
238+
MDString *S = cast<MDString>(N->getOperand(0));
239+
AllocTokenMetadata Metadata{S->getString(), containsPointer(N)};
240+
if (auto Token = getAllocToken(TokenMode::TypeHashPointerSplit, Metadata,
241+
MaxTokens))
242+
return *Token;
265243
}
266-
uint64_t Hash = H % HalfTokens; // base hash
267-
if (containsPointer(N))
268-
Hash += HalfTokens;
269-
return Hash;
244+
// Pick the fallback token (ClFallbackToken), which by default is 0, meaning
245+
// it'll fall into the pointer-less bucket. Override by setting
246+
// -alloc-token-fallback if that is the wrong choice.
247+
remarkNoMetadata(CB, ORE);
248+
return ClFallbackToken;
270249
}
271250
};
272251

llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ static_library("Support") {
4545
"ARMAttributeParser.cpp",
4646
"ARMBuildAttributes.cpp",
4747
"ARMWinEH.cpp",
48+
"AllocToken.cpp",
4849
"Allocator.cpp",
4950
"AutoConvert.cpp",
5051
"BalancedPartitioning.cpp",

0 commit comments

Comments
 (0)