-
Notifications
You must be signed in to change notification settings - Fork 787
[SYCL]Emit an error if an array size exceeds SPIR-V intermediate format limitations #2093
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 |
---|---|---|
|
@@ -229,6 +229,21 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, | |
!checkAllowedSYCLInitializer(VD, /*CheckValueDependent =*/true)) | ||
SYCLDiagIfDeviceCode(*Locs.begin(), diag::err_sycl_restrict) | ||
<< Sema::KernelConstStaticVariable; | ||
// Emit an error if a const global array's size exceeds SPIR-V | ||
// intermediate format limitations for SPIRV compatible devices. | ||
Comment on lines
+232
to
+233
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. Why you diagnose only global arrays usage? |
||
else if (IsConst && VD->hasGlobalStorage() && | ||
Context.getTargetInfo().getTriple().isSPIR() && | ||
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. Checking that the target triple is spir-based triple does not guarantee that the target output is SPIR-V. I'm not sure if we use device code output in non-SPIR-V form somewhere, but technically it will be weird if someone will try to emit valid LLVM IR for device code and get an error about something that is not supported in SPIR-V. |
||
!isArrayZeroInitialized(VD, /*CheckValueDependent =*/true)) { | ||
QualType Ty = VD->getType(); | ||
if (const auto *CAType = dyn_cast<ConstantArrayType>(Ty)) { | ||
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. I think you need to use 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. Yep, this could very well be a typedef wrapping the constant array type. |
||
assert(CAType); | ||
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. This assertion is weird. If |
||
const int MaxNumElements = 65535 - 3; | ||
srividya-sundaram marked this conversation as resolved.
Show resolved
Hide resolved
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. I think this line can be removed and you can just check if arrayElements > 65532 below. 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. It should likely be constexpr at least if you're keeping the variable. |
||
int64_t arrayElements = CAType->getSize().getSExtValue(); | ||
if (arrayElements > MaxNumElements) | ||
SYCLDiagIfDeviceCode(*Locs.begin(), | ||
diag::err_array_num_elements_exceeded); | ||
} | ||
} | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2077,6 +2077,21 @@ void Sema::finalizeSYCLDelayedAnalysis(const FunctionDecl *Caller, | |
} | ||
} | ||
|
||
bool Sema::isArrayZeroInitialized(VarDecl *VD, bool CheckValueDependent) { | ||
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. what is the purpose of CheckValueDependent here? It doesn't seem to be used. Additionally, you likely don't need to use it up the call chain either. |
||
assert(getLangOpts().SYCLIsDevice && | ||
"Should only be called during device compilation"); | ||
Comment on lines
+2081
to
+2082
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. I don't see anything SYCL-specific in this function. Should we really restrict it for using by other languages/models? |
||
if (VD->isInvalidDecl() || !VD->hasInit() || !VD->hasGlobalStorage()) | ||
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. Do you need |
||
return false; | ||
APValue *Value = nullptr; | ||
if (VD->getInit() && !VD->getInit()->isValueDependent()) | ||
Value = VD->evaluateValue(); | ||
// zero-initialized arrays do not have any initialized elements. | ||
if (Value && Value->isArray() && Value->hasArrayFiller() && | ||
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. Are these additional checks required to handle the case 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. I think this is overly constrained, yes. If all you care about is whether the array is default initialized (as this seems to be doing?), I believe you can do this without the evaluation. You should be able to just do VD->getAnyInitializer(), which should give you an InitListExpr since this is an array type. Then, you should be able to loop through its 'inits' to validate whether they evaluate to zero. This would also be able to catch the cases where you get int array[6] = {0,0};, which is ALSO zero initialized, but wouldn't be caught here as far as I can tell. 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. All this starts to become quite complex... 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. Typically we don't suppress warnings based on potential optimizations. If something is illegal with NO optimizations, it also stays illegal with O3. That is, the validity of a program should never depend on the optimization settings. 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. I think we agree. But here we try to guess in Sema something that is unsupported by some LLVM back-ends... If I understand the title of th PR, it is not about warning but error. 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.
Are you referring to the if checks as overly constrained here? If yes, then For the case 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.
Except you already know that the type is an array, since it is a ConstantArrayType, right?
From my reading of the code, that WILL diagnose (int array[67000] = {0,0}), since it won't be zero initialized, right? Since you'd return false in that case here. That is distinctly the incorrect behavior.
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.
Right, but since the size(6) is < 65532, the error will not be emitted. 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. Note the example you quoted. I did a larger array to show that your exception here based on zero-initialized is broken. I was using the '6' simply to be different from the element count (and not 0). If : Nor should: DefaultConstructible DC[67000] = {}; There is question whether Should be diagnosed. |
||
Value->getArrayInitializedElts() == 0) | ||
return true; | ||
return false; | ||
} | ||
|
||
bool Sema::checkAllowedSYCLInitializer(VarDecl *VD, bool CheckValueDependent) { | ||
assert(getLangOpts().SYCLIsDevice && | ||
"Should only be called during SYCL compilation"); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// RUN: %clang_cc1 -fsycl -fsycl-is-device -triple spir-unknown -verify -fsyntax-only %s | ||
// RUN: %clang_cc1 -fsycl -fsycl-is-device -triple spir64-unknown -verify -fsyntax-only %s | ||
|
||
const double big[67000] = {1.0, 2.0, 3.0}; | ||
const int zero_init_array[67000] = {}; | ||
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. another good repro is: const int zero_init_array2[67000] = {0,0,0,constexpr_fun_that_returns_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.
We care whether 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. Yeah, you'd have to detect the actual initializers. See: https://godbolt.org/z/Yo5bcx You probably ALSO care about this case: https://godbolt.org/z/v8MKrM Note that the default constructed "S2" is undef, and I'm not particularly sure what differentiates that. For example, a defaulted constructor on the empty type results in it still being 'undef', but an actual constructor will zero-init and call the constructor at global_var_init: https://godbolt.org/z/fvzK97 |
||
|
||
template <typename Name, typename Func> | ||
__attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) { | ||
kernelFunc(); // expected-note {{called by 'kernel_single_task<fake_kernel, (lambda}} | ||
} | ||
|
||
int main() { | ||
double hostResult = big[0]; // no error thrown, since accessing global const arrays with size > 65532 is valid from host code. | ||
kernel_single_task<class fake_kernel>([]() { | ||
int a = zero_init_array[0]; // no error thrown, since accessing zero-initialized arrays with size > 65532 is valid. | ||
double kernelGlobal = big[0]; // expected-error {{Due to SPIR-V intermediate format limitations, constant arrays with number of elements more than 65532 cannot be used in SYCL.You can workaround this limitation by splitting the array into several ones}} | ||
}); | ||
return 0; | ||
} |
Uh oh!
There was an error while loading. Please reload this page.
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 am not too fond of this diagnostic. How about -