Skip to content

Commit b288f5d

Browse files
[SYCL][clang] Implement merging of add_ir_attributes_* attributes (#20419)
This commit adds the implementation logic for merging __sycl_detail__::add_ir_attributes_* attributes, which will enable the ability to apply multiple of the same attribute to the same declaration/definition, as long as the values associated to the same names in the attributes do not conflict. This is needed for SYCL free function support as the way SYCL properties are applied are through macros expanding to __sycl_detail__::add_ir_attributes_* with a single name-value-pair. --------- Signed-off-by: Larsen, Steffen <steffen.larsen@intel.com>
1 parent 346ed55 commit b288f5d

File tree

3 files changed

+939
-36
lines changed

3 files changed

+939
-36
lines changed

clang/lib/Sema/SemaSYCLDeclAttr.cpp

Lines changed: 124 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -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

25722619
template <typename AddIRAttrT>
25732620
static 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+
25932687
SYCLAddIRAttributesFunctionAttr *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

Comments
 (0)