Skip to content
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

[SYCL] Emit a warning on constexprs captured in SYCL kernels #2824

Conversation

srividya-sundaram
Copy link
Contributor

@srividya-sundaram srividya-sundaram commented Nov 26, 2020

In some cases Clang FE captures constexprs variables into a lambda. This can cause performance problems in case of SYCL, because

  • All captured variables become a kernel parameter, which shouldn't be the case for constexprs
  • Captured constexpr will not appear as a compile-time constant to the compiler

This patch warns users that a constexpr has been captured as a kernel argument and is not a compile-time constant.
The exact wordings of the warning message is open for wordsmithing.

@srividya-sundaram
Copy link
Contributor Author

srividya-sundaram commented Nov 30, 2020

clang format fails for warning-flags.c, but formatting it results in modifying the file in a weird way and also appends the RUN lines together. Ex: see here

clang/include/clang/Basic/DiagnosticGroups.td Outdated Show resolved Hide resolved
clang/test/SemaSYCL/warn-constexpr-kernel-arg.cpp Outdated Show resolved Hide resolved
clang/test/Misc/warning-flags.c Outdated Show resolved Hide resolved
clang/lib/Sema/SemaSYCL.cpp Outdated Show resolved Hide resolved
clang/include/clang/Basic/DiagnosticGroups.td Outdated Show resolved Hide resolved
clang/include/clang/Basic/DiagnosticSemaKinds.td Outdated Show resolved Hide resolved
clang/test/SemaSYCL/warn-constexpr-kernel-arg.cpp Outdated Show resolved Hide resolved
@srividya-sundaram
Copy link
Contributor Author

@bader The test failures reported are all related to sycl-post-link tool in /localdisk2/sycl_ci/buildbot/worker/sycl-ubu-x64-pr/llvm.src/llvm/test/tools/sycl-post-link/

I verified the tests locally and they all pass. Could you clarify if this a buildbot related issue?
Also, clang-format check has been queued for a long time now.

@Fznamznon
Copy link
Contributor

@bader The test failures reported are all related to sycl-post-link tool in /localdisk2/sycl_ci/buildbot/worker/sycl-ubu-x64-pr/llvm.src/llvm/test/tools/sycl-post-link/

@AlexeySachkov , could you please take a look? Can it be caused by e481174 ?

@AlexeySachkov
Copy link
Contributor

@bader The test failures reported are all related to sycl-post-link tool in /localdisk2/sycl_ci/buildbot/worker/sycl-ubu-x64-pr/llvm.src/llvm/test/tools/sycl-post-link/

@AlexeySachkov , could you please take a look? Can it be caused by e481174 ?

Sure, I will take a look. It seems like pulldown has landed before my PR got merged, but after I had launched pre-commit: there was a change in typed attributes for function arguments, I just need to re-generate LLVM IR for those tests

@AlexeySachkov
Copy link
Contributor

@bader The test failures reported are all related to sycl-post-link tool in /localdisk2/sycl_ci/buildbot/worker/sycl-ubu-x64-pr/llvm.src/llvm/test/tools/sycl-post-link/

@AlexeySachkov , could you please take a look? Can it be caused by e481174 ?

Sure, I will take a look. It seems like pulldown has landed before my PR got merged, but after I had launched pre-commit: there was a change in typed attributes for function arguments, I just need to re-generate LLVM IR for those tests

Should be fixed by #2846

Copy link
Contributor

@elizabethandrews elizabethandrews left a comment

Choose a reason for hiding this comment

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

Thanks!

@srividya-sundaram
Copy link
Contributor Author

@bader This is ready to be merged.

@bader
Copy link
Contributor

bader commented Dec 3, 2020

It sounds like the compiler drops constexpr semantics. Could you clarify why this is not a compiler bug, please?

@srividya-sundaram
Copy link
Contributor Author

srividya-sundaram commented Dec 3, 2020

It sounds like the compiler drops constexpr semantics. Could you clarify why this is not a compiler bug, please?

Compiler captures a constexpr as a kernel argument only when constexpr is ODR-used inside the lambda.
In other cases, it is treated as a compile-time constant as it should be.
Since the compiler captures a constexpr value into the kernel lambda as a parameter only in some special cases (ODR-use of constexpr), this is treated as a warning, instead of an error.
Hope I understood your question correctly.

@premanandrao
Copy link
Contributor

It sounds like the compiler drops constexpr semantics. Could you clarify why this is not a compiler bug, please?

The warning generated is only for implicit captures. Since the address of the constexpr variable is taken, it gets turned into a kernel parameter. Otherwise, it remains constexpr. @erichkeane says that this could potentially be addressed in the library with overloads (and that it would be difficult to do so), but I didn't quite follow that thought.

h.single_task<LambdaKernel>(
[=]() {
// constexpr 'OdrUsedVar' is odr-used here.
const unsigned *ptr = &OdrUsedVar; // expected-warning {{captured constexpr 'OdrUsedVar' will be a kernel argument in device code}}
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't quite get the purpose of this warning.

I think in order to understand this warning message, user must know DPC++ implementation details about lowering lambda object into kernel function and how kernel function parameters are composed. Do you think it's clear for DPC++ users?

Another point it's generic C++ behavior and not SYCL specific issue:

template <typename T>
void foo(T t) {t();}
// ...
foo([=]() { const unsigned *ptr = &OdrUsedVar; }); // OdrUsedVar is captured and might cause performance issues
foo([=]() { unsigned x = 10 + OdrUsedVar; }); // OdrUsedVar is not captured. No performance issues?

Should we emit similar warning for any lambda expression?

It's probably more useful to implement such diagnostics in performance profiler because passing additional argument might be not a problem at all.

@premanandrao, @srividya-sundaram, @erichkeane, what do you think?

Copy link
Contributor Author

@srividya-sundaram srividya-sundaram Dec 4, 2020

Choose a reason for hiding this comment

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

tagging @kbobrovs to give his feedback as well since this was originally brought up by him.

Copy link
Contributor

Choose a reason for hiding this comment

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

One more thing: this diagnostics warns that current implementation is not optimal.
I assume if compiler detects odr-use of constexpr it can allocate a global constant/variable in device code and kernel function object can capture global object and avoid passing it via kernel argument. This seems to be valid implementation. Right?

Copy link
Contributor

Choose a reason for hiding this comment

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

It's probably more useful to implement such diagnostics in performance profiler because passing additional argument might be not a problem at all.

I suspect many people (like myself) writing code similar to

  constexpr int V = 137;

  auto f = [=](Id i) -> int {
    return (i * V).x;
  };

will expect V to be compile-time constant inside the lambda. In some cases this expectation is not true and V is captured and hence is not a compile-time constant. This can potentially lead to performance problems.

I'm not sure what 'performance compiler' is. If it can be built from this github repo - I'm OK with making this feature available only in 'performance compiler'.

Copy link
Contributor

Choose a reason for hiding this comment

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

FWIW, that is a fairly well known property of constexpr: It isn't necessarily a compile time constant unless you make it so in some way. I'm generally not in favor of a warning that tells you that the language is still working the way it is designed, particularly since there isn't a code-way to suppress this warning.

If we had some sort of perf-analysis tool, that would be a good place for that. Have we considered seeing if the Static Analysis effort would be a better place for this?

h.single_task<LambdaKernel>(
[=]() {
// constexpr 'OdrUsedVar' is odr-used here.
const unsigned *ptr = &OdrUsedVar; // expected-warning {{captured constexpr 'OdrUsedVar' will be a kernel argument in device code}}
Copy link
Contributor

Choose a reason for hiding this comment

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

It's probably more useful to implement such diagnostics in performance profiler because passing additional argument might be not a problem at all.

I suspect many people (like myself) writing code similar to

  constexpr int V = 137;

  auto f = [=](Id i) -> int {
    return (i * V).x;
  };

will expect V to be compile-time constant inside the lambda. In some cases this expectation is not true and V is captured and hence is not a compile-time constant. This can potentially lead to performance problems.

I'm not sure what 'performance compiler' is. If it can be built from this github repo - I'm OK with making this feature available only in 'performance compiler'.

@@ -7449,6 +7449,9 @@ let CategoryName = "Lambda Issue" in {
"%select{| explicitly}1 captured here">;
def err_implicit_this_capture : Error<
"implicit capture of 'this' is not allowed for kernel functions">;
def warn_constexpr_kernel_arg : Warning<
"captured constexpr '%0' will be a kernel argument in device code">,
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
"captured constexpr '%0' will be a kernel argument in device code">,
"captured constexpr '%0' will *not* be a compile-time constant in the device code">,

@erichkeane
Copy link
Contributor

I'm not in favor of putting a warning like this into the compiler. Warnings are supposed to be actionable, not informative. If there isn't a code-based way to suppress a warning (and get the behavior you want), they generally aren't put into the compiler.

The issue here is closer to a bug (though not quite?) in the library. We're implementing conversion operators that aren't constexpr, so they cause us to need to use the variable in an ODR way, and thus need to be captured. This is a 'feature' of the language.

IMO, if we want to warn on this, I'd suggest this go into the static analyzer.

@kbobrovs
Copy link
Contributor

kbobrovs commented Dec 7, 2020

Warnings are supposed to be actionable, not informative.

Agree. Possible action is to replace with #define. Or try to figure out the construct causing this (the * operator) and restructure the code (less attractive to a developer).

This is a 'feature' of the language.

I see. But I wonder what share of SYCL developers know C++ well enough to have the right expectation of the result of the code here :) I think such warning would save many people some time and annoy just few experts. But I'll let you FE folks decide what's best here.

@srividya-sundaram
Copy link
Contributor Author

Closing this PR since the above discussion suggests that this change should not be implemented in CFE.

jsji pushed a commit that referenced this pull request Nov 7, 2024
OpAtomicCompareExchangeWeak has been removed and #2665 added a validation for it.
This pull request replaces OpAtomicCompareExchangeWeak with OpAtomicCompareExchange.

Original commit:
KhronosGroup/SPIRV-LLVM-Translator@eb64e4d795006d5
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.

8 participants