Skip to content

Conversation

zahiraam
Copy link
Contributor

@zahiraam zahiraam commented Mar 15, 2021

This patch implements the support of a new FPGA function attribute ‘max_concurrency”. The attribute exists already for loops. It takes a single unsigned integer argument and has the following syntax:
[[intel::component_max_concurrency(n)]]

An example of it use:
[[intel::component_max_concurrency(n)]]
void foo() {
}
The LLVM IR representation will be function metadata:
!component_max_concurrency !0
!0 = !{!i32 n}

Max_concurrency applies to functions in device code. It is not be propagated to the caller.

Comment on lines 59 to 60
template <int NT>
[[intel::reqd_sub_group_size(NT)]] void func() {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to use [[intel::max_concurrency(NT)]] here?

[[intel::max_concurrency(2)]] for (int i = 0; i != 10; ++i) a[i] = 0;
}

[[intel::component_max_concurrency(2)]] void foo1 { }
Copy link
Contributor

@smanna12 smanna12 Mar 16, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are adding new spelling here. You did not add it inside Attr.td file and also CodeGen test is using existing loop attribute spelling [[intel::max_concurrency()]]. Are we going to use same loop attribute spelling as function attribute?

// CHECK: !17 = !{i32 2}
// CHECK: !18 = !{i32 3}

template <typename name, typename Func>
Copy link
Contributor

@smanna12 smanna12 Mar 16, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use updated guidelines for new FE tests:
Please refer section “Guidelines for adding DPC++ in-tree LIT tests (DPC++ Clang FE tests)” in the https://github.com/intel/llvm/blob/sycl/CONTRIBUTING.md guide for the suggested guidelines


if (const SYCLIntelFPGAMaxConcurrencyAttr *A =
FD->getAttr<SYCLIntelFPGAMaxConcurrencyAttr>()) {
const auto *CE = dyn_cast<ConstantExpr>(A->getNThreadsExpr());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you are missing an assert here before ArgVal.
assert(CE && "Not an integer constant expression");

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const auto *CE = dyn_cast<ConstantExpr>(A->getNThreadsExpr());
const auto *CE = cast<ConstantExpr>(A->getNThreadsExpr());

No need for a dyn_cast<> followed by an assert.

void bar() {
[[intel::max_concurrency(N)]] for(;;) { }
}
[[intel::component_max_concurrency(N)]] void bar1() { }
Copy link
Contributor

@smanna12 smanna12 Mar 16, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here, new attribute spelling, you did not use this spelling

Comment on lines 562 to 563
if (auto *A = FD->getAttr<SYCLIntelFPGAMaxConcurrencyAttr>())
Attrs.insert(A);
Copy link
Contributor

@smanna12 smanna12 Mar 16, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we going to propagate this attribute to the caller?

@smanna12
Copy link
Contributor

smanna12 commented Mar 16, 2021

Could you please provide description about this PR? Also need SemaSYCL test here. Thanks.

@smanna12 smanna12 requested a review from AaronBallman March 16, 2021 03:23
Copy link
Contributor

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of the sema tests are missing for testing the warning situations (applies to functions and not other types of declarations, etc).

I think we're also missing a "merge" function for the attribute as functions can have redeclarations. e.g., we want to catch things like:

[[intel::max_concurrency(4)]] void func();
[[intel::max_concurrency(5)]] void func() {}

CXX11<"intel","max_concurrency">];
let Subjects = SubjectList<[ForStmt, CXXForRangeStmt, WhileStmt, DoStmt],
let Subjects = SubjectList<[ForStmt, CXXForRangeStmt, WhileStmt, DoStmt, Function],
ErrorDiag, "'for', 'while', and 'do' statements">;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The text of the diagnostic needs to be updated as well.

}

def SYCLIntelFPGAMaxConcurrency : StmtAttr {
def SYCLIntelFPGAMaxConcurrency : InheritableAttr {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def SYCLIntelFPGAMaxConcurrency : InheritableAttr {
def SYCLIntelFPGAMaxConcurrency : DeclOrStmtAttr {

/// declaration.
void addSYCLIntelPipeIOAttr(Decl *D, const AttributeCommonInfo &CI, Expr *ID);

/// AddSYCLIntelFPGAMaxConcurrencyAttr - Adds a max_component attribute to a
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

max_component -- did you mean max_concurrency?


if (const SYCLIntelFPGAMaxConcurrencyAttr *A =
FD->getAttr<SYCLIntelFPGAMaxConcurrencyAttr>()) {
const auto *CE = dyn_cast<ConstantExpr>(A->getNThreadsExpr());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const auto *CE = dyn_cast<ConstantExpr>(A->getNThreadsExpr());
const auto *CE = cast<ConstantExpr>(A->getNThreadsExpr());

No need for a dyn_cast<> followed by an assert.

Fn->setMetadata("stall_enable", llvm::MDNode::get(Context, AttrMDArgs));
}

if (const SYCLIntelFPGAMaxConcurrencyAttr *A =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (const SYCLIntelFPGAMaxConcurrencyAttr *A =
if (const auto *A =

Because the type is spelled out explicitly in the initializer, this is a good time to use auto.

if (const SYCLIntelFPGAMaxConcurrencyAttr *A =
FD->getAttr<SYCLIntelFPGAMaxConcurrencyAttr>()) {
const auto *CE = dyn_cast<ConstantExpr>(A->getNThreadsExpr());
Optional<llvm::APSInt> ArgVal = CE->getResultAsAPSInt();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Optional<llvm::APSInt> ArgVal = CE->getResultAsAPSInt();
llvm::APSInt ArgVal = CE->getResultAsAPSInt();

The function doesn't return an Optional, so I assume this was unintentional.

@zahiraam
Copy link
Contributor Author

All of the sema tests are missing for testing the warning situations (applies to functions and not other types of declarations, etc).

I think we're also missing a "merge" function for the attribute as functions can have redeclarations. e.g., we want to catch things like:

[[intel::max_concurrency(4)]] void func();
[[intel::max_concurrency(5)]] void func() {}

@AaronBallman Forgot to work on this. Sorry.
I will do that now.

Comment on lines 3319 to 3337
case attr::Kind::SYCLIntelFPGAMaxConcurrency: {
auto *SIMCA = cast<SYCLIntelFPGAMaxConcurrencyAttr>(A);
if (auto *Existing =
SYCLKernel->getAttr<SYCLIntelFPGAMaxConcurrencyAttr>()) {
ASTContext &Ctx = getASTContext();
if (Existing->getNThreadsExpr() > SIMCA->getNThreadsExpr()) {
Diag(SYCLKernel->getLocation(),
diag::err_conflicting_sycl_kernel_attributes);
Diag(Existing->getLocation(), diag::note_conflicting_attribute);
Diag(SIMCA->getLocation(), diag::note_conflicting_attribute);
SYCLKernel->setInvalidDecl();
} else {
SYCLKernel->addAttr(A);
}
} else {
SYCLKernel->addAttr(A);
}
break;
}
Copy link
Contributor

@smanna12 smanna12 Mar 17, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i am wondering what is the purpose of adding this diagnostic here? I do not see any test regarding this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added to be able to check on things like this, previous attribute on a function.
[[intel::max_concurrency(4)]] void func();
[[intel::max_concurrency(5)]] void func() {}
I need to add a test case for this.

Copy link
Contributor

@smanna12 smanna12 Mar 17, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can add "merge" function to check this instead of SemaSYCL codes here:
SYCLIntelFPGAMaxConcurrencyAttr *Sema::MergeSSYCLIntelFPGAMaxConcurrencyAttr(
Decl *D, const SYCLIntelFPGAMaxConcurrencyAttr &A) {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Studying that! Thanks.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think adding the code here only handles diagnostics when applying attributes to SYCL kernel i.e. when attributes are propagated to kernel from device functions called by kernel. I don't think duplicate attributes on any other function will be handled by this

Based on code in L563, it looks like while the attribute can be explicitly specified on kernel, it is not propagated to kernel from device functions. In this case, I do not think this block of code is required. I think the "merge" function as @smanna12 should cover kernel function as well. However please verify with tests for 'normal' and kernel functions.

void bar() {
[[intel::max_concurrency(N)]] for(;;) { }
}
[[intel::max_concurrency(N)]] void bar1() { }
Copy link
Contributor

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.

E = Res.get();

// This attribute requires a strictly positive value.
if (ArgVal <= 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The 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.

@@ -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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment here describing what the test does.

int main() {
queue q;

kernel_single_task_1<class kernel_function>([]() {
Copy link
Contributor

Choose a reason for hiding this comment

The 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.

func<2>();
});

});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you also add an example that uses '0'?

@@ -0,0 +1,125 @@
// RUN: %clang_cc1 -fsycl-is-device -internal-isystem %S/Inputs -sycl-std=2020 -fsyntax-only -ast-dump -verify -pedantic %s | FileCheck %s

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment here indicating what this test does.


[[intel::max_concurrency(8)]] void dup();
[[intel::max_concurrency(9)]] void dup() {} // expected-error {{duplicate Intel FPGA function attribute 'max_concurrency'}}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you also add an example where the declaration and definition use the same value?

@zahiraam zahiraam closed this Mar 23, 2021
iclsrc pushed a commit that referenced this pull request Sep 27, 2025
d54f77c5 ("[NFC] Split of SPT and SPIR-V in header parsing (#2316)",
2024-03-11) made a copy of the error log, with the presumably unintended
consequence that errors are no longer propagated back to the SPIRVModule
itself.

Original commit:
KhronosGroup/SPIRV-LLVM-Translator@3d58c69cf2f3704
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants