diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 5bcbb34b7b93e..8b5e8314b884c 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2308,6 +2308,23 @@ def : MutualExclusions<[SYCLIntelFPGAIVDep, def : MutualExclusions<[SYCLIntelFPGAMaxConcurrency, SYCLIntelFPGADisableLoopPipelining]>; +def SYCLIntelFPGAPipeline : InheritableAttr { + let Spellings = [CXX11<"intel","fpga_pipeline">]; + let Args = [ExprArgument<"Value", /*optional*/1>]; + let LangOpts = [SYCLIsDevice, SilentlyIgnoreSYCLIsHost]; + let Subjects = SubjectList<[ForStmt, CXXForRangeStmt, WhileStmt, DoStmt], + ErrorDiag, "'for', 'while', and 'do' statements">; + let Documentation = [SYCLIntelFPGAPipelineAttrDocs]; + let IsStmtDependent = 1; +} + +def : MutualExclusions<[SYCLIntelFPGAInitiationInterval, + SYCLIntelFPGAPipeline]>; +def : MutualExclusions<[SYCLIntelFPGAIVDep, + SYCLIntelFPGAPipeline]>; +def : MutualExclusions<[SYCLIntelFPGAMaxConcurrency, + SYCLIntelFPGAPipeline]>; + def SYCLIntelFPGALoopCount : StmtAttr { let Spellings = [CXX11<"intel", "loop_count_min">, CXX11<"intel", "loop_count_max">, @@ -2340,6 +2357,9 @@ def SYCLIntelFPGAMaxInterleaving : StmtAttr { def : MutualExclusions<[SYCLIntelFPGADisableLoopPipelining, SYCLIntelFPGAMaxInterleaving]>; +def : MutualExclusions<[SYCLIntelFPGAPipeline, + SYCLIntelFPGAMaxInterleaving]>; + def SYCLIntelFPGASpeculatedIterations : StmtAttr { let Spellings = [CXX11<"intel", "speculated_iterations">]; let Subjects = SubjectList<[ForStmt, CXXForRangeStmt, WhileStmt, DoStmt], @@ -2352,6 +2372,9 @@ def SYCLIntelFPGASpeculatedIterations : StmtAttr { def : MutualExclusions<[SYCLIntelFPGADisableLoopPipelining, SYCLIntelFPGASpeculatedIterations]>; +def : MutualExclusions<[SYCLIntelFPGAPipeline, + SYCLIntelFPGASpeculatedIterations]>; + def SYCLIntelFPGANofusion : StmtAttr { let Spellings = [CXX11<"intel","nofusion">]; let Subjects = SubjectList<[ForStmt, CXXForRangeStmt, WhileStmt, DoStmt], diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 019fc814496be..40f6b5263da22 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -3291,6 +3291,9 @@ function, or in conjunction with ``max_interleaving``, ``speculated_iterations``, ``max_concurrency``, ``initiation_interval``, or ``ivdep``. +The ``[[intel::disable_loop_pipelining]]`` attribute spelling is a deprecated +synonym for ``[[[intel::fpga_pipeline]]`` and will be removed in the future. + .. code-block:: c++ void foo() { @@ -3303,6 +3306,58 @@ or ``ivdep``. }]; } +def SYCLIntelFPGAPipelineAttrDocs : Documentation { + let Category = DocCatVariable; + let Heading = "intel::fpga_pipeline"; + let Content = [{ +The ``intel::fpga_pipeline(N)`` attribute applies to a loop and it allows users +to disable or enable pipelining iterations of a loop. The attribute optionally +accepts an integer constant expression that is converted to `bool`. A `true` +value enables pipelining while a `false` value disables pipelining. The +optional argument defaults to `true`. This attribute cannot be applied to a +loop in conjunction with the ``max_interleaving``, ``speculated_iterations``, +``max_concurrency``, ``initiation_interval``, or ``ivdep`` attributes. + +.. code-block:: c++ + + // Disable loop pipelining + void bar() { + int a[10]; + [[[intel::fpga_pipeline(0)]] for (int i = 0; i != 10; ++i) a[i] = 0; + } + + // Enable loop pipelining + void foo() { + int var = 0; + [[intel::fpga_pipeline(1)]] for (int i = 0; i < 10; ++i) var++; + } + + void Array(int *array, size_t n) { + // identical to [[intel::fpga_pipeline(1)]] + [[intel::fpga_pipeline]] for (int i = 0; i < n; ++i) array[i] = 0; + } + + void count () { + int a1[10], int i = 0; + [[intel::fpga_pipeline(1)]] while (i < 10) { + a1[i] += 3; + } + + void check() { + int a = 10; + [[intel::fpga_pipeline(1)]] do { + a = a + 1; + } while (a < 20); + } + + template + void func() { + [[intel::fpga_pipeline(A)]] for(;;) { } + } + + }]; +} + def SYCLIntelFPGALoopCountAttrDocs : Documentation { let Category = DocCatVariable; let Heading = "intel::loop_count_min, intel::loop_count_max, intel::loop_count_avg, intel::loop_count"; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 6ba624c6b7c2b..e8516e5d046d2 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2277,6 +2277,9 @@ class Sema final { SYCLIntelFPGALoopCoalesceAttr * BuildSYCLIntelFPGALoopCoalesceAttr(const AttributeCommonInfo &CI, Expr *E); + SYCLIntelFPGAPipelineAttr * + BuildSYCLIntelFPGAPipelineAttr(const AttributeCommonInfo &CI, Expr *E); + bool CheckQualifiedFunctionForTypeId(QualType T, SourceLocation Loc); bool CheckFunctionReturnType(QualType T, SourceLocation Loc); diff --git a/clang/lib/CodeGen/CGLoopInfo.cpp b/clang/lib/CodeGen/CGLoopInfo.cpp index 714e0b2a0a51b..43b995e72d243 100644 --- a/clang/lib/CodeGen/CGLoopInfo.cpp +++ b/clang/lib/CodeGen/CGLoopInfo.cpp @@ -611,6 +611,14 @@ MDNode *LoopInfo::createMetadata( llvm::Type::getInt32Ty(Ctx), VC.second))}; LoopProperties.push_back(MDNode::get(Ctx, Vals)); } + + for (auto &FP : Attrs.SYCLIntelFPGAPipeline) { + Metadata *Vals[] = {MDString::get(Ctx, FP.first), + ConstantAsMetadata::get(ConstantInt::get( + llvm::Type::getInt32Ty(Ctx), FP.second))}; + LoopProperties.push_back(MDNode::get(Ctx, Vals)); + } + LoopProperties.insert(LoopProperties.end(), AdditionalLoopProperties.begin(), AdditionalLoopProperties.end()); return createFullUnrollMetadata(Attrs, LoopProperties, HasUserTransforms); @@ -654,6 +662,7 @@ void LoopAttributes::clear() { PipelineDisabled = false; PipelineInitiationInterval = 0; SYCLNofusionEnable = false; + SYCLIntelFPGAPipeline.clear(); MustProgress = false; } @@ -687,7 +696,8 @@ LoopInfo::LoopInfo(BasicBlock *Header, const LoopAttributes &Attrs, Attrs.UnrollEnable == LoopAttributes::Unspecified && Attrs.UnrollAndJamEnable == LoopAttributes::Unspecified && Attrs.DistributeEnable == LoopAttributes::Unspecified && !StartLoc && - Attrs.SYCLNofusionEnable == false && !EndLoc && !Attrs.MustProgress) + Attrs.SYCLNofusionEnable == false && + Attrs.SYCLIntelFPGAPipeline.empty() && !EndLoc && !Attrs.MustProgress) return; TempLoopID = MDNode::getTemporary(Header->getContext(), None); @@ -1011,6 +1021,8 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx, // emitted // For attribute nofusion: // 'llvm.loop.fusion.disable' metadata will be emitted + // For attribute fpga_pipeline: + // n - 'llvm.loop.intel.pipelining.enable, i32 n' metadata will be emitted for (const auto *A : Attrs) { if (const auto *IntelFPGAIVDep = dyn_cast(A)) addSYCLIVDepInfo(Header->getContext(), IntelFPGAIVDep->getSafelenValue(), @@ -1075,6 +1087,15 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx, if (isa(A)) setSYCLNofusionEnable(); + + if (const auto *IntelFPGAPipeline = + dyn_cast(A)) { + const auto *CE = cast(IntelFPGAPipeline->getValue()); + Optional ArgVal = CE->getResultAsAPSInt(); + unsigned int Value = ArgVal->getBoolValue() ? 1 : 0; + const char *Var = "llvm.loop.intel.pipelining.enable"; + setSYCLIntelFPGAPipeline(Var, Value); + } } setMustProgress(MustProgress); diff --git a/clang/lib/CodeGen/CGLoopInfo.h b/clang/lib/CodeGen/CGLoopInfo.h index f48cfb248c3cb..a0a2ae1f94292 100644 --- a/clang/lib/CodeGen/CGLoopInfo.h +++ b/clang/lib/CodeGen/CGLoopInfo.h @@ -152,6 +152,10 @@ struct LoopAttributes { /// Flag for llvm.loop.fusion.disable metatdata. bool SYCLNofusionEnable; + /// Value for fpga_pipeline variant and metadata. + llvm::SmallVector, 2> + SYCLIntelFPGAPipeline; + /// Value for whether the loop is required to make progress. bool MustProgress; }; @@ -407,6 +411,11 @@ class LoopInfoStack { /// Set flag of nofusion for the next loop pushed. void setSYCLNofusionEnable() { StagedAttrs.SYCLNofusionEnable = true; } + /// Set variant and value of fpga_pipeline for the next loop pushed. + void setSYCLIntelFPGAPipeline(const char *Var, unsigned int Value) { + StagedAttrs.SYCLIntelFPGAPipeline.push_back({Var, Value}); + } + /// Set no progress for the next loop pushed. void setMustProgress(bool P) { StagedAttrs.MustProgress = P; } diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 6340ab94aa3ea..1be01cf8f3906 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -364,6 +364,14 @@ void Sema::CheckDeprecatedSYCLAttributeSpelling(const ParsedAttr &A, Diag(A.getLoc(), diag::ext_sycl_2020_attr_spelling) << A; return; } + + // Deprecate [[intel::disable_loop_pipelining]] attribute spelling in favor + // of the SYCL FPGA attribute spelling [[intel::fpga_pipeline]]. + if (A.hasScope() && A.getScopeName()->isStr("intel") && + A.getAttrName()->isStr("disable_loop_pipelining")) { + DiagnoseDeprecatedAttribute(A, "intel", "fpga_pipeline"); + return; + } } /// Check if IdxExpr is a valid parameter index for a function or diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index fc70b53b3c8e2..001890cead8a3 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -219,6 +219,33 @@ static Attr *handleSYCLIntelFPGADisableLoopPipeliningAttr(Sema &S, Stmt *, return new (S.Context) SYCLIntelFPGADisableLoopPipeliningAttr(S.Context, A); } +// Handle [[intel:fpga_pipeline]] attribute. +static Attr *handleSYCLIntelFPGAPipelineAttr(Sema &S, Stmt *, + const ParsedAttr &A) { + // 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, A.getLoc()); + + return S.BuildSYCLIntelFPGAPipelineAttr(A, E); +} + +SYCLIntelFPGAPipelineAttr * +Sema::BuildSYCLIntelFPGAPipelineAttr(const AttributeCommonInfo &A, Expr *E) { + + if (!E->isValueDependent()) { + // Check if the expression is not value dependent. + llvm::APSInt ArgVal; + ExprResult Res = VerifyIntegerConstantExpression(E, &ArgVal); + if (Res.isInvalid()) + return nullptr; + E = Res.get(); + } + + return new (Context) SYCLIntelFPGAPipelineAttr(Context, A, E); +} + static bool checkSYCLIntelFPGAIVDepSafeLen(Sema &S, llvm::APSInt &Value, Expr *E) { if (!Value.isStrictlyPositive()) @@ -821,6 +848,7 @@ static void CheckForIncompatibleSYCLLoopAttributes( CheckForDuplicationSYCLLoopAttribute(S, Attrs, false); CheckRedundantSYCLIntelFPGAIVDepAttrs(S, Attrs); CheckForDuplicationSYCLLoopAttribute(S, Attrs); + CheckForDuplicationSYCLLoopAttribute(S, Attrs); } void CheckForIncompatibleUnrollHintAttributes( @@ -966,6 +994,8 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A, return handleUnlikely(S, St, A, Range); case ParsedAttr::AT_SYCLIntelFPGANofusion: return handleIntelFPGANofusionAttr(S, St, A); + case ParsedAttr::AT_SYCLIntelFPGAPipeline: + return handleSYCLIntelFPGAPipelineAttr(S, St, A); default: // N.B., ClangAttrEmitter.cpp emits a diagnostic helper that ensures a // declaration attribute is not written on a statement, but this code is diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 39da624efd3a4..4456dac787da7 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1110,6 +1110,8 @@ namespace { const SYCLIntelFPGASpeculatedIterationsAttr *SI); const SYCLIntelFPGALoopCountAttr * TransformSYCLIntelFPGALoopCountAttr(const SYCLIntelFPGALoopCountAttr *SI); + const SYCLIntelFPGAPipelineAttr * + TransformSYCLIntelFPGAPipelineAttr(const SYCLIntelFPGAPipelineAttr *SI); ExprResult TransformPredefinedExpr(PredefinedExpr *E); ExprResult TransformDeclRefExpr(DeclRefExpr *E); @@ -1601,6 +1603,13 @@ const LoopUnrollHintAttr *TemplateInstantiator::TransformLoopUnrollHintAttr( return getSema().BuildLoopUnrollHintAttr(*LU, TransformedExpr); } +const SYCLIntelFPGAPipelineAttr * +TemplateInstantiator::TransformSYCLIntelFPGAPipelineAttr( + const SYCLIntelFPGAPipelineAttr *PA) { + Expr *TransformedExpr = getDerived().TransformExpr(PA->getValue()).get(); + return getSema().BuildSYCLIntelFPGAPipelineAttr(*PA, TransformedExpr); +} + ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef( NonTypeTemplateParmDecl *parm, SourceLocation loc, diff --git a/clang/test/CodeGenSYCL/intel-fpga-loops.cpp b/clang/test/CodeGenSYCL/intel-fpga-loops.cpp index 44306a2660011..cbdfca71c2de9 100644 --- a/clang/test/CodeGenSYCL/intel-fpga-loops.cpp +++ b/clang/test/CodeGenSYCL/intel-fpga-loops.cpp @@ -20,6 +20,14 @@ // CHECK: br label %for.cond2, !llvm.loop ![[MD_LCA_1:[0-9]+]] // CHECK: br label %for.cond13, !llvm.loop ![[MD_LCA_2:[0-9]+]] // CHECK: br label %for.cond24, !llvm.loop ![[MD_LCA_3:[0-9]+]] +// CHECK: br label %for.cond, !llvm.loop ![[MD_FP:[0-9]+]] +// CHECK: br label %for.cond2, !llvm.loop ![[MD_FP_1:[0-9]+]] +// CHECK: br label %for.cond13, !llvm.loop ![[MD_FP_2:[0-9]+]] +// CHECK: br label %for.cond24, !llvm.loop ![[MD_FP_3:[0-9]+]] +// CHECK: br label %while.cond, !llvm.loop ![[MD_FP_4:[0-9]+]] +// CHECK: br i1 %cmp38, label %do.body, label %do.end, !llvm.loop ![[MD_FP_5:[0-9]+]] +// CHECK: br label %for.cond40, !llvm.loop ![[MD_FP_6:[0-9]+]] +// CHECK: br label %while.cond47, !llvm.loop ![[MD_FP_7:[0-9]+]] void disable_loop_pipelining() { int a[10]; @@ -126,6 +134,7 @@ void speculated_iterations() { a[i] = 0; } +// Add CodeGen tests for FPGA loop attribute: [[intel::fpga_pipeline()]]. template void loop_count_control() { int a[10]; @@ -150,6 +159,48 @@ void loop_count_control() { a[i] = 0; } +// Add CodeGen tests for Loop attribute: [[intel::fpga_pipeline()]]. +template +void fpga_pipeline() { + int a[10]; + // CHECK: ![[MD_FP]] = distinct !{![[MD_FP]], ![[MP]], ![[MD_fpga_pipeline:[0-9]+]]} + // CHECK-NEXT: ![[MD_fpga_pipeline]] = !{!"llvm.loop.intel.pipelining.enable", i32 1} + [[intel::fpga_pipeline(A)]] for (int i = 0; i != 10; ++i) + a[i] = 0; + + // CHECK: ![[MD_FP_1]] = distinct !{![[MD_FP_1]], ![[MP]], ![[MD_fpga_pipeline]]} + [[intel::fpga_pipeline(1)]] for (int i = 0; i != 10; ++i) + a[i] = 0; + + // CHECK: ![[MD_FP_2]] = distinct !{![[MD_FP_2]], ![[MP]], ![[MD_fpga_pipeline]]} + [[intel::fpga_pipeline]] for (int i = 0; i != 10; ++i) + a[i] = 0; + + // CHECK: ![[MD_FP_3]] = distinct !{![[MD_FP_3]], ![[MP]], ![[MD_dlp]]} + [[intel::fpga_pipeline(0)]] for (int i = 0; i != 10; ++i) + a[i] = 0; + + // CHECK: ![[MD_FP_4]] = distinct !{![[MD_FP_4]], ![[MP]], ![[MD_fpga_pipeline]]} + int j = 0; + [[intel::fpga_pipeline]] while (j < 10) { + a[j] += 3; + } + + // CHECK: ![[MD_FP_5]] = distinct !{![[MD_FP_5]], ![[MP]], ![[MD_fpga_pipeline]]} + int b = 10; + [[intel::fpga_pipeline(1)]] do { + b = b + 1; + } while (b < 20); + + // CHECK: ![[MD_FP_6]] = distinct !{![[MD_FP_6]], ![[MD_fpga_pipeline]]} + int c[] = {0, 1, 2, 3, 4, 5}; + [[intel::fpga_pipeline(A)]] for (int n : c) { n *= 2; } + + // CHECK: ![[MD_FP_7]] = distinct !{![[MD_FP_7]], ![[MP]], ![[MD_fpga_pipeline]]} + int k = 0; + [[intel::fpga_pipeline(-1)]] while (k < 20) { a[k] += 2; } +} + template __attribute__((sycl_kernel)) void kernel_single_task(const Func &kernelFunc) { kernelFunc(); @@ -165,6 +216,7 @@ int main() { max_interleaving<3, 0>(); speculated_iterations<4, 0>(); loop_count_control<12>(); + fpga_pipeline<1>(); }); return 0; } diff --git a/clang/test/SemaSYCL/intel-fpga-loops.cpp b/clang/test/SemaSYCL/intel-fpga-loops.cpp index 4d7c37d81b1a7..68c23e66d183c 100644 --- a/clang/test/SemaSYCL/intel-fpga-loops.cpp +++ b/clang/test/SemaSYCL/intel-fpga-loops.cpp @@ -26,6 +26,8 @@ void foo() { [[intel::loop_count_avg(6)]] int l[10]; // expected-error@+1{{'loop_count' attribute cannot be applied to a declaration}} [[intel::loop_count(8)]] int m[10]; + // expected-error@+1{{'fpga_pipeline' attribute cannot be applied to a declaration}} + [[intel::fpga_pipeline(1)]] int n[10]; } // Test for deprecated spelling of Intel FPGA loop attributes @@ -122,14 +124,18 @@ void boo() { // expected-error@+1 {{'loop_count' attribute takes one argument}} [[intel::loop_count(6, 9)]] for (int i = 0; i != 10; ++i) a[i] = 0; + + // expected-error@+1 {{'fpga_pipeline' attribute takes no more than 1 argument}} + [[intel::fpga_pipeline(1, 2)]] for (int i = 0; i != 10; ++i) + a[i] = 0; } // Test for incorrect argument value for Intel FPGA loop attributes void goo() { int a[10]; // no diagnostics are expected - [[intel::disable_loop_pipelining]] for (int i = 0; i != 10; ++i) - a[i] = 0; + [[intel::fpga_pipeline]] for (int i = 0; i != 10; ++i) + a[i] = 0; // no diagnostics are expected [[intel::max_concurrency(0)]] for (int i = 0; i != 10; ++i) a[i] = 0; @@ -216,6 +222,16 @@ void goo() { // expected-error@+1 {{'loop_count' attribute requires a non-negative integral compile time constant expression}} [[intel::loop_count(-1)]] for (int i = 0; i != 10; ++i) a[i] = 0; + + // no diagnostics are expected + [[intel::fpga_pipeline(0)]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // no diagnostics are expected + [[intel::fpga_pipeline(-1)]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // expected-error@+1 {{integral constant expression must have integral or unscoped enumeration type, not 'const char[4]'}} + [[intel::fpga_pipeline("abc")]] for (int i = 0; i != 10; ++i) + a[i] = 0; } // Test for Intel FPGA loop attributes duplication @@ -253,10 +269,10 @@ void zoo() { [[intel::max_concurrency(2)]] [[intel::initiation_interval(2)]] for (int i = 0; i != 10; ++i) a[i] = 0; - [[intel::disable_loop_pipelining]] - // expected-error@+1 {{duplicate Intel FPGA loop attribute 'disable_loop_pipelining'}} - [[intel::disable_loop_pipelining]] for (int i = 0; i != 10; ++i) - a[i] = 0; + [[intel::fpga_pipeline]] + // expected-error@+1 {{duplicate Intel FPGA loop attribute 'fpga_pipeline'}} + [[intel::fpga_pipeline]] for (int i = 0; i != 10; ++i) + a[i] = 0; [[intel::loop_coalesce(2)]] // expected-error@+2 {{duplicate Intel FPGA loop attribute 'loop_coalesce'}} [[intel::max_interleaving(1)]] @@ -339,44 +355,34 @@ void zoo() { // Test for Intel FPGA loop attributes compatibility void loop_attrs_compatibility() { int a[10]; - // no diagnostics are expected - [[intel::disable_loop_pipelining]] - [[intel::loop_coalesce]] for (int i = 0; i != 10; ++i) - a[i] = 0; - // expected-error@+3 {{'max_interleaving' and 'disable_loop_pipelining' attributes are not compatible}} + [[intel::fpga_pipeline]] [[intel::loop_coalesce]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // expected-error@+4 {{'max_interleaving' and 'disable_loop_pipelining' attributes are not compatible}} // expected-note@+1 {{conflicting attribute is here}} - [[intel::disable_loop_pipelining]] + [[intel::disable_loop_pipelining]] // expected-warning {{attribute 'intel::disable_loop_pipelining' is deprecated}} \ + // expected-note {{did you mean to use 'intel::fpga_pipeline' instead?}} [[intel::max_interleaving(0)]] for (int i = 0; i != 10; ++i) - a[i] = 0; - // expected-error@+3 {{'disable_loop_pipelining' and 'speculated_iterations' attributes are not compatible}} - // expected-note@+1 {{conflicting attribute is here}} - [[intel::speculated_iterations(0)]] - [[intel::disable_loop_pipelining]] for (int i = 0; i != 10; ++i) - a[i] = 0; - // expected-error@+3 {{'max_concurrency' and 'disable_loop_pipelining' attributes are not compatible}} + a[i] = 0; + + // expected-error@+2 {{'fpga_pipeline' and 'speculated_iterations' attributes are not compatible}} // expected-note@+1 {{conflicting attribute is here}} - [[intel::disable_loop_pipelining]] - [[intel::max_concurrency(0)]] for (int i = 0; i != 10; ++i) - a[i] = 0; - // expected-error@+3 {{'disable_loop_pipelining' and 'initiation_interval' attributes are not compatible}} + [[intel::speculated_iterations(0)]] [[intel::fpga_pipeline]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // expected-error@+2 {{'fpga_pipeline' and 'initiation_interval' attributes are not compatible}} // expected-note@+1 {{conflicting attribute is here}} - [[intel::initiation_interval(10)]] - [[intel::disable_loop_pipelining]] for (int i = 0; i != 10; ++i) - a[i] = 0; - // expected-error@+3 {{'ivdep' and 'disable_loop_pipelining' attributes are not compatible}} - // expected-note@+1 {{conflicting attribute is here}} - [[intel::disable_loop_pipelining]] - [[intel::ivdep]] for (int i = 0; i != 10; ++i) - a[i] = 0; + [[intel::initiation_interval(10)]] [[intel::fpga_pipeline]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // no diagnostics are expected - [[intel::disable_loop_pipelining]] - [[intel::nofusion]] for (int i = 0; i != 10; ++i) - a[i] = 0; + [[intel::fpga_pipeline]] [[intel::loop_coalesce]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // no diagnostics are expected - [[intel::disable_loop_pipelining]] - [[intel::loop_count_avg(8)]] - for (int i = 0; i != 10; ++i) - a[i] = 0; + [[intel::fpga_pipeline]] [[intel::nofusion]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // no diagnostics are expected + [[intel::fpga_pipeline]] [[intel::loop_count_avg(8)]] for (int i = 0; i != 10; ++i) + a[i] = 0; [[intel::loop_count_min(8)]] for (int i = 0; i != 10; ++i) a[i] = 0; @@ -385,6 +391,21 @@ void loop_attrs_compatibility() { a[i] = 0; [[intel::loop_count(8)]] for (int i = 0; i != 10; ++i) a[i] = 0; + + // expected-error@+2 {{'fpga_pipeline' and 'max_concurrency' attributes are not compatible}} + // expected-note@+1 {{conflicting attribute is here}} + [[intel::max_concurrency(2)]] [[intel::fpga_pipeline(1)]] for (int i = 0; i != 10; ++i) + a[i] = 0; + + // expected-error@+2 {{'fpga_pipeline' and 'max_interleaving' attributes are not compatible}} + // expected-note@+1 {{conflicting attribute is here}} + [[intel::max_interleaving(2)]] [[intel::fpga_pipeline]] for (int i = 0; i != 10; ++i) + a[i] = 0; + + // expected-error@+2 {{'fpga_pipeline' and 'ivdep' attributes are not compatible}} + // expected-note@+1 {{conflicting attribute is here}} + [[intel::ivdep]] [[intel::fpga_pipeline]] for (int i = 0; i != 10; ++i) + a[i] = 0; } template @@ -544,6 +565,17 @@ void loop_count_control_dependent() { a[i] = 0; } +template +void fpga_pipeline_dependent() { + int a[10]; + [[intel::fpga_pipeline(C)]] for (int i = 0; i != 10; ++i) + a[i] = 0; + + // expected-error@+1 {{duplicate Intel FPGA loop attribute 'fpga_pipeline'}} + [[intel::fpga_pipeline(A)]] [[intel::fpga_pipeline(B)]] for (int i = 0; i != 10; ++i) + a[i] = 0; +} + void check_max_concurrency_expression() { int a[10]; // Test that checks expression is not a constant expression. @@ -640,6 +672,22 @@ void check_loop_count_expression() { a[i] = 0; } +void check_loop_fpga_pipeline_expression() { + int a[10]; + + // Test that checks expression is not a constant expression. + int foo; // expected-note {{declared here}} + // expected-error@+2{{expression is not an integral constant expression}} + // expected-note@+1{{read of non-const variable 'foo' is not allowed in a constant expression}} + [[intel::fpga_pipeline(foo + 1)]] for (int i = 0; i != 10; ++i) + a[i] = 0; + + // Test that checks expression is a constant expression. + constexpr int bar = 0; + [[intel::fpga_pipeline(bar + 1)]] for (int i = 0; i != 10; ++i) // OK + a[i] = 0; +} + // Test that checks wrong template instantiation and ensures that the type // is checked properly when instantiating from the template definition. struct S {}; @@ -681,6 +729,11 @@ void check_loop_attr_template_instantiation() { // expected-error@+1 {{integral constant expression must have integral or unscoped enumeration type, not 'float'}} [[intel::loop_count(Ty{})]] for (int i = 0; i != 10; ++i) a[i] = 0; + + // expected-error@+2 {{integral constant expression must have integral or unscoped enumeration type, not 'S'}} + // expected-error@+1 {{integral constant expression must have integral or unscoped enumeration type, not 'float'}} + [[intel::fpga_pipeline(Ty{})]] for (int i = 0; i != 10; ++i) + a[i] = 0; } int main() { @@ -703,12 +756,14 @@ int main() { speculated_iterations_dependent<1, 8, -3, 0>(); // expected-note{{in instantiation of function template specialization 'speculated_iterations_dependent<1, 8, -3, 0>' requested here}} loop_coalesce_dependent<-1, 4, 0>(); // expected-note{{in instantiation of function template specialization 'loop_coalesce_dependent<-1, 4, 0>' requested here}} loop_count_control_dependent<3, 2, -1>(); // expected-note{{in instantiation of function template specialization 'loop_count_control_dependent<3, 2, -1>' requested here}} + fpga_pipeline_dependent<1, 1, 0>(); check_max_concurrency_expression(); check_max_interleaving_expression(); check_speculated_iterations_expression(); check_loop_coalesce_expression(); check_initiation_interval_expression(); check_loop_count_expression(); + check_loop_fpga_pipeline_expression(); check_loop_attr_template_instantiation(); //expected-note{{in instantiation of function template specialization 'check_loop_attr_template_instantiation' requested here}} check_loop_attr_template_instantiation(); //expected-note{{in instantiation of function template specialization 'check_loop_attr_template_instantiation' requested here}} }); diff --git a/clang/test/SemaSYCL/intel-fpga-pipeline-ast.cpp b/clang/test/SemaSYCL/intel-fpga-pipeline-ast.cpp new file mode 100644 index 0000000000000..e2fecd866891d --- /dev/null +++ b/clang/test/SemaSYCL/intel-fpga-pipeline-ast.cpp @@ -0,0 +1,70 @@ +// RUN: %clang_cc1 -fsycl-is-device -internal-isystem %S/Inputs -fsyntax-only -ast-dump -Wno-sycl-2017-compat -verify %s | FileCheck %s +// expected-no-diagnostics + +// Add AST tests for Loop attribute: [[intel::fpga_pipeline()]]. + +#include "sycl.hpp" + +using namespace cl::sycl; +queue q; + +template +void fpga_pipeline() { + int a1[10], a2[10]; + // CHECK: AttributedStmt + // CHECK-NEXT: SYCLIntelFPGAPipelineAttr + [[intel::fpga_pipeline(A)]] for (int p = 0; p < 10; ++p) { + a1[p] = a2[p] = 0; + } + + // CHECK: AttributedStmt + // CHECK-NEXT: SYCLIntelFPGAPipelineAttr + // CHECK-NEXT: ConstantExpr{{.*}}'int' + // CHECK-NEXT: value: Int 1 + // CHECK-NEXT: IntegerLiteral{{.*}}1{{$}} + int i = 0; + [[intel::fpga_pipeline]] while (i < 10) { + a1[i] += 3; + } + + // CHECK: AttributedStmt + // CHECK-NEXT: SYCLIntelFPGAPipelineAttr + // CHECK-NEXT: ConstantExpr{{.*}}'int' + // CHECK-NEXT: value: Int 1 + // CHECK-NEXT: IntegerLiteral{{.*}}1{{$}} + for (int i = 0; i < 10; ++i) { + [[intel::fpga_pipeline(1)]] for (int j = 0; j < 10; ++j) { + a1[i] += a1[j]; + } + } + + // CHECK: AttributedStmt + // CHECK-NEXT: SYCLIntelFPGAPipelineAttr + // CHECK-NEXT: ConstantExpr{{.*}}'int' + // CHECK-NEXT: value: Int 0 + // CHECK-NEXT: IntegerLiteral{{.*}}0{{$}} + [[intel::fpga_pipeline(0)]] for (int i = 0; i != 10; ++i) + a1[i] = 0; + + // CHECK: AttributedStmt + // CHECK-NEXT: SYCLIntelFPGAPipelineAttr + // CHECK-NEXT: ConstantExpr{{.*}}'int' + // CHECK-NEXT: value: Int 1 + // CHECK-NEXT: IntegerLiteral{{.*}}1{{$}} + int b = 10; + [[intel::fpga_pipeline(1)]] do { + b = b + 1; + } while (b < 20); + + // CHECK: AttributedStmt + // CHECK-NEXT: SYCLIntelFPGAPipelineAttr + int c[] = {0, 1, 2, 3, 4, 5}; + [[intel::fpga_pipeline(A)]] for (int n : c) { n *= 2; } +} + +int main() { + q.submit([&](handler &h) { + h.single_task([]() { fpga_pipeline<1>(); }); + }); + return 0; +}