Skip to content

[WIP] Unique stable name #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
0ff40f9
Add tests
schittir May 4, 2021
4c53337
Add more tests
schittir May 6, 2021
3e06737
Edit builtin documentation
schittir May 11, 2021
81b49f8
Edit documentation per review comments
schittir May 11, 2021
9993946
Fix typos per Aaron's review
schittir May 12, 2021
6c01690
Update doc with Aaron's feedback on non-lambda types
schittir May 13, 2021
e2ae208
Changing text per Aaron's suggestion
schittir May 13, 2021
be023e8
Add SemaSYCL tests
schittir May 13, 2021
9ebbc6c
Add more tests
schittir May 14, 2021
c73731b
Merge remote-tracking branch 'origin/unique_stable_name_reimpl' into …
schittir May 14, 2021
6840213
Edit parsing test per review comments
schittir May 14, 2021
a8867d4
Changing test case now that mangling for trailing types is implemented
schittir May 14, 2021
375e87d
Fix minor issues because lit test failed
schittir May 14, 2021
764a4b0
Add another test case per Aaron's suggestion and fix ifconstexpr case
schittir May 15, 2021
0ec2d07
Group cases that trigger errors in a separate section
schittir May 15, 2021
8ddd3a9
Add number markers to diagnostics
schittir May 18, 2021
c636401
Merge remote-tracking branch 'origin/unique_stable_name_reimpl' into …
schittir May 18, 2021
52862e8
Adding kernelSingleTask bookmark and cleaning up some comments
schittir May 18, 2021
874d44f
Minor change - add space
schittir May 18, 2021
e5ac8fc
Merge remote-tracking branch 'origin/unique_stable_name_reimpl' into …
schittir May 18, 2021
96bb440
Add more CodeGen tests including TODO and FIXMEs, and address review …
schittir May 19, 2021
a08a5ac
Add SemaSYCL test cases and address review comments
schittir May 19, 2021
bdffe7e
Add bookmarks to notes
schittir May 19, 2021
b2584b2
Merge remote-tracking branch 'origin/unique_stable_name_reimpl' into …
schittir May 19, 2021
53a414b
Move CHECK strings around per Erich's review
schittir May 19, 2021
41ffe76
Add two cases per Aaron's suggestion
schittir May 19, 2021
4fa5e27
Update SemaSYCL test comments
schittir May 19, 2021
5b0018e
Moved CHECK lines per new comments
schittir May 20, 2021
ad7eadb
Update comments and diagnostics in SemaSYCL test
schittir May 20, 2021
10643c8
Merge remote-tracking branch 'origin/unique_stable_name_reimpl' into …
schittir May 20, 2021
07c5fbd
Add and move around CHECK lines per Erich's comments
schittir May 21, 2021
8e56614
Minor change to address review comment
schittir May 24, 2021
5bc1061
Reorganize SemaSYCL test and change diagnostic messages accordingly
schittir May 25, 2021
3e19ec4
Minor edits and fixing typos
schittir May 25, 2021
e2edc31
Change comments per Aaron's review and minor fixes
schittir May 25, 2021
5003b2b
Minor change - number the kernel calls and lambdas in (mostly) textua…
schittir May 25, 2021
dbada48
Address the remaining review comments
schittir May 25, 2021
8fd77bd
Change comments per review - catching the remaining things
schittir May 25, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 29 additions & 15 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2316,24 +2316,38 @@ argument.

``__builtin_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.
(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.

This builtin is superior to RTTI for this purpose for two reasons. First, this
value is computed entirely at compile time, so it can be used in constant
expressions. Second, this value encodes lambda functions based on line-number
rather than the order in which it appears in a function. This is valuable
because it is stable in cases where an unrelated lambda is introduced
conditionally in the same function.

The current implementation of this builtin uses a slightly modified Itanium
Mangler to produce the unique name. The lambda ordinal is replaced with one or
more line/column pairs in the format ``LINE->COL``, separated with a ``~``
character. Typically, only one pair will be included, however in the case of
macro expansions the entire macro expansion stack is expressed.
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_unique_stable_name( type-id );

// Computes a unique stable name for the type of the given expression.
constexpr const char * __builtin_unique_stable_name( expression );

Multiprecision Arithmetic Builtins
----------------------------------
Expand Down
165 changes: 165 additions & 0 deletions clang/test/CodeGenSYCL/unique_stable_name.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
// 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 [[INT1_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: @[[INT:[^\w]+]] = private unnamed_addr constant [[INT_SIZE:\[[0-9]+ x i8\]]] 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: @usn_str.8 = private unnamed_addr constant [36 x i8] c"_ZTSZZ4mainENKUlvE10001_clEvEUlvE2_\00", align 1
// CHECK: @usn_str.9 = 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:[^\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_unique_stable_name(T));
}

template <typename T>
void lambda_in_dependent_function() {
auto y = [] {};
puts(__builtin_unique_stable_name(y));
}

template <typename Tw, typename Tz>
void lambda_two_dep() {
auto z = [] {};
puts(__builtin_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_unique_stable_name(p));
}

#define DEF_IN_MACRO() \
auto MACRO_X = []() {}; \
auto MACRO_Y = []() {}; \
puts(__builtin_unique_stable_name(MACRO_X)); \
puts(__builtin_unique_stable_name(MACRO_Y));

#define MACRO_CALLS_MACRO() \
{ DEF_IN_MACRO(); } \
{ DEF_IN_MACRO(); }

template <typename Ty>
auto func() -> decltype(__builtin_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* ()* @_Z4funcI4DerpEDTu20__unique_stable_nameXsrT_3strEEEv)

auto l1 = []() { return 1; };
auto l2 = [](decltype(l1) *l = nullptr) { return 2; };
kernel_single_task<class kernel3>(l2);
puts(__builtin_unique_stable_name(l2));
// CHECK: call spir_func void @_Z18kernel_single_taskIZ4mainE7kernel3Z4mainEUlPZ4mainEUlvE_E_EvT0_
// CHECK: call spir_func void @puts(i8* getelementptr inbounds ([[LAMBDA_K3_SIZE]], [[LAMBDA_K3_SIZE]]* @[[LAMBDA_KERNEL3]]

constexpr const char str[] = "lalala";
static_assert(__builtin_strcmp(__builtin_unique_stable_name(str), "_ZTSA7_Kc\0") == 0, "unexpected mangling");

int i = 0;
puts(__builtin_unique_stable_name(i++));
// CHECK: store i32 0, i32* %i
// CHECK: call spir_func void @puts(i8* getelementptr inbounds ([[INT1_SIZE]], [[INT1_SIZE]]* @[[INT1]]

// FIXME: Ensure that j is incremented because VLAs are terrible
int j = 55;
puts(__builtin_unique_stable_name(int[++j]));
// CHECK: store i32 55, i32* %j
// CHECK: call spir_func void @puts(i8* getelementptr inbounds ([[STRING_SIZE]], [[STRING_SIZE]]* @[[STRING]]

// CHECK: define internal spir_func void @_Z18kernel_single_taskIZ4mainE7kernel2PFPKcvEEvT0_
// CHECK: declare spir_func i8* @_Z4funcI4DerpEDTu20__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_unique_stable_name(int));
// CHECK: call spir_func void @puts(i8* getelementptr inbounds ([[INT_SIZE]], [[INT_SIZE]]* @[[INT]]

auto x = []() {};
puts(__builtin_unique_stable_name(x));
puts(__builtin_unique_stable_name(decltype(x)));
// CHECK: call spir_func void @puts(i8* getelementptr inbounds ([[LAMBDA_X_SIZE]], [[LAMBDA_X_SIZE]]* @[[LAMBDA_X]]
// CHECK: call spir_func void @puts(i8* getelementptr inbounds ([[LAMBDA_Y_SIZE]], [[LAMBDA_Y_SIZE]]* @[[LAMBDA_Y]]

DEF_IN_MACRO();
// CHECK: call spir_func void @puts(i8* getelementptr inbounds ([[MACRO_SIZE]], [[MACRO_SIZE]]* @[[MACRO_X]]
// CHECK: call spir_func void @puts(i8* getelementptr inbounds ([[MACRO_SIZE]], [[MACRO_SIZE]]* @[[MACRO_Y]]

MACRO_CALLS_MACRO();
// CHECK: call spir_func void @puts(i8* getelementptr inbounds ([[MACRO_MACRO_SIZE]], [[MACRO_MACRO_SIZE]]* @[[MACRO_MACRO_X]]
// CHECK: call spir_func void @puts(i8* getelementptr inbounds ([[MACRO_MACRO_SIZE]], [[MACRO_MACRO_SIZE]]* @[[MACRO_MACRO_Y]]

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: store i32 5, i32* %a, align 4
// CHECK: store double 1.070000e+01, double* %b, align 8
// 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* getelementptr inbounds ([[INT1_SIZE]], [[INT1_SIZE]]* @[[INT1]]

// CHECK: define internal spir_func void @_Z14template_paramIZZ4mainENKUlvE0_clEvEUlvE_Evv
// CHECK: call spir_func void @puts(i8* getelementptr inbounds ([[LAMBDA_SIZE]], [[LAMBDA_SIZE]]* @[[LAMBDA]]

// CHECK: define linkonce_odr spir_func void @_Z28lambda_in_dependent_functionIiEvv
// CHECK: call spir_func void @puts(i8* getelementptr inbounds ([[DEP_INT_SIZE]], [[DEP_INT_SIZE]]* @[[LAMBDA_IN_DEP_INT]]

// CHECK: define internal spir_func void @_Z28lambda_in_dependent_functionIZZ4mainENKUlvE0_clEvEUlvE_Evv
// CHECK: call spir_func void @puts(i8* getelementptr inbounds ([[DEP_LAMBDA_SIZE]], [[DEP_LAMBDA_SIZE]]* @[[LAMBDA_IN_DEP_X]]

// CHECK: define linkonce_odr spir_func void @_Z13lambda_no_depIidEvT_T0_(i32 %a, double %b)
// CHECK: call spir_func void @puts(i8* getelementptr inbounds ([[NO_DEP_LAMBDA_SIZE]], [[NO_DEP_LAMBDA_SIZE]]* @[[LAMBDA_NO_DEP]]

// CHECK: define internal spir_func void @_Z14lambda_two_depIZZ4mainENKUlvE0_clEvEUliE_ZZ4mainENKS0_clEvEUldE_Evv
// CHECK: call spir_func void @puts(i8* getelementptr inbounds ([[DEP_LAMBDA1_SIZE]], [[DEP_LAMBDA1_SIZE]]* @[[LAMBDA_TWO_DEP]]

// CHECK: define internal spir_func void @_Z14lambda_two_depIZZ4mainENKUlvE0_clEvEUldE_ZZ4mainENKS0_clEvEUliE_Evv
// CHECK: call spir_func void @puts(i8* getelementptr inbounds ([[DEP_LAMBDA2_SIZE]], [[DEP_LAMBDA2_SIZE]]* @[[LAMBDA_TWO_DEP2]]
42 changes: 42 additions & 0 deletions clang/test/ParserSYCL/unique_stable_name.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-unused %s

namespace NS {
int good = 55;
}

void f(int var) {
// expected-error@+1{{expected '(' after '__builtin_unique_stable_name'}}
__builtin_unique_stable_name int; // Correct usage is __builtin_unique_stable_name(int);

// expected-error@+1{{expected '(' after '__builtin_unique_stable_name'}}
__builtin_unique_stable_name {int}; // Correct usage is __builtin_unique_stable_name(int);

// expected-error@+2{{expected ')'}}
// expected-note@+1{{to match this '('}}
__builtin_unique_stable_name(int; // Missing paren before semicolon

// expected-error@+2{{expected ')'}}
// expected-note@+1{{to match this '('}}
__builtin_unique_stable_name(int, float); // Missing paren before comma

__builtin_unique_stable_name(var);
__builtin_unique_stable_name(NS::good);

// expected-error@+1{{expected expression}}
__builtin_unique_stable_name(for (int i = 0; i < 10; ++i) {})
__builtin_unique_stable_name({
(for (int i = 0; i < 10; ++i){})})
}

template <typename T>
void f2() {
__builtin_unique_stable_name(typename T::good_type);
}

struct S {
class good_type {};
};

void use() {
f2<S>();
}
Loading