erichkeane updated this revision to Diff 348025.
erichkeane marked 7 inline comments as done.
erichkeane added a comment.
Fix comments from aaron.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D103112/new/
https://reviews.llvm.org/D103112
Files:
clang/docs/LanguageExtensions.rst
clang/include/clang/AST/ASTContext.h
clang/include/clang/AST/ComputeDependence.h
clang/include/clang/AST/Expr.h
clang/include/clang/AST/JSONNodeDumper.h
clang/include/clang/AST/Mangle.h
clang/include/clang/AST/RecursiveASTVisitor.h
clang/include/clang/AST/TextNodeDumper.h
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Basic/StmtNodes.td
clang/include/clang/Basic/TokenKinds.def
clang/include/clang/Parse/Parser.h
clang/include/clang/Sema/Sema.h
clang/include/clang/Serialization/ASTBitCodes.h
clang/lib/AST/ASTContext.cpp
clang/lib/AST/ComputeDependence.cpp
clang/lib/AST/Expr.cpp
clang/lib/AST/ExprClassification.cpp
clang/lib/AST/ExprConstant.cpp
clang/lib/AST/ItaniumMangle.cpp
clang/lib/AST/JSONNodeDumper.cpp
clang/lib/AST/StmtPrinter.cpp
clang/lib/AST/StmtProfile.cpp
clang/lib/AST/TextNodeDumper.cpp
clang/lib/Basic/IdentifierTable.cpp
clang/lib/CodeGen/CGExprScalar.cpp
clang/lib/Parse/ParseExpr.cpp
clang/lib/Sema/SemaExceptionSpec.cpp
clang/lib/Sema/SemaExpr.cpp
clang/lib/Sema/SemaLambda.cpp
clang/lib/Sema/SemaSYCL.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/lib/Sema/TreeTransform.h
clang/lib/Serialization/ASTReaderStmt.cpp
clang/lib/Serialization/ASTWriterStmt.cpp
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
clang/test/AST/ast-print-sycl-unique-stable-name.cpp
clang/test/CodeGenSYCL/unique_stable_name.cpp
clang/test/ParserSYCL/unique_stable_name.cpp
clang/test/ParserSYCL/unique_stable_name_sycl_only.cpp
clang/test/SemaSYCL/unique_stable_name.cpp
clang/tools/libclang/CXCursor.cpp
Index: clang/tools/libclang/CXCursor.cpp
===================================================================
--- clang/tools/libclang/CXCursor.cpp
+++ clang/tools/libclang/CXCursor.cpp
@@ -336,6 +336,7 @@
case Stmt::ObjCBoxedExprClass:
case Stmt::ObjCSubscriptRefExprClass:
case Stmt::RecoveryExprClass:
+ case Stmt::SYCLUniqueStableNameExprClass:
K = CXCursor_UnexposedExpr;
break;
Index: clang/test/SemaSYCL/unique_stable_name.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaSYCL/unique_stable_name.cpp
@@ -0,0 +1,208 @@
+// RUN: %clang_cc1 %s -std=c++17 -triple x86_64-pc-windows-msvc -fsycl-is-device -verify -fsyntax-only -Wno-unused
+// RUN: %clang_cc1 %s -std=c++17 -triple x86_64-linux-gnu -fsycl-is-device -verify -fsyntax-only -Wno-unused
+
+template <typename KernelName, typename KernelType>
+[[clang::sycl_kernel]] void kernel_single_task(KernelType kernelFunc) { // #kernelSingleTask
+ kernelFunc();
+}
+
+// kernel1 - expect error
+// The current function is named with a lambda (i.e., takes a lambda as a
+// template parameter. Call the builtin on the current function then it is
+// passed to a kernel. Test that passing the given function to the unique
+// stable name builtin and then to the kernel throws an error because the
+// latter causes its name mangling to change.
+template <typename Func>
+void kernel1func(const Func &F1) {
+ constexpr const char *F1_output = __builtin_sycl_unique_stable_name(F1); // #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
+}
+
+void callkernel1() {
+ kernel1func([]() {}); // #kernel1func_call
+}
+
+// kernel2 - expect error
+// The current function is named with a lambda (i.e., takes a lambda as a
+// template parameter). Call the builtin on the given function,
+// then an empty lambda is passed to kernel.
+// Test that passing the given function to the unique stable name builtin and
+// then passing a different lambda to the kernel still throws an error because
+// the calling context is part of naming the kernel. Even though the given
+// function (F2) is not passed to the kernel, its mangling changes due to
+// kernel call with the unrelated lambda.
+template <typename Func>
+void kernel2func(const Func &F2) {
+ constexpr const char *F2_output = __builtin_sycl_unique_stable_name(F2); // #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>([]() {});
+}
+
+void callkernel2() {
+ kernel2func([]() {}); // #kernel2func_call
+}
+
+template <template <typename> typename Outer, typename Inner>
+struct S {
+ void operator()() const;
+};
+
+template <typename Ty>
+struct Tangerine {};
+
+template <typename Func>
+void kernel3_4func(const Func &F) {
+ // Test that passing the same lambda to two kernels does not cause an error
+ // because the kernel uses do not interfere with each other or invalidate
+ // the stable name in any way.
+ kernel_single_task<class kernel3>(F);
+ kernel_single_task<class kernel4>(F);
+ // Using the same functor twice should be fine
+}
+
+// kernel3 and kernel4 - expect no errors
+void callkernel3_4() {
+ kernel3_4func([]() {});
+}
+
+template <typename T>
+static constexpr const char *output1 = __builtin_sycl_unique_stable_name(T);
+
+#define MACRO() \
+ auto l14 = []() { return 1; }; \
+ constexpr const char *l14_output = __builtin_sycl_unique_stable_name(l14);
+
+int main() {
+
+ // kernel5 - expect no error
+ // Test that passing the lambda to the unique stable name builtin and then
+ // using the lambda in a way that does not contribute to the kernel name
+ // does not cause an error because the stable name is not invalidated in
+ // this situation.
+ auto l5 = []() {};
+ constexpr const char *l5_output = __builtin_sycl_unique_stable_name(l5);
+ kernel_single_task<class kernel5>(
+ [=]() { l5(); }); // Used in the kernel, but not the kernel name itself
+
+ // kernel6 - expect 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.
+ auto l6 = []() { return 1; };
+ constexpr const char *l6_output = __builtin_sycl_unique_stable_name(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
+ // 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.
+ auto l7 = []() { return 1; };
+ auto l8 = [](decltype(l7) *derp = nullptr) { return 2; };
+ constexpr const char *l7_output = __builtin_sycl_unique_stable_name(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.
+ auto l9 = []() { return 1; };
+ auto l10 = []() { return 2; };
+ constexpr const char *l10_output = __builtin_sycl_unique_stable_name(l10); // #USN_l10
+ 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);
+ }
+
+ // kernel11 - expect no error
+ // Test that passing a lambda to the unique stable name builtin and then
+ // passing a second lambda capturing the first one to the kernel does not
+ // throw an error because the first lambda is not involved in naming the
+ // kernel i.e., the mangling does not change.
+ auto l11 = []() { return 1; };
+ auto l12 = [l11]() { return 2; };
+ constexpr const char *l11_output = __builtin_sycl_unique_stable_name(l11);
+ kernel_single_task<class kernel11>(l12);
+
+ // kernel12 - expect an 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
+ // 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(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
+ // 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}}
+ kernel_single_task<class kernel13>(
+ []() {
+ MACRO(); // #USN_MACRO
+ });
+}
+
+namespace NS {}
+
+void f() {
+ // expected-error@+1{{use of undeclared identifier 'bad_var'}}
+ __builtin_sycl_unique_stable_name(bad_var);
+ // expected-error@+1{{use of undeclared identifier 'bad'}}
+ __builtin_sycl_unique_stable_name(bad::type);
+ // expected-error@+1{{no member named 'still_bad' in namespace 'NS'}}
+ __builtin_sycl_unique_stable_name(NS::still_bad);
+
+ // FIXME: warning about side-effects in an unevaluated context expected, but
+ // none currently emitted.
+ int i = 0;
+ __builtin_sycl_unique_stable_name(i++);
+
+ // Tests that use within a VLA does not diagnose as a side-effecting use in
+ // an unevaluated context because the use within a VLA extent forces
+ // evaluation.
+ int j = 55;
+ __builtin_sycl_unique_stable_name(int[++j]); // no warning expected
+}
+
+template <typename T>
+void f2() {
+ // expected-error@+1{{no member named 'bad_val' in 'St'}}
+ __builtin_sycl_unique_stable_name(T::bad_val);
+ // expected-error@+1{{no type named 'bad_type' in 'St'}}
+ __builtin_sycl_unique_stable_name(typename T::bad_type);
+}
+
+struct St {};
+
+void use() {
+ // expected-note@+1{{in instantiation of}}
+ f2<St>();
+}
Index: clang/test/ParserSYCL/unique_stable_name_sycl_only.cpp
===================================================================
--- /dev/null
+++ clang/test/ParserSYCL/unique_stable_name_sycl_only.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fsyntax-only -verify=notsycl -Wno-unused %s
+// RUN: %clang_cc1 -fsyntax-only -fsycl-is-host -verify=sycl -Wno-unused %s
+// RUN: %clang_cc1 -fsyntax-only -fsycl-is-device -verify=sycl -Wno-unused %s
+
+// sycl-no-diagnostics
+void foo() {
+ // notsycl-error@+1{{expected '(' for function-style cast or type construction}}
+ __builtin_sycl_unique_stable_name(int);
+}
Index: clang/test/ParserSYCL/unique_stable_name.cpp
===================================================================
--- /dev/null
+++ clang/test/ParserSYCL/unique_stable_name.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -fsycl-is-device -fsyntax-only -verify -Wno-unused %s
+
+namespace NS {
+int good = 55;
+}
+
+void f(int var) {
+ // expected-error@+1{{expected '(' after '__builtin_sycl_unique_stable_name'}}
+ __builtin_sycl_unique_stable_name int; // Correct usage is __builtin_sycl_unique_stable_name(int);
+
+ // expected-error@+1{{expected '(' after '__builtin_sycl_unique_stable_name'}}
+ __builtin_sycl_unique_stable_name{int}; // Correct usage is __builtin_sycl_unique_stable_name(int);
+
+ // expected-error@+2{{expected ')'}}
+ // expected-note@+1{{to match this '('}}
+ __builtin_sycl_unique_stable_name(int; // Missing paren before semicolon
+
+ // expected-error@+2{{expected ')'}}
+ // expected-note@+1{{to match this '('}}
+ __builtin_sycl_unique_stable_name(int, float); // Missing paren before comma
+
+ __builtin_sycl_unique_stable_name(var);
+ __builtin_sycl_unique_stable_name(NS::good);
+
+ // expected-error@+1{{expected expression}}
+ __builtin_sycl_unique_stable_name(for (int i = 0; i < 10; ++i) {})
+ __builtin_sycl_unique_stable_name({
+ (for (int i = 0; i < 10; ++i){})})
+}
+
+template <typename T>
+void f2() {
+ __builtin_sycl_unique_stable_name(typename T::good_type);
+}
+
+struct S {
+ class good_type {};
+};
+
+void use() {
+ f2<S>();
+}
Index: clang/test/CodeGenSYCL/unique_stable_name.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenSYCL/unique_stable_name.cpp
@@ -0,0 +1,162 @@
+// 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: @[[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: @[[LAMBDA_Y:[^\w]+]] = private unnamed_addr constant [[LAMBDA_Y_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: @[[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_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_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",
+
+extern "C" void puts(const char *) {}
+
+template <typename T>
+void template_param() {
+ puts(__builtin_sycl_unique_stable_name(T));
+}
+
+template <typename T>
+void lambda_in_dependent_function() {
+ auto y = [] {};
+ puts(__builtin_sycl_unique_stable_name(y));
+}
+
+template <typename Tw, typename Tz>
+void lambda_two_dep() {
+ auto z = [] {};
+ puts(__builtin_sycl_unique_stable_name(z));
+}
+
+template <typename Tw, typename Tz>
+void lambda_no_dep(Tw a, Tz b) {
+ auto p = [](Tw a, Tz b) { return ((Tz)a + b); };
+ puts(__builtin_sycl_unique_stable_name(p));
+}
+
+#define DEF_IN_MACRO() \
+ auto MACRO_X = []() {}; \
+ auto MACRO_Y = []() {}; \
+ puts(__builtin_sycl_unique_stable_name(MACRO_X)); \
+ puts(__builtin_sycl_unique_stable_name(MACRO_Y));
+
+#define MACRO_CALLS_MACRO() \
+ { DEF_IN_MACRO(); } \
+ { DEF_IN_MACRO(); }
+
+template <typename Ty>
+auto func() -> decltype(__builtin_sycl_unique_stable_name(Ty::str));
+
+struct Derp {
+ static constexpr const char str[] = "derp derp derp";
+};
+
+template <typename KernelName, typename KernelType>
+[[clang::sycl_kernel]] void kernel_single_task(KernelType kernelFunc) {
+ kernelFunc();
+}
+
+int main() {
+ kernel_single_task<class kernel2>(func<Derp>);
+ // CHECK: call spir_func void @_Z18kernel_single_taskIZ4mainE7kernel2PFPKcvEEvT0_(i8 addrspace(4)* ()* @_Z4funcI4DerpEDTu33__builtin_sycl_unique_stable_nameXsrT_3strEEEv)
+
+ auto l1 = []() { return 1; };
+ auto l2 = [](decltype(l1) *l = nullptr) { return 2; };
+ kernel_single_task<class kernel3>(l2);
+ puts(__builtin_sycl_unique_stable_name(l2));
+ // CHECK: call spir_func void @_Z18kernel_single_taskIZ4mainE7kernel3Z4mainEUlPZ4mainEUlvE_E_EvT0_
+ // CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[LAMBDA_K3_SIZE]], [[LAMBDA_K3_SIZE]]* @[[LAMBDA_KERNEL3]], i32 0, i32 0) to i8 addrspace(4)*))
+
+ constexpr const char str[] = "lalala";
+ static_assert(__builtin_strcmp(__builtin_sycl_unique_stable_name(str), "_ZTSA7_Kc\0") == 0, "unexpected mangling");
+
+ int i = 0;
+ puts(__builtin_sycl_unique_stable_name(i++));
+ // CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[INT_SIZE]], [[INT_SIZE]]* @[[INT1]], i32 0, i32 0) to i8 addrspace(4)*))
+
+ // FIXME: Ensure that j is incremented because VLAs are terrible.
+ int j = 55;
+ puts(__builtin_sycl_unique_stable_name(int[++j]));
+ // CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[STRING_SIZE]], [[STRING_SIZE]]* @[[STRING]], i32 0, i32 0) to i8 addrspace(4)*))
+
+ // CHECK: define internal spir_func void @_Z18kernel_single_taskIZ4mainE7kernel2PFPKcvEEvT0_
+ // CHECK: declare spir_func i8 addrspace(4)* @_Z4funcI4DerpEDTu33__builtin_sycl_unique_stable_nameXsrT_3strEEEv
+ // CHECK: define internal spir_func void @_Z18kernel_single_taskIZ4mainE7kernel3Z4mainEUlPZ4mainEUlvE_E_EvT0_
+ // CHECK: define internal spir_func void @_Z18kernel_single_taskIZ4mainE6kernelZ4mainEUlvE0_EvT0_
+
+ kernel_single_task<class kernel>(
+ []() {
+ puts(__builtin_sycl_unique_stable_name(int));
+ // CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[INT_SIZE]], [[INT_SIZE]]* @[[INT2]], i32 0, i32 0) to i8 addrspace(4)*))
+
+ auto x = []() {};
+ puts(__builtin_sycl_unique_stable_name(x));
+ puts(__builtin_sycl_unique_stable_name(decltype(x)));
+ // CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[LAMBDA_X_SIZE]], [[LAMBDA_X_SIZE]]* @[[LAMBDA_X]], i32 0, i32 0) to i8 addrspace(4)*))
+ // CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[LAMBDA_Y_SIZE]], [[LAMBDA_Y_SIZE]]* @[[LAMBDA_Y]], i32 0, i32 0) to i8 addrspace(4)*))
+
+ DEF_IN_MACRO();
+ // CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[MACRO_SIZE]], [[MACRO_SIZE]]* @[[MACRO_X]], i32 0, i32 0) to i8 addrspace(4)*))
+ // CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[MACRO_SIZE]], [[MACRO_SIZE]]* @[[MACRO_Y]], i32 0, i32 0) to i8 addrspace(4)*))
+
+ MACRO_CALLS_MACRO();
+ // CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[MACRO_MACRO_SIZE]], [[MACRO_MACRO_SIZE]]* @[[MACRO_MACRO_X]], i32 0, i32 0) to i8 addrspace(4)*))
+ // CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[MACRO_MACRO_SIZE]], [[MACRO_MACRO_SIZE]]* @[[MACRO_MACRO_Y]], i32 0, i32 0) to i8 addrspace(4)*))
+
+ template_param<int>();
+ // CHECK: call spir_func void @_Z14template_paramIiEvv
+
+ template_param<decltype(x)>();
+ // CHECK: call spir_func void @_Z14template_paramIZZ4mainENKUlvE0_clEvEUlvE_Evv
+
+ lambda_in_dependent_function<int>();
+ // CHECK: call spir_func void @_Z28lambda_in_dependent_functionIiEvv
+
+ lambda_in_dependent_function<decltype(x)>();
+ // CHECK: call spir_func void @_Z28lambda_in_dependent_functionIZZ4mainENKUlvE0_clEvEUlvE_Evv
+
+ lambda_no_dep<int, double>(3, 5.5);
+ // CHECK: call spir_func void @_Z13lambda_no_depIidEvT_T0_(i32 3, double 5.500000e+00)
+
+ int a = 5;
+ double b = 10.7;
+ auto y = [](int a) { return a; };
+ auto z = [](double b) { return b; };
+ lambda_two_dep<decltype(y), decltype(z)>();
+ // CHECK: call spir_func void @_Z14lambda_two_depIZZ4mainENKUlvE0_clEvEUliE_ZZ4mainENKS0_clEvEUldE_Evv
+
+ lambda_two_dep<decltype(z), decltype(y)>();
+ // CHECK: call spir_func void @_Z14lambda_two_depIZZ4mainENKUlvE0_clEvEUldE_ZZ4mainENKS0_clEvEUliE_Evv
+ });
+}
+
+// CHECK: define linkonce_odr spir_func void @_Z14template_paramIiEvv
+// CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[INT_SIZE]], [[INT_SIZE]]* @[[INT3]], i32 0, i32 0) to i8 addrspace(4)*))
+
+// CHECK: define internal spir_func void @_Z14template_paramIZZ4mainENKUlvE0_clEvEUlvE_Evv
+// CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[LAMBDA_SIZE]], [[LAMBDA_SIZE]]* @[[LAMBDA]], i32 0, i32 0) to i8 addrspace(4)*))
+
+// CHECK: define linkonce_odr spir_func void @_Z28lambda_in_dependent_functionIiEvv
+// CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[DEP_INT_SIZE]], [[DEP_INT_SIZE]]* @[[LAMBDA_IN_DEP_INT]], i32 0, i32 0) to i8 addrspace(4)*))
+
+// CHECK: define internal spir_func void @_Z28lambda_in_dependent_functionIZZ4mainENKUlvE0_clEvEUlvE_Evv
+// CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[DEP_LAMBDA_SIZE]], [[DEP_LAMBDA_SIZE]]* @[[LAMBDA_IN_DEP_X]], i32 0, i32 0) to i8 addrspace(4)*))
+
+// CHECK: define linkonce_odr spir_func void @_Z13lambda_no_depIidEvT_T0_(i32 %a, double %b)
+// CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[NO_DEP_LAMBDA_SIZE]], [[NO_DEP_LAMBDA_SIZE]]* @[[LAMBDA_NO_DEP]], i32 0, i32 0) to i8 addrspace(4)*))
+
+// CHECK: define internal spir_func void @_Z14lambda_two_depIZZ4mainENKUlvE0_clEvEUliE_ZZ4mainENKS0_clEvEUldE_Evv
+// CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[DEP_LAMBDA1_SIZE]], [[DEP_LAMBDA1_SIZE]]* @[[LAMBDA_TWO_DEP]], i32 0, i32 0) to i8 addrspace(4)*))
+
+// CHECK: define internal spir_func void @_Z14lambda_two_depIZZ4mainENKUlvE0_clEvEUldE_ZZ4mainENKS0_clEvEUliE_Evv
+// CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[DEP_LAMBDA2_SIZE]], [[DEP_LAMBDA2_SIZE]]* @[[LAMBDA_TWO_DEP2]], i32 0, i32 0) to i8 addrspace(4)*))
Index: clang/test/AST/ast-print-sycl-unique-stable-name.cpp
===================================================================
--- /dev/null
+++ clang/test/AST/ast-print-sycl-unique-stable-name.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -ast-print -fsycl-is-device %s -o - -triple spir64-sycldevice | FileCheck %s
+
+template <typename T>
+void WrappedInTemplate(T t) {
+ (void)__builtin_sycl_unique_stable_name(T);
+ (void)__builtin_sycl_unique_stable_name(typename T::type);
+ (void)__builtin_sycl_unique_stable_name(t.foo());
+}
+
+struct Type {
+ using type = int;
+
+ double foo();
+};
+
+void use() {
+ WrappedInTemplate(Type{});
+}
+
+// CHECK: template <typename T> void WrappedInTemplate(T t)
+// CHECK: __builtin_sycl_unique_stable_name(T);
+// CHECK: __builtin_sycl_unique_stable_name(typename T::type);
+// CHECK: __builtin_sycl_unique_stable_name(t.foo());
+
+// CHECK: template<> void WrappedInTemplate<Type>(Type t)
+// CHECK: __builtin_sycl_unique_stable_name(Type);
+// CHECK: __builtin_sycl_unique_stable_name(typename Type::type);
+// CHECK: __builtin_sycl_unique_stable_name(double);
Index: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1419,6 +1419,7 @@
case Stmt::OMPArraySectionExprClass:
case Stmt::OMPArrayShapingExprClass:
case Stmt::OMPIteratorExprClass:
+ case Stmt::SYCLUniqueStableNameExprClass:
case Stmt::TypeTraitExprClass: {
Bldr.takeNodes(Pred);
ExplodedNodeSet preVisit;
Index: clang/lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterStmt.cpp
+++ clang/lib/Serialization/ASTWriterStmt.cpp
@@ -580,6 +580,22 @@
Code = serialization::EXPR_CONSTANT;
}
+void ASTStmtWriter::VisitSYCLUniqueStableNameExpr(SYCLUniqueStableNameExpr *E) {
+ VisitExpr(E);
+
+ Record.writeBool(E->isExpr());
+ Record.AddSourceLocation(E->getLocation());
+ Record.AddSourceLocation(E->getLParenLocation());
+ Record.AddSourceLocation(E->getRParenLocation());
+
+ if (E->isExpr())
+ Record.AddStmt(E->getExpr());
+ else
+ Record.AddTypeSourceInfo(E->getTypeSourceInfo());
+
+ Code = serialization::EXPR_SYCL_UNIQUE_STABLE_NAME;
+}
+
void ASTStmtWriter::VisitPredefinedExpr(PredefinedExpr *E) {
VisitExpr(E);
Index: clang/lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderStmt.cpp
+++ clang/lib/Serialization/ASTReaderStmt.cpp
@@ -581,6 +581,22 @@
E->setSubExpr(Record.readSubExpr());
}
+void ASTStmtReader::VisitSYCLUniqueStableNameExpr(SYCLUniqueStableNameExpr *E) {
+ VisitExpr(E);
+
+ bool IsExpr = Record.readBool();
+ assert(E->isExpr() == IsExpr &&
+ "Wrong sycl-unique-stable-name trailing type");
+ E->setLocation(readSourceLocation());
+ E->setLParenLocation(readSourceLocation());
+ E->setRParenLocation(readSourceLocation());
+
+ if (IsExpr)
+ E->setExpr(Record.readExpr());
+ else
+ E->setTypeSourceInfo(Record.readTypeSourceInfo());
+}
+
void ASTStmtReader::VisitPredefinedExpr(PredefinedExpr *E) {
VisitExpr(E);
bool HasFunctionName = Record.readInt();
@@ -2802,6 +2818,11 @@
/*StorageKind=*/Record[ASTStmtReader::NumExprFields]));
break;
+ case EXPR_SYCL_UNIQUE_STABLE_NAME:
+ S = SYCLUniqueStableNameExpr::CreateEmpty(
+ Context, /*IsExpr*/ Record[ASTStmtReader::NumExprFields]);
+ break;
+
case EXPR_PREDEFINED:
S = PredefinedExpr::CreateEmpty(
Context,
Index: clang/lib/Sema/TreeTransform.h
===================================================================
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -2399,6 +2399,19 @@
return SEHFinallyStmt::Create(getSema().getASTContext(), Loc, Block);
}
+ ExprResult RebuildSYCLUniqueStableNameExpr(SourceLocation OpLoc,
+ SourceLocation LParen,
+ SourceLocation RParen, Expr *E) {
+ return getSema().BuildSYCLUniqueStableNameExpr(OpLoc, LParen, RParen, E);
+ }
+
+ ExprResult RebuildSYCLUniqueStableNameExpr(SourceLocation OpLoc,
+ SourceLocation LParen,
+ SourceLocation RParen,
+ TypeSourceInfo *TSI) {
+ return getSema().BuildSYCLUniqueStableNameExpr(OpLoc, LParen, RParen, TSI);
+ }
+
/// Build a new predefined expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -10172,6 +10185,47 @@
return TransformExpr(E->getSubExpr());
}
+template <typename Derived>
+ExprResult TreeTransform<Derived>::TransformSYCLUniqueStableNameExpr(
+ SYCLUniqueStableNameExpr *E) {
+ if (!E->isTypeDependent())
+ return E;
+
+ if (E->isExpr()) {
+ EnterExpressionEvaluationContext Unevaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::Unevaluated,
+ Sema::ReuseLambdaContextDecl);
+
+ ExprResult ER = getDerived().TransformExpr(E->getExpr());
+
+ if (ER.isInvalid())
+ return ExprError();
+
+ ER = getSema().CheckPlaceholderExpr(ER.get());
+
+ if (ER.isInvalid())
+ return ExprError();
+
+ if (!getDerived().AlwaysRebuild() && E->getExpr() == ER.get())
+ return E;
+
+ return getDerived().RebuildSYCLUniqueStableNameExpr(
+ E->getLocation(), E->getLParenLocation(), E->getRParenLocation(),
+ ER.get());
+ }
+
+ TypeSourceInfo *NewT = getDerived().TransformType(E->getTypeSourceInfo());
+
+ if (!NewT)
+ return ExprError();
+
+ if (!getDerived().AlwaysRebuild() && E->getTypeSourceInfo() == NewT)
+ return E;
+
+ return getDerived().RebuildSYCLUniqueStableNameExpr(
+ E->getLocation(), E->getLParenLocation(), E->getRParenLocation(), NewT);
+}
+
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformPredefinedExpr(PredefinedExpr *E) {
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -548,6 +548,35 @@
S.addAMDGPUWavesPerEUAttr(New, Attr, MinExpr, MaxExpr);
}
+// This doesn't take any template parameters, but we have a custom action that
+// needs to happen when the kernel itself is instantiated. We need to run the
+// ItaniumMangler to mark the names required to name this kernel.
+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()));
+}
+
/// Determine whether the attribute A might be relevent to the declaration D.
/// If not, we can skip instantiating it. The attribute may or may not have
/// been instantiated yet.
@@ -723,6 +752,11 @@
continue;
}
+ if (auto *A = dyn_cast<SYCLKernelAttr>(TmplAttr)) {
+ instantiateDependentSYCLKernelAttr(*this, TemplateArgs, *A, New);
+ continue;
+ }
+
assert(!TmplAttr->isPackExpansion());
if (TmplAttr->isLateParsed() && LateAttrs) {
// Late parsed attributes must be instantiated and attached after the
Index: clang/lib/Sema/SemaSYCL.cpp
===================================================================
--- clang/lib/Sema/SemaSYCL.cpp
+++ clang/lib/Sema/SemaSYCL.cpp
@@ -8,6 +8,7 @@
// This implements Semantic Analysis for SYCL constructs.
//===----------------------------------------------------------------------===//
+#include "clang/AST/Mangle.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaDiagnostic.h"
@@ -47,3 +48,33 @@
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 ShouldMangleCallback = [](ASTContext &Ctx, const CXXRecordDecl *RD) {
+ // We ALWAYS want to descend into the lambda mangling for these.
+ return true;
+ };
+ auto MangleCallback = [](ASTContext &Ctx, const CXXRecordDecl *RD,
+ raw_ostream &) { Ctx.AddSYCLKernelNamingDecl(RD); };
+
+ QualType Ty = GetSYCLKernelObjectType(FD);
+ std::unique_ptr<MangleContext> Ctx{ItaniumMangleContext::create(
+ Context, Context.getDiagnostics(), ShouldMangleCallback, MangleCallback)};
+ llvm::raw_null_ostream Out;
+ Ctx->mangleTypeName(Ty, Out);
+}
Index: clang/lib/Sema/SemaLambda.cpp
===================================================================
--- clang/lib/Sema/SemaLambda.cpp
+++ clang/lib/Sema/SemaLambda.cpp
@@ -461,11 +461,15 @@
std::tie(MCtx, ManglingContextDecl) =
getCurrentMangleNumberContext(Class->getDeclContext());
bool HasKnownInternalLinkage = false;
- if (!MCtx && getLangOpts().CUDA) {
+ if (!MCtx && (getLangOpts().CUDA || getLangOpts().SYCLIsDevice ||
+ getLangOpts().SYCLIsHost)) {
// Force lambda numbering in CUDA/HIP as we need to name lambdas following
// ODR. Both device- and host-compilation need to have a consistent naming
// on kernel functions. As lambdas are potential part of these `__global__`
// function names, they needs numbering following ODR.
+ // Also force for SYCL, since we need this for the
+ // __builtin_sycl_unique_stable_name implementation, which depends on lambda
+ // mangling.
MCtx = getMangleNumberingContext(Class, ManglingContextDecl);
assert(MCtx && "Retrieving mangle numbering context failed!");
HasKnownInternalLinkage = true;
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -3506,6 +3506,46 @@
return PredefinedExpr::Create(Context, Loc, ResTy, IK, SL);
}
+ExprResult Sema::BuildSYCLUniqueStableNameExpr(SourceLocation OpLoc,
+ SourceLocation LParen,
+ SourceLocation RParen,
+ TypeSourceInfo *TSI) {
+ return SYCLUniqueStableNameExpr::Create(Context, OpLoc, LParen, RParen, TSI);
+}
+ExprResult Sema::BuildSYCLUniqueStableNameExpr(SourceLocation OpLoc,
+ SourceLocation LParen,
+ SourceLocation RParen, Expr *E) {
+ // If this isn't dependent anymore, we know the type, so convert to a Type
+ // based version of the SYCLUniqueStableNameExpr.
+ if (E->isInstantiationDependent())
+ return SYCLUniqueStableNameExpr::Create(Context, OpLoc, LParen, RParen, E);
+
+ return BuildSYCLUniqueStableNameExpr(
+ OpLoc, LParen, RParen, Context.getTrivialTypeSourceInfo(E->getType()));
+}
+
+ExprResult Sema::ActOnSYCLUniqueStableNameExpr(SourceLocation OpLoc,
+ SourceLocation LParen,
+ SourceLocation RParen,
+ ParsedType ParsedTy) {
+ TypeSourceInfo *TSI = nullptr;
+ QualType Ty = GetTypeFromParser(ParsedTy, &TSI);
+
+ if (Ty.isNull())
+ return ExprError();
+ if (!TSI)
+ TSI = Context.getTrivialTypeSourceInfo(Ty, LParen);
+
+ return BuildSYCLUniqueStableNameExpr(OpLoc, LParen, RParen, TSI);
+}
+
+ExprResult Sema::ActOnSYCLUniqueStableNameExpr(SourceLocation OpLoc,
+ SourceLocation LParen,
+ SourceLocation RParen,
+ Expr *Operand) {
+ return BuildSYCLUniqueStableNameExpr(OpLoc, LParen, RParen, Operand);
+}
+
ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
PredefinedExpr::IdentKind IK;
Index: clang/lib/Sema/SemaExceptionSpec.cpp
===================================================================
--- clang/lib/Sema/SemaExceptionSpec.cpp
+++ clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1575,6 +1575,8 @@
return mergeCanThrow(CT, canThrow(TS->getTryBody()));
}
+ case Stmt::SYCLUniqueStableNameExprClass:
+ return CT_Cannot;
case Stmt::NoStmtClass:
llvm_unreachable("Invalid class for statement");
}
Index: clang/lib/Parse/ParseExpr.cpp
===================================================================
--- clang/lib/Parse/ParseExpr.cpp
+++ clang/lib/Parse/ParseExpr.cpp
@@ -1469,6 +1469,9 @@
case tok::kw_this:
Res = ParseCXXThis();
break;
+ case tok::kw___builtin_sycl_unique_stable_name:
+ Res = ParseSYCLUniqueStableNameExpression();
+ break;
case tok::annot_typename:
if (isStartOfObjCClassMessageMissingOpenBracket()) {
@@ -2324,6 +2327,44 @@
return Operand;
}
+/// Parse a __builtin_sycl_unique_stable_name expression. Accepts a type-id or
+/// an arbitrary expression as a parameter.
+ExprResult Parser::ParseSYCLUniqueStableNameExpression() {
+ assert(Tok.is(tok::kw___builtin_sycl_unique_stable_name) &&
+ "Not __bulitin_sycl_unique_stable_name");
+
+ SourceLocation OpLoc = ConsumeToken();
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+
+ // __builtin_sycl_unique_stable_name expressions are always parenthesized.
+ if (T.expectAndConsume(diag::err_expected_lparen_after,
+ "__builtin_sycl_unique_stable_name"))
+ return ExprError();
+
+ if (isTypeIdInParens()) {
+ TypeResult Ty = ParseTypeName();
+ T.consumeClose();
+
+ if (Ty.isInvalid())
+ return ExprError();
+
+ return Actions.ActOnSYCLUniqueStableNameExpr(
+ OpLoc, T.getOpenLocation(), T.getCloseLocation(), Ty.get());
+ }
+
+ EnterExpressionEvaluationContext Unevaluated(
+ Actions, Sema::ExpressionEvaluationContext::Unevaluated);
+ ExprResult Result = ParseExpression();
+
+ if (Result.isInvalid()) {
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return Result;
+ }
+
+ T.consumeClose();
+ return Actions.ActOnSYCLUniqueStableNameExpr(
+ OpLoc, T.getOpenLocation(), T.getCloseLocation(), Result.get());
+}
/// Parse a sizeof or alignof expression.
///
Index: clang/lib/CodeGen/CGExprScalar.cpp
===================================================================
--- clang/lib/CodeGen/CGExprScalar.cpp
+++ clang/lib/CodeGen/CGExprScalar.cpp
@@ -486,6 +486,8 @@
return CGF.EmitPseudoObjectRValue(E).getScalarVal();
}
+ Value *VisitSYCLUniqueStableNameExpr(SYCLUniqueStableNameExpr *E);
+
Value *VisitOpaqueValueExpr(OpaqueValueExpr *E) {
if (E->isGLValue())
return EmitLoadOfLValue(CGF.getOrCreateOpaqueLValueMapping(E),
@@ -1581,6 +1583,25 @@
return llvm::UndefValue::get(CGF.ConvertType(E->getType()));
}
+Value *
+ScalarExprEmitter::VisitSYCLUniqueStableNameExpr(SYCLUniqueStableNameExpr *E) {
+ ASTContext &Context = CGF.getContext();
+ llvm::Optional<LangAS> GlobalAS =
+ Context.getTargetInfo().getConstantAddressSpace();
+ llvm::Constant *GlobalConstStr = Builder.CreateGlobalStringPtr(
+ E->ComputeName(Context), "__usn_str",
+ static_cast<unsigned>(GlobalAS.getValueOr(LangAS::Default)));
+
+ unsigned ExprAS = Context.getTargetAddressSpace(E->getType());
+
+ if (GlobalConstStr->getType()->getPointerAddressSpace() == ExprAS)
+ return GlobalConstStr;
+
+ llvm::Type *EltTy = GlobalConstStr->getType()->getPointerElementType();
+ llvm::PointerType *NewPtrTy = llvm::PointerType::get(EltTy, ExprAS);
+ return Builder.CreateAddrSpaceCast(GlobalConstStr, NewPtrTy, "usn_addr_cast");
+}
+
Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
// Vector Mask Case
if (E->getNumSubExprs() == 2) {
Index: clang/lib/Basic/IdentifierTable.cpp
===================================================================
--- clang/lib/Basic/IdentifierTable.cpp
+++ clang/lib/Basic/IdentifierTable.cpp
@@ -107,8 +107,9 @@
KEYCXX20 = 0x200000,
KEYOPENCLCXX = 0x400000,
KEYMSCOMPAT = 0x800000,
+ KEYSYCL = 0x1000000,
KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20,
- KEYALL = (0xffffff & ~KEYNOMS18 &
+ KEYALL = (0xfffffff & ~KEYNOMS18 &
~KEYNOOPENCL) // KEYNOMS18 and KEYNOOPENCL are used to exclude.
};
@@ -155,6 +156,8 @@
if (LangOpts.CPlusPlus && (Flags & KEYALLCXX)) return KS_Future;
if (LangOpts.CPlusPlus && !LangOpts.CPlusPlus20 && (Flags & CHAR8SUPPORT))
return KS_Future;
+ if ((LangOpts.SYCLIsDevice || LangOpts.SYCLIsHost) && Flags & KEYSYCL)
+ return KS_Enabled;
return KS_Disabled;
}
Index: clang/lib/AST/TextNodeDumper.cpp
===================================================================
--- clang/lib/AST/TextNodeDumper.cpp
+++ clang/lib/AST/TextNodeDumper.cpp
@@ -1018,6 +1018,12 @@
OS << " isFreeIvar";
}
+void TextNodeDumper::VisitSYCLUniqueStableNameExpr(
+ const SYCLUniqueStableNameExpr *Node) {
+ if (Node->isTypeSourceInfo())
+ dumpType(Node->getTypeSourceInfo()->getType());
+}
+
void TextNodeDumper::VisitPredefinedExpr(const PredefinedExpr *Node) {
OS << " " << PredefinedExpr::getIdentKindName(Node->getIdentKind());
}
Index: clang/lib/AST/StmtProfile.cpp
===================================================================
--- clang/lib/AST/StmtProfile.cpp
+++ clang/lib/AST/StmtProfile.cpp
@@ -1190,6 +1190,16 @@
}
}
+void StmtProfiler::VisitSYCLUniqueStableNameExpr(
+ const SYCLUniqueStableNameExpr *S) {
+ VisitExpr(S);
+ ID.AddBoolean(S->isExpr());
+ if (S->isExpr())
+ VisitStmt(S->getExpr());
+ else
+ VisitType(S->getTypeSourceInfo()->getType());
+}
+
void StmtProfiler::VisitPredefinedExpr(const PredefinedExpr *S) {
VisitExpr(S);
ID.AddInteger(S->getIdentKind());
Index: clang/lib/AST/StmtPrinter.cpp
===================================================================
--- clang/lib/AST/StmtPrinter.cpp
+++ clang/lib/AST/StmtPrinter.cpp
@@ -1081,6 +1081,16 @@
OS << "]";
}
+void StmtPrinter::VisitSYCLUniqueStableNameExpr(
+ SYCLUniqueStableNameExpr *Node) {
+ OS << "__builtin_sycl_unique_stable_name(";
+ if (Node->isExpr())
+ PrintExpr(Node->getExpr());
+ else
+ Node->getTypeSourceInfo()->getType().print(OS, Policy);
+ OS << ")";
+}
+
void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) {
OS << PredefinedExpr::getIdentKindName(Node->getIdentKind());
}
Index: clang/lib/AST/JSONNodeDumper.cpp
===================================================================
--- clang/lib/AST/JSONNodeDumper.cpp
+++ clang/lib/AST/JSONNodeDumper.cpp
@@ -1164,6 +1164,13 @@
}
}
+void JSONNodeDumper::VisitSYCLUniqueStableNameExpr(
+ const SYCLUniqueStableNameExpr *E) {
+ if (E->isTypeSourceInfo())
+ JOS.attribute("typeSourceInfo",
+ createQualType(E->getTypeSourceInfo()->getType()));
+}
+
void JSONNodeDumper::VisitPredefinedExpr(const PredefinedExpr *PE) {
JOS.attribute("name", PredefinedExpr::getIdentKindName(PE->getIdentKind()));
}
Index: clang/lib/AST/ItaniumMangle.cpp
===================================================================
--- clang/lib/AST/ItaniumMangle.cpp
+++ clang/lib/AST/ItaniumMangle.cpp
@@ -125,14 +125,20 @@
typedef std::pair<const DeclContext*, IdentifierInfo*> DiscriminatorKeyTy;
llvm::DenseMap<DiscriminatorKeyTy, unsigned> Discriminator;
llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier;
+ const ShouldCallKernelCallbackTy ShouldCallKernelCallback = nullptr;
+ const KernelMangleCallbackTy KernelMangleCallback = nullptr;
bool IsDevCtx = false;
bool NeedsUniqueInternalLinkageNames = false;
public:
- explicit ItaniumMangleContextImpl(ASTContext &Context,
- DiagnosticsEngine &Diags)
- : ItaniumMangleContext(Context, Diags) {}
+ explicit ItaniumMangleContextImpl(
+ ASTContext &Context, DiagnosticsEngine &Diags,
+ ShouldCallKernelCallbackTy ShouldCallKernelCB,
+ KernelMangleCallbackTy KernelCB)
+ : ItaniumMangleContext(Context, Diags),
+ ShouldCallKernelCallback(ShouldCallKernelCB),
+ KernelMangleCallback(KernelCB) {}
/// @name Mangler Entry Points
/// @{
@@ -246,6 +252,13 @@
return Name;
}
+ ShouldCallKernelCallbackTy getShouldCallKernelCallback() const override {
+ return ShouldCallKernelCallback;
+ }
+ KernelMangleCallbackTy getKernelMangleCallback() const override {
+ return KernelMangleCallback;
+ }
+
/// @}
};
@@ -1515,7 +1528,9 @@
// <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()) {
+ if (Record->isLambda() && (Record->getLambdaManglingNumber() ||
+ Context.getShouldCallKernelCallback()(
+ Context.getASTContext(), Record))) {
assert(!AdditionalAbiTags &&
"Lambda type cannot have additional abi tags");
mangleLambda(Record);
@@ -1953,9 +1968,17 @@
// if the host-side CXX ABI has different numbering for lambda. In such case,
// if the mangle context is that device-side one, use the device-side lambda
// mangling number for this lambda.
+
unsigned Number = Context.isDeviceMangleContext()
? Lambda->getDeviceLambdaManglingNumber()
: Lambda->getLambdaManglingNumber();
+
+ if (Context.getShouldCallKernelCallback()(Context.getASTContext(), Lambda)) {
+ Context.getKernelMangleCallback()(Context.getASTContext(), Lambda, Out);
+ Out << '_';
+ return;
+ }
+
assert(Number > 0 && "Lambda should be mangled as an unnamed class");
if (Number > 1)
mangleNumber(Number - 2);
@@ -5026,6 +5049,19 @@
Out << "v18co_yield";
mangleExpression(cast<CoawaitExpr>(E)->getOperand());
break;
+ case Expr::SYCLUniqueStableNameExprClass: {
+ const auto *USN = cast<SYCLUniqueStableNameExpr>(E);
+ NotPrimaryExpr();
+
+ Out << "u33__builtin_sycl_unique_stable_name";
+ if (USN->isExpr())
+ mangleTemplateArgExpr(USN->getExpr());
+ else
+ mangleType(USN->getTypeSourceInfo()->getType());
+
+ Out << "E";
+ break;
+ }
}
if (AsTemplateArg && !IsPrimaryExpr)
@@ -6378,7 +6414,17 @@
Mangler.mangleLambdaSig(Lambda);
}
-ItaniumMangleContext *
-ItaniumMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) {
- return new ItaniumMangleContextImpl(Context, Diags);
+ItaniumMangleContext *ItaniumMangleContext::create(ASTContext &Context,
+ DiagnosticsEngine &Diags) {
+ return new ItaniumMangleContextImpl(
+ Context, Diags, [](ASTContext &, const CXXRecordDecl *) { return false; },
+ [](ASTContext &, const CXXRecordDecl *, raw_ostream &) {});
+}
+
+ItaniumMangleContext *ItaniumMangleContext::create(
+ ASTContext &Context, DiagnosticsEngine &Diags,
+ ShouldCallKernelCallbackTy ShouldCallKernelCallback,
+ KernelMangleCallbackTy MangleCallback) {
+ return new ItaniumMangleContextImpl(Context, Diags, ShouldCallKernelCallback,
+ MangleCallback);
}
Index: clang/lib/AST/ExprConstant.cpp
===================================================================
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -8669,6 +8669,26 @@
return true;
}
+ 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);
+ QualType ArrayTy = Info.Ctx.getConstantArrayType(CharTy, Size, nullptr,
+ ArrayType::Normal, 0);
+
+ StringLiteral *SL =
+ StringLiteral::Create(Info.Ctx, ResultStr, StringLiteral::Ascii,
+ /*Pascal*/ false, ArrayTy, E->getLocation());
+
+ evaluateLValue(SL, Result);
+ Result.addArray(Info, E, cast<ConstantArrayType>(ArrayTy));
+ return true;
+ }
+
// FIXME: Missing: @protocol, @selector
};
} // end anonymous namespace
@@ -10367,7 +10387,8 @@
Result = APValue(APValue::UninitArray(), 0,
CAT->getSize().getZExtValue());
- if (!Result.hasArrayFiller()) return true;
+ if (!Result.hasArrayFiller())
+ return true;
// Zero-initialize all elements.
LValue Subobject = This;
@@ -15154,6 +15175,7 @@
case Expr::CoawaitExprClass:
case Expr::DependentCoawaitExprClass:
case Expr::CoyieldExprClass:
+ case Expr::SYCLUniqueStableNameExprClass:
return ICEDiag(IK_NotICE, E->getBeginLoc());
case Expr::InitListExprClass: {
Index: clang/lib/AST/ExprClassification.cpp
===================================================================
--- clang/lib/AST/ExprClassification.cpp
+++ clang/lib/AST/ExprClassification.cpp
@@ -433,6 +433,9 @@
case Expr::CoawaitExprClass:
case Expr::CoyieldExprClass:
return ClassifyInternal(Ctx, cast<CoroutineSuspendExpr>(E)->getResumeExpr());
+ case Expr::SYCLUniqueStableNameExprClass:
+ return Cl::CL_PRValue;
+ break;
}
llvm_unreachable("unhandled expression kind in classification");
Index: clang/lib/AST/Expr.cpp
===================================================================
--- clang/lib/AST/Expr.cpp
+++ clang/lib/AST/Expr.cpp
@@ -504,6 +504,100 @@
return getNameInfo().getEndLoc();
}
+SYCLUniqueStableNameExpr::SYCLUniqueStableNameExpr(SourceLocation OpLoc,
+ SourceLocation LParen,
+ SourceLocation RParen,
+ QualType ResultTy,
+ TypeSourceInfo *TSI)
+ : Expr(SYCLUniqueStableNameExprClass, ResultTy, VK_RValue, OK_Ordinary),
+ OpLoc(OpLoc), LParen(LParen), RParen(RParen), Kind(ParamKind::Type) {
+ setTypeSourceInfo(TSI);
+ setDependence(computeDependence(this));
+}
+
+SYCLUniqueStableNameExpr::SYCLUniqueStableNameExpr(EmptyShell Empty,
+ QualType ResultTy,
+ bool IsExpr)
+ : Expr(SYCLUniqueStableNameExprClass, ResultTy, VK_RValue, OK_Ordinary) {
+ Kind = IsExpr ? ParamKind::Expr : ParamKind::Type;
+}
+
+SYCLUniqueStableNameExpr::SYCLUniqueStableNameExpr(SourceLocation OpLoc,
+ SourceLocation LParen,
+ SourceLocation RParen,
+ QualType ResultTy, Expr *E)
+ : Expr(SYCLUniqueStableNameExprClass, ResultTy, VK_RValue, OK_Ordinary),
+ OpLoc(OpLoc), LParen(LParen), RParen(RParen), Kind(ParamKind::Expr) {
+ setExpr(E);
+ setDependence(computeDependence(this));
+}
+
+SYCLUniqueStableNameExpr *
+SYCLUniqueStableNameExpr::Create(const ASTContext &Ctx, SourceLocation OpLoc,
+ SourceLocation LParen, SourceLocation RParen,
+ Expr *E) {
+ assert(E->isInstantiationDependent() &&
+ "Expr type only valid if the expr is dependent");
+ void *Mem = Ctx.Allocate(totalSizeToAlloc<Stmt *, TypeSourceInfo *>(1, 0),
+ alignof(SYCLUniqueStableNameExpr));
+
+ QualType ResultTy = Ctx.getPointerType(Ctx.CharTy.withConst());
+ return new (Mem) SYCLUniqueStableNameExpr(OpLoc, LParen, RParen, ResultTy, E);
+}
+
+SYCLUniqueStableNameExpr *
+SYCLUniqueStableNameExpr::Create(const ASTContext &Ctx, SourceLocation OpLoc,
+ SourceLocation LParen, SourceLocation RParen,
+ TypeSourceInfo *TSI) {
+ void *Mem = Ctx.Allocate(totalSizeToAlloc<Stmt *, TypeSourceInfo *>(1, 0),
+ alignof(SYCLUniqueStableNameExpr));
+ QualType ResultTy = Ctx.getPointerType(Ctx.CharTy.withConst());
+ return new (Mem)
+ SYCLUniqueStableNameExpr(OpLoc, LParen, RParen, ResultTy, TSI);
+}
+
+SYCLUniqueStableNameExpr *
+SYCLUniqueStableNameExpr::CreateEmpty(const ASTContext &Ctx, bool IsExpr) {
+ void *Mem =
+ Ctx.Allocate(totalSizeToAlloc<Stmt *, TypeSourceInfo *>(IsExpr, !IsExpr),
+ alignof(SYCLUniqueStableNameExpr));
+ QualType ResultTy = Ctx.getPointerType(Ctx.CharTy.withConst());
+ return new (Mem) SYCLUniqueStableNameExpr(EmptyShell(), ResultTy, IsExpr);
+}
+
+std::string SYCLUniqueStableNameExpr::ComputeName(ASTContext &Context) const {
+ return SYCLUniqueStableNameExpr::ComputeName(Context,
+ getTypeSourceInfo()->getType());
+}
+
+std::string SYCLUniqueStableNameExpr::ComputeName(ASTContext &Context,
+ QualType Ty) {
+ auto ShouldMangleCallback = [](ASTContext &Ctx, const CXXRecordDecl *RD) {
+ return Ctx.IsSYCLKernelNamingDecl(RD);
+ };
+ auto MangleCallback = [](ASTContext &Ctx, const CXXRecordDecl *RD,
+ raw_ostream &OS) {
+ assert(Ctx.IsSYCLKernelNamingDecl(RD) && "Not a sycl kernel?");
+ // 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'()
+ OS << (10'000 + Ctx.GetSYCLKernelNamingIndex(RD));
+ };
+ std::unique_ptr<MangleContext> Ctx{ItaniumMangleContext::create(
+ Context, Context.getDiagnostics(), ShouldMangleCallback, MangleCallback)};
+
+ std::string Buffer;
+ Buffer.reserve(128);
+ llvm::raw_string_ostream Out(Buffer);
+ Ctx->mangleTypeName(Ty, Out);
+
+ return Out.str();
+}
+
PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK,
StringLiteral *SL)
: Expr(PredefinedExprClass, FNTy, VK_LValue, OK_Ordinary) {
@@ -3381,6 +3475,7 @@
case SourceLocExprClass:
case ConceptSpecializationExprClass:
case RequiresExprClass:
+ case SYCLUniqueStableNameExprClass:
// These never have a side-effect.
return false;
Index: clang/lib/AST/ComputeDependence.cpp
===================================================================
--- clang/lib/AST/ComputeDependence.cpp
+++ clang/lib/AST/ComputeDependence.cpp
@@ -556,6 +556,12 @@
return D;
}
+ExprDependence clang::computeDependence(SYCLUniqueStableNameExpr *E) {
+ if (E->isExpr())
+ return E->getExpr()->getDependence();
+ return toExprDependence(E->getTypeSourceInfo()->getType()->getDependence());
+}
+
ExprDependence clang::computeDependence(PredefinedExpr *E) {
return toExprDependence(E->getType()->getDependence()) &
~ExprDependence::UnexpandedPack;
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -11648,3 +11648,89 @@
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().SYCLIsDevice || getLangOpts().SYCLIsHost) &&
+ "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 CXXRecordDecl *RD) const {
+ assert((getLangOpts().SYCLIsDevice || getLangOpts().SYCLIsHost) &&
+ "Only valid for SYCL programs");
+ 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.
+static void FilterSYCLKernelNamingDecls(
+ ASTContext &Ctx, const CXXRecordDecl *RD,
+ llvm::SmallVectorImpl<const CXXRecordDecl *> &Decls) {
+ static std::unique_ptr<ItaniumMangleContext> Mangler{
+ ItaniumMangleContext::create(Ctx, Ctx.getDiagnostics())};
+
+ llvm::SmallString<128> LambdaSig;
+ llvm::raw_svector_ostream Out(LambdaSig);
+ Mangler->mangleLambdaSig(RD, Out);
+
+ llvm::erase_if(Decls, [&LambdaSig](const CXXRecordDecl *LocalRD) {
+ llvm::SmallString<128> LocalLambdaSig;
+ llvm::raw_svector_ostream LocalOut(LocalLambdaSig);
+ Mangler->mangleLambdaSig(LocalRD, LocalOut);
+ return LambdaSig != LocalLambdaSig;
+ });
+}
+
+unsigned ASTContext::GetSYCLKernelNamingIndex(const CXXRecordDecl *RD) const {
+ assert((getLangOpts().SYCLIsDevice || getLangOpts().SYCLIsHost) &&
+ "Only valid for SYCL programs");
+ assert(IsSYCLKernelNamingDecl(RD) &&
+ "Lambda not involved in mangling asked for a naming index?");
+
+ RD = RD->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()};
+
+ // If we are in an itanium situation, the mangling-numbers for a lambda depend
+ // on the mangled signature, so sort by that. Only TargetCXXABI::Microsoft
+ // doesn't use the itanium mangler, and just sets the lambda mangling number
+ // incrementally, with no consideration to the signature.
+ if (Target->getCXXABI().getKind() != TargetCXXABI::Microsoft)
+ FilterSYCLKernelNamingDecls(const_cast<ASTContext &>(*this), RD, Decls);
+
+ llvm::sort(Decls, [](const CXXRecordDecl *LHS, const CXXRecordDecl *RHS) {
+ return LHS->getLambdaManglingNumber() < RHS->getLambdaManglingNumber();
+ });
+
+ return llvm::find(Decls, RD) - Decls.begin();
+}
Index: clang/include/clang/Serialization/ASTBitCodes.h
===================================================================
--- clang/include/clang/Serialization/ASTBitCodes.h
+++ clang/include/clang/Serialization/ASTBitCodes.h
@@ -1960,6 +1960,9 @@
// FixedPointLiteral
EXPR_FIXEDPOINT_LITERAL,
+
+ // SYCLUniqueStableNameExpr
+ EXPR_SYCL_UNIQUE_STABLE_NAME,
};
/// The kinds of designators that can occur in a
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -911,6 +911,10 @@
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 {
@@ -5190,6 +5194,22 @@
ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind);
ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val);
+ ExprResult BuildSYCLUniqueStableNameExpr(SourceLocation OpLoc,
+ SourceLocation LParen,
+ SourceLocation RParen,
+ TypeSourceInfo *TSI);
+ ExprResult BuildSYCLUniqueStableNameExpr(SourceLocation OpLoc,
+ SourceLocation LParen,
+ SourceLocation RParen, Expr *E);
+ ExprResult ActOnSYCLUniqueStableNameExpr(SourceLocation OpLoc,
+ SourceLocation LParen,
+ SourceLocation RParen,
+ ParsedType ParsedTy);
+ ExprResult ActOnSYCLUniqueStableNameExpr(SourceLocation OpLoc,
+ SourceLocation LParen,
+ SourceLocation RParen,
+ Expr *Operand);
+
bool CheckLoopHintExpr(Expr *E, SourceLocation Loc);
ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = nullptr);
Index: clang/include/clang/Parse/Parser.h
===================================================================
--- clang/include/clang/Parse/Parser.h
+++ clang/include/clang/Parse/Parser.h
@@ -1800,6 +1800,7 @@
ExprResult ParsePostfixExpressionSuffix(ExprResult LHS);
ExprResult ParseUnaryExprOrTypeTraitExpression();
ExprResult ParseBuiltinPrimaryExpression();
+ ExprResult ParseSYCLUniqueStableNameExpression();
ExprResult ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
bool &isCastExpr,
Index: clang/include/clang/Basic/TokenKinds.def
===================================================================
--- clang/include/clang/Basic/TokenKinds.def
+++ clang/include/clang/Basic/TokenKinds.def
@@ -694,11 +694,12 @@
ALIAS("_pascal" , __pascal , KEYBORLAND)
// Clang Extensions.
-KEYWORD(__builtin_convertvector , KEYALL)
-ALIAS("__char16_t" , char16_t , KEYCXX)
-ALIAS("__char32_t" , char32_t , KEYCXX)
-KEYWORD(__builtin_bit_cast , KEYALL)
-KEYWORD(__builtin_available , KEYALL)
+KEYWORD(__builtin_convertvector , KEYALL)
+ALIAS("__char16_t" , char16_t , KEYCXX)
+ALIAS("__char32_t" , char32_t , KEYCXX)
+KEYWORD(__builtin_bit_cast , KEYALL)
+KEYWORD(__builtin_available , KEYALL)
+KEYWORD(__builtin_sycl_unique_stable_name, KEYSYCL)
// Clang-specific keywords enabled only in testing.
TESTING_KEYWORD(__unknown_anytype , KEYALL)
Index: clang/include/clang/Basic/StmtNodes.td
===================================================================
--- clang/include/clang/Basic/StmtNodes.td
+++ clang/include/clang/Basic/StmtNodes.td
@@ -57,6 +57,7 @@
// Expressions
def Expr : StmtNode<ValueStmt, 1>;
def PredefinedExpr : StmtNode<Expr>;
+def SYCLUniqueStableNameExpr : StmtNode<Expr>;
def DeclRefExpr : StmtNode<Expr>;
def IntegerLiteral : StmtNode<Expr>;
def FixedPointLiteral : StmtNode<Expr>;
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6352,6 +6352,11 @@
def warn_gnu_null_ptr_arith : Warning<
"arithmetic on a null pointer treated as a cast from integer to pointer is a GNU extension">,
InGroup<NullPointerArithmetic>, 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">,
Index: clang/include/clang/AST/TextNodeDumper.h
===================================================================
--- clang/include/clang/AST/TextNodeDumper.h
+++ clang/include/clang/AST/TextNodeDumper.h
@@ -249,6 +249,7 @@
void VisitCastExpr(const CastExpr *Node);
void VisitImplicitCastExpr(const ImplicitCastExpr *Node);
void VisitDeclRefExpr(const DeclRefExpr *Node);
+ void VisitSYCLUniqueStableNameExpr(const SYCLUniqueStableNameExpr *Node);
void VisitPredefinedExpr(const PredefinedExpr *Node);
void VisitCharacterLiteral(const CharacterLiteral *Node);
void VisitIntegerLiteral(const IntegerLiteral *Node);
Index: clang/include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- clang/include/clang/AST/RecursiveASTVisitor.h
+++ clang/include/clang/AST/RecursiveASTVisitor.h
@@ -2651,6 +2651,10 @@
DEF_TRAVERSE_STMT(ObjCAvailabilityCheckExpr, {})
DEF_TRAVERSE_STMT(ParenExpr, {})
DEF_TRAVERSE_STMT(ParenListExpr, {})
+DEF_TRAVERSE_STMT(SYCLUniqueStableNameExpr, {
+ if (S->isTypeSourceInfo())
+ TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
+})
DEF_TRAVERSE_STMT(PredefinedExpr, {})
DEF_TRAVERSE_STMT(ShuffleVectorExpr, {})
DEF_TRAVERSE_STMT(ConvertVectorExpr, {})
Index: clang/include/clang/AST/Mangle.h
===================================================================
--- clang/include/clang/AST/Mangle.h
+++ clang/include/clang/AST/Mangle.h
@@ -173,6 +173,10 @@
class ItaniumMangleContext : public MangleContext {
public:
+ using ShouldCallKernelCallbackTy = bool (*)(ASTContext &,
+ const CXXRecordDecl *);
+ using KernelMangleCallbackTy = void (*)(ASTContext &, const CXXRecordDecl *,
+ raw_ostream &);
explicit ItaniumMangleContext(ASTContext &C, DiagnosticsEngine &D)
: MangleContext(C, D, MK_Itanium) {}
@@ -195,12 +199,21 @@
virtual void mangleDynamicStermFinalizer(const VarDecl *D, raw_ostream &) = 0;
+ // These have to live here, otherwise the CXXNameMangler won't have access to
+ // them.
+ virtual ShouldCallKernelCallbackTy getShouldCallKernelCallback() const = 0;
+ virtual KernelMangleCallbackTy getKernelMangleCallback() const = 0;
+
static bool classof(const MangleContext *C) {
return C->getKind() == MK_Itanium;
}
static ItaniumMangleContext *create(ASTContext &Context,
DiagnosticsEngine &Diags);
+ static ItaniumMangleContext *
+ create(ASTContext &Context, DiagnosticsEngine &Diags,
+ ShouldCallKernelCallbackTy ShouldKernelMangleCB,
+ KernelMangleCallbackTy KernelMangleCB);
};
class MicrosoftMangleContext : public MangleContext {
Index: clang/include/clang/AST/JSONNodeDumper.h
===================================================================
--- clang/include/clang/AST/JSONNodeDumper.h
+++ clang/include/clang/AST/JSONNodeDumper.h
@@ -263,6 +263,7 @@
void VisitBlockDecl(const BlockDecl *D);
void VisitDeclRefExpr(const DeclRefExpr *DRE);
+ void VisitSYCLUniqueStableNameExpr(const SYCLUniqueStableNameExpr *E);
void VisitPredefinedExpr(const PredefinedExpr *PE);
void VisitUnaryOperator(const UnaryOperator *UO);
void VisitBinaryOperator(const BinaryOperator *BO);
Index: clang/include/clang/AST/Expr.h
===================================================================
--- clang/include/clang/AST/Expr.h
+++ clang/include/clang/AST/Expr.h
@@ -2039,6 +2039,120 @@
}
};
+// This represents a use of the __builtin_sycl_unique_stable_name, which takes either
+// a type-id or an expression, and at CodeGen time emits a unique string
+// representation of the type (or type of the expression) in a way that permits
+// us to properly encode information about the SYCL kernels.
+class SYCLUniqueStableNameExpr final
+ : public Expr,
+ private llvm::TrailingObjects<SYCLUniqueStableNameExpr, Stmt *,
+ TypeSourceInfo *> {
+ friend class ASTStmtReader;
+ friend TrailingObjects;
+ SourceLocation OpLoc, LParen, RParen;
+ // Note: We store a Stmt* instead of the Expr* so that we can implement
+ // 'children'.
+ enum class ParamKind { Type, Expr };
+ ParamKind Kind;
+
+ SYCLUniqueStableNameExpr(EmptyShell Empty, QualType ResultTy, bool IsExpr);
+ SYCLUniqueStableNameExpr(SourceLocation OpLoc, SourceLocation LParen,
+ SourceLocation RParen, QualType ResultTy,
+ TypeSourceInfo *TSI);
+ SYCLUniqueStableNameExpr(SourceLocation OpLoc, SourceLocation LParen,
+ SourceLocation RParen, QualType ResultTy, Expr *E);
+
+ size_t numTrailingObjects(OverloadToken<TypeSourceInfo *>) const {
+ return Kind == ParamKind::Type ? 1 : 0;
+ }
+ size_t numTrailingObjects(OverloadToken<Stmt *>) const {
+ return Kind == ParamKind::Expr ? 1 : 0;
+ }
+ void setTypeSourceInfo(TypeSourceInfo *Ty) {
+ assert(Kind == ParamKind::Type &&
+ "TypeSourceInfo only valid for SYCLUniqueStableName of a Type");
+ *getTrailingObjects<TypeSourceInfo *>() = Ty;
+ }
+ void setExpr(Expr *E) {
+ assert(Kind == ParamKind::Expr &&
+ "Expr only valid for SYCLUniqueStableName of an Expr");
+ assert(E->isInstantiationDependent() &&
+ "Expr type only valid if the expr is dependent");
+ *getTrailingObjects<Stmt *>() = E;
+ }
+
+ void setLocation(SourceLocation L) { OpLoc = L; }
+ void setLParenLocation(SourceLocation L) { LParen = L; }
+ void setRParenLocation(SourceLocation L) { RParen = L; }
+
+public:
+ TypeSourceInfo *getTypeSourceInfo() {
+ assert(Kind == ParamKind::Type &&
+ "TypeSourceInfo only valid for SYCLUniqueStableName of a Type");
+ return *getTrailingObjects<TypeSourceInfo *>();
+ }
+
+ const TypeSourceInfo *getTypeSourceInfo() const {
+ assert(Kind == ParamKind::Type &&
+ "TypeSourceInfo only valid for SYCLUniqueStableName of a Type");
+ return *getTrailingObjects<TypeSourceInfo *>();
+ }
+
+ Expr *getExpr() {
+ assert(Kind == ParamKind::Expr &&
+ "Expr only valid for SYCLUniqueStableName of an Expr");
+ return cast<Expr>(*getTrailingObjects<Stmt *>());
+ }
+
+ const Expr *getExpr() const {
+ assert(Kind == ParamKind::Expr &&
+ "Expr only valid for SYCLUniqueStableName of an Expr");
+ return cast<Expr>(*getTrailingObjects<Stmt *>());
+ }
+
+ bool isExpr() const { return Kind == ParamKind::Expr; }
+
+ bool isTypeSourceInfo() const { return Kind == ParamKind::Type; }
+
+ static SYCLUniqueStableNameExpr *
+ Create(const ASTContext &Ctx, SourceLocation OpLoc, SourceLocation LParen,
+ SourceLocation RParen, TypeSourceInfo *TSI);
+
+ static SYCLUniqueStableNameExpr *Create(const ASTContext &Ctx,
+ SourceLocation OpLoc,
+ SourceLocation LParen,
+ SourceLocation RParen, Expr *E);
+ static SYCLUniqueStableNameExpr *CreateEmpty(const ASTContext &Ctx,
+ bool IsExpr);
+
+ SourceLocation getBeginLoc() const { return getLocation(); }
+ SourceLocation getEndLoc() const { return RParen; }
+ SourceLocation getLocation() const { return OpLoc; }
+ SourceLocation getLParenLocation() const { return LParen; }
+ SourceLocation getRParenLocation() const { return RParen; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == SYCLUniqueStableNameExprClass;
+ }
+
+ // Iterators
+ child_range children() {
+ return child_range(getTrailingObjects<Stmt *>(),
+ getTrailingObjects<Stmt *>() + isExpr());
+ }
+ const_child_range children() const {
+ return const_child_range(getTrailingObjects<Stmt *>(),
+ getTrailingObjects<Stmt *>() + isExpr());
+ }
+
+ // Convenience function to generate the name of the currently stored type.
+ std::string ComputeName(ASTContext &Context) const;
+
+ // Get the generated name of the type. Note that this only works after all
+ // kernels have been instantiated.
+ static std::string ComputeName(ASTContext &Context, QualType Ty);
+};
+
/// ParenExpr - This represents a parethesized expression, e.g. "(1)". This
/// AST node is only formed if full location information is requested.
class ParenExpr : public Expr {
Index: clang/include/clang/AST/ComputeDependence.h
===================================================================
--- clang/include/clang/AST/ComputeDependence.h
+++ clang/include/clang/AST/ComputeDependence.h
@@ -78,6 +78,7 @@
class CXXFoldExpr;
class TypeTraitExpr;
class ConceptSpecializationExpr;
+class SYCLUniqueStableNameExpr;
class PredefinedExpr;
class CallExpr;
class OffsetOfExpr;
@@ -165,6 +166,7 @@
ExprDependence computeDependence(ConceptSpecializationExpr *E,
bool ValueDependent);
+ExprDependence computeDependence(SYCLUniqueStableNameExpr *E);
ExprDependence computeDependence(PredefinedExpr *E);
ExprDependence computeDependence(CallExpr *E, llvm::ArrayRef<Expr *> PreArgs);
ExprDependence computeDependence(OffsetOfExpr *E);
Index: clang/include/clang/AST/ASTContext.h
===================================================================
--- clang/include/clang/AST/ASTContext.h
+++ clang/include/clang/AST/ASTContext.h
@@ -3158,10 +3158,26 @@
StringRef getCUIDHash() const;
+ void AddSYCLKernelNamingDecl(const CXXRecordDecl *RD);
+ bool IsSYCLKernelNamingDecl(const CXXRecordDecl *RD) const;
+ unsigned GetSYCLKernelNamingIndex(const CXXRecordDecl *RD) const;
+ /// 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_unique_stable_name.
+ llvm::DenseMap<const DeclContext *,
+ llvm::SmallPtrSet<const CXXRecordDecl *, 4>>
+ SYCLKernelNamingTypes;
};
/// Insertion operator for diagnostics.
Index: clang/docs/LanguageExtensions.rst
===================================================================
--- clang/docs/LanguageExtensions.rst
+++ clang/docs/LanguageExtensions.rst
@@ -1794,7 +1794,7 @@
metaprogramming algorithms to be able to specify/detect types generically.
- the generated kernel binary does not contain indirect calls because they
- are eliminated using compiler optimizations e.g. devirtualization.
+ are eliminated using compiler optimizations e.g. devirtualization.
- the selected target supports the function pointer like functionality e.g.
most CPU targets.
@@ -2404,6 +2404,44 @@
int *pb =__builtin_preserve_access_index(&v->c[3].b);
__builtin_preserve_access_index(v->j);
+``__builtin_sycl_unique_stable_name``
+-------------------------------------
+
+``__builtin_sycl_unique_stable_name()`` is a builtin that takes a type or unevaluated
+expression and produces a string literal containing a unique name for the type
+(or type of the expression) that is stable across split compilations, mainly to
+support SYCL/Data Parallel C++ language.
+
+In cases where the split compilation needs to share a unique token for a type
+across the boundary (such as in an offloading situation), this name can be used
+for lookup purposes, such as in the SYCL Integration Header.
+
+The value of this builtin is computed entirely at compile time, so it can be
+used in constant expressions. This value encodes lambda functions based on a
+stable numbering order in which they appear in their local declaration contexts.
+Once this builtin is evaluated in a constexpr context, it is erroneous to use
+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.
+
+**Syntax**:
+
+.. code-block:: c
+
+ // Computes a unique stable name for the given type.
+ constexpr const char * __builtin_sycl_unique_stable_name( type-id );
+
+ // Computes a unique stable name for the type of the given expression.
+ constexpr const char * __builtin_sycl_unique_stable_name( expression );
+
Multiprecision Arithmetic Builtins
----------------------------------
@@ -2598,7 +2636,7 @@
``__builtin_memcpy_inline`` has been designed as a building block for efficient
``memcpy`` implementations. It is identical to ``__builtin_memcpy`` but also
guarantees not to call any external functions. See LLVM IR `llvm.memcpy.inline
-<https://llvm.org/docs/LangRef.html#llvm-memcpy-inline-intrinsic>`_ intrinsic
+<https://llvm.org/docs/LangRef.html#llvm-memcpy-inline-intrinsic>`_ intrinsic
for more information.
This is useful to implement a custom version of ``memcpy``, implement a
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits