-
Notifications
You must be signed in to change notification settings - Fork 791
[SYCL][FPGA] Allowing max-concurrency attribute on functions. #3362
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6294,6 +6294,74 @@ static void handleSYCLIntelPipeIOAttr(Sema &S, Decl *D, | |
S.addSYCLIntelPipeIOAttr(D, Attr, E); | ||
} | ||
|
||
SYCLIntelFPGAMaxConcurrencyAttr *Sema::MergeSYCLIntelFPGAMaxConcurrencyAttr( | ||
Decl *D, const SYCLIntelFPGAMaxConcurrencyAttr &A) { | ||
// Check to see if there's a duplicate attribute with different values | ||
// already applied to the declaration. | ||
if (const auto *DeclAttr = D->getAttr<SYCLIntelFPGAMaxConcurrencyAttr>()) { | ||
const auto *DeclExpr = dyn_cast<ConstantExpr>(DeclAttr->getNThreadsExpr()); | ||
const auto *MergeExpr = dyn_cast<ConstantExpr>(A.getNThreadsExpr()); | ||
if (DeclExpr && MergeExpr && | ||
DeclExpr->getResultAsAPSInt() != MergeExpr->getResultAsAPSInt()) { | ||
Diag(DeclAttr->getLocation(), diag::err_sycl_attr_duplication) | ||
<< 1 << 1 << DeclAttr; | ||
return nullptr; | ||
} | ||
} | ||
// TODO | ||
// max_concurrency and disable_component_pipelining attributes can't be applied | ||
// to the same function. | ||
// if (checkAttrMutualExclusion<IntelDisableComponentPipeline>(S, D, AL)) | ||
// return; | ||
|
||
return ::new (Context) | ||
SYCLIntelFPGAMaxConcurrencyAttr(Context, A, A.getNThreadsExpr()); | ||
} | ||
|
||
void Sema::AddSYCLIntelFPGAMaxConcurrencyAttr(Decl *D, | ||
const AttributeCommonInfo &CI, | ||
Expr *E) { | ||
if (!E->isValueDependent()) { | ||
llvm::APSInt ArgVal; | ||
ExprResult Res = VerifyIntegerConstantExpression(E, &ArgVal); | ||
if (Res.isInvalid()) | ||
return; | ||
E = Res.get(); | ||
|
||
// This attribute requires a strictly positive value. | ||
if (ArgVal <= 0) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Document description says non-negative values are allowed, and that zero means unbounded. |
||
Diag(E->getExprLoc(), diag::err_attribute_requires_positive_integer) | ||
<< CI << /*positive*/ 0; | ||
return; | ||
} | ||
|
||
if (const auto *DeclAttr = D->getAttr<SYCLIntelFPGAMaxConcurrencyAttr>()) { | ||
const auto *DeclExpr = | ||
dyn_cast<ConstantExpr>(DeclAttr->getNThreadsExpr()); | ||
if (DeclExpr && ArgVal != DeclExpr->getResultAsAPSInt()) { | ||
Diag(CI.getLoc(), diag::warn_duplicate_attribute) << CI; | ||
Diag(DeclAttr->getLoc(), diag::note_previous_attribute); | ||
return; | ||
} | ||
} | ||
} | ||
|
||
D->addAttr(::new (Context) SYCLIntelFPGAMaxConcurrencyAttr(Context, CI, E)); | ||
} | ||
|
||
static void handleSYCLIntelFPGAMaxConcurrencyAttr(Sema &S, Decl *D, | ||
const ParsedAttr &A) { | ||
S.CheckDeprecatedSYCLAttributeSpelling(A); | ||
// TODO | ||
// max_concurrency and disable_component_pipelining attributes can't be | ||
// applied to the same function. if | ||
// (checkAttrMutualExclusion<IntelDisableComponentPipeline>(S, D, AL)) | ||
// return; | ||
|
||
Expr *E = A.getArgAsExpr(0); | ||
S.AddSYCLIntelFPGAMaxConcurrencyAttr(D, A, E); | ||
} | ||
|
||
namespace { | ||
struct IntrinToName { | ||
uint32_t Id; | ||
|
@@ -9547,6 +9615,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, | |
case ParsedAttr::AT_SYCLIntelPipeIO: | ||
handleSYCLIntelPipeIOAttr(S, D, AL); | ||
break; | ||
case ParsedAttr::AT_SYCLIntelFPGAMaxConcurrency: | ||
handleSYCLIntelFPGAMaxConcurrencyAttr(S, D, AL); | ||
break; | ||
|
||
// Swift attributes. | ||
case ParsedAttr::AT_SwiftAsyncName: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
// RUN: %clang_cc1 -fsycl-is-device -internal-isystem %S/Inputs -disable-llvm-passes -triple spir64-unknown-unknown-sycldevice -sycl-std=2020 -emit-llvm -o - %s | FileCheck %s | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add a comment here describing what the test does. |
||
#include "sycl.hpp" | ||
|
||
// CHECK: br label %for.cond, !llvm.loop ![[MD_MC:[0-9]+]] | ||
// CHECK: br label %for.cond2, !llvm.loop ![[MD_MC_1:[0-9]+]] | ||
|
||
// CHECK: define {{.*}}spir_kernel void @"{{.*}}kernel_name1"() #0 {{.*}} !max_concurrency ![[NUM1:[0-9]+]] | ||
// CHECK: define {{.*}}spir_kernel void @"{{.*}}kernel_name3"() #0 {{.*}} !max_concurrency ![[NUM2:[0-9]+]] | ||
// CHECK: define {{.*}}spir_kernel void @"{{.*}}kernel_name4"() #0 {{.*}} !max_concurrency ![[NUM1:[0-9]+]] | ||
|
||
template <int A> | ||
void max_concurrency() { | ||
int a[10]; | ||
// CHECK: ![[MD_MC]] = distinct !{![[MD_MC]], ![[MP:[0-9]+]], ![[MD_max_concurrency:[0-9]+]]} | ||
// CHECK-NEXT: ![[MP]] = !{!"llvm.loop.mustprogress"} | ||
// CHECK-NEXT: ![[MD_max_concurrency]] = !{!"llvm.loop.max_concurrency.count", i32 5} | ||
[[intel::max_concurrency(A)]] for (int i = 0; i != 10; ++i) | ||
a[i] = 0; | ||
// CHECK: ![[MD_MC_1]] = distinct !{![[MD_MC_1]], ![[MP]], ![[MD_max_concurrency_1:[0-9]+]]} | ||
// CHECK-NEXT: ![[MD_max_concurrency_1]] = !{!"llvm.loop.max_concurrency.count", i32 4} | ||
[[intel::max_concurrency(4)]] for (int i = 0; i != 10; ++i) | ||
a[i] = 0; | ||
} | ||
|
||
// CHECK: ![[NUM1]] = !{i32 4} | ||
// CHECK: ![[NUM2]] = !{i32 3} | ||
|
||
template <typename name, typename Func> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please use updated guidelines for new FE tests: |
||
__attribute__((sycl_kernel)) void kernel_single_task_1(const Func &kernelFunc) { | ||
kernelFunc(); | ||
} | ||
|
||
using namespace cl::sycl; | ||
|
||
class Functor1 { | ||
public: | ||
[[intel::max_concurrency(4)]] void operator()() const {} | ||
}; | ||
|
||
[[intel::max_concurrency(2)]] void foo() {} | ||
|
||
class Functor2 { | ||
public: | ||
void operator()() const { | ||
foo(); | ||
} | ||
}; | ||
|
||
template <int NT> | ||
class Functor3 { | ||
public: | ||
[[intel::max_concurrency(NT)]] void operator()() const {} | ||
}; | ||
|
||
template <int NT> | ||
[[intel::max_concurrency(NT)]] void func() {} | ||
|
||
int main() { | ||
queue q; | ||
|
||
kernel_single_task_1<class kernel_function>([]() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. New guidelines suggest using kernel_single_task from the sycl.hpp header instead. |
||
max_concurrency<5>(); | ||
}); | ||
|
||
q.submit([&](handler &h) { | ||
Functor1 f1; | ||
h.single_task<class kernel_name1>(f1); | ||
|
||
Functor2 f2; | ||
h.single_task<class kernel_name2>(f2); | ||
|
||
h.single_task<class kernel_name3>( | ||
[]() [[intel::max_concurrency(3)]]{}); | ||
|
||
Functor3<4> f3; | ||
h.single_task<class kernel_name4>(f3); | ||
|
||
h.single_task<class kernel_name5>([]() { | ||
func<2>(); | ||
}); | ||
|
||
}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you also add an example that uses '0'? |
||
|
||
|
||
return 0; | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This example is missing the template keyword that introduces N.