-
Notifications
You must be signed in to change notification settings - Fork 797
[SYCL] Turn indirectly-callable
property into sycl_device
attribute
#13819
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 | ||
---|---|---|---|---|
|
@@ -1768,6 +1768,30 @@ class SYCLAddIRAttrMemberCodeHolder<code Code> { | |||
|
||||
// Common class for SYCL add_ir_attributes_* attributes. | ||||
def SYCLAddIRAttrCommonMembers : SYCLAddIRAttrMemberCodeHolder<[{ | ||||
static std::optional<std::string> | ||||
getValidAttributeNameAsString(const APValue &Value, | ||||
const ASTContext &Context, | ||||
QualType ValueQType) { | ||||
assert(!Value.isLValue()); | ||||
if (ValueQType->isCharType()) { | ||||
char C = static_cast<char>(Value.getInt().getExtValue()); | ||||
return std::string(&C, 1); | ||||
} | ||||
if (ValueQType->isArrayType() && | ||||
(ValueQType->getArrayElementTypeNoTypeQual()->isCharType())) { | ||||
SmallString<10> StrBuffer; | ||||
for (unsigned I = 0; I < Value.getArrayInitializedElts(); ++I) { | ||||
const APValue &ArrayElem = Value.getArrayInitializedElt(I); | ||||
char C = static_cast<char>(ArrayElem.getInt().getExtValue()); | ||||
smanna12 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
if (C == '\0') | ||||
break; | ||||
StrBuffer += C; | ||||
} | ||||
return std::string(StrBuffer); | ||||
} | ||||
return std::nullopt; | ||||
} | ||||
|
||||
static std::optional<std::string> | ||||
getValidAttributeNameAsString(const Expr *NameE, const ASTContext &Context) { | ||||
if (const auto *NameLiteral = dyn_cast<StringLiteral>(NameE)) | ||||
|
@@ -1782,7 +1806,8 @@ def SYCLAddIRAttrCommonMembers : SYCLAddIRAttrMemberCodeHolder<[{ | |||
NameLValue = NameCE->getAPValueResult(); | ||||
|
||||
if (!NameLValue.isLValue()) | ||||
return std::nullopt; | ||||
return getValidAttributeNameAsString(NameLValue, Context, | ||||
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 for reviewers: this particular change was done to avoid assertion failure due to invalid attribute name (
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'm a little confused. Why did your change cause this and the test mentioned below to break? I understand 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 honestly don't understand that myself. I can do a bit more of a debugging here to see why we see this particular AST and not another. My current guess is that it can be related to evaluation of 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. Ok, I seem to have figured it out. The issue is reproducible even without my changes, it is just hidden by the test without my changes. If you try to compile the following file with plain
Because the test also contains lines that cause compilation errors, we exit early from parsing/handling some of the things and therefore we don't see this assert. With the attribute arguments analysis performed earlier, we always go through that path and any "early exits" due to errors in the code do not help us avoid this issue. |
||||
NameCE->getType()); | ||||
|
||||
if (const auto *NameValExpr = | ||||
NameLValue.getLValueBase().dyn_cast<const Expr *>()) | ||||
|
@@ -1816,10 +1841,10 @@ def SYCLAddIRAttrCommonMembers : SYCLAddIRAttrMemberCodeHolder<[{ | |||
ValueQType->getArrayElementTypeNoTypeQual() | ||||
->isIntegralOrEnumerationType())) { | ||||
SmallString<10> StrBuffer; | ||||
for (unsigned I = 0; I < Value.getArraySize(); ++I) { | ||||
for (unsigned I = 0; I < Value.getArrayInitializedElts(); ++I) { | ||||
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 for reviewers: this particular change was done to avoid assertion failure within
|
||||
const APValue &ArrayElem = Value.getArrayInitializedElt(I); | ||||
char C = static_cast<char>(ArrayElem.getInt().getExtValue()); | ||||
if (C == 0) | ||||
if (C == '\0') | ||||
break; | ||||
StrBuffer += C; | ||||
} | ||||
|
@@ -1859,7 +1884,7 @@ def SYCLAddIRAttrCommonMembers : SYCLAddIRAttrMemberCodeHolder<[{ | |||
SmallString<10> StrBuffer; | ||||
for (const auto *InitE : InitListE->inits()) { | ||||
const Expr *InitNoImpCastE = InitE->IgnoreParenImpCasts(); | ||||
char C = 0; | ||||
char C = '\0'; | ||||
if (const auto *CharacterVal = | ||||
dyn_cast<CharacterLiteral>(InitNoImpCastE)) | ||||
C = static_cast<char>(CharacterVal->getValue()); | ||||
|
@@ -1870,7 +1895,7 @@ def SYCLAddIRAttrCommonMembers : SYCLAddIRAttrMemberCodeHolder<[{ | |||
return std::nullopt; | ||||
|
||||
// Null terminator will end the string reading. | ||||
if (C == 0) | ||||
if (C == '\0') | ||||
break; | ||||
|
||||
StrBuffer += C; | ||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
// RUN: %clang_cc1 -fsycl-is-device -std=gnu++11 -ast-dump %s | FileCheck %s | ||
|
||
// add_ir_attributes_function attribute used to represent compile-time SYCL | ||
// properties and some of those properties are intended to be turned into | ||
// attributes to enable various diagnostics. | ||
// | ||
// This test is intended to check one (and only, at least for now) of such | ||
// tranformations: property with "indirectly-callable" key should have the same | ||
// effect as applying sycl_device attribute and the test checks that we do add | ||
// that attribute implicitly. | ||
|
||
// CHECK-LABEL: ToBeTurnedIntoDeviceFunction 'void ()' | ||
// CHECK: SYCLAddIRAttributesFunctionAttr | ||
// CHECK: SYCLDeviceAttr {{.*}} Implicit | ||
[[__sycl_detail__::add_ir_attributes_function("indirectly-callable", "void")]] | ||
void ToBeTurnedIntoDeviceFunction(); | ||
|
||
// CHECK-LABEL: NotToBeTurnedIntoDeviceFunction 'void ()' | ||
// CHECK-NOT: SYCLDeviceAttr {{.*}} Implicit | ||
// CHECK: SYCLAddIRAttributesFunctionAttr | ||
// CHECK-NOT: SYCLDeviceAttr {{.*}} Implicit | ||
[[__sycl_detail__::add_ir_attributes_function("not-indirectly-callable", "void")]] | ||
void NotToBeTurnedIntoDeviceFunction(); | ||
|
||
template <int V> | ||
struct Metadata { | ||
static constexpr const char *name = "not-indirectly-callable"; | ||
static constexpr const char *value = "void"; | ||
}; | ||
|
||
template <> | ||
struct Metadata<42> { | ||
static constexpr const char *name = "indirectly-callable"; | ||
static constexpr const char *value = "void"; | ||
}; | ||
|
||
// CHECK-LABEL: ToBeTurnedIntoDeviceFunctionAttrTemplateArgs 'void ()' | ||
// CHECK: SYCLAddIRAttributesFunctionAttr | ||
// CHECK: SYCLDeviceAttr {{.*}} Implicit | ||
[[__sycl_detail__::add_ir_attributes_function(Metadata<42>::name, Metadata<42>::value)]] | ||
void ToBeTurnedIntoDeviceFunctionAttrTemplateArgs(); | ||
|
||
// CHECK-LABEL: NotToBeTurnedIntoDeviceFunctionAttrTemplateArgs 'void ()' | ||
// CHECK-NOT: SYCLDeviceAttr {{.*}} Implicit | ||
// CHECK: SYCLAddIRAttributesFunctionAttr | ||
// CHECK-NOT: SYCLDeviceAttr {{.*}} Implicit | ||
[[__sycl_detail__::add_ir_attributes_function(Metadata<1>::name, Metadata<1>::value)]] | ||
void NotToBeTurnedIntoDeviceFunctionAttrTemplateArgs(); | ||
|
||
// CHECK-LABEL: class Base definition | ||
class Base { | ||
// CHECK-LABEL: ToBeTurnedIntoDeviceFunctionAttrTemplateArgs 'void ()' | ||
// CHECK: SYCLAddIRAttributesFunctionAttr | ||
// CHECK: SYCLDeviceAttr {{.*}} Implicit | ||
[[__sycl_detail__::add_ir_attributes_function(Metadata<42>::name, Metadata<42>::value)]] | ||
virtual void ToBeTurnedIntoDeviceFunctionAttrTemplateArgs(); | ||
|
||
// CHECK-LABEL: NotToBeTurnedIntoDeviceFunctionAttrTemplateArgs 'void ()' | ||
// CHECK-NOT: SYCLDeviceAttr {{.*}} Implicit | ||
// CHECK: SYCLAddIRAttributesFunctionAttr | ||
// CHECK-NOT: SYCLDeviceAttr {{.*}} Implicit | ||
[[__sycl_detail__::add_ir_attributes_function(Metadata<1>::name, Metadata<1>::value)]] | ||
virtual void NotToBeTurnedIntoDeviceFunctionAttrTemplateArgs(); | ||
}; | ||
|
||
// CHECK-LABEL: class Derived definition | ||
class Derived : public Base { | ||
// CHECK-LABEL: ToBeTurnedIntoDeviceFunctionAttrTemplateArgs 'void ()' | ||
// CHECK: SYCLAddIRAttributesFunctionAttr | ||
// CHECK: SYCLDeviceAttr {{.*}} Implicit | ||
[[__sycl_detail__::add_ir_attributes_function(Metadata<42>::name, Metadata<42>::value)]] | ||
void ToBeTurnedIntoDeviceFunctionAttrTemplateArgs() override; | ||
|
||
// CHECK-LABEL: NotToBeTurnedIntoDeviceFunctionAttrTemplateArgs 'void ()' | ||
// CHECK-NOT: SYCLDeviceAttr {{.*}} Implicit | ||
// CHECK: SYCLAddIRAttributesFunctionAttr | ||
// CHECK-NOT: SYCLDeviceAttr {{.*}} Implicit | ||
[[__sycl_detail__::add_ir_attributes_function(Metadata<1>::name, Metadata<1>::value)]] | ||
void NotToBeTurnedIntoDeviceFunctionAttrTemplateArgs() override; | ||
}; | ||
|
||
// CHECK-LABEL: class SubDerived definition | ||
class SubDerived : public Derived { | ||
// CHECK-LABEL: ToBeTurnedIntoDeviceFunctionAttrTemplateArgs 'void ()' | ||
// CHECK: SYCLAddIRAttributesFunctionAttr | ||
// CHECK: SYCLDeviceAttr {{.*}} Implicit | ||
[[__sycl_detail__::add_ir_attributes_function(Metadata<2>::name, Metadata<42>::name, Metadata<2>::value, Metadata<42>::value)]] | ||
void ToBeTurnedIntoDeviceFunctionAttrTemplateArgs() override; | ||
|
||
// CHECK-LABEL: NotToBeTurnedIntoDeviceFunctionAttrTemplateArgs 'void ()' | ||
// CHECK-NOT: SYCLDeviceAttr {{.*}} Implicit | ||
// CHECK: SYCLAddIRAttributesFunctionAttr | ||
// CHECK-NOT: SYCLDeviceAttr {{.*}} Implicit | ||
[[__sycl_detail__::add_ir_attributes_function(Metadata<1>::name, Metadata<2>::name, Metadata<1>::value, Metadata<2>::value)]] | ||
void NotToBeTurnedIntoDeviceFunctionAttrTemplateArgs() override; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
// RUN: %clang_cc1 -fsycl-is-device -fcxx-exceptions -triple spir64 \ | ||
// RUN: -aux-triple x86_64-unknown-linux-gnu -Wno-return-type -verify \ | ||
// RUN: -Wno-sycl-2017-compat -fsyntax-only -std=c++17 %s | ||
|
||
// add_ir_attributes_function attribute used to represent compile-time SYCL | ||
// properties and some of those properties are intended to be turned into | ||
// attributes to enable various diagnostics. | ||
// | ||
// "indirectly-callable" property is supposed to be turned into sycl_device | ||
// attribute to make sure that functions market with that property are being | ||
// diagnosed for violating SYCL device code restrictions. | ||
// | ||
// This test ensures that this is indeed the case. | ||
|
||
namespace std { | ||
class type_info; // needed to make typeid compile without corresponding include | ||
} // namespace std | ||
|
||
[[__sycl_detail__::add_ir_attributes_function("indirectly-callable", "void")]] | ||
void cannot_use_recursion() { | ||
// expected-error@+2 {{SYCL kernel cannot call a recursive function}} | ||
// expected-note@-2 {{function implemented using recursion declared here}} | ||
cannot_use_recursion(); | ||
} | ||
|
||
[[__sycl_detail__::add_ir_attributes_function("indirectly-callable", "void")]] | ||
void cannot_allocate_storage() { | ||
new int; // expected-error {{SYCL kernel cannot allocate storage}} | ||
} | ||
|
||
[[__sycl_detail__::add_ir_attributes_function("indirectly-callable", "void")]] | ||
void cannot_use_rtti() { | ||
(void)typeid(int); // expected-error {{SYCL kernel cannot use rtti}} | ||
} | ||
|
||
[[__sycl_detail__::add_ir_attributes_function("indirectly-callable", "void")]] | ||
void cannot_use_zero_length_array() { | ||
// expected-error@+1 {{zero-length arrays are not permitted in SYCL device code}} | ||
int mosterArr[0]; | ||
} | ||
|
||
[[__sycl_detail__::add_ir_attributes_function("indirectly-callable", "void")]] | ||
void cannot_use_long_double() { | ||
// expected-error@+1 {{'long double' is not supported on this target}} | ||
long double terrorLD; | ||
} | ||
|
||
[[__sycl_detail__::add_ir_attributes_function("indirectly-callable", "void")]] | ||
void cannot_use_exceptions() { | ||
try { // expected-error {{SYCL kernel cannot use exceptions}} | ||
; | ||
} catch (...) { | ||
; | ||
} | ||
throw 20; // expected-error {{SYCL kernel cannot use exceptions}} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.