[AllocToken] Refactor stateless token calculation into Support (#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.
This commit is contained in:
Marco Elver
2025-10-22 10:27:55 +02:00
committed by GitHub
parent dda30e1b7d
commit eeffaf110e
5 changed files with 128 additions and 39 deletions

View File

@@ -0,0 +1,58 @@
//===- llvm/Support/AllocToken.h - Allocation Token Calculation -----*- C++ -*//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Definition of AllocToken modes and shared calculation of stateless token IDs.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_ALLOCTOKEN_H
#define LLVM_SUPPORT_ALLOCTOKEN_H
#include "llvm/ADT/SmallString.h"
#include <cstdint>
#include <optional>
namespace llvm {
/// Modes for generating allocation token IDs.
enum class AllocTokenMode {
/// Incrementally increasing token ID.
Increment,
/// Simple mode that returns a statically-assigned random token ID.
Random,
/// Token ID based on allocated type hash.
TypeHash,
/// Token ID based on allocated type hash, where the top half ID-space is
/// reserved for types that contain pointers and the bottom half for types
/// that do not contain pointers.
TypeHashPointerSplit,
};
/// Metadata about an allocation used to generate a token ID.
struct AllocTokenMetadata {
SmallString<64> TypeName;
bool ContainsPointer;
};
/// Calculates stable allocation token ID. Returns std::nullopt for stateful
/// modes that are only available in the AllocToken pass.
///
/// \param Mode The token generation mode.
/// \param Metadata The metadata about the allocation.
/// \param MaxTokens The maximum number of tokens (must not be 0)
/// \return The calculated allocation token ID, or std::nullopt.
LLVM_ABI std::optional<uint64_t>
getAllocToken(AllocTokenMode Mode, const AllocTokenMetadata &Metadata,
uint64_t MaxTokens);
} // end namespace llvm
#endif // LLVM_SUPPORT_ALLOCTOKEN_H

View File

@@ -0,0 +1,50 @@
//===- AllocToken.cpp - Allocation Token Calculation ----------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Definition of AllocToken modes and shared calculation of stateless token IDs.
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/AllocToken.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/SipHash.h"
using namespace llvm;
static uint64_t getStableHash(const AllocTokenMetadata &Metadata,
uint64_t MaxTokens) {
return getStableSipHash(Metadata.TypeName) % MaxTokens;
}
std::optional<uint64_t> llvm::getAllocToken(AllocTokenMode Mode,
const AllocTokenMetadata &Metadata,
uint64_t MaxTokens) {
assert(MaxTokens && "Must provide non-zero max tokens");
switch (Mode) {
case AllocTokenMode::Increment:
case AllocTokenMode::Random:
// Stateful modes cannot be implemented as a pure function.
return std::nullopt;
case AllocTokenMode::TypeHash:
return getStableHash(Metadata, MaxTokens);
case AllocTokenMode::TypeHashPointerSplit: {
if (MaxTokens == 1)
return 0;
const uint64_t HalfTokens = MaxTokens / 2;
uint64_t Hash = getStableHash(Metadata, HalfTokens);
if (Metadata.ContainsPointer)
Hash += HalfTokens;
return Hash;
}
}
llvm_unreachable("");
}

View File

@@ -149,6 +149,7 @@ add_llvm_component_library(LLVMSupport
AArch64BuildAttributes.cpp
ARMAttributeParser.cpp
ARMWinEH.cpp
AllocToken.cpp
Allocator.cpp
AutoConvert.cpp
Base64.cpp

View File

@@ -36,6 +36,7 @@
#include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/AllocToken.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
@@ -54,29 +55,12 @@
#include <variant>
using namespace llvm;
using TokenMode = AllocTokenMode;
#define DEBUG_TYPE "alloc-token"
namespace {
//===--- Constants --------------------------------------------------------===//
enum class TokenMode : unsigned {
/// Incrementally increasing token ID.
Increment = 0,
/// Simple mode that returns a statically-assigned random token ID.
Random = 1,
/// Token ID based on allocated type hash.
TypeHash = 2,
/// Token ID based on allocated type hash, where the top half ID-space is
/// reserved for types that contain pointers and the bottom half for types
/// that do not contain pointers.
TypeHashPointerSplit = 3,
};
//===--- Command-line options ---------------------------------------------===//
cl::opt<TokenMode> ClMode(
@@ -217,22 +201,19 @@ public:
using ModeBase::ModeBase;
uint64_t operator()(const CallBase &CB, OptimizationRemarkEmitter &ORE) {
const auto [N, H] = getHash(CB, ORE);
return N ? boundedToken(H) : H;
}
protected:
std::pair<MDNode *, uint64_t> getHash(const CallBase &CB,
OptimizationRemarkEmitter &ORE) {
if (MDNode *N = getAllocTokenMetadata(CB)) {
MDString *S = cast<MDString>(N->getOperand(0));
return {N, getStableSipHash(S->getString())};
AllocTokenMetadata Metadata{S->getString(), containsPointer(N)};
if (auto Token = getAllocToken(TokenMode::TypeHash, Metadata, MaxTokens))
return *Token;
}
// Fallback.
remarkNoMetadata(CB, ORE);
return {nullptr, ClFallbackToken};
return ClFallbackToken;
}
protected:
/// Remark that there was no precise type information.
static void remarkNoMetadata(const CallBase &CB,
OptimizationRemarkEmitter &ORE) {
@@ -253,20 +234,18 @@ public:
using TypeHashMode::TypeHashMode;
uint64_t operator()(const CallBase &CB, OptimizationRemarkEmitter &ORE) {
if (MaxTokens == 1)
return 0;
const uint64_t HalfTokens = MaxTokens / 2;
const auto [N, H] = getHash(CB, ORE);
if (!N) {
// Pick the fallback token (ClFallbackToken), which by default is 0,
// meaning it'll fall into the pointer-less bucket. Override by setting
// -alloc-token-fallback if that is the wrong choice.
return H;
if (MDNode *N = getAllocTokenMetadata(CB)) {
MDString *S = cast<MDString>(N->getOperand(0));
AllocTokenMetadata Metadata{S->getString(), containsPointer(N)};
if (auto Token = getAllocToken(TokenMode::TypeHashPointerSplit, Metadata,
MaxTokens))
return *Token;
}
uint64_t Hash = H % HalfTokens; // base hash
if (containsPointer(N))
Hash += HalfTokens;
return Hash;
// Pick the fallback token (ClFallbackToken), which by default is 0, meaning
// it'll fall into the pointer-less bucket. Override by setting
// -alloc-token-fallback if that is the wrong choice.
remarkNoMetadata(CB, ORE);
return ClFallbackToken;
}
};

View File

@@ -45,6 +45,7 @@ static_library("Support") {
"ARMAttributeParser.cpp",
"ARMBuildAttributes.cpp",
"ARMWinEH.cpp",
"AllocToken.cpp",
"Allocator.cpp",
"AutoConvert.cpp",
"BalancedPartitioning.cpp",