Change __builtin_sycl_unique_stable_name to just use an Itanium mangling

After significant problems in our downstream with the previous
implementation, the SYCL standard has opted to make using macros/etc to
change kernel-naming-lambdas in any way UB (even passively). As a
result, we are able to just emit the itanium mangling.

However, this DOES require a little work in the CXXABI, as the microsoft
and itanium mangler use different numbering schemes for lambdas.  This
patch adds a pair of mangling contexts that use the normal 'itanium'
mangling strategy to fill in the "DeviceManglingNumber" used previously
by CUDA.

Differential Revision: https://reviews.llvm.org/D110281
This commit is contained in:
Erich Keane 2021-09-22 12:24:53 -07:00
parent 72d991c42e
commit 9324cc2ca9
15 changed files with 119 additions and 248 deletions

View file

@ -2521,12 +2521,9 @@ it in an instantiation which changes its value.
In order to produce the unique name, the current implementation of the bultin
uses Itanium mangling even if the host compilation uses a different name
mangling scheme at runtime. The mangler marks all the lambdas required to name
the SYCL kernel and emits a stable local ordering of the respective lambdas,
starting from ``10000``. The initial value of ``10000`` serves as an obvious
differentiator from ordinary lambda mangling numbers but does not serve any
other purpose and may change in the future. The resulting pattern is
demanglable. When non-lambda types are passed to the builtin, the mangler emits
their usual pattern without any special treatment.
the SYCL kernel and emits a stable local ordering of the respective lambdas.
The resulting pattern is demanglable. When non-lambda types are passed to the
builtin, the mangler emits their usual pattern without any special treatment.
**Syntax**:

View file

@ -3239,31 +3239,10 @@ public:
StringRef getCUIDHash() const;
void AddSYCLKernelNamingDecl(const CXXRecordDecl *RD);
bool IsSYCLKernelNamingDecl(const NamedDecl *RD) const;
unsigned GetSYCLKernelNamingIndex(const NamedDecl *RD);
/// A SourceLocation to store whether we have evaluated a kernel name already,
/// and where it happened. If so, we need to diagnose an illegal use of the
/// builtin.
llvm::MapVector<const SYCLUniqueStableNameExpr *, std::string>
SYCLUniqueStableNameEvaluatedValues;
private:
/// All OMPTraitInfo objects live in this collection, one per
/// `pragma omp [begin] declare variant` directive.
SmallVector<std::unique_ptr<OMPTraitInfo>, 4> OMPTraitInfoVector;
/// A list of the (right now just lambda decls) declarations required to
/// name all the SYCL kernels in the translation unit, so that we can get the
/// correct kernel name, as well as implement
/// __builtin_sycl_unique_stable_name.
llvm::DenseMap<const DeclContext *,
llvm::SmallPtrSet<const CXXRecordDecl *, 4>>
SYCLKernelNamingTypes;
std::unique_ptr<ItaniumMangleContext> SYCLKernelFilterContext;
void FilterSYCLKernelNamingDecls(
const CXXRecordDecl *RD,
llvm::SmallVectorImpl<const CXXRecordDecl *> &Decls);
};
/// Insertion operator for diagnostics.

View file

@ -6409,11 +6409,6 @@ def warn_gnu_null_ptr_arith : Warning<
def warn_pointer_sub_null_ptr : Warning<
"performing pointer subtraction with a null pointer %select{has|may have}0 undefined behavior">,
InGroup<NullPointerSubtraction>, DefaultIgnore;
def err_kernel_invalidates_sycl_unique_stable_name
: Error<"kernel instantiation changes the result of an evaluated "
"'__builtin_sycl_unique_stable_name'">;
def note_sycl_unique_stable_name_evaluated_here
: Note<"'__builtin_sycl_unique_stable_name' evaluated here">;
def warn_floatingpoint_eq : Warning<
"comparing floating point with == or != is unsafe">,

View file

@ -914,10 +914,6 @@ public:
OpaqueParser = P;
}
// Does the work necessary to deal with a SYCL kernel lambda. At the moment,
// this just marks the list of lambdas required to name the kernel.
void AddSYCLKernelLambda(const FunctionDecl *FD);
class DelayedDiagnostics;
class DelayedDiagnosticsState {

View file

@ -11801,86 +11801,3 @@ StringRef ASTContext::getCUIDHash() const {
CUIDHash = llvm::utohexstr(llvm::MD5Hash(LangOpts.CUID), /*LowerCase=*/true);
return CUIDHash;
}
// Get the closest named parent, so we can order the sycl naming decls somewhere
// that mangling is meaningful.
static const DeclContext *GetNamedParent(const CXXRecordDecl *RD) {
const DeclContext *DC = RD->getDeclContext();
while (!isa<NamedDecl, TranslationUnitDecl>(DC))
DC = DC->getParent();
return DC;
}
void ASTContext::AddSYCLKernelNamingDecl(const CXXRecordDecl *RD) {
assert(getLangOpts().isSYCL() && "Only valid for SYCL programs");
RD = RD->getCanonicalDecl();
const DeclContext *DC = GetNamedParent(RD);
assert(RD->getLocation().isValid() &&
"Invalid location on kernel naming decl");
(void)SYCLKernelNamingTypes[DC].insert(RD);
}
bool ASTContext::IsSYCLKernelNamingDecl(const NamedDecl *ND) const {
assert(getLangOpts().isSYCL() && "Only valid for SYCL programs");
const auto *RD = dyn_cast<CXXRecordDecl>(ND);
if (!RD)
return false;
RD = RD->getCanonicalDecl();
const DeclContext *DC = GetNamedParent(RD);
auto Itr = SYCLKernelNamingTypes.find(DC);
if (Itr == SYCLKernelNamingTypes.end())
return false;
return Itr->getSecond().count(RD);
}
// Filters the Decls list to those that share the lambda mangling with the
// passed RD.
void ASTContext::FilterSYCLKernelNamingDecls(
const CXXRecordDecl *RD,
llvm::SmallVectorImpl<const CXXRecordDecl *> &Decls) {
if (!SYCLKernelFilterContext)
SYCLKernelFilterContext.reset(
ItaniumMangleContext::create(*this, getDiagnostics()));
llvm::SmallString<128> LambdaSig;
llvm::raw_svector_ostream Out(LambdaSig);
SYCLKernelFilterContext->mangleLambdaSig(RD, Out);
llvm::erase_if(Decls, [this, &LambdaSig](const CXXRecordDecl *LocalRD) {
llvm::SmallString<128> LocalLambdaSig;
llvm::raw_svector_ostream LocalOut(LocalLambdaSig);
SYCLKernelFilterContext->mangleLambdaSig(LocalRD, LocalOut);
return LambdaSig != LocalLambdaSig;
});
}
unsigned ASTContext::GetSYCLKernelNamingIndex(const NamedDecl *ND) {
assert(getLangOpts().isSYCL() && "Only valid for SYCL programs");
assert(IsSYCLKernelNamingDecl(ND) &&
"Lambda not involved in mangling asked for a naming index?");
const CXXRecordDecl *RD = cast<CXXRecordDecl>(ND)->getCanonicalDecl();
const DeclContext *DC = GetNamedParent(RD);
auto Itr = SYCLKernelNamingTypes.find(DC);
assert(Itr != SYCLKernelNamingTypes.end() && "Not a valid DeclContext?");
const llvm::SmallPtrSet<const CXXRecordDecl *, 4> &Set = Itr->getSecond();
llvm::SmallVector<const CXXRecordDecl *> Decls{Set.begin(), Set.end()};
FilterSYCLKernelNamingDecls(RD, Decls);
llvm::sort(Decls, [](const CXXRecordDecl *LHS, const CXXRecordDecl *RHS) {
return LHS->getLambdaManglingNumber() < RHS->getLambdaManglingNumber();
});
return llvm::find(Decls, RD) - Decls.begin();
}

View file

@ -545,20 +545,10 @@ std::string SYCLUniqueStableNameExpr::ComputeName(ASTContext &Context,
QualType Ty) {
auto MangleCallback = [](ASTContext &Ctx,
const NamedDecl *ND) -> llvm::Optional<unsigned> {
// This replaces the 'lambda number' in the mangling with a unique number
// based on its order in the declaration. To provide some level of visual
// notability (actual uniqueness from normal lambdas isn't necessary, as
// these are used differently), we add 10,000 to the number.
// For example:
// _ZTSZ3foovEUlvE10005_
// Demangles to: typeinfo name for foo()::'lambda10005'()
// Note that the mangler subtracts 2, since with normal lambdas the lambda
// mangling number '0' is an anonymous struct mangle, and '1' is omitted.
// So 10,002 results in the first number being 10,000.
if (Ctx.IsSYCLKernelNamingDecl(ND))
return 10'002 + Ctx.GetSYCLKernelNamingIndex(ND);
return llvm::None;
if (const auto *RD = dyn_cast<CXXRecordDecl>(ND))
return RD->getDeviceLambdaManglingNumber();
};
std::unique_ptr<MangleContext> Ctx{ItaniumMangleContext::create(
Context, Context.getDiagnostics(), MangleCallback)};

View file

@ -8674,8 +8674,6 @@ public:
bool VisitSYCLUniqueStableNameExpr(const SYCLUniqueStableNameExpr *E) {
std::string ResultStr = E->ComputeName(Info.Ctx);
Info.Ctx.SYCLUniqueStableNameEvaluatedValues[E] = ResultStr;
QualType CharTy = Info.Ctx.CharTy.withConst();
APInt Size(Info.Ctx.getTypeSize(Info.Ctx.getSizeType()),
ResultStr.size() + 1);

View file

@ -181,6 +181,37 @@ public:
}
};
// A version of this for SYCL that makes sure that 'device' mangling context
// matches the lambda mangling number, so that __builtin_sycl_unique_stable_name
// can be consistently generated between a MS and Itanium host by just referring
// to the device mangling number.
class ItaniumSYCLNumberingContext : public ItaniumNumberingContext {
llvm::DenseMap<const CXXMethodDecl *, unsigned> ManglingNumbers;
using ManglingItr = decltype(ManglingNumbers)::iterator;
public:
ItaniumSYCLNumberingContext(ItaniumMangleContext *Mangler)
: ItaniumNumberingContext(Mangler) {}
unsigned getManglingNumber(const CXXMethodDecl *CallOperator) override {
unsigned Number = ItaniumNumberingContext::getManglingNumber(CallOperator);
std::pair<ManglingItr, bool> emplace_result =
ManglingNumbers.try_emplace(CallOperator, Number);
(void)emplace_result;
assert(emplace_result.second && "Lambda number set multiple times?");
return Number;
}
using ItaniumNumberingContext::getManglingNumber;
unsigned getDeviceManglingNumber(const CXXMethodDecl *CallOperator) override {
ManglingItr Itr = ManglingNumbers.find(CallOperator);
assert(Itr != ManglingNumbers.end() && "Lambda not yet mangled?");
return Itr->second;
}
};
class ItaniumCXXABI : public CXXABI {
private:
std::unique_ptr<MangleContext> Mangler;
@ -249,6 +280,9 @@ public:
std::unique_ptr<MangleNumberingContext>
createMangleNumberingContext() const override {
if (Context.getLangOpts().isSYCL())
return std::make_unique<ItaniumSYCLNumberingContext>(
cast<ItaniumMangleContext>(Mangler.get()));
return std::make_unique<ItaniumNumberingContext>(
cast<ItaniumMangleContext>(Mangler.get()));
}

View file

@ -1518,9 +1518,16 @@ void CXXNameMangler::mangleUnqualifiedName(GlobalDecl GD,
// <lambda-sig> ::= <template-param-decl>* <parameter-type>+
// # Parameter types or 'v' for 'void'.
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(TD)) {
if (Record->isLambda() && (Record->getLambdaManglingNumber() ||
Context.getDiscriminatorOverride()(
Context.getASTContext(), Record))) {
llvm::Optional<unsigned> DeviceNumber =
Context.getDiscriminatorOverride()(Context.getASTContext(), Record);
// If we have a device-number via the discriminator, use that to mangle
// the lambda, otherwise use the typical lambda-mangling-number. In either
// case, a '0' should be mangled as a normal unnamed class instead of as a
// lambda.
if (Record->isLambda() &&
((DeviceNumber && *DeviceNumber > 0) ||
(!DeviceNumber && Record->getLambdaManglingNumber() > 0))) {
assert(!AdditionalAbiTags &&
"Lambda type cannot have additional abi tags");
mangleLambda(Record);
@ -1960,8 +1967,8 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
// mangling number for this lambda.
llvm::Optional<unsigned> DeviceNumber =
Context.getDiscriminatorOverride()(Context.getASTContext(), Lambda);
unsigned Number = DeviceNumber.hasValue() ? *DeviceNumber
: Lambda->getLambdaManglingNumber();
unsigned Number =
DeviceNumber ? *DeviceNumber : Lambda->getLambdaManglingNumber();
assert(Number > 0 && "Lambda should be mangled as an unnamed class");
if (Number > 1)

View file

@ -78,6 +78,19 @@ public:
}
};
class MSSYCLNumberingContext : public MicrosoftNumberingContext {
std::unique_ptr<MangleNumberingContext> DeviceCtx;
public:
MSSYCLNumberingContext(MangleContext *DeviceMangler) {
DeviceCtx = createItaniumNumberingContext(DeviceMangler);
}
unsigned getDeviceManglingNumber(const CXXMethodDecl *CallOperator) override {
return DeviceCtx->getManglingNumber(CallOperator);
}
};
class MicrosoftCXXABI : public CXXABI {
ASTContext &Context;
llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> RecordToCopyCtor;
@ -100,6 +113,10 @@ public:
DeviceMangler.reset(
Context.createMangleContext(Context.getAuxTargetInfo()));
}
else if (Context.getLangOpts().isSYCL()) {
DeviceMangler.reset(
ItaniumMangleContext::create(Context, Context.getDiagnostics()));
}
}
MemberPointerInfo
@ -162,7 +179,11 @@ public:
if (Context.getLangOpts().CUDA && Context.getAuxTargetInfo()) {
assert(DeviceMangler && "Missing device mangler");
return std::make_unique<MSHIPNumberingContext>(DeviceMangler.get());
} else if (Context.getLangOpts().isSYCL()) {
assert(DeviceMangler && "Missing device mangler");
return std::make_unique<MSSYCLNumberingContext>(DeviceMangler.get());
}
return std::make_unique<MicrosoftNumberingContext>();
}
};

View file

@ -48,35 +48,3 @@ bool Sema::checkSYCLDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) {
return DiagKind != SemaDiagnosticBuilder::K_Immediate &&
DiagKind != SemaDiagnosticBuilder::K_ImmediateWithCallStack;
}
// The SYCL kernel's 'object type' used for diagnostics and naming/mangling is
// the first parameter to a sycl_kernel labeled function template. In SYCL1.2.1,
// this was passed by value, and in SYCL2020, it is passed by reference.
static QualType GetSYCLKernelObjectType(const FunctionDecl *KernelCaller) {
assert(KernelCaller->getNumParams() > 0 && "Insufficient kernel parameters");
QualType KernelParamTy = KernelCaller->getParamDecl(0)->getType();
// SYCL 2020 kernels are passed by reference.
if (KernelParamTy->isReferenceType())
return KernelParamTy->getPointeeType();
// SYCL 1.2.1
return KernelParamTy;
}
void Sema::AddSYCLKernelLambda(const FunctionDecl *FD) {
auto MangleCallback = [](ASTContext &Ctx,
const NamedDecl *ND) -> llvm::Optional<unsigned> {
if (const auto *RD = dyn_cast<CXXRecordDecl>(ND))
Ctx.AddSYCLKernelNamingDecl(RD);
// We always want to go into the lambda mangling (skipping the unnamed
// struct version), so make sure we return a value here.
return 1;
};
QualType Ty = GetSYCLKernelObjectType(FD);
std::unique_ptr<MangleContext> Ctx{ItaniumMangleContext::create(
Context, Context.getDiagnostics(), MangleCallback)};
llvm::raw_null_ostream Out;
Ctx->mangleTypeName(Ty, Out);
}

View file

@ -556,26 +556,6 @@ static void instantiateDependentAMDGPUWavesPerEUAttr(
static void instantiateDependentSYCLKernelAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const SYCLKernelAttr &Attr, Decl *New) {
// Functions cannot be partially specialized, so if we are being instantiated,
// we are obviously a complete specialization. Since this attribute is only
// valid on function template declarations, we know that this is a full
// instantiation of a kernel.
S.AddSYCLKernelLambda(cast<FunctionDecl>(New));
// Evaluate whether this would change any of the already evaluated
// __builtin_sycl_unique_stable_name values.
for (auto &Itr : S.Context.SYCLUniqueStableNameEvaluatedValues) {
const std::string &CurName = Itr.first->ComputeName(S.Context);
if (Itr.second != CurName) {
S.Diag(New->getLocation(),
diag::err_kernel_invalidates_sycl_unique_stable_name);
S.Diag(Itr.first->getLocation(),
diag::note_sycl_unique_stable_name_evaluated_here);
// Update this so future diagnostics work correctly.
Itr.second = CurName;
}
}
New->addAttr(Attr.clone(S.getASTContext()));
}

View file

@ -1,22 +1,22 @@
// RUN: %clang_cc1 -triple spir64-unknown-unknown-sycldevice -fsycl-is-device -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s
// CHECK: @[[LAMBDA_KERNEL3:[^\w]+]] = private unnamed_addr constant [[LAMBDA_K3_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ4mainEUlPZ4mainEUlvE10000_E10000_\00"
// CHECK: @[[LAMBDA_KERNEL3:[^\w]+]] = private unnamed_addr constant [[LAMBDA_K3_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ4mainEUlPZ4mainEUlvE_E_\00"
// CHECK: @[[INT1:[^\w]+]] = private unnamed_addr constant [[INT_SIZE:\[[0-9]+ x i8\]]] c"_ZTSi\00"
// CHECK: @[[STRING:[^\w]+]] = private unnamed_addr constant [[STRING_SIZE:\[[0-9]+ x i8\]]] c"_ZTSAppL_ZZ4mainE1jE_i\00",
// CHECK: @[[INT2:[^\w]+]] = private unnamed_addr constant [[INT_SIZE]] c"_ZTSi\00"
// CHECK: @[[LAMBDA_X:[^\w]+]] = private unnamed_addr constant [[LAMBDA_X_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE10001_clEvEUlvE_\00"
// CHECK: @[[MACRO_X:[^\w]+]] = private unnamed_addr constant [[MACRO_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE10001_clEvEUlvE0_\00"
// CHECK: @[[MACRO_Y:[^\w]+]] = private unnamed_addr constant [[MACRO_SIZE]] c"_ZTSZZ4mainENKUlvE10001_clEvEUlvE1_\00"
// CHECK: @{{.*}} = private unnamed_addr constant [36 x i8] c"_ZTSZZ4mainENKUlvE10001_clEvEUlvE2_\00", align 1
// CHECK: @{{.*}} = private unnamed_addr constant [36 x i8] c"_ZTSZZ4mainENKUlvE10001_clEvEUlvE3_\00", align 1
// CHECK: @[[MACRO_MACRO_X:[^\w]+]] = private unnamed_addr constant [[MACRO_MACRO_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE10001_clEvEUlvE4_\00"
// CHECK: @[[MACRO_MACRO_Y:[^\w]+]] = private unnamed_addr constant [[MACRO_MACRO_SIZE]] c"_ZTSZZ4mainENKUlvE10001_clEvEUlvE5_\00"
// CHECK: @[[LAMBDA_X:[^\w]+]] = private unnamed_addr constant [[LAMBDA_X_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE_\00"
// CHECK: @[[MACRO_X:[^\w]+]] = private unnamed_addr constant [[MACRO_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE0_\00"
// CHECK: @[[MACRO_Y:[^\w]+]] = private unnamed_addr constant [[MACRO_SIZE]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE1_\00"
// CHECK: @{{.*}} = private unnamed_addr constant [32 x i8] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE2_\00", align 1
// CHECK: @{{.*}} = private unnamed_addr constant [32 x i8] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE3_\00", align 1
// CHECK: @[[MACRO_MACRO_X:[^\w]+]] = private unnamed_addr constant [[MACRO_MACRO_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE4_\00"
// CHECK: @[[MACRO_MACRO_Y:[^\w]+]] = private unnamed_addr constant [[MACRO_MACRO_SIZE]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE5_\00"
// CHECK: @[[INT3:[^\w]+]] = private unnamed_addr constant [[INT_SIZE]] c"_ZTSi\00"
// CHECK: @[[LAMBDA:[^\w]+]] = private unnamed_addr constant [[LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE10001_clEvEUlvE_\00"
// CHECK: @[[LAMBDA:[^\w]+]] = private unnamed_addr constant [[LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE_\00"
// CHECK: @[[LAMBDA_IN_DEP_INT:[^\w]+]] = private unnamed_addr constant [[DEP_INT_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ28lambda_in_dependent_functionIiEvvEUlvE_\00",
// CHECK: @[[LAMBDA_IN_DEP_X:[^\w]+]] = private unnamed_addr constant [[DEP_LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ28lambda_in_dependent_functionIZZ4mainENKUlvE10001_clEvEUlvE_EvvEUlvE_\00",
// CHECK: @[[LAMBDA_IN_DEP_X:[^\w]+]] = private unnamed_addr constant [[DEP_LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ28lambda_in_dependent_functionIZZ4mainENKUlvE0_clEvEUlvE_EvvEUlvE_\00",
// CHECK: @[[LAMBDA_NO_DEP:[^\w]+]] = private unnamed_addr constant [[NO_DEP_LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ13lambda_no_depIidEvT_T0_EUlidE_\00",
// CHECK: @[[LAMBDA_TWO_DEP:[^\w]+]] = private unnamed_addr constant [[DEP_LAMBDA1_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ14lambda_two_depIZZ4mainENKUlvE10001_clEvEUliE_ZZ4mainENKS0_clEvEUldE_EvvEUlvE_\00",
// CHECK: @[[LAMBDA_TWO_DEP2:[^\w]+]] = private unnamed_addr constant [[DEP_LAMBDA2_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ14lambda_two_depIZZ4mainENKUlvE10001_clEvEUldE_ZZ4mainENKS0_clEvEUliE_EvvEUlvE_\00",
// CHECK: @[[LAMBDA_TWO_DEP:[^\w]+]] = private unnamed_addr constant [[DEP_LAMBDA1_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ14lambda_two_depIZZ4mainENKUlvE0_clEvEUliE_ZZ4mainENKS0_clEvEUldE_EvvEUlvE_\00",
// CHECK: @[[LAMBDA_TWO_DEP2:[^\w]+]] = private unnamed_addr constant [[DEP_LAMBDA2_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ14lambda_two_depIZZ4mainENKUlvE0_clEvEUldE_ZZ4mainENKS0_clEvEUliE_EvvEUlvE_\00",
extern "C" void puts(const char *) {}

View file

@ -38,7 +38,7 @@ int main() {
// Make sure the following 3 are the same between the host and device compile.
// Note that these are NOT the same value as eachother, they differ by the
// signature.
// CHECK: private unnamed_addr constant [22 x i8] c"_ZTSZ4mainEUlvE10000_\00"
// CHECK: private unnamed_addr constant [22 x i8] c"_ZTSZ4mainEUliE10000_\00"
// CHECK: private unnamed_addr constant [22 x i8] c"_ZTSZ4mainEUldE10000_\00"
// CHECK: private unnamed_addr constant [17 x i8] c"_ZTSZ4mainEUlvE_\00"
// CHECK: private unnamed_addr constant [17 x i8] c"_ZTSZ4mainEUliE_\00"
// CHECK: private unnamed_addr constant [17 x i8] c"_ZTSZ4mainEUldE_\00"
}

View file

@ -15,10 +15,6 @@ template <typename KernelName, typename KernelType>
template <typename Func>
void kernel1func(const Func &F1) {
constexpr const char *F1_output = __builtin_sycl_unique_stable_name(Func); // #USN_F1
// expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}}
// expected-note@#kernel1func_call{{in instantiation of function template specialization}}
// expected-note@#USN_F1{{'__builtin_sycl_unique_stable_name' evaluated here}}
// expected-note@+1{{in instantiation of function template specialization}}
kernel_single_task<class kernel1>(F1); // #kernel1_call
}
@ -38,10 +34,6 @@ void callkernel1() {
template <typename Func>
void kernel2func(const Func &F2) {
constexpr const char *F2_output = __builtin_sycl_unique_stable_name(Func); // #USN_F2
// expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}}
// expected-note@#kernel2func_call{{in instantiation of function template specialization}}
// expected-note@#USN_F2{{'__builtin_sycl_unique_stable_name' evaluated here}}
// expected-note@+1{{in instantiation of function template specialization}}
kernel_single_task<class kernel2>([]() {});
}
@ -93,40 +85,34 @@ int main() {
kernel_single_task<class kernel5>(
[=]() { l5(); }); // Used in the kernel, but not the kernel name itself
// kernel6 - expect error
// kernel6 - expect no error
// Test that passing the lambda to the unique stable name builtin and then
// using the same lambda in the naming of a kernel causes a diagnostic on the
// kernel use due to the change in results to the stable name.
// using the same lambda in the naming of a kernel does not cause a diagnostic
// on the kernel use due to the change in results to the stable name.
auto l6 = []() { return 1; };
constexpr const char *l6_output =
__builtin_sycl_unique_stable_name(decltype(l6)); // #USN_l6
// expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}}
// expected-note@#USN_l6{{'__builtin_sycl_unique_stable_name' evaluated here}}
// expected-note@+1{{in instantiation of function template specialization}}
kernel_single_task<class kernel6>(l6); // Used in the kernel name after builtin
// kernel7 - expect error
// kernel7 - expect no error
// Same as kernel11 (below) except make the lambda part of naming the kernel.
// Test that passing a lambda to the unique stable name builtin and then
// passing a second lambda to the kernel throws an error because the first
// lambda is included in the signature of the second lambda, hence it changes
// the mangling of the kernel.
// passing a second lambda to the kernel does not throw an error because the
// first lambda is included in the signature of the second lambda, but does
// not change the mangling of the kernel.
auto l7 = []() { return 1; };
auto l8 = [](decltype(l7) *derp = nullptr) { return 2; };
constexpr const char *l7_output =
__builtin_sycl_unique_stable_name(decltype(l7)); // #USN_l7
// expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}}
// expected-note@#USN_l7{{'__builtin_sycl_unique_stable_name' evaluated here}}
// expected-note@+1{{in instantiation of function template specialization}}
kernel_single_task<class kernel7>(l8);
// kernel8 and kernel9 - expect error
// Tests that passing a lambda to the unique stable name builtin and passing it
// to a kernel called with an if constexpr branch causes a diagnostic on the
// kernel9 use due to the change in the results to the stable name. This happens
// even though the use of kernel9 happens in the false branch of a constexpr if
// because both the true and the false branches cause the instantiation of
// kernel_single_task.
// kernel8 and kernel9 - expect no error
// Tests that passing a lambda to the unique stable name builtin and passing
// it to a kernel called with an if constexpr branch does not cause a
// diagnostic on the kernel9 as it does not change the result to the stable
// name. This is interesting even though the use of kernel9 happens in the
// false branch of a constexpr if because both the true and the false branches
// cause the instantiation of kernel_single_task.
auto l9 = []() { return 1; };
auto l10 = []() { return 2; };
constexpr const char *l10_output =
@ -134,9 +120,6 @@ int main() {
if constexpr (1) {
kernel_single_task<class kernel8>(l9);
} else {
// expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}}
// expected-note@#USN_l10{{'__builtin_sycl_unique_stable_name' evaluated here}}
// expected-note@+1{{in instantiation of function template specialization}}
kernel_single_task<class kernel9>(l10);
}
@ -151,26 +134,20 @@ int main() {
__builtin_sycl_unique_stable_name(decltype(l11));
kernel_single_task<class kernel11>(l12);
// kernel12 - expect an error
// kernel12 - expect no error
// Test that passing a lambda to the unique stable name builtin and then
// passing it to the kernel as a template template parameter causes a
// passing it to the kernel as a template template parameter does not cause a
// diagnostic on the kernel use due to template template parameter being
// involved in the mangling of the kernel name.
auto l13 = []() { return 1; };
constexpr const char *l13_output =
__builtin_sycl_unique_stable_name(decltype(l13)); // #USN_l13
// expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}}
// expected-note@#USN_l13{{'__builtin_sycl_unique_stable_name' evaluated here}}
// expected-note@+1{{in instantiation of function template specialization}}
kernel_single_task<class kernel12>(S<Tangerine, decltype(l13)>{});
// kernel13 - expect an error
// kernel13 - expect no error
// Test that passing a lambda to the unique stable name builtin within a macro
// and then calling the macro within the kernel causes an error on the kernel
// and diagnoses in all the expected places despite the use of a macro.
// expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}}
// expected-note@#USN_MACRO{{'__builtin_sycl_unique_stable_name' evaluated here}}
// expected-note@+1{{in instantiation of function template specialization}}
// and then calling the macro within the kernel does not cause an error on the
// kernel.
kernel_single_task<class kernel13>(
[]() {
MACRO(); // #USN_MACRO
@ -213,3 +190,15 @@ void use() {
// expected-note@+1{{in instantiation of}}
f2<St>();
}
// A previous implementation resulted in this being an example of the
// kernel-ordering and lexical lambda ordering issue.
void out_of_order_use() {
auto x = [](){};
auto y = [](){};
kernel_single_task<decltype(y)>(y);
constexpr auto USN =__builtin_sycl_unique_stable_name(decltype(y));
(void)USN;
kernel_single_task<decltype(x)>(x);
}