@@ -3175,31 +3175,113 @@ static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) {
31753175 S.addIntelTripleArgAttr <WorkGroupAttr>(D, AL, XDimExpr, YDimExpr, ZDimExpr);
31763176}
31773177
3178- // Handles work_group_size_hint.
3179- static void handleWorkGroupSizeHint (Sema &S, Decl *D, const ParsedAttr &AL) {
3180- S.CheckDeprecatedSYCLAttributeSpelling (AL);
3178+ // Returns a DupArgResult value; Same means the args have the same value,
3179+ // Different means the args do not have the same value, and Unknown means that
3180+ // the args cannot (yet) be compared.
3181+ enum class DupArgResult { Unknown, Same, Different };
3182+ static DupArgResult AreArgValuesIdentical (const Expr *LHS, const Expr *RHS) {
3183+ // If either operand is still value dependent, we can't test anything.
3184+ const auto *LHSCE = dyn_cast<ConstantExpr>(LHS);
3185+ const auto *RHSCE = dyn_cast<ConstantExpr>(RHS);
3186+ if (!LHSCE || !RHSCE)
3187+ return DupArgResult::Unknown;
3188+
3189+ // Otherwise, test that the values.
3190+ return LHSCE->getResultAsAPSInt () == RHSCE->getResultAsAPSInt ()
3191+ ? DupArgResult::Same
3192+ : DupArgResult::Different;
3193+ }
3194+
3195+ void Sema::AddWorkGroupSizeHintAttr (Decl *D, const AttributeCommonInfo &CI,
3196+ Expr *XDim, Expr *YDim, Expr *ZDim) {
3197+ // Returns nullptr if diagnosing, otherwise returns the original expression
3198+ // or the original expression converted to a constant expression.
3199+ auto CheckAndConvertArg = [&](Expr *E) -> Expr * {
3200+ // We can only check if the expression is not value dependent.
3201+ if (!E->isValueDependent ()) {
3202+ llvm::APSInt ArgVal;
3203+ ExprResult Res = VerifyIntegerConstantExpression (E, &ArgVal);
3204+ if (Res.isInvalid ())
3205+ return nullptr ;
3206+ E = Res.get ();
31813207
3182- uint32_t WGSize[3 ];
3183- for (unsigned i = 0 ; i < AL.getNumArgs (); ++i) {
3184- if (!checkUInt32Argument (S, AL, AL.getArgAsExpr (i), WGSize[i], i,
3185- /* StrictlyUnsigned=*/ true ))
3186- return ;
3208+ // This attribute requires a strictly positive value.
3209+ if (ArgVal <= 0 ) {
3210+ Diag (E->getExprLoc (), diag::err_attribute_requires_positive_integer)
3211+ << CI << /* positive*/ 0 ;
3212+ return nullptr ;
3213+ }
3214+ }
3215+
3216+ return E;
3217+ };
31873218
3188- if (WGSize[i] == 0 ) {
3189- S.Diag (AL.getLoc (), diag::err_attribute_argument_is_zero)
3190- << AL << AL.getArgAsExpr (i)->getSourceRange ();
3219+ // Check all three argument values, and if any are bad, bail out. This will
3220+ // convert the given expressions into constant expressions when possible.
3221+ XDim = CheckAndConvertArg (XDim);
3222+ YDim = CheckAndConvertArg (YDim);
3223+ ZDim = CheckAndConvertArg (ZDim);
3224+ if (!XDim || !YDim || !ZDim)
3225+ return ;
3226+
3227+ // If the attribute was already applied with different arguments, then
3228+ // diagnose the second attribute as a duplicate and don't add it.
3229+ if (const auto *Existing = D->getAttr <WorkGroupSizeHintAttr>()) {
3230+ DupArgResult Results[] = {AreArgValuesIdentical (XDim, Existing->getXDim ()),
3231+ AreArgValuesIdentical (YDim, Existing->getYDim ()),
3232+ AreArgValuesIdentical (ZDim, Existing->getZDim ())};
3233+ // If any of the results are known to be different, we can diagnose at this
3234+ // point and drop the attribute.
3235+ if (llvm::is_contained (Results, DupArgResult::Different)) {
3236+ Diag (CI.getLoc (), diag::warn_duplicate_attribute) << CI;
3237+ Diag (Existing->getLoc (), diag::note_previous_attribute);
31913238 return ;
31923239 }
3240+ // If all of the results are known to be the same, we can silently drop the
3241+ // attribute. Otherwise, we have to add the attribute and resolve its
3242+ // differences later.
3243+ if (llvm::all_of (Results,
3244+ [](DupArgResult V) { return V == DupArgResult::Same; }))
3245+ return ;
31933246 }
31943247
3195- WorkGroupSizeHintAttr *Existing = D->getAttr <WorkGroupSizeHintAttr>();
3196- if (Existing &&
3197- !(Existing->getXDim () == WGSize[0 ] && Existing->getYDim () == WGSize[1 ] &&
3198- Existing->getZDim () == WGSize[2 ]))
3199- S.Diag (AL.getLoc (), diag::warn_duplicate_attribute) << AL;
3248+ D->addAttr (::new (Context)
3249+ WorkGroupSizeHintAttr (Context, CI, XDim, YDim, ZDim));
3250+ }
3251+
3252+ WorkGroupSizeHintAttr *
3253+ Sema::MergeWorkGroupSizeHintAttr (Decl *D, const WorkGroupSizeHintAttr &A) {
3254+ // Check to see if there's a duplicate attribute already applied.
3255+ if (const auto *DeclAttr = D->getAttr <WorkGroupSizeHintAttr>()) {
3256+ DupArgResult Results[] = {
3257+ AreArgValuesIdentical (DeclAttr->getXDim (), A.getXDim ()),
3258+ AreArgValuesIdentical (DeclAttr->getYDim (), A.getYDim ()),
3259+ AreArgValuesIdentical (DeclAttr->getZDim (), A.getZDim ())};
3260+
3261+ // If any of the results are known to be different, we can diagnose at this
3262+ // point and drop the attribute.
3263+ if (llvm::is_contained (Results, DupArgResult::Different)) {
3264+ Diag (DeclAttr->getLoc (), diag::warn_duplicate_attribute) << &A;
3265+ Diag (A.getLoc (), diag::note_previous_attribute);
3266+ return nullptr ;
3267+ }
3268+ // If all of the results are known to be the same, we can silently drop the
3269+ // attribute. Otherwise, we have to add the attribute and resolve its
3270+ // differences later.
3271+ if (llvm::all_of (Results,
3272+ [](DupArgResult V) { return V == DupArgResult::Same; }))
3273+ return nullptr ;
3274+ }
3275+ return ::new (Context)
3276+ WorkGroupSizeHintAttr (Context, A, A.getXDim (), A.getYDim (), A.getZDim ());
3277+ }
3278+
3279+ // Handles work_group_size_hint.
3280+ static void handleWorkGroupSizeHint (Sema &S, Decl *D, const ParsedAttr &AL) {
3281+ S.CheckDeprecatedSYCLAttributeSpelling (AL);
32003282
3201- D-> addAttr (:: new (S. Context ) WorkGroupSizeHintAttr (S. Context , AL, WGSize[ 0 ] ,
3202- WGSize[ 1 ], WGSize[ 2 ] ));
3283+ S. AddWorkGroupSizeHintAttr (D , AL, AL. getArgAsExpr ( 0 ), AL. getArgAsExpr ( 1 ) ,
3284+ AL. getArgAsExpr ( 2 ));
32033285}
32043286
32053287void Sema::AddIntelReqdSubGroupSize (Decl *D, const AttributeCommonInfo &CI,
0 commit comments