Skip to content

[SYCL] Refactor of FPGA loop fusion function attributes #3298

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 6 commits into from
Mar 7, 2021
Merged
Show file tree
Hide file tree
Changes from 3 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
8 changes: 4 additions & 4 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -3471,8 +3471,6 @@ class Sema final {
EnforceTCBLeafAttr *mergeEnforceTCBLeafAttr(Decl *D,
const EnforceTCBLeafAttr &AL);

SYCLIntelLoopFuseAttr *
mergeSYCLIntelLoopFuseAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E);
void mergeDeclAttributes(NamedDecl *New, Decl *Old,
AvailabilityMergeKind AMK = AMK_Redeclaration);
void MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New,
Expand Down Expand Up @@ -10232,6 +10230,10 @@ class Sema final {
Expr *E);
SYCLIntelNoGlobalWorkOffsetAttr *MergeSYCLIntelNoGlobalWorkOffsetAttr(
Decl *D, const SYCLIntelNoGlobalWorkOffsetAttr &A);
void AddSYCLIntelLoopFuseAttr(Decl *D, const AttributeCommonInfo &CI,
Expr *E);
SYCLIntelLoopFuseAttr *
MergeSYCLIntelLoopFuseAttr(Decl *D, const SYCLIntelLoopFuseAttr &A);

/// AddAlignedAttr - Adds an aligned attribute to a particular declaration.
void AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,
Expand Down Expand Up @@ -10286,8 +10288,6 @@ class Sema final {
/// addSYCLIntelPipeIOAttr - Adds a pipe I/O attribute to a particular
/// declaration.
void addSYCLIntelPipeIOAttr(Decl *D, const AttributeCommonInfo &CI, Expr *ID);
void addSYCLIntelLoopFuseAttr(Decl *D, const AttributeCommonInfo &CI,
Expr *E);

bool checkNSReturnsRetainedReturnType(SourceLocation loc, QualType type);
bool checkAllowedSYCLInitializer(VarDecl *VD,
Expand Down
9 changes: 6 additions & 3 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -983,10 +983,13 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,

if (getLangOpts().SYCLIsDevice && D) {
if (const auto *A = D->getAttr<SYCLIntelLoopFuseAttr>()) {
Expr *E = A->getValue();
const Expr *Arg = A->getValue();
const auto *CE = cast<ConstantExpr>(Arg);
assert(CE && "Not an integer constant expression");
Optional<llvm::APSInt> ArgVal = CE->getResultAsAPSInt();
llvm::Metadata *AttrMDArgs[] = {
llvm::ConstantAsMetadata::get(Builder.getInt32(
E->getIntegerConstantExpr(D->getASTContext())->getZExtValue())),
llvm::ConstantAsMetadata::get(
Builder.getInt32(ArgVal->getZExtValue())),
llvm::ConstantAsMetadata::get(
A->isIndependent() ? Builder.getInt32(1) : Builder.getInt32(0))};
Fn->setMetadata("loop_fuse",
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 @@ -2612,8 +2612,8 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
NewAttr = S.mergeImportModuleAttr(D, *IMA);
else if (const auto *INA = dyn_cast<WebAssemblyImportNameAttr>(Attr))
NewAttr = S.mergeImportNameAttr(D, *INA);
else if (const auto *LFA = dyn_cast<SYCLIntelLoopFuseAttr>(Attr))
NewAttr = S.mergeSYCLIntelLoopFuseAttr(D, *LFA, LFA->getValue());
else if (const auto *A = dyn_cast<SYCLIntelLoopFuseAttr>(Attr))
NewAttr = S.MergeSYCLIntelLoopFuseAttr(D, *A);
else if (const auto *TCBA = dyn_cast<EnforceTCBAttr>(Attr))
NewAttr = S.mergeEnforceTCBAttr(D, *TCBA);
else if (const auto *TCBLA = dyn_cast<EnforceTCBLeafAttr>(Attr))
Expand Down
142 changes: 74 additions & 68 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3453,87 +3453,93 @@ static void handleMaxGlobalWorkDimAttr(Sema &S, Decl *D, const ParsedAttr &A) {
S.addIntelSingleArgAttr<SYCLIntelMaxGlobalWorkDimAttr>(D, A, E);
}

SYCLIntelLoopFuseAttr *
Sema::mergeSYCLIntelLoopFuseAttr(Decl *D, const AttributeCommonInfo &CI,
Expr *E) {
// Handles [[intel::loop_fuse]] and [[intel::loop_fuse_independent]].
void Sema::AddSYCLIntelLoopFuseAttr(Decl *D, const AttributeCommonInfo &CI,
Expr *E) {
if (!E->isValueDependent()) {
// Validate that we have an integer constant expression and then store the
// converted constant expression into the semantic attribute so that we
// don't have to evaluate it again later.
llvm::APSInt ArgVal;
ExprResult Res = VerifyIntegerConstantExpression(E, &ArgVal);
if (Res.isInvalid())
return;
E = Res.get();

if (const auto ExistingAttr = D->getAttr<SYCLIntelLoopFuseAttr>()) {
// This attribute requires a non-negative value.
if (ArgVal < 0) {
Diag(E->getExprLoc(), diag::err_attribute_requires_positive_integer)
<< CI << /*non-negative*/ 1;
return;
}
// Check to see if there's a duplicate attribute with different values
// already applied to the declaration.
if (const auto *DeclAttr = D->getAttr<SYCLIntelLoopFuseAttr>()) {
// If the other attribute argument is instantiation dependent, we won't
// have converted it to a constant expression yet and thus we test
// whether this is a null pointer.
const auto *DeclExpr = dyn_cast<ConstantExpr>(DeclAttr->getValue());
if (DeclExpr && ArgVal != DeclExpr->getResultAsAPSInt()) {
Diag(CI.getLoc(), diag::warn_duplicate_attribute) << CI;
Diag(DeclAttr->getLoc(), diag::note_previous_attribute);
return;
}
// [[intel::loop_fuse]] and [[intel::loop_fuse_independent]] are
// incompatible.
// FIXME: If additional spellings are provided for this attribute,
// this code will do the wrong thing.
if (DeclAttr->getAttributeSpellingListIndex() !=
CI.getAttributeSpellingListIndex()) {
Diag(CI.getLoc(), diag::err_attributes_are_not_compatible)
<< CI << DeclAttr;
Diag(DeclAttr->getLocation(), diag::note_conflicting_attribute);
return;
}
}
}

D->addAttr(::new (Context) SYCLIntelLoopFuseAttr(Context, CI, E));
}

SYCLIntelLoopFuseAttr *
Sema::MergeSYCLIntelLoopFuseAttr(Decl *D, const SYCLIntelLoopFuseAttr &A) {
// Check to see if there's a duplicate attribute with different values
// already applied to the declaration.
if (const auto *DeclAttr = D->getAttr<SYCLIntelLoopFuseAttr>()) {
const auto *DeclExpr = dyn_cast<ConstantExpr>(DeclAttr->getValue());
const auto *MergeExpr = dyn_cast<ConstantExpr>(A.getValue());
if (DeclExpr && MergeExpr &&
DeclExpr->getResultAsAPSInt() != MergeExpr->getResultAsAPSInt()) {
Diag(DeclAttr->getLoc(), diag::warn_duplicate_attribute) << &A;
Diag(A.getLoc(), diag::note_previous_attribute);
return nullptr;
}
// [[intel::loop_fuse]] and [[intel::loop_fuse_independent]] are
// incompatible.
// FIXME: If additional spellings are provided for this attribute,
// this code will do the wrong thing.
if (ExistingAttr->getAttributeSpellingListIndex() !=
CI.getAttributeSpellingListIndex()) {
Diag(CI.getLoc(), diag::err_attributes_are_not_compatible)
<< CI << ExistingAttr;
Diag(ExistingAttr->getLocation(), diag::note_conflicting_attribute);
if (DeclAttr->getAttributeSpellingListIndex() !=
A.getAttributeSpellingListIndex()) {
Diag(A.getLoc(), diag::err_attributes_are_not_compatible)
<< &A << DeclAttr;
Diag(DeclAttr->getLoc(), diag::note_conflicting_attribute);
return nullptr;
}

if (!E->isValueDependent()) {
Optional<llvm::APSInt> ArgVal = E->getIntegerConstantExpr(Context);
Optional<llvm::APSInt> ExistingArgVal =
ExistingAttr->getValue()->getIntegerConstantExpr(Context);

assert(ArgVal && ExistingArgVal &&
"Argument should be an integer constant expression");
// Compare attribute argument value and warn if there is a mismatch.
if (ArgVal->getExtValue() != ExistingArgVal->getExtValue())
Diag(ExistingAttr->getLoc(), diag::warn_duplicate_attribute)
<< ExistingAttr;
}

// If there is no mismatch, silently ignore duplicate attribute.
return nullptr;
}
return ::new (Context) SYCLIntelLoopFuseAttr(Context, CI, E);
}

static bool checkSYCLIntelLoopFuseArgument(Sema &S,
const AttributeCommonInfo &CI,
Expr *E) {
// Dependent expressions are checked when instantiated.
if (E->isValueDependent())
return false;

Optional<llvm::APSInt> ArgVal = E->getIntegerConstantExpr(S.Context);
if (!ArgVal) {
S.Diag(E->getExprLoc(), diag::err_attribute_argument_type)
<< CI << AANT_ArgumentIntegerConstant << E->getSourceRange();
return true;
}

if (!ArgVal->isNonNegative()) {
S.Diag(E->getExprLoc(), diag::err_attribute_requires_positive_integer)
<< CI << /*non-negative*/ 1;
return true;
}

return false;
return ::new (Context) SYCLIntelLoopFuseAttr(Context, A, A.getValue());
}

void Sema::addSYCLIntelLoopFuseAttr(Decl *D, const AttributeCommonInfo &CI,
Expr *E) {
assert(E && "argument has unexpected null value");

if (checkSYCLIntelLoopFuseArgument(*this, CI, E))
return;

SYCLIntelLoopFuseAttr *NewAttr = mergeSYCLIntelLoopFuseAttr(D, CI, E);

if (NewAttr)
D->addAttr(NewAttr);
}
static void handleSYCLIntelLoopFuseAttr(Sema &S, Decl *D, const ParsedAttr &A) {
S.CheckDeprecatedSYCLAttributeSpelling(A);

// Handles [[intel::loop_fuse]] and [[intel::loop_fuse_independent]].
static void handleLoopFuseAttr(Sema &S, Decl *D, const ParsedAttr &Attr) {
// Default argument value is set to 1.
Expr *E = Attr.isArgExpr(0)
? Attr.getArgAsExpr(0)
// If no attribute argument is specified, set to default value '1'.
Expr *E = A.isArgExpr(0)
? A.getArgAsExpr(0)
: IntegerLiteral::Create(S.Context, llvm::APInt(32, 1),
S.Context.IntTy, Attr.getLoc());
S.Context.IntTy, A.getLoc());

S.addSYCLIntelLoopFuseAttr(D, Attr, E);
S.AddSYCLIntelLoopFuseAttr(D, A, E);
}

static void handleVecTypeHint(Sema &S, Decl *D, const ParsedAttr &AL) {
Expand Down Expand Up @@ -9136,7 +9142,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleUseStallEnableClustersAttr(S, D, AL);
break;
case ParsedAttr::AT_SYCLIntelLoopFuse:
handleLoopFuseAttr(S, D, AL);
handleSYCLIntelLoopFuseAttr(S, D, AL);
break;
case ParsedAttr::AT_VecTypeHint:
handleVecTypeHint(S, D, AL);
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,7 @@ static void instantiateSYCLIntelLoopFuseAttr(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult Result = S.SubstExpr(Attr->getValue(), TemplateArgs);
if (!Result.isInvalid())
S.addSYCLIntelLoopFuseAttr(New, *Attr, Result.getAs<Expr>());
S.AddSYCLIntelLoopFuseAttr(New, *Attr, Result.getAs<Expr>());
}

static void instantiateIntelReqdSubGroupSize(
Expand Down
38 changes: 31 additions & 7 deletions clang/test/SemaSYCL/loop_fusion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[[intel::loop_fuse(5)]] int a; // expected-error{{'loop_fuse' attribute only applies to functions}}

[[intel::loop_fuse("foo")]] void func() {} // expected-error{{'loop_fuse' attribute requires an integer constant}}
[[intel::loop_fuse("foo")]] void func() {} // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'const char [4]'}}

[[intel::loop_fuse(1048577)]] void func1() {} // OK
[[intel::loop_fuse_independent(-1)]] void func2() {} // expected-error{{'loop_fuse_independent' attribute requires a non-negative integral compile time constant expression}}
Expand All @@ -14,19 +14,22 @@
[[intel::loop_fuse]] [[intel::loop_fuse]] void func5() {}
[[intel::loop_fuse_independent(10)]] [[intel::loop_fuse_independent(10)]] void func6() {}

[[intel::loop_fuse]] [[intel::loop_fuse(10)]] void func7() {} // expected-warning {{attribute 'loop_fuse' is already applied with different arguments}}
[[intel::loop_fuse_independent(5)]] [[intel::loop_fuse_independent(10)]] void func8() {} // expected-warning {{attribute 'loop_fuse_independent' is already applied with different arguments}}
[[intel::loop_fuse]] // expected-note {{previous attribute is here}}
[[intel::loop_fuse(10)]] void func7() {} // expected-warning {{attribute 'loop_fuse' is already applied with different arguments}}

[[intel::loop_fuse_independent(5)]] // expected-note {{previous attribute is here}}
[[intel::loop_fuse_independent(10)]] void func8() {} // expected-warning {{attribute 'loop_fuse_independent' is already applied with different arguments}}

[[intel::loop_fuse]] void func9();
[[intel::loop_fuse]] void func9();

[[intel::loop_fuse_independent(10)]] void func10();
[[intel::loop_fuse_independent(10)]] void func10();

[[intel::loop_fuse(1)]] void func11();
[[intel::loop_fuse(1)]] void func11(); // expected-note {{previous attribute is here}}
[[intel::loop_fuse(3)]] void func11(); // expected-warning {{attribute 'loop_fuse' is already applied with different arguments}}

[[intel::loop_fuse_independent(1)]] void func12();
[[intel::loop_fuse_independent(1)]] void func12(); // expected-note {{previous attribute is here}}
[[intel::loop_fuse_independent(3)]] void func12(); // expected-warning {{attribute 'loop_fuse_independent' is already applied with different arguments}}

// expected-error@+2 {{'loop_fuse_independent' and 'loop_fuse' attributes are not compatible}}
Expand All @@ -51,13 +54,34 @@ template <int N>
[[intel::loop_fuse(N)]] void func17(); // expected-error{{'loop_fuse' attribute requires a non-negative integral compile time constant expression}}

template <typename Ty>
[[intel::loop_fuse(Ty{})]] void func18() {} // expected-error{{'loop_fuse' attribute requires an integer constant}}
[[intel::loop_fuse(Ty{})]] void func18() {} // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'float'}}

template <int size>
[[intel::loop_fuse(12)]] void func19(); // expected-note {{previous attribute is here}}
template <int size>
[[intel::loop_fuse(size)]] void func19() {} // expected-warning {{attribute 'loop_fuse' is already applied with different arguments}}

template <int size>
[[intel::loop_fuse_independent(5)]] void func20(); // expected-note {{previous attribute is here}}
template <int size>
[[intel::loop_fuse_independent(size)]] void func20() {} // expected-warning {{attribute 'loop_fuse_independent' is already applied with different arguments}}

void checkTemplates() {
func17<-1>(); // expected-note{{in instantiation of}}
func17<0>(); // OK
func18<float>(); // expected-note{{in instantiation of}}
func19<20>(); //expected-note {{in instantiation of function template specialization 'func19<20>' requested here}}
func20<14>(); //expected-note {{in instantiation of function template specialization 'func20<14>' requested here}}
}

// expected-note@+3 {{declared here}}
// expected-note@+3 {{non-constexpr function 'baz' cannot be used in a constant expression}}
// expected-error@+2 {{expression is not an integral constant expression}}
int baz();
[[intel::loop_fuse(baz())]] void func19(); // expected-error{{'loop_fuse' attribute requires an integer constant}}
[[intel::loop_fuse(baz())]] void func21();

[[intel::loop_fuse_independent]]
[[intel::loop_fuse_independent]] void func22() {} //OK

[[intel::loop_fuse_independent]] // expected-note {{previous attribute is here}}
[[intel::loop_fuse_independent(10)]] void func23() {} // expected-warning {{attribute 'loop_fuse_independent' is already applied with different arguments}}
16 changes: 16 additions & 0 deletions clang/test/SemaSYCL/loop_fusion_ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,32 @@ queue q;
// CHECK: FunctionDecl {{.*}} func1 'void ()'
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: SYCLIntelLoopFuseAttr {{.*}} loop_fuse
// CHECK-NEXT: ConstantExpr{{.*}}'int'
// CHECK-NEXT: value: Int 1
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1
[[intel::loop_fuse]] void func1() {}

// CHECK: FunctionDecl {{.*}} func2 'void ()'
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: SYCLIntelLoopFuseAttr {{.*}} loop_fuse
// CHECK-NEXT: ConstantExpr{{.*}}'int'
// CHECK-NEXT: value: Int 0
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0
[[intel::loop_fuse(0)]] void func2() {}

// CHECK: FunctionDecl {{.*}} func3 'void ()'
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: SYCLIntelLoopFuseAttr {{.*}} loop_fuse_independent
// CHECK-NEXT: ConstantExpr{{.*}}'int'
// CHECK-NEXT: value: Int 1
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1
[[intel::loop_fuse_independent]] void func3() {}

// CHECK: FunctionDecl {{.*}} func4 'void ()'
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: SYCLIntelLoopFuseAttr {{.*}} loop_fuse_independent
// CHECK-NEXT: ConstantExpr{{.*}}'int'
// CHECK-NEXT: value: Int 3
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 3
[[intel::loop_fuse_independent(3)]] void func4() {}

Expand All @@ -38,6 +46,8 @@ queue q;
// CHECK-NEXT: TemplateArgument integral 1
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: SYCLIntelLoopFuseAttr {{.*}} loop_fuse
// CHECK-NEXT: ConstantExpr{{.*}}'int'
// CHECK-NEXT: value: Int 1
// CHECK-NEXT: SubstNonTypeTemplateParmExpr
// CHECK-NEXT: NonTypeTemplateParmDecl
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1
Expand All @@ -53,6 +63,8 @@ template <int N>
// CHECK-NEXT: TemplateArgument integral 5
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: SYCLIntelLoopFuseAttr {{.*}} loop_fuse_independent
// CHECK-NEXT: ConstantExpr{{.*}}'int'
// CHECK-NEXT: value: Int 5
// CHECK-NEXT: SubstNonTypeTemplateParmExpr
// CHECK-NEXT: NonTypeTemplateParmDecl
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 5
Expand Down Expand Up @@ -83,6 +95,8 @@ void foo() {

// CHECK: FunctionDecl {{.*}}kernel_name_2
// CHECK: SYCLIntelLoopFuseAttr {{.*}} loop_fuse
// CHECK-NEXT: ConstantExpr{{.*}}'int'
// CHECK-NEXT: value: Int 3
// CHECK-NEXT: SubstNonTypeTemplateParmExpr
// CHECK-NEXT: NonTypeTemplateParmDecl
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 3
Expand All @@ -91,6 +105,8 @@ void foo() {

// CHECK: FunctionDecl {{.*}}kernel_name_3
// CHECK: SYCLIntelLoopFuseAttr {{.*}} loop_fuse_independent
// CHECK-NEXT: ConstantExpr{{.*}}'int'
// CHECK-NEXT: value: Int 1
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1
h.single_task<class kernel_name_3>(
[]() [[intel::loop_fuse_independent]]{});
Expand Down