Skip to content

[SYCL][FPGA] Refactor [[intel::max_work_group_size()]] attribute implementation #5392

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Feb 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -1406,17 +1406,20 @@ def SYCLIntelMaxWorkGroupSize : InheritableAttr {
let LangOpts = [SYCLIsDevice, SYCLIsHost];
let Subjects = SubjectList<[Function], ErrorDiag>;
let AdditionalMembers = [{
ArrayRef<const Expr *> dimensions() const {
return {getXDim(), getYDim(), getZDim()};
}
Optional<llvm::APSInt> getXDimVal(ASTContext &Ctx) const {
return getXDim()->getIntegerConstantExpr(Ctx);
Optional<llvm::APSInt> getXDimVal() const {
if (const auto *CE = dyn_cast<ConstantExpr>(getXDim()))
return CE->getResultAsAPSInt();
return None;
}
Optional<llvm::APSInt> getYDimVal(ASTContext &Ctx) const {
return getYDim()->getIntegerConstantExpr(Ctx);
Optional<llvm::APSInt> getYDimVal() const {
if (const auto *CE = dyn_cast<ConstantExpr>(getYDim()))
return CE->getResultAsAPSInt();
return None;
}
Optional<llvm::APSInt> getZDimVal(ASTContext &Ctx) const {
return getZDim()->getIntegerConstantExpr(Ctx);
Optional<llvm::APSInt> getZDimVal() const {
if (const auto *CE = dyn_cast<ConstantExpr>(getZDim()))
return CE->getResultAsAPSInt();
return None;
}
}];
let Documentation = [SYCLIntelMaxWorkGroupSizeAttrDocs];
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -10559,6 +10559,11 @@ class Sema final {
const SYCLUsesAspectsAttr &A);
void AddSYCLUsesAspectsAttr(Decl *D, const AttributeCommonInfo &CI,
Expr **Exprs, unsigned Size);
void AddSYCLIntelMaxWorkGroupSizeAttr(Decl *D, const AttributeCommonInfo &CI,
Expr *XDim, Expr *YDim, Expr *ZDim);
SYCLIntelMaxWorkGroupSizeAttr *
MergeSYCLIntelMaxWorkGroupSizeAttr(Decl *D,
const SYCLIntelMaxWorkGroupSizeAttr &A);
/// AddAlignedAttr - Adds an aligned attribute to a particular declaration.
void AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,
bool IsPackExpansion);
Expand Down
26 changes: 9 additions & 17 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -743,24 +743,16 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,

if (const SYCLIntelMaxWorkGroupSizeAttr *A =
FD->getAttr<SYCLIntelMaxWorkGroupSizeAttr>()) {
ASTContext &ClangCtx = FD->getASTContext();
Optional<llvm::APSInt> XDimVal = A->getXDimVal(ClangCtx);
Optional<llvm::APSInt> YDimVal = A->getYDimVal(ClangCtx);
Optional<llvm::APSInt> ZDimVal = A->getZDimVal(ClangCtx);

// For a SYCLDevice SYCLIntelMaxWorkGroupSizeAttr arguments are reversed.
if (getLangOpts().SYCLIsDevice)
std::swap(XDimVal, ZDimVal);

llvm::Metadata *AttrMDArgs[] = {
llvm::ConstantAsMetadata::get(
Builder.getInt32(XDimVal->getZExtValue())),
llvm::ConstantAsMetadata::get(
Builder.getInt32(YDimVal->getZExtValue())),
llvm::ConstantAsMetadata::get(
Builder.getInt32(ZDimVal->getZExtValue()))};
Fn->setMetadata("max_work_group_size",
llvm::MDNode::get(Context, AttrMDArgs));
// Attributes arguments (first and third) are reversed on SYCLDevice.
if (getLangOpts().SYCLIsDevice) {
llvm::Metadata *AttrMDArgs[] = {
llvm::ConstantAsMetadata::get(Builder.getInt(*A->getZDimVal())),
llvm::ConstantAsMetadata::get(Builder.getInt(*A->getYDimVal())),
llvm::ConstantAsMetadata::get(Builder.getInt(*A->getXDimVal()))};
Fn->setMetadata("max_work_group_size",
llvm::MDNode::get(Context, AttrMDArgs));
}
}

if (const auto *A = FD->getAttr<SYCLIntelNoGlobalWorkOffsetAttr>()) {
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2732,6 +2732,8 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
NewAttr = S.MergeSYCLUsesAspectsAttr(D, *A);
else if (const auto *A = dyn_cast<SYCLIntelPipeIOAttr>(Attr))
NewAttr = S.MergeSYCLIntelPipeIOAttr(D, *A);
else if (const auto *A = dyn_cast<SYCLIntelMaxWorkGroupSizeAttr>(Attr))
NewAttr = S.MergeSYCLIntelMaxWorkGroupSizeAttr(D, *A);
else if (Attr->shouldInheritEvenIfAlreadyPresent() || !DeclHasAttr(D, Attr))
NewAttr = cast<InheritableAttr>(Attr->clone(S.Context));

Expand Down Expand Up @@ -3433,8 +3435,6 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,

checkDimensionsAndSetDiagnostics<ReqdWorkGroupSizeAttr>(*this, New, Old);

checkDimensionsAndSetDiagnostics<SYCLIntelMaxWorkGroupSizeAttr>(*this, New,
Old);
if (const auto *ILA = New->getAttr<InternalLinkageAttr>())
if (!Old->hasAttr<InternalLinkageAttr>()) {
Diag(New->getLocation(), diag::err_attribute_missing_on_first_decl)
Expand Down
162 changes: 149 additions & 13 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3205,12 +3205,9 @@ static bool checkWorkGroupSizeValues(Sema &S, Decl *D, const ParsedAttr &AL) {
ASTContext &Ctx = S.getASTContext();

if (const auto *A = D->getAttr<SYCLIntelMaxWorkGroupSizeAttr>()) {
if (!((getExprValue(AL.getArgAsExpr(0), Ctx) <=
getExprValue(A->getXDim(), Ctx)) &&
(getExprValue(AL.getArgAsExpr(1), Ctx) <=
getExprValue(A->getYDim(), Ctx)) &&
(getExprValue(AL.getArgAsExpr(2), Ctx) <=
getExprValue(A->getZDim(), Ctx)))) {
if (!((getExprValue(AL.getArgAsExpr(0), Ctx) <= *A->getXDimVal()) &&
(getExprValue(AL.getArgAsExpr(1), Ctx) <= *A->getYDimVal()) &&
(getExprValue(AL.getArgAsExpr(2), Ctx) <= *A->getZDimVal()))) {
S.Diag(AL.getLoc(), diag::err_conflicting_sycl_function_attributes)
<< AL << A->getSpelling();
Result &= false;
Expand All @@ -3232,19 +3229,18 @@ static bool checkWorkGroupSizeValues(Sema &S, Decl *D, const ParsedAttr &AL) {
return Result;
}

// Handles reqd_work_group_size and max_work_group_size.
// Handles reqd_work_group_size.
template <typename WorkGroupAttr>
static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) {
if (D->isInvalidDecl())
return;

S.CheckDeprecatedSYCLAttributeSpelling(AL);
// __attribute__((reqd_work_group_size)), [[cl::reqd_work_group_size]], and
// [[intel::max_work_group_size]] all require exactly three arguments.
// __attribute__((reqd_work_group_size)) and [[cl::reqd_work_group_size]]
// all require exactly three arguments.
if ((AL.getKind() == ParsedAttr::AT_ReqdWorkGroupSize &&
AL.getAttributeSpellingListIndex() ==
ReqdWorkGroupSizeAttr::CXX11_cl_reqd_work_group_size) ||
AL.getKind() == ParsedAttr::AT_SYCLIntelMaxWorkGroupSize ||
AL.getSyntax() == ParsedAttr::AS_GNU) {
if (!AL.checkExactlyNumArgs(S, 3))
return;
Expand Down Expand Up @@ -3308,8 +3304,8 @@ static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}

// If the declaration has a SYCLIntelMaxWorkGroupSizeAttr or
// ReqdWorkGroupSizeAttr, check to see if they hold equal values
// If the declaration has a ReqdWorkGroupSizeAttr,
// check to see if they hold equal values
// (1, 1, 1) in case the value of SYCLIntelMaxGlobalWorkDimAttr
// equals to 0.
if (const auto *DeclAttr = D->getAttr<SYCLIntelMaxGlobalWorkDimAttr>()) {
Expand Down Expand Up @@ -3454,6 +3450,146 @@ static void handleWorkGroupSizeHint(Sema &S, Decl *D, const ParsedAttr &AL) {
AL.getArgAsExpr(2));
}

// Handles max_work_group_size attribute.
// If the [[intel::max_work_group_size(X, Y, Z)]] attribute is specified on a
// declaration along with [[intel::max_global_work_dim()]] attribute,
// check to see if all arguments of [[intel::max_work_group_size(X, Y, Z)]]
// attribute hold value 1 in case the argument of
// [[intel::max_global_work_dim()]] attribute equals to 0.
static bool InvalidWorkGroupSizeAttrs(const Expr *MGValue, const Expr *XDim,
const Expr *YDim, const Expr *ZDim) {
// If any of the operand is still value dependent, we can't test anything.
const auto *MGValueExpr = dyn_cast<ConstantExpr>(MGValue);
const auto *XDimExpr = dyn_cast<ConstantExpr>(XDim);
const auto *YDimExpr = dyn_cast<ConstantExpr>(YDim);
const auto *ZDimExpr = dyn_cast<ConstantExpr>(ZDim);

if (!MGValueExpr || !XDimExpr || !YDimExpr || !ZDimExpr)
return false;

// Otherwise, check if the attribute values are equal to one.
return (MGValueExpr->getResultAsAPSInt() == 0 &&
(XDimExpr->getResultAsAPSInt() != 1 ||
YDimExpr->getResultAsAPSInt() != 1 ||
ZDimExpr->getResultAsAPSInt() != 1));
}

void Sema::AddSYCLIntelMaxWorkGroupSizeAttr(Decl *D,
const AttributeCommonInfo &CI,
Expr *XDim, Expr *YDim,
Expr *ZDim) {
// Returns nullptr if diagnosing, otherwise returns the original expression
// or the original expression converted to a constant expression.
auto CheckAndConvertArg = [&](Expr *E) -> Expr * {
// Check if the expression is not value dependent.
if (!E->isValueDependent()) {
llvm::APSInt ArgVal;
ExprResult Res = VerifyIntegerConstantExpression(E, &ArgVal);
if (Res.isInvalid())
return nullptr;
E = Res.get();

// This attribute requires a strictly positive value.
if (ArgVal <= 0) {
Diag(E->getExprLoc(), diag::err_attribute_requires_positive_integer)
<< CI << /*positive*/ 0;
return nullptr;
}
}
return E;
};

// Check all three argument values, and if any are bad, bail out. This will
// convert the given expressions into constant expressions when possible.
XDim = CheckAndConvertArg(XDim);
YDim = CheckAndConvertArg(YDim);
ZDim = CheckAndConvertArg(ZDim);
if (!XDim || !YDim || !ZDim)
return;

// If the declaration has a SYCLIntelMaxWorkGroupSizeAttr, check to see if
// the attribute holds equal values to (1, 1, 1) in case the value of
// SYCLIntelMaxGlobalWorkDimAttr equals to 0.
if (const auto *DeclAttr = D->getAttr<SYCLIntelMaxGlobalWorkDimAttr>()) {
if (InvalidWorkGroupSizeAttrs(DeclAttr->getValue(), XDim, YDim, ZDim)) {
Diag(CI.getLoc(), diag::err_sycl_x_y_z_arguments_must_be_one)
<< CI << DeclAttr;
return;
}
}

// If the attribute was already applied with different arguments, then
// diagnose the second attribute as a duplicate and don't add it.
if (const auto *Existing = D->getAttr<SYCLIntelMaxWorkGroupSizeAttr>()) {
DupArgResult Results[] = {AreArgValuesIdentical(XDim, Existing->getXDim()),
AreArgValuesIdentical(YDim, Existing->getYDim()),
AreArgValuesIdentical(ZDim, Existing->getZDim())};
// If any of the results are known to be different, we can diagnose at this
// point and drop the attribute.
if (llvm::is_contained(Results, DupArgResult::Different)) {
Diag(CI.getLoc(), diag::warn_duplicate_attribute) << CI;
Diag(Existing->getLoc(), diag::note_previous_attribute);
return;
}
// If all of the results are known to be the same, we can silently drop the
// attribute. Otherwise, we have to add the attribute and resolve its
// differences later.
if (llvm::all_of(Results,
[](DupArgResult V) { return V == DupArgResult::Same; }))
return;
}

D->addAttr(::new (Context)
SYCLIntelMaxWorkGroupSizeAttr(Context, CI, XDim, YDim, ZDim));
}

SYCLIntelMaxWorkGroupSizeAttr *Sema::MergeSYCLIntelMaxWorkGroupSizeAttr(
Decl *D, const SYCLIntelMaxWorkGroupSizeAttr &A) {
// Check to see if there's a duplicate attribute already applied.
if (const auto *DeclAttr = D->getAttr<SYCLIntelMaxWorkGroupSizeAttr>()) {
DupArgResult Results[] = {
AreArgValuesIdentical(DeclAttr->getXDim(), A.getXDim()),
AreArgValuesIdentical(DeclAttr->getYDim(), A.getYDim()),
AreArgValuesIdentical(DeclAttr->getZDim(), A.getZDim())};

// If any of the results are known to be different, we can diagnose at this
// point and drop the attribute.
if (llvm::is_contained(Results, DupArgResult::Different)) {
Diag(DeclAttr->getLoc(), diag::warn_duplicate_attribute) << &A;
Diag(A.getLoc(), diag::note_previous_attribute);
return nullptr;
}
// If all of the results are known to be the same, we can silently drop the
// attribute. Otherwise, we have to add the attribute and resolve its
// differences later.
if (llvm::all_of(Results,
[](DupArgResult V) { return V == DupArgResult::Same; }))
return nullptr;
}

// If the declaration has a SYCLIntelMaxWorkGroupSizeAttr,
// check to see if the attribute holds equal values to
// (1, 1, 1) in case the value of SYCLIntelMaxGlobalWorkDimAttr
// equals to 0.
if (const auto *DeclAttr = D->getAttr<SYCLIntelMaxGlobalWorkDimAttr>()) {
if (InvalidWorkGroupSizeAttrs(DeclAttr->getValue(), A.getXDim(),
A.getYDim(), A.getZDim())) {
Diag(A.getLoc(), diag::err_sycl_x_y_z_arguments_must_be_one)
<< &A << DeclAttr;
return nullptr;
}
}

return ::new (Context) SYCLIntelMaxWorkGroupSizeAttr(
Context, A, A.getXDim(), A.getYDim(), A.getZDim());
}

static void handleSYCLIntelMaxWorkGroupSize(Sema &S, Decl *D,
const ParsedAttr &AL) {
S.AddSYCLIntelMaxWorkGroupSizeAttr(D, AL, AL.getArgAsExpr(0),
AL.getArgAsExpr(1), AL.getArgAsExpr(2));
}

void Sema::AddIntelReqdSubGroupSize(Decl *D, const AttributeCommonInfo &CI,
Expr *E) {
if (!E->isValueDependent()) {
Expand Down Expand Up @@ -10331,7 +10467,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleWorkGroupSize<ReqdWorkGroupSizeAttr>(S, D, AL);
break;
case ParsedAttr::AT_SYCLIntelMaxWorkGroupSize:
handleWorkGroupSize<SYCLIntelMaxWorkGroupSizeAttr>(S, D, AL);
handleSYCLIntelMaxWorkGroupSize(S, D, AL);
break;
case ParsedAttr::AT_IntelReqdSubGroupSize:
handleIntelReqdSubGroupSize(S, D, AL);
Expand Down
12 changes: 6 additions & 6 deletions clang/lib/Sema/SemaSYCL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3889,9 +3889,9 @@ static void PropagateAndDiagnoseDeviceAttr(
} else if (auto *Existing =
SYCLKernel->getAttr<SYCLIntelMaxWorkGroupSizeAttr>()) {
ASTContext &Ctx = S.getASTContext();
if (Existing->getXDimVal(Ctx) < RWGSA->getXDimVal(Ctx) ||
Existing->getYDimVal(Ctx) < RWGSA->getYDimVal(Ctx) ||
Existing->getZDimVal(Ctx) < RWGSA->getZDimVal(Ctx)) {
if (*Existing->getXDimVal() < RWGSA->getXDimVal(Ctx) ||
*Existing->getYDimVal() < RWGSA->getYDimVal(Ctx) ||
*Existing->getZDimVal() < RWGSA->getZDimVal(Ctx)) {
S.Diag(SYCLKernel->getLocation(),
diag::err_conflicting_sycl_kernel_attributes);
S.Diag(Existing->getLocation(), diag::note_conflicting_attribute);
Expand All @@ -3909,9 +3909,9 @@ static void PropagateAndDiagnoseDeviceAttr(
auto *SIMWGSA = cast<SYCLIntelMaxWorkGroupSizeAttr>(A);
if (auto *Existing = SYCLKernel->getAttr<ReqdWorkGroupSizeAttr>()) {
ASTContext &Ctx = S.getASTContext();
if (Existing->getXDimVal(Ctx) > SIMWGSA->getXDimVal(Ctx) ||
Existing->getYDimVal(Ctx) > SIMWGSA->getYDimVal(Ctx) ||
Existing->getZDimVal(Ctx) > SIMWGSA->getZDimVal(Ctx)) {
if (Existing->getXDimVal(Ctx) > *SIMWGSA->getXDimVal() ||
Existing->getYDimVal(Ctx) > *SIMWGSA->getYDimVal() ||
Existing->getZDimVal(Ctx) > *SIMWGSA->getZDimVal()) {
S.Diag(SYCLKernel->getLocation(),
diag::err_conflicting_sycl_kernel_attributes);
S.Diag(Existing->getLocation(), diag::note_conflicting_attribute);
Expand Down
23 changes: 21 additions & 2 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,25 @@ static void instantiateWorkGroupSizeHintAttr(
ZResult.get());
}

static void instantiateSYCLIntelMaxWorkGroupSizeAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const SYCLIntelMaxWorkGroupSizeAttr *A, Decl *New) {
EnterExpressionEvaluationContext Unevaluated(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult XResult = S.SubstExpr(A->getXDim(), TemplateArgs);
if (XResult.isInvalid())
return;
ExprResult YResult = S.SubstExpr(A->getYDim(), TemplateArgs);
if (YResult.isInvalid())
return;
ExprResult ZResult = S.SubstExpr(A->getZDim(), TemplateArgs);
if (ZResult.isInvalid())
return;

S.AddSYCLIntelMaxWorkGroupSizeAttr(New, *A, XResult.get(), YResult.get(),
ZResult.get());
}

// This doesn't take any template parameters, but we have a custom action that
// needs to happen when the kernel itself is instantiated. We need to run the
// ItaniumMangler to mark the names required to name this kernel.
Expand Down Expand Up @@ -1045,8 +1064,8 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
}
if (const auto *SYCLIntelMaxWorkGroupSize =
dyn_cast<SYCLIntelMaxWorkGroupSizeAttr>(TmplAttr)) {
instantiateIntelSYCTripleLFunctionAttr<SYCLIntelMaxWorkGroupSizeAttr>(
*this, TemplateArgs, SYCLIntelMaxWorkGroupSize, New);
instantiateSYCLIntelMaxWorkGroupSizeAttr(*this, TemplateArgs,
SYCLIntelMaxWorkGroupSize, New);
continue;
}
if (const auto *SYCLIntelMaxConcurrency =
Expand Down
Loading