Skip to content

Commit 3c22af9

Browse files
authored
[SYCL] Refactor the way we handle duplicate attribute logic (#3224)
The existing code does not handle things like redeclarations or template instantiations properly. This refactoring changes things to be a bit more like they would be upstream for other attributes. Namely, it splits out an Add method that can be used for template instantiation as well as regular attribute handling, and a Merge method to handle redeclarations. This patch only handles [[intel::reqd_sub_group_size]] and [[intel::num_simd_work_items]] currently. Other attributes will be handled in follow-up work.
1 parent 2ffe840 commit 3c22af9

11 files changed

+213
-64
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1393,7 +1393,7 @@ def IntelReqdSubGroupSize: InheritableAttr {
13931393
let Spellings = [GNU<"intel_reqd_sub_group_size">,
13941394
CXX11<"intel", "reqd_sub_group_size">];
13951395
let Args = [ExprArgument<"Value">];
1396-
let Subjects = SubjectList<[Function, CXXMethod], ErrorDiag>;
1396+
let Subjects = SubjectList<[Function], ErrorDiag>;
13971397
let Documentation = [IntelReqdSubGroupSizeDocs];
13981398
let LangOpts = [OpenCL, SYCLIsDevice, SYCLIsHost];
13991399
}

clang/include/clang/Sema/Sema.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10210,6 +10210,16 @@ class Sema final {
1021010210
template <typename AttrType>
1021110211
void addIntelTripleArgAttr(Decl *D, const AttributeCommonInfo &CI,
1021210212
Expr *XDimExpr, Expr *YDimExpr, Expr *ZDimExpr);
10213+
void AddIntelReqdSubGroupSize(Decl *D, const AttributeCommonInfo &CI,
10214+
Expr *E);
10215+
IntelReqdSubGroupSizeAttr *
10216+
MergeIntelReqdSubGroupSizeAttr(Decl *D, const IntelReqdSubGroupSizeAttr &A);
10217+
void AddSYCLIntelNumSimdWorkItemsAttr(Decl *D, const AttributeCommonInfo &CI,
10218+
Expr *E);
10219+
SYCLIntelNumSimdWorkItemsAttr *
10220+
MergeSYCLIntelNumSimdWorkItemsAttr(Decl *D,
10221+
const SYCLIntelNumSimdWorkItemsAttr &A);
10222+
1021310223
/// AddAlignedAttr - Adds an aligned attribute to a particular declaration.
1021410224
void AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,
1021510225
bool IsPackExpansion);
@@ -13068,16 +13078,14 @@ void Sema::addIntelSingleArgAttr(Decl *D, const AttributeCommonInfo &CI,
1306813078
return;
1306913079
E = ICE.get();
1307013080
int32_t ArgInt = ArgVal.getSExtValue();
13071-
if (CI.getParsedKind() == ParsedAttr::AT_IntelReqdSubGroupSize ||
13072-
CI.getParsedKind() == ParsedAttr::AT_IntelFPGAMaxReplicates) {
13081+
if (CI.getParsedKind() == ParsedAttr::AT_IntelFPGAMaxReplicates) {
1307313082
if (ArgInt <= 0) {
1307413083
Diag(E->getExprLoc(), diag::err_attribute_requires_positive_integer)
1307513084
<< CI << /*positive*/ 0;
1307613085
return;
1307713086
}
1307813087
}
13079-
if (CI.getParsedKind() == ParsedAttr::AT_SYCLIntelMaxGlobalWorkDim ||
13080-
CI.getParsedKind() == ParsedAttr::AT_SYCLIntelNumSimdWorkItems) {
13088+
if (CI.getParsedKind() == ParsedAttr::AT_SYCLIntelMaxGlobalWorkDim) {
1308113089
if (ArgInt < 0) {
1308213090
Diag(E->getExprLoc(), diag::err_attribute_requires_positive_integer)
1308313091
<< CI << /*non-negative*/ 1;

clang/lib/Sema/SemaDecl.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2618,6 +2618,10 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
26182618
NewAttr = S.mergeEnforceTCBAttr(D, *TCBA);
26192619
else if (const auto *TCBLA = dyn_cast<EnforceTCBLeafAttr>(Attr))
26202620
NewAttr = S.mergeEnforceTCBLeafAttr(D, *TCBLA);
2621+
else if (const auto *A = dyn_cast<IntelReqdSubGroupSizeAttr>(Attr))
2622+
NewAttr = S.MergeIntelReqdSubGroupSizeAttr(D, *A);
2623+
else if (const auto *A = dyn_cast<SYCLIntelNumSimdWorkItemsAttr>(Attr))
2624+
NewAttr = S.MergeSYCLIntelNumSimdWorkItemsAttr(D, *A);
26212625
else if (Attr->shouldInheritEvenIfAlreadyPresent() || !DeclHasAttr(D, Attr))
26222626
NewAttr = cast<InheritableAttr>(Attr->clone(S.Context));
26232627

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 123 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3209,65 +3209,148 @@ static void handleWorkGroupSizeHint(Sema &S, Decl *D, const ParsedAttr &AL) {
32093209
WGSize[1], WGSize[2]));
32103210
}
32113211

3212-
// Handles intel_reqd_sub_group_size.
3213-
static void handleSubGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) {
3214-
if (S.LangOpts.SYCLIsHost)
3212+
void Sema::AddIntelReqdSubGroupSize(Decl *D, const AttributeCommonInfo &CI,
3213+
Expr *E) {
3214+
if (LangOpts.SYCLIsHost)
32153215
return;
32163216

3217-
Expr *E = AL.getArgAsExpr(0);
3217+
if (!E->isValueDependent()) {
3218+
// Validate that we have an integer constant expression and then store the
3219+
// converted constant expression into the semantic attribute so that we
3220+
// don't have to evaluate it again later.
3221+
llvm::APSInt ArgVal;
3222+
ExprResult Res = VerifyIntegerConstantExpression(E, &ArgVal);
3223+
if (Res.isInvalid())
3224+
return;
3225+
E = Res.get();
32183226

3219-
if (D->getAttr<IntelReqdSubGroupSizeAttr>())
3220-
S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL;
3227+
// This attribute requires a strictly positive value.
3228+
if (ArgVal <= 0) {
3229+
Diag(E->getExprLoc(), diag::err_attribute_requires_positive_integer)
3230+
<< CI << /*positive*/ 0;
3231+
return;
3232+
}
3233+
3234+
// Check to see if there's a duplicate attribute with different values
3235+
// already applied to the declaration.
3236+
if (const auto *DeclAttr = D->getAttr<IntelReqdSubGroupSizeAttr>()) {
3237+
// If the other attribute argument is instantiation dependent, we won't
3238+
// have converted it to a constant expression yet and thus we test
3239+
// whether this is a null pointer.
3240+
const auto *DeclExpr = dyn_cast<ConstantExpr>(DeclAttr->getValue());
3241+
if (DeclExpr && ArgVal != DeclExpr->getResultAsAPSInt()) {
3242+
Diag(CI.getLoc(), diag::warn_duplicate_attribute) << CI;
3243+
Diag(DeclAttr->getLoc(), diag::note_previous_attribute);
3244+
return;
3245+
}
3246+
}
3247+
}
32213248

3222-
S.addIntelSingleArgAttr<IntelReqdSubGroupSizeAttr>(D, AL, E);
3249+
D->addAttr(::new (Context) IntelReqdSubGroupSizeAttr(Context, CI, E));
32233250
}
32243251

3225-
// Handles num_simd_work_items.
3226-
static void handleNumSimdWorkItemsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
3227-
if (D->isInvalidDecl())
3228-
return;
3252+
IntelReqdSubGroupSizeAttr *
3253+
Sema::MergeIntelReqdSubGroupSizeAttr(Decl *D,
3254+
const IntelReqdSubGroupSizeAttr &A) {
3255+
// Check to see if there's a duplicate attribute with different values
3256+
// already applied to the declaration.
3257+
if (const auto *DeclAttr = D->getAttr<IntelReqdSubGroupSizeAttr>()) {
3258+
const auto *DeclExpr = dyn_cast<ConstantExpr>(DeclAttr->getValue());
3259+
const auto *MergeExpr = dyn_cast<ConstantExpr>(A.getValue());
3260+
if (DeclExpr && MergeExpr &&
3261+
DeclExpr->getResultAsAPSInt() != MergeExpr->getResultAsAPSInt()) {
3262+
Diag(DeclAttr->getLoc(), diag::warn_duplicate_attribute) << &A;
3263+
Diag(A.getLoc(), diag::note_previous_attribute);
3264+
return nullptr;
3265+
}
3266+
}
3267+
return ::new (Context) IntelReqdSubGroupSizeAttr(Context, A, A.getValue());
3268+
}
32293269

3270+
static void handleIntelReqdSubGroupSize(Sema &S, Decl *D,
3271+
const ParsedAttr &AL) {
32303272
Expr *E = AL.getArgAsExpr(0);
3273+
S.AddIntelReqdSubGroupSize(D, AL, E);
3274+
}
32313275

3232-
if (D->getAttr<SYCLIntelNumSimdWorkItemsAttr>())
3233-
S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL;
3234-
3235-
S.CheckDeprecatedSYCLAttributeSpelling(AL);
3236-
3276+
void Sema::AddSYCLIntelNumSimdWorkItemsAttr(Decl *D,
3277+
const AttributeCommonInfo &CI,
3278+
Expr *E) {
32373279
if (!E->isValueDependent()) {
3280+
// Validate that we have an integer constant expression and then store the
3281+
// converted constant expression into the semantic attribute so that we
3282+
// don't have to evaluate it again later.
32383283
llvm::APSInt ArgVal;
3239-
ExprResult ICE = S.VerifyIntegerConstantExpression(E, &ArgVal);
3240-
3241-
if (ICE.isInvalid())
3284+
ExprResult Res = VerifyIntegerConstantExpression(E, &ArgVal);
3285+
if (Res.isInvalid())
32423286
return;
3287+
E = Res.get();
32433288

3244-
E = ICE.get();
3245-
int64_t NumSimdWorkItems = ArgVal.getSExtValue();
3246-
3247-
if (NumSimdWorkItems == 0) {
3248-
S.Diag(E->getExprLoc(), diag::err_attribute_argument_is_zero)
3249-
<< AL << E->getSourceRange();
3289+
// This attribute requires a strictly positive value.
3290+
if (ArgVal <= 0) {
3291+
Diag(E->getExprLoc(), diag::err_attribute_requires_positive_integer)
3292+
<< CI << /*positive*/ 0;
32503293
return;
32513294
}
32523295

3253-
if (const auto *A = D->getAttr<ReqdWorkGroupSizeAttr>()) {
3254-
ASTContext &Ctx = S.getASTContext();
3255-
Optional<llvm::APSInt> XDimVal = A->getXDimVal(Ctx);
3256-
Optional<llvm::APSInt> YDimVal = A->getYDimVal(Ctx);
3257-
Optional<llvm::APSInt> ZDimVal = A->getZDimVal(Ctx);
3258-
3259-
if (!(XDimVal->getZExtValue() % NumSimdWorkItems == 0 ||
3260-
YDimVal->getZExtValue() % NumSimdWorkItems == 0 ||
3261-
ZDimVal->getZExtValue() % NumSimdWorkItems == 0)) {
3262-
S.Diag(AL.getLoc(), diag::err_sycl_num_kernel_wrong_reqd_wg_size)
3263-
<< AL << A;
3264-
S.Diag(A->getLocation(), diag::note_conflicting_attribute);
3296+
// Check to see if there's a duplicate attribute with different values
3297+
// already applied to the declaration.
3298+
if (const auto *DeclAttr = D->getAttr<SYCLIntelNumSimdWorkItemsAttr>()) {
3299+
// If the other attribute argument is instantiation dependent, we won't
3300+
// have converted it to a constant expression yet and thus we test
3301+
// whether this is a null pointer.
3302+
const auto *DeclExpr = dyn_cast<ConstantExpr>(DeclAttr->getValue());
3303+
if (DeclExpr && ArgVal != DeclExpr->getResultAsAPSInt()) {
3304+
Diag(CI.getLoc(), diag::warn_duplicate_attribute) << CI;
3305+
Diag(DeclAttr->getLoc(), diag::note_previous_attribute);
3306+
return;
3307+
}
3308+
}
3309+
3310+
// If the declaration has an [[intel::reqd_work_group_size]] attribute,
3311+
// check to see if can be evenly divided by the num_simd_work_items attr.
3312+
if (const auto *DeclAttr = D->getAttr<ReqdWorkGroupSizeAttr>()) {
3313+
Optional<llvm::APSInt> XDimVal = DeclAttr->getXDimVal(Context);
3314+
Optional<llvm::APSInt> YDimVal = DeclAttr->getYDimVal(Context);
3315+
Optional<llvm::APSInt> ZDimVal = DeclAttr->getZDimVal(Context);
3316+
3317+
if (!(*XDimVal % ArgVal == 0 || *YDimVal % ArgVal == 0 ||
3318+
*ZDimVal % ArgVal == 0)) {
3319+
Diag(CI.getLoc(), diag::err_sycl_num_kernel_wrong_reqd_wg_size)
3320+
<< CI << DeclAttr;
3321+
Diag(DeclAttr->getLocation(), diag::note_conflicting_attribute);
32653322
return;
32663323
}
32673324
}
32683325
}
32693326

3270-
S.addIntelSingleArgAttr<SYCLIntelNumSimdWorkItemsAttr>(D, AL, E);
3327+
D->addAttr(::new (Context) SYCLIntelNumSimdWorkItemsAttr(Context, CI, E));
3328+
}
3329+
3330+
SYCLIntelNumSimdWorkItemsAttr *Sema::MergeSYCLIntelNumSimdWorkItemsAttr(
3331+
Decl *D, const SYCLIntelNumSimdWorkItemsAttr &A) {
3332+
// Check to see if there's a duplicate attribute with different values
3333+
// already applied to the declaration.
3334+
if (const auto *DeclAttr = D->getAttr<SYCLIntelNumSimdWorkItemsAttr>()) {
3335+
const auto *DeclExpr = dyn_cast<ConstantExpr>(DeclAttr->getValue());
3336+
const auto *MergeExpr = dyn_cast<ConstantExpr>(A.getValue());
3337+
if (DeclExpr && MergeExpr &&
3338+
DeclExpr->getResultAsAPSInt() != MergeExpr->getResultAsAPSInt()) {
3339+
Diag(DeclAttr->getLoc(), diag::warn_duplicate_attribute) << &A;
3340+
Diag(A.getLoc(), diag::note_previous_attribute);
3341+
return nullptr;
3342+
}
3343+
}
3344+
return ::new (Context)
3345+
SYCLIntelNumSimdWorkItemsAttr(Context, A, A.getValue());
3346+
}
3347+
3348+
static void handleSYCLIntelNumSimdWorkItemsAttr(Sema &S, Decl *D,
3349+
const ParsedAttr &A) {
3350+
S.CheckDeprecatedSYCLAttributeSpelling(A);
3351+
3352+
Expr *E = A.getArgAsExpr(0);
3353+
S.AddSYCLIntelNumSimdWorkItemsAttr(D, A, E);
32713354
}
32723355

32733356
// Handles use_stall_enable_clusters
@@ -8848,10 +8931,10 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
88488931
handleWorkGroupSize<SYCLIntelMaxWorkGroupSizeAttr>(S, D, AL);
88498932
break;
88508933
case ParsedAttr::AT_IntelReqdSubGroupSize:
8851-
handleSubGroupSize(S, D, AL);
8934+
handleIntelReqdSubGroupSize(S, D, AL);
88528935
break;
88538936
case ParsedAttr::AT_SYCLIntelNumSimdWorkItems:
8854-
handleNumSimdWorkItemsAttr(S, D, AL);
8937+
handleSYCLIntelNumSimdWorkItemsAttr(S, D, AL);
88558938
break;
88568939
case ParsedAttr::AT_SYCLIntelSchedulerTargetFmaxMhz:
88578940
handleSchedulerTargetFmaxMhzAttr(S, D, AL);

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,26 @@ static void instantiateSYCLIntelLoopFuseAttr(
643643
S.addSYCLIntelLoopFuseAttr(New, *Attr, Result.getAs<Expr>());
644644
}
645645

646+
static void instantiateIntelReqdSubGroupSize(
647+
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
648+
const IntelReqdSubGroupSizeAttr *A, Decl *New) {
649+
EnterExpressionEvaluationContext Unevaluated(
650+
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
651+
ExprResult Result = S.SubstExpr(A->getValue(), TemplateArgs);
652+
if (!Result.isInvalid())
653+
S.AddIntelReqdSubGroupSize(New, *A, Result.getAs<Expr>());
654+
}
655+
656+
static void instantiateSYCLIntelNumSimdWorkItemsAttr(
657+
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
658+
const SYCLIntelNumSimdWorkItemsAttr *A, Decl *New) {
659+
EnterExpressionEvaluationContext Unevaluated(
660+
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
661+
ExprResult Result = S.SubstExpr(A->getValue(), TemplateArgs);
662+
if (!Result.isInvalid())
663+
S.AddSYCLIntelNumSimdWorkItemsAttr(New, *A, Result.getAs<Expr>());
664+
}
665+
646666
template <typename AttrName>
647667
static void instantiateIntelSYCLFunctionAttr(
648668
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
@@ -834,14 +854,14 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
834854
}
835855
if (const auto *IntelReqdSubGroupSize =
836856
dyn_cast<IntelReqdSubGroupSizeAttr>(TmplAttr)) {
837-
instantiateIntelSYCLFunctionAttr<IntelReqdSubGroupSizeAttr>(
838-
*this, TemplateArgs, IntelReqdSubGroupSize, New);
857+
instantiateIntelReqdSubGroupSize(*this, TemplateArgs,
858+
IntelReqdSubGroupSize, New);
839859
continue;
840860
}
841861
if (const auto *SYCLIntelNumSimdWorkItems =
842862
dyn_cast<SYCLIntelNumSimdWorkItemsAttr>(TmplAttr)) {
843-
instantiateIntelSYCLFunctionAttr<SYCLIntelNumSimdWorkItemsAttr>(
844-
*this, TemplateArgs, SYCLIntelNumSimdWorkItems, New);
863+
instantiateSYCLIntelNumSimdWorkItemsAttr(*this, TemplateArgs,
864+
SYCLIntelNumSimdWorkItems, New);
845865
continue;
846866
}
847867
if (const auto *SYCLIntelSchedulerTargetFmaxMhz =

clang/test/Misc/pragma-attribute-supported-attributes-list.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
// CHECK-NEXT: IBAction (SubjectMatchRule_objc_method_is_instance)
7272
// CHECK-NEXT: IFunc (SubjectMatchRule_function)
7373
// CHECK-NEXT: InitPriority (SubjectMatchRule_variable)
74-
// CHECK-NEXT: IntelReqdSubGroupSize (SubjectMatchRule_function, SubjectMatchRule_function_is_member)
74+
// CHECK-NEXT: IntelReqdSubGroupSize (SubjectMatchRule_function)
7575
// CHECK-NEXT: InternalLinkage (SubjectMatchRule_variable, SubjectMatchRule_function, SubjectMatchRule_record)
7676
// CHECK-NEXT: LTOVisibilityPublic (SubjectMatchRule_record)
7777
// CHECK-NEXT: Leaf (SubjectMatchRule_function)

clang/test/SemaOpenCL/invalid-kernel-attrs.cl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ kernel __attribute__((intel_reqd_sub_group_size(0))) void kernel15() {} // expec
3939

4040
kernel __attribute__((intel_reqd_sub_group_size(-1))) void kernel16() {} // expected-error {{'intel_reqd_sub_group_size' attribute requires a positive integral compile time constant expression}}
4141

42-
kernel __attribute__((intel_reqd_sub_group_size(8))) __attribute__((intel_reqd_sub_group_size(16))) void kernel17() {} //expected-warning{{attribute 'intel_reqd_sub_group_size' is already applied with different parameters}}
42+
kernel __attribute__((intel_reqd_sub_group_size(8))) __attribute__((intel_reqd_sub_group_size(16))) void kernel17() {} //expected-warning{{attribute 'intel_reqd_sub_group_size' is already applied with different parameters}} \
43+
// expected-note {{previous attribute is here}}
4344

4445
__kernel __attribute__((work_group_size_hint(8,-16,32))) void neg1() {} //expected-error{{'work_group_size_hint' attribute requires a non-negative integral compile time constant expression}}
4546
__kernel __attribute__((reqd_work_group_size(8, 16, -32))) void neg2() {} //expected-warning{{implicit conversion changes signedness: 'int' to 'unsigned long long'}}

0 commit comments

Comments
 (0)