================
@@ -0,0 +1,74 @@
+// RUN: %clang_cc1 -fsycl-is-device -O0 -triple spirv64-unknown-unknown \
+// RUN: -emit-llvm %s -o - | FileCheck %s --check-prefix=DEVICE
+
+// RUN: %clang_cc1 -fsycl-is-host -O0 -triple spirv64-unknown-unknown \
+// RUN: -emit-llvm %s -o - | FileCheck %s --check-prefix=HOST
+
+// RUN: %clang_cc1 -fsycl-is-device -emit-llvm \
+// RUN: -aux-triple x86_64-pc-windows-msvc -triple spir-unknown--unknown \
+// RUN: %s -o - | FileCheck %s --check-prefix=MSVC
+
+namespace QL {
+ auto dg1 = [] { return 1; };
+ inline auto dg_inline1 = [] { return 1; };
+}
+
+namespace QL {
+ auto dg2 = [] { return 2; };
+ template<int N>
+ auto dg_template = [] { return N; };
+}
+
+using namespace QL;
+template<typename T>
+[[clang::sycl_kernel_entry_point(T)]] void f(T t) {
+ t();
+}
+
+void g() {
+ f(dg1);
+ f(dg2);
+ f(dg_inline1);
+ f(dg_template<3>);
+}
+
+// HOST: @_ZN2QL3dg1E = internal global %class.anon undef, align 1
+// HOST: @_ZN2QL3dg2E = internal global %class.anon.0 undef, align 1
+// HOST: @_ZN2QL10dg_inline1E = linkonce_odr global %class.anon.2 undef,
comdat, align 1
+// HOST: @_ZN2QL11dg_templateILi3EEE = linkonce_odr global %class.anon.4
undef, comdat, align 1
+
+// DEVICE: define spir_kernel void @_ZTSN2QL3dg1MUlvE_E
+// DEVICE: call spir_func noundef i32 @_ZNK2QL3dg1MUlvE_clEv
+// DEVICE: define internal spir_func noundef i32 @_ZNK2QL3dg1MUlvE_clEv
+// DEVICE: define spir_kernel void @_ZTSN2QL3dg2MUlvE_E
+// DEVICE: call spir_func noundef i32 @_ZNK2QL3dg2MUlvE_clEv
+// DEVICE: define internal spir_func noundef i32 @_ZNK2QL3dg2MUlvE_clEv
+// DEVICE: define spir_kernel void @_ZTSN2QL10dg_inline1MUlvE_E
+// DEVICE: call spir_func noundef i32 @_ZNK2QL10dg_inline1MUlvE_clEv
+// DEVICE: define linkonce_odr spir_func noundef i32
@_ZNK2QL10dg_inline1MUlvE_clEv
+// DEVICE: define spir_kernel void @_ZTSN2QL11dg_templateILi3EEMUlvE_E
+// DEVICE: call spir_func noundef i32 @_ZNK2QL11dg_templateILi3EEMUlvE_clEv
+// DEVICE: define linkonce_odr spir_func noundef i32
@_ZNK2QL11dg_templateILi3EEMUlvE_clEv
+
+// HOST: define spir_func void @_Z1gv
+// HOST: call spir_func void @_Z1fIN2QL3dg1MUlvE_EEvT_
+// HOST: call spir_func void @_Z1fIN2QL3dg2MUlvE_EEvT_
+// HOST: call spir_func void @_Z1fIN2QL10dg_inline1MUlvE_EEvT_
+// HOST: call spir_func void @_Z1fIN2QL11dg_templateILi3EEMUlvE_EEvT_
+// HOST: define internal spir_func void @_Z1fIN2QL3dg1MUlvE_EEvT
+// HOST: define internal spir_func void @_Z1fIN2QL3dg2MUlvE_EEvT_
+// HOST: define linkonce_odr spir_func void @_Z1fIN2QL10dg_inline1MUlvE_EEvT_
+// HOST: define linkonce_odr spir_func void
@_Z1fIN2QL11dg_templateILi3EEMUlvE_EEvT_
+
+// MSVC: define dso_local spir_kernel void @_ZTSN2QL3dg1MUlvE_E
+// MSVC: call spir_func noundef i32 @_ZNK2QL3dg1MUlvE_clEv
+// MSVC: define internal spir_func noundef i32 @_ZNK2QL3dg1MUlvE_clEv
+// MSVC: define dso_local spir_kernel void @_ZTSN2QL3dg2MUlvE_E
+// MSVC: call spir_func noundef i32 @_ZNK2QL3dg2MUlvE_clEv
+// MSVC: define internal spir_func noundef i32 @_ZNK2QL3dg2MUlvE_clEv
+// MSVC: define dso_local spir_kernel void @_ZTSN2QL10dg_inline1MUlvE_E
+// MSVC: call spir_func noundef i32 @_ZNK2QL10dg_inline1MUlvE_clEv
+// MSVC: define linkonce_odr spir_func noundef i32
@_ZNK2QL10dg_inline1MUlvE_clEv
+// MSVC: define dso_local spir_kernel void @_ZTSN2QL11dg_templateILi3EEMUlvE_E
+// MSVC: call spir_func noundef i32 @_ZNK2QL11dg_templateILi3EEMUlvE_clEv
+// MSVC: define linkonce_odr spir_func noundef i32
@_ZNK2QL11dg_templateILi3EEMUlvE_clEv
----------------
tahonermann wrote:
I've been looking at mangled names generated by GCC and Clang in order to
convince myself that these changes won't cause other problems. The good news is
that, I think, these changes are a strict improvement over the status quo. The
bad news is, there appear to be a lot of problems with mangling of lambdas in
Clang (and a few in GCC). I don't have a comprehensive set of cases to review,
but I think the following case provides a good starting point for discussion.
Tagging @zygoloid and @rjmccall for any thoughts they have.
In the following, the "SYCL" annotation means Clang with CUDA, HIP, or SYCL
enabled, it doesn't matter which. I chose SYCL because that is what I'm using
in the examples. The annotated mangled names correspond to the generated call
operator for the lambda expression that appears in each example.
https://godbolt.org/z/j7roYMsEv
```
extern int x;
template<int (*FP)()>
auto vt = FP;
namespace ns {
// GCC: _ZNK2nsUlvE0_clEv
// Clang: _ZNK2nsUlvE_clEv
// SYCL: _ZNK2nsUlvE0_clEv
template<int (*FP)() = [] { return x+1; }>
inline auto v1 = FP;
int usev1() { return v1<>(); }
// GCC: _ZNK2ns2v2MUlvE_clEv
// Clang: _ZNK2ns3$_0clEv
// SYCL: _ZNK2nsUlvE1_clEv
inline auto& v2 = vt<[] { return x+2; }>;
int usev2() { return v2(); }
// GCC: _ZNK2nsUlvE2_clEv
// Clang: _ZNK2nsUlvE0_clEv
// SYCL: _ZNK2nsUlvE3_clEv
template<int (*FP)() = [] { return x+3; }>
inline auto v3 = FP;
int usev3() { return v3<>(); }
} // ns namespace
```
A few observations:
- GCC appears to allocate a discriminator for lambda expressions in dependent
contexts (even when they are not dependent). Clang presumably does as well, but
only when an external mangling is being used. This explains the mangling
differences for `v1` above.
- Neither GCC nor Clang incorporate the variable declaration context (see
[`<closure-prefix>`](https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.closure-prefix))
in the mangled names for lambdas that appear in default arguments of template
parameters. I think they should. The Itanium C++ ABI doesn't appear to address
this possibility, at least not in [5.1.8, "Closure Types
(Lambdas)"](https://itanium-cxx-abi.github.io/cxx-abi/abi.html#closure-types).
- `v2` is the case that is particularly interesting for this PR. GCC includes a
`<closure-prefix>`, Clang generates a private name, and Clang+SYCL generates an
external name without a `<closure-prefix>`. The latter consumes a discriminator
from the enclosing namespace and therefore affects the names produced for `v3`.
- GCC and Clang+SYCL agree on the mangling for the `v1` case. Observable
effects from the `v2` case lead them to disagree for the `v3` case (if the `v2`
case is removed, they do agree on `v3`).
The current changes in this PR have no effect on this example. Ideally,
additional changes would be made to include a `<closure-prefix>` in the
mangling for the `v2` case.
The question for this PR is, how far should we go in addressing this and other
cases? I have, or will have, additional test cases, but it might be best to
file new issues for those and follow up on them separately. I suspect some of
the other examples I have might warrant new issues for the Itanium C++ ABI to
address.
https://github.com/llvm/llvm-project/pull/159115
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits