-
Notifications
You must be signed in to change notification settings - Fork 769
[SYCL] Fix FE attribute handling in SYCL_EXTERNAL functions. #1778
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
Conversation
SYCL_EXTERNAL functions are not included into the device declarations set which is iterated during SYCL attribute propagation and checking. Signed-off-by: Konstantin S Bobrovsky <konstantin.s.bobrovsky@intel.com>
[[cl::intel_reqd_sub_group_size(2)]] void sg_size2() {} | ||
|
||
// expected-note@+2 {{conflicting attribute is here}} | ||
// expected-error@+1 {{conflicting attributes applied to a SYCL kernel}} |
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 diagnostic doesn't seem to be correct, because function it is pointing to is not a SYCL kernel
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 diagnostic seems strange as well, why does it think that sg_size4 and sg_size2 are the same kernel?
Should this conflict be diagnosed on a call expression instead?
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 diagnostic doesn't seem to be correct, because function it is pointing to is not a SYCL kernel
OK
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 diagnostic seems strange as well, why does it think that sg_size4 and sg_size2 are the same kernel?
Why do you think "it think that sg_size4 and sg_size2 are the same kernel" - please elaborate.
Should this conflict be diagnosed on a call expression instead?
This is a question to existing design. I'm not changing anything in the diagnostics mechanism. I'm fixing existing bug where SYCL_EXTERNAL functions were missing in that diagnostics - I add them.
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.
From the error message, it says "conflicting attributes applied to a SYCL kernel". From the notes, it specifies attributes on two separate declarations.
So by reading the error + notes, it implies that there are two conflicting attributes on a single kernel, yet they are on different functions.
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 error message existed before - I did not invent it, I just used it for SYCL_EXTERNAL function. Do you suggest to fix prior problems?
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.
We do this already? We have other conditions where we diagnose an error on a kernel about conflicting attributes, and then point to an attribute on another declaration?
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.
Yep. SYCL attributes are propagated from called device function up to the kernel (AFAIK it is spec defined behavior which I find pretty magic), sometimes there are several functions called from kernel and their attribute values can conflict. Diagnosing happens here
llvm/clang/lib/Sema/SemaSYCL.cpp
Line 1484 in 12d14e8
Diag(SYCLKernel->getLocation(), |
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.
Ah, well, the way we report that is awful. But not needing to be fixed in this patch. Thanks @Fznamznon. The error-message should likely be changed to be more clear about this if anyone ends up getting to it.
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.
I don't really see value in this diagnostic. Does application of intel_reqd_sub_group_size
attribute to function which is not called from a kernel make sense?
Imagine that SYCL_EXTERNAL
function has some intel_reqd_sub_group_size
in the translation unit where it is defined and declaration of this function in the translation unit doesn't have intel_reqd_sub_group_size
. Or it has some other value in intel_reqd_sub_group_size
attribute. We cannot diagnose this in FE. FE can just miss propagation of this attribute to the kernel from
called SYCL_EXTERNAL
function if user didn't mark declaration of it. I think there are a lot of other cases which cannot be handled/diagnosed by FE.
@@ -12556,7 +12556,7 @@ class Sema final { | |||
private: | |||
// We store SYCL Kernels here and handle separately -- which is a hack. | |||
// FIXME: It would be best to refactor this. | |||
SmallVector<Decl*, 4> SyclDeviceDecls; | |||
llvm::SetVector<Decl *> SyclDeviceDecls; |
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.
Why make this change? Switching to a setVector doesn't seem to help anything here, particularly when we are using it like a vector.
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.
SetVector allows both deduplication and deterministic iteration order. The former is needed because SYCL_EXTERNAL functions can also be called from kernels, in which case addSyclDeviceDecl(FD) on vector would lead to duplicates. The latter is needed for deterministic compiler behavior.
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.
Thanks for clarifying. Can you elaborate the problem better in the pull request message? I still don't have a good hold of the problem you're trying to solve.
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.
It is all in the test case I added:
[[cl::intel_reqd_sub_group_size(2)]] void sg_size2() {}
[[cl::intel_reqd_sub_group_size(4)]] __attribute__((sycl_device)) void sg_size4() {
sg_size2();
}
SYCL_EXTERNAL function with reqd_sub_group_size 4 calls a function with reqd_sub_group_size 2. This shoud be an error. Existing implementation detects it only when there is a kernel in place of SYCL_EXTERNAL function, and silently generates incorrect code for SYCL_EXTERNAL.
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.
SYCL_EXTERNAL
== __attribute__((sycl_device))
, BTW
[[cl::intel_reqd_sub_group_size(2)]] void sg_size2() {} | ||
|
||
// expected-note@+2 {{conflicting attribute is here}} | ||
// expected-error@+1 {{conflicting attributes applied to a SYCL kernel}} |
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 diagnostic seems strange as well, why does it think that sg_size4 and sg_size2 are the same kernel?
Should this conflict be diagnosed on a call expression instead?
Signed-off-by: Konstantin S Bobrovsky <konstantin.s.bobrovsky@intel.com>
I do see the value. This case can and should be diagnosed. Imagine that |
I meant that I don't see value in propagation of attributes to |
OK. The original comment contained objection to the diagnostics. If this really about propagation - I did not invent attributes propagation. BTW, I removed propagating sycl_explicit_simd, as agreed with @DenisBakhvalov |
You invented propagation up to |
As I explained above, SYCL_EXTERNAL deserves similar error checking for attribute compatibility as kernels do and the test that comes with this patch shows the problematic case. If you have another opinion - please provide some justification please. |
Okay, I had some offline discussion with @AlexeySachkov regarding my concerns. It seems we do need some checks for attributes inconsistency, although we don't need attribute propagation. The current code for diagnosing nailed to propagation, so removing of propagation is not really in scope of your change. |
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.
Code is OK, but I'd like @AlexeySachkov to approve first.
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.
Still is ok, @AlexeySachkov please take a look.
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.
Overall, LGTM. Two minor comments
[[cl::intel_reqd_sub_group_size(2)]] void sg_size2() {} | ||
|
||
// expected-note@+2 {{conflicting attribute is here}} | ||
// expected-error@+1 {{conflicting attributes applied to a SYCL kernel}} |
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.
// expected-error@+1 {{conflicting attributes applied to a SYCL kernel}} | |
// expected-error@+1 {{conflicting attributes applied to a SYCL kernel or SYCL_EXTERNAL function}} |
@@ -1460,6 +1460,15 @@ void Sema::MarkDevice(void) { | |||
// it is recursive. | |||
MarkDeviceFunction Marker(*this); | |||
Marker.SYCLCG.addToCallGraph(getASTContext().getTranslationUnitDecl()); | |||
|
|||
// Iterate through SYCL_EXTERNAL functions and add them to the device decls. | |||
for (const auto &entry : *Marker.SYCLCG.getRoot()) { |
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.
IIRC, @Fznamznon pointed out that this won't add class member functions, which are marked as SYCL_EXTERNAL
into list of device functions which needs to be checked.
This is not critical, I guess, but I think deserves double-checking and probably a TODO
, that attribute handling should be improved for class member functions as well
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.
I wasn't sure about it, so I double checked it locally, seems everything is fine with class members, but we could add a corresponding test in next patches.
Fixed an issue with comparing pointers to Attr objects rather than values passed to the attribute in source code. Refactored IntelReqdSubGroupSizeAttr class to store evaluated value of attribute value for further uses to avoid evaluating it each time we need that value to check something. The bug were uncovered after intel#1778 landed, but it had been introduced in intel#1807
Signed-off-by: Arvind Sudarsanam <arvind.sudarsanam@intel.com> Original commit: KhronosGroup/SPIRV-LLVM-Translator@e06e46d
SYCL_EXTERNAL functions are not included into the device declarations
set which is iterated during SYCL attribute propagation and checking.
This leads e.g. to the following code getting silently accepted:
SYCL_EXTERNAL function with reqd_sub_group_size 4 calls a function with reqd_sub_group_size 2. This shoud be an error. Existing implementation detects it only when there is a kernel in place of SYCL_EXTERNAL function
Signed-off-by: Konstantin S Bobrovsky konstantin.s.bobrovsky@intel.com