@@ -1537,6 +1537,20 @@ void SemaSYCL::addSYCLAddIRAttributesFunctionAttr(
15371537 if (evaluateAddIRAttributesArgs (Attr->args_begin (), Attr->args_size (), *this ,
15381538 CI))
15391539 return ;
1540+
1541+ // There could be multiple of the same attribute applied to the same
1542+ // declaration. If so, we want to merge them.
1543+ // If there are still dependent expressions in the attribute, we delay merging
1544+ // till after instantiation.
1545+ if (!hasDependentExpr (Attr->args_begin (), Attr->args_size ()) &&
1546+ D->hasAttr <SYCLAddIRAttributesFunctionAttr>()) {
1547+ Attr = mergeSYCLAddIRAttributesFunctionAttr (D, *Attr);
1548+
1549+ // If null is returned, the attribute did not change after merge and we can
1550+ // exit.
1551+ if (!Attr)
1552+ return ;
1553+ }
15401554 D->addAttr (Attr);
15411555
15421556 // There are compile-time SYCL properties which we would like to turn into
@@ -1574,6 +1588,20 @@ void SemaSYCL::addSYCLAddIRAttributesKernelParameterAttr(
15741588 if (evaluateAddIRAttributesArgs (Attr->args_begin (), Attr->args_size (), *this ,
15751589 CI))
15761590 return ;
1591+
1592+ // There could be multiple of the same attribute applied to the same argument.
1593+ // If so, we want to merge them.
1594+ // If there are still dependent expressions in the attribute, we delay merging
1595+ // till after instantiation.
1596+ if (!hasDependentExpr (Attr->args_begin (), Attr->args_size ()) &&
1597+ D->hasAttr <SYCLAddIRAttributesKernelParameterAttr>()) {
1598+ Attr = mergeSYCLAddIRAttributesKernelParameterAttr (D, *Attr);
1599+
1600+ // If null is returned, the attribute did not change after merge and we can
1601+ // exit.
1602+ if (!Attr)
1603+ return ;
1604+ }
15771605 D->addAttr (Attr);
15781606}
15791607
@@ -1585,6 +1613,20 @@ void SemaSYCL::addSYCLAddIRAttributesGlobalVariableAttr(
15851613 if (evaluateAddIRAttributesArgs (Attr->args_begin (), Attr->args_size (), *this ,
15861614 CI))
15871615 return ;
1616+
1617+ // There could be multiple of the same attribute applied to the same global
1618+ // variable. If so, we want to merge them.
1619+ // If there are still dependent expressions in the attribute, we delay merging
1620+ // till after instantiation.
1621+ if (!hasDependentExpr (Attr->args_begin (), Attr->args_size ()) &&
1622+ D->hasAttr <SYCLAddIRAttributesGlobalVariableAttr>()) {
1623+ Attr = mergeSYCLAddIRAttributesGlobalVariableAttr (D, *Attr);
1624+
1625+ // If null is returned, the attribute did not change after merge and we can
1626+ // exit.
1627+ if (!Attr)
1628+ return ;
1629+ }
15881630 D->addAttr (Attr);
15891631}
15901632
@@ -2559,43 +2601,98 @@ void SemaSYCL::handleSYCLAddIRAttributesFunctionAttr(Decl *D,
25592601 addSYCLAddIRAttributesFunctionAttr (D, A, Args);
25602602}
25612603
2562- static bool hasSameSYCLAddIRAttributes (
2604+ static bool hasConflictingSYCLAddIRAttributes (
25632605 const SmallVector<std::pair<std::string, std::string>, 4 > &LAttrs,
25642606 const SmallVector<std::pair<std::string, std::string>, 4 > &RAttrs) {
2565- std::set<std::pair<std::string, std::string>> LNameValSet{LAttrs.begin (),
2566- LAttrs.end ()};
2567- std::set<std::pair<std::string, std::string>> RNameValSet{RAttrs.begin (),
2568- RAttrs.end ()};
2569- return LNameValSet == RNameValSet;
2607+ std::unordered_map<std::string, std::string> LNameValMap;
2608+ for (const std::pair<std::string, std::string> &NameValuePair : LAttrs)
2609+ LNameValMap[NameValuePair.first ] = NameValuePair.second ;
2610+
2611+ return std::any_of (
2612+ RAttrs.begin (), RAttrs.end (),
2613+ [&](const std::pair<std::string, std::string> &NameValuePair) {
2614+ auto It = LNameValMap.find (NameValuePair.first );
2615+ return It != LNameValMap.end () && NameValuePair.second != It->second ;
2616+ });
25702617}
25712618
25722619template <typename AddIRAttrT>
25732620static bool checkSYCLAddIRAttributesMergeability (const AddIRAttrT &NewAttr,
25742621 const AddIRAttrT &ExistingAttr,
25752622 SemaSYCL &S) {
25762623 ASTContext &Context = S.getASTContext ();
2577- // If there are no dependent argument expressions and the filters or the
2578- // attributes are different, then fail due to differing duplicates.
2579- if (!S.hasDependentExpr (NewAttr.args_begin (), NewAttr.args_size ()) &&
2580- !S.hasDependentExpr (ExistingAttr.args_begin (),
2581- ExistingAttr.args_size ()) &&
2582- (NewAttr.getAttributeFilter () != ExistingAttr.getAttributeFilter () ||
2583- !hasSameSYCLAddIRAttributes (
2584- NewAttr.getAttributeNameValuePairs (Context),
2585- ExistingAttr.getAttributeNameValuePairs (Context)))) {
2624+
2625+ // If there are dependent argument expressions, then merging cannot be done
2626+ // yet. In that case, it is deferred till after instantiation.
2627+ if (S.hasDependentExpr (NewAttr.args_begin (), NewAttr.args_size ()) ||
2628+ S.hasDependentExpr (ExistingAttr.args_begin (), ExistingAttr.args_size ()))
2629+ return true ;
2630+
2631+ // If the filters differ or the attributes are conflicting, then fail due to
2632+ // differing duplicates.
2633+ if (NewAttr.getAttributeFilter () != ExistingAttr.getAttributeFilter () ||
2634+ hasConflictingSYCLAddIRAttributes (
2635+ NewAttr.getAttributeNameValuePairs (Context),
2636+ ExistingAttr.getAttributeNameValuePairs (Context))) {
25862637 S.Diag (ExistingAttr.getLoc (), diag::err_duplicate_attribute) << &NewAttr;
25872638 S.Diag (NewAttr.getLoc (), diag::note_conflicting_attribute);
25882639 return true ;
25892640 }
25902641 return false ;
25912642}
25922643
2644+ template <typename AddIRAttrT>
2645+ static AddIRAttrT *getMergedSYCLAddIRAttribute (const AddIRAttrT &Attr1,
2646+ const AddIRAttrT &Attr2,
2647+ SemaSYCL &S) {
2648+ ASTContext &Context = S.getASTContext ();
2649+ bool AttrHasFilterList = Attr1.hasFilterList ();
2650+
2651+ // Get the vectors of name-value-pairs here so we can create string references
2652+ // to them for the map.
2653+ llvm::SmallVector<std::pair<std::string, std::string>, 4 > Attr1NVPairs =
2654+ Attr1.getAttributeNameValuePairs (Context);
2655+ llvm::SmallVector<std::pair<std::string, std::string>, 4 > Attr2NVPairs =
2656+ Attr2.getAttributeNameValuePairs (Context);
2657+
2658+ // Collect all the unique attribute names and their corresponding values. This
2659+ // relies on the uniqueness having been confirmed first and that the
2660+ // attributes appear in the same order as in the name-value-pairs.
2661+ llvm::SmallMapVector<StringRef, std::pair<Expr *, Expr *>, 4 > AttrExprByName;
2662+ for (const auto &[Attr, NVPairs] : {std::make_pair (Attr1, Attr1NVPairs),
2663+ std::make_pair (Attr2, Attr2NVPairs)}) {
2664+ for (size_t I = 0 ; I < NVPairs.size (); ++I) {
2665+ AttrExprByName[NVPairs[I].first ] = std::make_pair (
2666+ (Attr.args_begin () + AttrHasFilterList)[I],
2667+ (Attr.args_begin () + AttrHasFilterList + (Attr.args_size () / 2 ))[I]);
2668+ }
2669+ }
2670+
2671+ // Create a list of new arguments, starting with the filter if present.
2672+ llvm::SmallVector<Expr *, 4 > NewArgs;
2673+ NewArgs.resize (AttrExprByName.size () * 2 + AttrHasFilterList);
2674+ if (AttrHasFilterList)
2675+ NewArgs[0 ] = *Attr1.args_begin ();
2676+
2677+ // Then insert all the unique attributes found previously.
2678+ for (size_t I = 0 ; I < AttrExprByName.size (); ++I) {
2679+ const std::pair<Expr *, Expr *> &Exprs = AttrExprByName.begin ()[I].second ;
2680+ NewArgs[I + AttrHasFilterList] = Exprs.first ;
2681+ NewArgs[I + AttrExprByName.size () + AttrHasFilterList] = Exprs.second ;
2682+ }
2683+
2684+ return AddIRAttrT::Create (Context, NewArgs.data (), NewArgs.size (), Attr1);
2685+ }
2686+
25932687SYCLAddIRAttributesFunctionAttr *SemaSYCL::mergeSYCLAddIRAttributesFunctionAttr (
25942688 Decl *D, const SYCLAddIRAttributesFunctionAttr &A) {
25952689 if (const auto *ExistingAttr =
25962690 D->getAttr <SYCLAddIRAttributesFunctionAttr>()) {
2597- checkSYCLAddIRAttributesMergeability (A, *ExistingAttr, *this );
2598- return nullptr ;
2691+ if (checkSYCLAddIRAttributesMergeability (A, *ExistingAttr, *this ))
2692+ return nullptr ;
2693+
2694+ D->dropAttr <SYCLAddIRAttributesFunctionAttr>();
2695+ return getMergedSYCLAddIRAttribute (A, *ExistingAttr, *this );
25992696 }
26002697 ASTContext &Context = getASTContext ();
26012698 return A.clone (Context);
@@ -2618,8 +2715,11 @@ SemaSYCL::mergeSYCLAddIRAttributesKernelParameterAttr(
26182715 Decl *D, const SYCLAddIRAttributesKernelParameterAttr &A) {
26192716 if (const auto *ExistingAttr =
26202717 D->getAttr <SYCLAddIRAttributesKernelParameterAttr>()) {
2621- checkSYCLAddIRAttributesMergeability (A, *ExistingAttr, *this );
2622- return nullptr ;
2718+ if (checkSYCLAddIRAttributesMergeability (A, *ExistingAttr, *this ))
2719+ return nullptr ;
2720+
2721+ D->dropAttr <SYCLAddIRAttributesKernelParameterAttr>();
2722+ return getMergedSYCLAddIRAttribute (A, *ExistingAttr, *this );
26232723 }
26242724 ASTContext &Context = getASTContext ();
26252725 return A.clone (Context);
@@ -2642,8 +2742,11 @@ SemaSYCL::mergeSYCLAddIRAttributesGlobalVariableAttr(
26422742 Decl *D, const SYCLAddIRAttributesGlobalVariableAttr &A) {
26432743 if (const auto *ExistingAttr =
26442744 D->getAttr <SYCLAddIRAttributesGlobalVariableAttr>()) {
2645- checkSYCLAddIRAttributesMergeability (A, *ExistingAttr, *this );
2646- return nullptr ;
2745+ if (checkSYCLAddIRAttributesMergeability (A, *ExistingAttr, *this ))
2746+ return nullptr ;
2747+
2748+ D->dropAttr <SYCLAddIRAttributesGlobalVariableAttr>();
2749+ return getMergedSYCLAddIRAttribute (A, *ExistingAttr, *this );
26472750 }
26482751 ASTContext &Context = getASTContext ();
26492752 return A.clone (Context);
0 commit comments