-
Notifications
You must be signed in to change notification settings - Fork 740
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[SYCL][clang] Emit default template arguments in integration header (#…
…16005) For free function kernels support clang forward declares the kernel itself as well as its parameter types. In case a free function kernel has a parameter that is templated and has a default template argument, all template arguments including arguments that match default arguments must be printed in kernel's forward declarations, for example ``` template <typename T, typename = int> struct Arg { T val; }; // For the kernel SYCL_EXT_ONEAPI_FUNCTION_PROPERTY( (ext::oneapi::experimental::nd_range_kernel<1>)) void foo(Arg<int> arg) { arg.val = 42; } // Integration header must contain void foo(Arg<int, int> arg); ``` Unfortunately, even though integration header emission already has extensive support for forward declarations priting, some modifications to clang's type printing are still required, since neither of existing PrintingPolicy flags help to reach the correct result. Using `SuppressDefaultTemplateArgs = true` doesn't help without printing canonical types, printing canonical types for the case like ``` template <typename T> SYCL_EXT_ONEAPI_FUNCTION_PROPERTY( (ext::oneapi::experimental::nd_range_kernel<1>)) void foo(Arg<T> arg) { arg.val = 42; } // Printing canonical types is causing the following integration header template <typename T> void foo(Arg<type-parameter-0-0, int> arg); ``` Using `SkipCanonicalizationOfTemplateTypeParms` field of printing policy doesn't help here since at the one point where it is checked we take canonical type of `Arg`, not its parameters and it will contain template argument types in canonical type after that.
- Loading branch information
Showing
4 changed files
with
185 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
100 changes: 100 additions & 0 deletions
100
clang/test/CodeGenSYCL/free_function_default_template_arguments.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
// RUN: %clang_cc1 -fsycl-is-device -internal-isystem %S/Inputs -triple spir64-unknown-unknown -sycl-std=2020 -fsycl-int-header=%t.h %s | ||
// RUN: FileCheck -input-file=%t.h %s | ||
|
||
// This test checks integration header contents for free functions kernels with | ||
// parameter types that have default template arguments. | ||
|
||
#include "mock_properties.hpp" | ||
#include "sycl.hpp" | ||
|
||
namespace ns { | ||
|
||
struct notatuple { | ||
int a; | ||
}; | ||
|
||
namespace ns1 { | ||
template <typename A = notatuple> | ||
class hasDefaultArg { | ||
|
||
}; | ||
} | ||
|
||
template <typename T, typename = int, int a = 12, typename = notatuple, typename ...TS> struct Arg { | ||
T val; | ||
}; | ||
|
||
[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", | ||
2)]] void | ||
simple(Arg<char>){ | ||
} | ||
|
||
} | ||
|
||
[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", | ||
2)]] void | ||
simple1(ns::Arg<ns::ns1::hasDefaultArg<>>){ | ||
} | ||
|
||
|
||
template <typename T> | ||
[[__sycl_detail__::add_ir_attributes_function("sycl-nd-range-kernel", 2)]] void | ||
templated(ns::Arg<T, float, 3>, T end) { | ||
} | ||
|
||
template void templated(ns::Arg<int, float, 3>, int); | ||
|
||
using namespace ns; | ||
|
||
template <typename T> | ||
[[__sycl_detail__::add_ir_attributes_function("sycl-nd-range-kernel", 2)]] void | ||
templated2(Arg<T, notatuple>, T end) { | ||
} | ||
|
||
template void templated2(Arg<int, notatuple>, int); | ||
|
||
template <typename T, int a = 3> | ||
[[__sycl_detail__::add_ir_attributes_function("sycl-nd-range-kernel", 2)]] void | ||
templated3(Arg<T, notatuple, a, ns1::hasDefaultArg<>, int, int>, T end) { | ||
} | ||
|
||
template void templated3(Arg<int, notatuple, 3, ns1::hasDefaultArg<>, int, int>, int); | ||
|
||
// CHECK: Forward declarations of kernel and its argument types: | ||
// CHECK-NEXT: namespace ns { | ||
// CHECK-NEXT: struct notatuple; | ||
// CHECK-NEXT: } | ||
// CHECK-NEXT: namespace ns { | ||
// CHECK-NEXT: template <typename T, typename, int a, typename, typename ...TS> struct Arg; | ||
// CHECK-NEXT: } | ||
|
||
// CHECK: void ns::simple(ns::Arg<char, int, 12, ns::notatuple>); | ||
// CHECK-NEXT: static constexpr auto __sycl_shim1() { | ||
// CHECK-NEXT: return (void (*)(struct ns::Arg<char, int, 12, struct ns::notatuple>))simple; | ||
// CHECK-NEXT: } | ||
|
||
// CHECK: Forward declarations of kernel and its argument types: | ||
// CHECK: namespace ns { | ||
// CHECK: namespace ns1 { | ||
// CHECK-NEXT: template <typename A> class hasDefaultArg; | ||
// CHECK-NEXT: } | ||
|
||
// CHECK: void simple1(ns::Arg<ns::ns1::hasDefaultArg<ns::notatuple>, int, 12, ns::notatuple>); | ||
// CHECK-NEXT: static constexpr auto __sycl_shim2() { | ||
// CHECK-NEXT: return (void (*)(struct ns::Arg<class ns::ns1::hasDefaultArg<struct ns::notatuple>, int, 12, struct ns::notatuple>))simple1; | ||
// CHECK-NEXT: } | ||
|
||
// CHECK: template <typename T> void templated(ns::Arg<T, float, 3, ns::notatuple>, T end); | ||
// CHECK-NEXT: static constexpr auto __sycl_shim3() { | ||
// CHECK-NEXT: return (void (*)(struct ns::Arg<int, float, 3, struct ns::notatuple>, int))templated<int>; | ||
// CHECK-NEXT: } | ||
|
||
// CHECK: template <typename T> void templated2(ns::Arg<T, ns::notatuple, 12, ns::notatuple>, T end); | ||
// CHECK-NEXT: static constexpr auto __sycl_shim4() { | ||
// CHECK-NEXT: return (void (*)(struct ns::Arg<int, struct ns::notatuple, 12, struct ns::notatuple>, int))templated2<int>; | ||
// CHECK-NEXT: } | ||
|
||
// CHECK: template <typename T, int a> void templated3(ns::Arg<T, ns::notatuple, a, ns::ns1::hasDefaultArg<ns::notatuple>, int, int>, T end); | ||
// CHECK-NEXT: static constexpr auto __sycl_shim5() { | ||
// CHECK-NEXT: return (void (*)(struct ns::Arg<int, struct ns::notatuple, 3, class ns::ns1::hasDefaultArg<struct ns::notatuple>, int, int>, int))templated3<int, 3>; | ||
// CHECK-NEXT: } |