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:
parent
72d991c42e
commit
9324cc2ca9
|
@ -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**:
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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">,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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)};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
||||
|
|
|
@ -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 *) {}
|
||||
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue