mirror of
https://github.com/intel/llvm.git
synced 2026-01-13 11:02:04 +08:00
[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:
58
llvm/include/llvm/Support/AllocToken.h
Normal file
58
llvm/include/llvm/Support/AllocToken.h
Normal 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
|
||||
50
llvm/lib/Support/AllocToken.cpp
Normal file
50
llvm/lib/Support/AllocToken.cpp
Normal 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("");
|
||||
}
|
||||
@@ -149,6 +149,7 @@ add_llvm_component_library(LLVMSupport
|
||||
AArch64BuildAttributes.cpp
|
||||
ARMAttributeParser.cpp
|
||||
ARMWinEH.cpp
|
||||
AllocToken.cpp
|
||||
Allocator.cpp
|
||||
AutoConvert.cpp
|
||||
Base64.cpp
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ static_library("Support") {
|
||||
"ARMAttributeParser.cpp",
|
||||
"ARMBuildAttributes.cpp",
|
||||
"ARMWinEH.cpp",
|
||||
"AllocToken.cpp",
|
||||
"Allocator.cpp",
|
||||
"AutoConvert.cpp",
|
||||
"BalancedPartitioning.cpp",
|
||||
|
||||
Reference in New Issue
Block a user