Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions clang/docs/AllocToken.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ The default mode to calculate tokens is:
pointers.

Other token ID assignment modes are supported, but they may be subject to
change or removal. These may (experimentally) be selected with ``-mllvm
-alloc-token-mode=<mode>``:
change or removal. These may (experimentally) be selected with ``-Xclang
-falloc-token-mode=<mode>``:

* ``typehash``: This mode assigns a token ID based on the hash of the allocated
type's name.
Expand Down
35 changes: 35 additions & 0 deletions clang/include/clang/AST/InferAlloc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//===--- InferAlloc.h - Allocation type inference ---------------*- 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
//
//===----------------------------------------------------------------------===//
//
// This file defines interfaces for allocation-related type inference.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_AST_INFERALLOC_H
#define LLVM_CLANG_AST_INFERALLOC_H

#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "llvm/Support/AllocToken.h"
#include <optional>

namespace clang {
namespace infer_alloc {

/// Infer the possible allocated type from an allocation call expression.
QualType inferPossibleType(const CallExpr *E, const ASTContext &Ctx,
const CastExpr *CastE);

/// Get the information required for construction of an allocation token ID.
std::optional<llvm::AllocTokenMetadata>
getAllocTokenMetadata(QualType T, const ASTContext &Ctx);

} // namespace infer_alloc
} // namespace clang

#endif // LLVM_CLANG_AST_INFERALLOC_H
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -4727,6 +4727,13 @@ def PtrauthStringDiscriminator : Builtin {
let Prototype = "size_t(char const*)";
}

// AllocToken builtins.
def InferAllocToken : Builtin {
let Spellings = ["__builtin_infer_alloc_token"];
let Attributes = [NoThrow, Const, Pure, CustomTypeChecking, Constexpr, UnevaluatedArguments];
let Prototype = "size_t(...)";
}

// OpenCL v2.0 s6.13.16, s9.17.3.5 - Pipe functions.
// We need the generic prototype, since the packet type could be anything.
def ReadPipe : OCLPipeLangBuiltin {
Expand Down
4 changes: 0 additions & 4 deletions clang/include/clang/Basic/CodeGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -447,10 +447,6 @@ class CodeGenOptions : public CodeGenOptionsBase {

std::optional<double> AllowRuntimeCheckSkipHotCutoff;

/// Maximum number of allocation tokens (0 = no max), nullopt if none set (use
/// pass default).
std::optional<uint64_t> AllocTokenMax;

/// List of backend command-line options for -fembed-bitcode.
std::vector<uint8_t> CmdArgs;

Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/DiagnosticASTKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,12 @@ def note_constexpr_assumption_failed : Note<
def note_constexpr_countzeroes_zero : Note<
"evaluation of %select{__builtin_elementwise_clzg|__builtin_elementwise_ctzg}0 "
"with a zero value is undefined">;
def note_constexpr_infer_alloc_token_type_inference_failed : Note<
"could not infer allocation type for __builtin_infer_alloc_token">;
def note_constexpr_infer_alloc_token_no_metadata : Note<
"could not get token metadata for inferred type">;
def note_constexpr_infer_alloc_token_stateful_mode : Note<
"stateful alloc token mode not supported in constexpr">;
def err_experimental_clang_interp_failed : Error<
"the experimental clang interpreter failed to evaluate an expression">;

Expand Down
8 changes: 8 additions & 0 deletions clang/include/clang/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "llvm/ADT/FloatingPointMode.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/DXContainer.h"
#include "llvm/Support/AllocToken.h"
#include "llvm/TargetParser/Triple.h"
#include <optional>
#include <string>
Expand Down Expand Up @@ -565,6 +566,13 @@ class LangOptions : public LangOptionsBase {
bool AtomicFineGrainedMemory = false;
bool AtomicIgnoreDenormalMode = false;

/// Maximum number of allocation tokens (0 = no max), nullopt if none set (use
/// target default).
std::optional<uint64_t> AllocTokenMax;

/// The allocation token mode.
std::optional<llvm::AllocTokenMode> AllocTokenMode;

LangOptions();

/// Set language defaults for the given input language and
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -2751,6 +2751,10 @@ def falloc_token_max_EQ : Joined<["-"], "falloc-token-max=">,
MetaVarName<"<N>">,
HelpText<"Limit to maximum N allocation tokens (0 = no max)">;

def falloc_token_mode_EQ : Joined<["-"], "falloc-token-mode=">,
Group<f_Group>, Visibility<[CC1Option]>,
HelpText<"Set the allocation token mode (experimental)">;

def fallow_runtime_check_skip_hot_cutoff_EQ
: Joined<["-"], "fallow-runtime-check-skip-hot-cutoff=">,
Group<f_clang_Group>,
Expand Down
44 changes: 44 additions & 0 deletions clang/lib/AST/ByteCode/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
#include "Interp.h"
#include "InterpBuiltinBitCast.h"
#include "PrimType.h"
#include "clang/AST/InferAlloc.h"
#include "clang/AST/OSLog.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/AllocToken.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/SipHash.h"

Expand Down Expand Up @@ -1306,6 +1308,45 @@ interp__builtin_ptrauth_string_discriminator(InterpState &S, CodePtr OpPC,
return true;
}

static bool interp__builtin_infer_alloc_token(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const CallExpr *Call) {
const ASTContext &ASTCtx = S.getASTContext();
uint64_t BitWidth = ASTCtx.getTypeSize(ASTCtx.getSizeType());
auto Mode =
ASTCtx.getLangOpts().AllocTokenMode.value_or(llvm::DefaultAllocTokenMode);
uint64_t MaxTokens =
ASTCtx.getLangOpts().AllocTokenMax.value_or(~0ULL >> (64 - BitWidth));

// We do not read any of the arguments; discard them.
for (int I = Call->getNumArgs() - 1; I >= 0; --I)
discard(S.Stk, *S.getContext().classify(Call->getArg(I)));

// Note: Type inference from a surrounding cast is not supported in
// constexpr evaluation.
QualType AllocType = infer_alloc::inferPossibleType(Call, ASTCtx, nullptr);
if (AllocType.isNull()) {
S.CCEDiag(Call,
diag::note_constexpr_infer_alloc_token_type_inference_failed);
return false;
}

auto ATMD = infer_alloc::getAllocTokenMetadata(AllocType, ASTCtx);
if (!ATMD) {
S.CCEDiag(Call, diag::note_constexpr_infer_alloc_token_no_metadata);
return false;
}

auto MaybeToken = llvm::getAllocToken(Mode, *ATMD, MaxTokens);
if (!MaybeToken) {
S.CCEDiag(Call, diag::note_constexpr_infer_alloc_token_stateful_mode);
return false;
}

pushInteger(S, llvm::APInt(BitWidth, *MaybeToken), ASTCtx.getSizeType());
return true;
}

static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const CallExpr *Call) {
Expand Down Expand Up @@ -3489,6 +3530,9 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
case Builtin::BI__builtin_ptrauth_string_discriminator:
return interp__builtin_ptrauth_string_discriminator(S, OpPC, Frame, Call);

case Builtin::BI__builtin_infer_alloc_token:
return interp__builtin_infer_alloc_token(S, OpPC, Frame, Call);

case Builtin::BI__noop:
pushInteger(S, 0, Call->getType());
return true;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ add_clang_library(clangAST
ExternalASTMerger.cpp
ExternalASTSource.cpp
FormatString.cpp
InferAlloc.cpp
InheritViz.cpp
ByteCode/BitcastBuffer.cpp
ByteCode/ByteCodeEmitter.cpp
Expand Down
22 changes: 22 additions & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "clang/AST/CharUnits.h"
#include "clang/AST/CurrentSourceLocExprScope.h"
#include "clang/AST/Expr.h"
#include "clang/AST/InferAlloc.h"
#include "clang/AST/OSLog.h"
#include "clang/AST/OptionalDiagnostic.h"
#include "clang/AST/RecordLayout.h"
Expand Down Expand Up @@ -14415,6 +14416,27 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
return Success(Result, E);
}

case Builtin::BI__builtin_infer_alloc_token: {
// If we fail to infer a type, this fails to be a constant expression; this
// can be checked with __builtin_constant_p(...).
QualType AllocType = infer_alloc::inferPossibleType(E, Info.Ctx, nullptr);
if (AllocType.isNull())
return Error(
E, diag::note_constexpr_infer_alloc_token_type_inference_failed);
auto ATMD = infer_alloc::getAllocTokenMetadata(AllocType, Info.Ctx);
if (!ATMD)
return Error(E, diag::note_constexpr_infer_alloc_token_no_metadata);
auto Mode =
Info.getLangOpts().AllocTokenMode.value_or(llvm::DefaultAllocTokenMode);
uint64_t BitWidth = Info.Ctx.getTypeSize(Info.Ctx.getSizeType());
uint64_t MaxTokens =
Info.getLangOpts().AllocTokenMax.value_or(~0ULL >> (64 - BitWidth));
auto MaybeToken = llvm::getAllocToken(Mode, *ATMD, MaxTokens);
if (!MaybeToken)
return Error(E, diag::note_constexpr_infer_alloc_token_stateful_mode);
return Success(llvm::APInt(BitWidth, *MaybeToken), E);
}

case Builtin::BI__builtin_ffs:
case Builtin::BI__builtin_ffsl:
case Builtin::BI__builtin_ffsll: {
Expand Down
Loading
Loading