Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
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
3 changes: 2 additions & 1 deletion clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -12676,7 +12676,8 @@ def err_free_function_variadic_args : Error<
"free function kernel cannot be a variadic function">;
def err_free_function_return_type : Error<
"SYCL free function kernel should have return type 'void'">;

def err_free_function_first_occurrence_missing_attr: Error<
"the first occurrence of kernel free function should be declared with attribute add_ir_attributes_function with 'sycl-nd-range-kernel' or 'sycl-single-task-kernel'">;

// SYCL kernel entry point diagnostics
def err_sycl_entry_point_invalid : Error<
Expand Down
31 changes: 25 additions & 6 deletions clang/lib/Sema/SemaSYCL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1160,14 +1160,33 @@ static target getAccessTarget(QualType FieldTy,
}

bool SemaSYCL::isFreeFunction(const FunctionDecl *FD) {
for (auto *IRAttr : FD->specific_attrs<SYCLAddIRAttributesFunctionAttr>()) {
SmallVector<std::pair<std::string, std::string>, 4> NameValuePairs =
IRAttr->getAttributeNameValuePairs(getASTContext());
for (const auto &NameValuePair : NameValuePairs) {
if (NameValuePair.first == "sycl-nd-range-kernel" ||
NameValuePair.first == "sycl-single-task-kernel") {
clang::SourceLocation Loc = FD->getLocation();
bool NextDeclaredWithAttr = false;
for (clang::FunctionDecl *Redecl : FD->redecls()) {
bool IsFreeFunctionAttr = false;
for (auto *IRAttr :
Redecl->specific_attrs<SYCLAddIRAttributesFunctionAttr>()) {
SmallVector<std::pair<std::string, std::string>, 4> NameValuePairs =
IRAttr->getAttributeNameValuePairs(getASTContext());
const auto it = std::find_if(
NameValuePairs.begin(), NameValuePairs.end(),
[](const auto &NameValuePair) {
return NameValuePair.first == "sycl-nd-range-kernel" ||
NameValuePair.first == "sycl-single-task-kernel";
});
IsFreeFunctionAttr = it != NameValuePairs.end();
}
if (Redecl->isFirstDecl()) {
if (IsFreeFunctionAttr)
return true;
if (NextDeclaredWithAttr) {
Diag(Loc, diag::err_free_function_first_occurrence_missing_attr);
Diag(Redecl->getLocation(), diag::note_previous_declaration);
return false;
}
} else {
Loc = Redecl->getLocation();
NextDeclaredWithAttr = IsFreeFunctionAttr;
}
}
return false;
Expand Down
16 changes: 16 additions & 0 deletions clang/test/SemaSYCL/free_function_negative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,22 @@ foo(int start, ...) { // expected-error {{free function kernel cannot be a varia
foo1(int start, ...) { // expected-error {{free function kernel cannot be a variadic function}}
}

// expected-note@+1 {{conflicting attribute is here}}
[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 1)]] void
foo2(int start);

// expected-error@+1 {{attribute 'add_ir_attributes_function' is already applied with different arguments}}
[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 2)]] void
foo2(int start) {
}

// expected-note@+1 {{previous declaration is here}}
void foo3(int start, int *ptr);

// expected-error@+2 {{the first occurrence of kernel free function should be declared with attribute add_ir_attributes_function with 'sycl-nd-range-kernel' or 'sycl-single-task-kernel'}}
[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 2)]] void
foo3(int start, int *ptr){}

// expected-error@+2 {{a function with a default argument value cannot be used to define SYCL free function kernel}}
[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 2)]] void
singleTaskKernelDefaultValues(int Value = 1) {
Expand Down
82 changes: 82 additions & 0 deletions sycl/test-e2e/Experimental/free_functions/redeclaration.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// REQUIRES: aspect-usm_shared_allocations
// RUN: %{build} -o %t.out
// RUN: %{run} %t.out

// The name mangling for free function kernels currently does not work with PTX.
// UNSUPPORTED: cuda, hip
// UNSUPPORTED-INTENDED: Not implemented yet for Nvidia/AMD backends.

#include <iostream>
#include <sycl/detail/core.hpp>
#include <sycl/ext/oneapi/free_function_queries.hpp>
#include <sycl/kernel_bundle.hpp>
#include <sycl/usm.hpp>

namespace syclext = sycl::ext::oneapi;
namespace syclexp = sycl::ext::oneapi::experimental;

static constexpr size_t NUM = 1024;
static constexpr size_t WGSIZE = 16;

int check_result(int *ptr) {
for (size_t i = 0; i < NUM; ++i) {
const float expected = 3 + static_cast<int>(i);
if (ptr[i] != expected) {
std::cout << "Kernel execution did not produce the expected result\n";
return 1;
}
}
return 0;
}

SYCL_EXT_ONEAPI_FUNCTION_PROPERTY((syclexp::nd_range_kernel<1>))
void free_func(int start, int *ptr);

SYCL_EXT_ONEAPI_FUNCTION_PROPERTY((syclexp::nd_range_kernel<1>))
void free_func(int start, int *ptr);

SYCL_EXT_ONEAPI_FUNCTION_PROPERTY((syclexp::nd_range_kernel<1>))
void free_func1(int start, int *ptr);

void free_func1(int start, int *ptr);

static int call_kernel_code(sycl::queue &q, sycl::kernel &kernel) {
int *ptr = sycl::malloc_shared<int>(NUM, q);
q.submit([&](sycl::handler &cgh) {
cgh.set_args(3, ptr);
sycl::nd_range ndr{{NUM}, {WGSIZE}};
cgh.parallel_for(ndr, kernel);
}).wait();
const int ret = check_result(ptr);
sycl::free(ptr, q);
return ret;
}

template <auto Func>
int test_declarations(sycl::queue &q, sycl::context &ctxt) {
auto exe_bndl =
syclexp::get_kernel_bundle<Func, sycl::bundle_state::executable>(ctxt);
sycl::kernel k_func = exe_bndl.template ext_oneapi_get_kernel<Func>();
return call_kernel_code(q, k_func);
}

#define KERNEL_CODE(start, ptr) \
size_t id = \
syclext::this_work_item::get_nd_item<1>().get_global_linear_id(); \
ptr[id] = start + static_cast<int>(id);

SYCL_EXT_ONEAPI_FUNCTION_PROPERTY((syclexp::nd_range_kernel<1>))
void free_func(int start, int *ptr) { KERNEL_CODE(start, ptr); }

SYCL_EXT_ONEAPI_FUNCTION_PROPERTY((syclexp::nd_range_kernel<1>))
void free_func1(int start, int *ptr) { KERNEL_CODE(start, ptr); }

int main() {
sycl::queue q;
sycl::context ctxt = q.get_context();

int result{0};
result |= test_declarations<free_func>(q, ctxt);
result |= test_declarations<free_func1>(q, ctxt);
return result;
}
Loading