Skip to content

Commit a2583ec

Browse files
[SYCL][Clang] Implements __sycl_detail__::add_ir_attributes_* attributes (#5535)
These changes introduce three new `__sycl_detail__` attributes: * `add_ir_attributes_function` - Adds IR attributes to a function. This attribute is applied directly to the function. * `add_ir_attributes_kernel_parameter` - Adds IR attributes to a parameter of a kernel function. This attribute can be applied to the paramters of the `__init` in classes with the `__attribute__((sycl_special_class))` and the resulting IR attributes will propagate to the parameters of a kernel function using this class. * `add_ir_attributes_global_variable` - Adds IR attributes to a global variable. This attribute is applied to the definition of the class that is the type of the global variable. The parameter-space of these functions are all as follows: * The first parameter can optionally be an initializer list. This is referred to as the "filter list" and must contain only string literals. These are used for limiting valid IR attributes for a given application of the clang attribute. * The remaining parameter is varidic and will require N*2 arguments, where N is the number of IR attributes to add. The first N arguments must evaluate to a string denoting the name of the IR attribute, whereas the following N are the values of the attribute. The values are paired with the names in the same order as they appear. See https://github.com/intel/llvm/blob/sycl/sycl/doc/CompileTimeProperties.md for more details.
1 parent 5cb6f4d commit a2583ec

28 files changed

+6028
-6
lines changed

clang/include/clang/AST/Attr.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,16 @@
1717
#include "clang/AST/AttrIterator.h"
1818
#include "clang/AST/Decl.h"
1919
#include "clang/AST/Expr.h"
20+
#include "clang/AST/ExprCXX.h"
2021
#include "clang/AST/Type.h"
2122
#include "clang/Basic/AttrKinds.h"
2223
#include "clang/Basic/AttributeCommonInfo.h"
23-
#include "clang/Basic/LangOptions.h"
2424
#include "clang/Basic/LLVM.h"
25+
#include "clang/Basic/LangOptions.h"
2526
#include "clang/Basic/OpenMPKinds.h"
2627
#include "clang/Basic/Sanitizers.h"
2728
#include "clang/Basic/SourceLocation.h"
29+
#include "llvm/ADT/SmallSet.h"
2830
#include "llvm/ADT/StringSwitch.h"
2931
#include "llvm/Support/ErrorHandling.h"
3032
#include "llvm/Support/VersionTuple.h"

clang/include/clang/Basic/Attr.td

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1478,6 +1478,213 @@ def SYCLIntelLoopFuse : InheritableAttr {
14781478
let SupportsNonconformingLambdaSyntax = 1;
14791479
}
14801480

1481+
class SYCLAddIRAttrMemberCodeHolder<code Code> {
1482+
code MemberCode = Code;
1483+
}
1484+
1485+
// Common class for SYCL add_ir_attributes_* attributes.
1486+
def SYCLAddIRAttrCommonMembers : SYCLAddIRAttrMemberCodeHolder<[{
1487+
static Optional<std::string>
1488+
getValidAttributeNameAsString(const Expr *NameE, const ASTContext &Context) {
1489+
if (const auto *NameLiteral = dyn_cast<StringLiteral>(NameE))
1490+
return NameLiteral->getString().str();
1491+
1492+
const auto *NameCE = dyn_cast<ConstantExpr>(NameE);
1493+
if (!NameCE)
1494+
return None;
1495+
1496+
APValue NameLValue;
1497+
if (!NameCE->isCXX11ConstantExpr(Context, &NameLValue))
1498+
NameLValue = NameCE->getAPValueResult();
1499+
1500+
if (!NameLValue.isLValue())
1501+
return None;
1502+
1503+
if (const auto *NameValExpr =
1504+
NameLValue.getLValueBase().dyn_cast<const Expr *>())
1505+
return getValidAttributeNameAsString(NameValExpr, Context);
1506+
1507+
if (const auto *NameValDecl =
1508+
NameLValue.getLValueBase().dyn_cast<const ValueDecl *>()) {
1509+
if (const auto *NameVarDecl = dyn_cast<const VarDecl>(NameValDecl)) {
1510+
return getValidAttributeNameAsString(NameVarDecl->getInit(), Context);
1511+
}
1512+
}
1513+
return None;
1514+
}
1515+
1516+
static Optional<std::string>
1517+
getValidAttributeValueAsString(const APValue &Value,
1518+
const ASTContext &Context,
1519+
QualType ValueQType) {
1520+
assert(!Value.isLValue());
1521+
if (ValueQType->isCharType()) {
1522+
char C = static_cast<char>(Value.getInt().getExtValue());
1523+
return std::string(&C, 1);
1524+
}
1525+
if (ValueQType->isBooleanType())
1526+
return std::string(Value.getInt().getExtValue() ? "true" : "false");
1527+
if (ValueQType->isIntegralOrEnumerationType() ||
1528+
ValueQType->isFloatingType())
1529+
return Value.getAsString(Context, ValueQType);
1530+
return None;
1531+
}
1532+
1533+
static Optional<std::string>
1534+
getValidAttributeValueAsString(const Expr *ValueE,
1535+
const ASTContext &Context) {
1536+
if (ValueE->getType()->isNullPtrType())
1537+
return std::string("");
1538+
if (const auto *StringVal = dyn_cast<StringLiteral>(ValueE))
1539+
return StringVal->getString().str();
1540+
if (const auto *BoolVal = dyn_cast<CXXBoolLiteralExpr>(ValueE))
1541+
return std::string(BoolVal->getValue() ? "true" : "false");
1542+
if (const auto *FloatingVal = dyn_cast<FloatingLiteral>(ValueE))
1543+
return APValue(FloatingVal->getValue())
1544+
.getAsString(Context, ValueE->getType());
1545+
if (const auto *CharacterVal = dyn_cast<CharacterLiteral>(ValueE)) {
1546+
char C = static_cast<char>(CharacterVal->getValue());
1547+
return std::string(&C, 1);
1548+
}
1549+
if (const auto *IntegerVal = dyn_cast<IntegerLiteral>(ValueE)) {
1550+
SmallString<10> IntegerStrBuffer;
1551+
IntegerVal->getValue().toString(IntegerStrBuffer, 10,
1552+
ValueE->getType()->isSignedIntegerType());
1553+
return std::string(IntegerStrBuffer);
1554+
}
1555+
1556+
const auto *ValueCE = dyn_cast<ConstantExpr>(ValueE);
1557+
if (!ValueCE)
1558+
return None;
1559+
1560+
APValue ValueAPV;
1561+
if (!ValueCE->isCXX11ConstantExpr(Context, &ValueAPV))
1562+
ValueAPV = ValueCE->getAPValueResult();
1563+
1564+
if (!ValueAPV.isLValue())
1565+
return getValidAttributeValueAsString(ValueAPV, Context,
1566+
ValueCE->getType());
1567+
1568+
if (ValueAPV.getLValueBase().isNull())
1569+
return std::string("");
1570+
1571+
if (const auto *ValueValExpr =
1572+
ValueAPV.getLValueBase().dyn_cast<const Expr *>())
1573+
return getValidAttributeValueAsString(ValueValExpr, Context);
1574+
1575+
if (const auto *ValueValDecl =
1576+
ValueAPV.getLValueBase().dyn_cast<const ValueDecl *>()) {
1577+
if (const auto *ValueVarDecl = dyn_cast<const VarDecl>(ValueValDecl)) {
1578+
return getValidAttributeValueAsString(ValueVarDecl->getInit(), Context);
1579+
}
1580+
}
1581+
return None;
1582+
}
1583+
1584+
static Optional<llvm::SmallSet<StringRef, 4>> getAttributeFilterFromExprs(
1585+
Expr **AttributeExprs, size_t AttributeExprsSize) {
1586+
if (!AttributeExprsSize)
1587+
return None;
1588+
1589+
const auto *FilterListE = dyn_cast<InitListExpr>(AttributeExprs[0]);
1590+
if (!FilterListE)
1591+
return None;
1592+
1593+
llvm::SmallSet<StringRef, 4> Filter;
1594+
for (const Expr *FilterE : FilterListE->inits()) {
1595+
const auto *FilterStrLit = dyn_cast<StringLiteral>(FilterE);
1596+
assert(FilterStrLit && "Element in filter list is not a string literal.");
1597+
Filter.insert(FilterStrLit->getString());
1598+
}
1599+
return Filter;
1600+
}
1601+
1602+
Optional<llvm::SmallSet<StringRef, 4>> getAttributeFilter() const {
1603+
return getAttributeFilterFromExprs(args_begin(), args_size());
1604+
}
1605+
1606+
bool hasFilterList() const {
1607+
return args_size() && isa<InitListExpr>(*args_begin());
1608+
}
1609+
1610+
SmallVector<std::pair<std::string, std::string>, 4>
1611+
getFilteredAttributeNameValuePairs(
1612+
const Optional<llvm::SmallSet<StringRef, 4>> &AttributeNameFilter,
1613+
const ASTContext &Context) const {
1614+
Expr **AttributeExprs = args_begin() + hasFilterList();
1615+
size_t AttributeExprsSize = args_size() - hasFilterList();
1616+
1617+
assert((AttributeExprsSize & 1) == 0 && "Too few remaining expressions.");
1618+
1619+
SmallVector<std::pair<std::string, std::string>, 4> Attrs;
1620+
for (size_t I = 0; I < AttributeExprsSize / 2; ++I) {
1621+
Optional<std::string> NameStr =
1622+
getValidAttributeNameAsString(AttributeExprs[I], Context);
1623+
assert(NameStr && "Attribute name is not a valid string.");
1624+
1625+
// If attribute name is empty, then skip attribute.
1626+
if (NameStr->empty())
1627+
continue;
1628+
1629+
// If attribute name is not in the filter, we skip it.
1630+
if (AttributeNameFilter && !AttributeNameFilter->contains(*NameStr))
1631+
continue;
1632+
1633+
Optional<std::string> ValueStr = getValidAttributeValueAsString(
1634+
AttributeExprs[I + AttributeExprsSize / 2], Context);
1635+
assert(ValueStr && "Attribute value is not a valid type.");
1636+
1637+
Attrs.push_back(std::make_pair(*NameStr, *ValueStr));
1638+
}
1639+
1640+
return Attrs;
1641+
}
1642+
1643+
SmallVector<std::pair<std::string, std::string>, 4>
1644+
getFilteredAttributeNameValuePairs(const ASTContext &Context) const {
1645+
Optional<llvm::SmallSet<StringRef, 4>> AttributeNameFilter =
1646+
getAttributeFilter();
1647+
return getFilteredAttributeNameValuePairs(AttributeNameFilter, Context);
1648+
}
1649+
1650+
SmallVector<std::pair<std::string, std::string>, 4>
1651+
getAttributeNameValuePairs(const ASTContext &Context) const {
1652+
return getFilteredAttributeNameValuePairs(None, Context);
1653+
}
1654+
}]>;
1655+
1656+
def SYCLAddIRAttributesFunction : InheritableAttr {
1657+
let Spellings = [CXX11<"__sycl_detail__", "add_ir_attributes_function">];
1658+
let Args = [VariadicExprArgument<"Args">];
1659+
let LangOpts = [SYCLIsDevice, SilentlyIgnoreSYCLIsHost];
1660+
let Subjects = SubjectList<[Function], ErrorDiag>;
1661+
let AcceptsExprPack = 1;
1662+
let AdditionalMembers = SYCLAddIRAttrCommonMembers.MemberCode;
1663+
let Documentation = [SYCLAddIRAttributesFunctionDocs];
1664+
}
1665+
1666+
def SYCLAddIRAttributesKernelParameter : InheritableAttr {
1667+
let Spellings = [CXX11<"__sycl_detail__",
1668+
"add_ir_attributes_kernel_parameter">];
1669+
let Args = [VariadicExprArgument<"Args">];
1670+
let LangOpts = [SYCLIsDevice, SilentlyIgnoreSYCLIsHost];
1671+
let Subjects = SubjectList<[ParmVar], ErrorDiag>;
1672+
let AcceptsExprPack = 1;
1673+
let AdditionalMembers = SYCLAddIRAttrCommonMembers.MemberCode;
1674+
let Documentation = [SYCLAddIRAttributesKernelParameterDocs];
1675+
}
1676+
1677+
def SYCLAddIRAttributesGlobalVariable : InheritableAttr {
1678+
let Spellings = [CXX11<"__sycl_detail__",
1679+
"add_ir_attributes_global_variable">];
1680+
let Args = [VariadicExprArgument<"Args">];
1681+
let LangOpts = [SYCLIsDevice, SilentlyIgnoreSYCLIsHost];
1682+
let Subjects = SubjectList<[Record], ErrorDiag>;
1683+
let AcceptsExprPack = 1;
1684+
let AdditionalMembers = SYCLAddIRAttrCommonMembers.MemberCode;
1685+
let Documentation = [SYCLAddIRAttributesGlobalVariableDocs];
1686+
}
1687+
14811688
def C11NoReturn : InheritableAttr {
14821689
let Spellings = [Keyword<"_Noreturn">];
14831690
let Subjects = SubjectList<[Function], ErrorDiag>;

0 commit comments

Comments
 (0)