diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index fc8d392e3937a..9e8a188a285a9 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1654,6 +1654,57 @@ def SYCLIntelFPGAMaxConcurrency : Attr { let Documentation = [SYCLIntelFPGAMaxConcurrencyAttrDocs]; } +def SYCLIntelFPGALoopCoalesce : Attr { + let Spellings = [CXX11<"intelfpga","loop_coalesce">]; + let Args = [ExprArgument<"NExpr">]; + let LangOpts = [SYCLIsDevice, SYCLIsHost]; + let HasCustomTypeTransform = 1; + let AdditionalMembers = [{ + static const char *getName() { + return "loop_coalesce"; + } + }]; + let Documentation = [SYCLIntelFPGALoopCoalesceAttrDocs]; +} + +def SYCLIntelFPGADisableLoopPipelining : Attr { + let Spellings = [CXX11<"intelfpga","disable_loop_pipelining">]; + let LangOpts = [SYCLIsDevice, SYCLIsHost]; + let HasCustomTypeTransform = 1; + let AdditionalMembers = [{ + static const char *getName() { + return "disable_loop_pipelining"; + } + }]; + let Documentation = [SYCLIntelFPGADisableLoopPipeliningAttrDocs]; +} + +def SYCLIntelFPGAMaxInterleaving : Attr { + let Spellings = [CXX11<"intelfpga","max_interleaving">]; + let Args = [ExprArgument<"NExpr">]; + let LangOpts = [SYCLIsDevice, SYCLIsHost]; + let HasCustomTypeTransform = 1; + let AdditionalMembers = [{ + static const char *getName() { + return "max_interleaving"; + } + }]; + let Documentation = [SYCLIntelFPGAMaxInterleavingAttrDocs]; +} + +def SYCLIntelFPGASpeculatedIterations : Attr { + let Spellings = [CXX11<"intelfpga","speculated_iterations">]; + let Args = [ExprArgument<"NExpr">]; + let LangOpts = [SYCLIsDevice, SYCLIsHost]; + let HasCustomTypeTransform = 1; + let AdditionalMembers = [{ + static const char *getName() { + return "speculated_iterations"; + } + }]; + let Documentation = [SYCLIntelFPGASpeculatedIterationsAttrDocs]; +} + def IntelFPGALocalNonConstVar : SubsetSubjecthasLocalStorage() && S->getKind() != Decl::ImplicitParam && diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 58af06c66bb84..d445d7c0ad991 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -2090,6 +2090,53 @@ be applied multiple times to the same loop. }]; } +def SYCLIntelFPGALoopCoalesceAttrDocs : Documentation { + let Category = DocCatVariable; + let Heading = "loop_coalesce"; + let Content = [{ +This attribute applies to a loop. Indicates that the loop nest should be +coalesced into a single loop without affecting functionality. Parameter N is +optional. If specified, it shall be a positive integer, and indicates how many +of the nested loop levels should be coalesced. + }]; +} + +def SYCLIntelFPGADisableLoopPipeliningAttrDocs : Documentation { + let Category = DocCatVariable; + let Heading = "disable_loop_pipelining"; + let Content = [{ +This attribute applies to a loop. Disables pipelining of the loop data path, +causing the loop to be executed serially. Cannot be used on the same loop in +conjunction with max_interleaving, speculated_iterations, max_concurrency, ii +or ivdep. + }]; +} + +def SYCLIntelFPGAMaxInterleavingAttrDocs : Documentation { + let Category = DocCatVariable; + let Heading = "max_interleaving"; + let Content = [{ +This attribute applies to a loop. Places a maximum limit N on the number of +interleaved invocations of an inner loop by an outer loop (note, this does not +mean that this attribute can only be applied to inner loops in user code - outer +loops in user code may still be contained in an implicit loop due to NDRange). +Parameter N is mandatory, and shall be non-negative integer. Cannot be +used on the same loop in conjunction with disable_loop_pipelining. + }]; +} + +def SYCLIntelFPGASpeculatedIterationsAttrDocs : Documentation { + let Category = DocCatVariable; + let Heading = "speculated_iterations"; + let Content = [{ +This attribute applies to a loop. Specifies the number of concurrent speculated +iterations that will be in flight for a loop invocation (i.e. the exit +condition for these iterations will not have been evaluated yet). +Parameter N is mandatory, and may either be 0, or a positive integer. Cannot be +used on the same loop in conjunction with disable_loop_pipelining. + }]; +} + def SYCLDeviceIndirectlyCallableDocs : Documentation { let Category = DocCatFunction; let Heading = "intel::device_indirectly_callable"; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 353ca10894b92..d211214acc8b1 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1719,7 +1719,7 @@ class Sema final { Expr *Expr2); template FPGALoopAttrT *BuildSYCLIntelFPGALoopAttr(const AttributeCommonInfo &A, - Expr *E); + Expr *E = nullptr); LoopUnrollHintAttr *BuildLoopUnrollHintAttr(const AttributeCommonInfo &A, Expr *E); diff --git a/clang/lib/CodeGen/CGLoopInfo.cpp b/clang/lib/CodeGen/CGLoopInfo.cpp index 5a2ddad981931..0f85c700aa442 100644 --- a/clang/lib/CodeGen/CGLoopInfo.cpp +++ b/clang/lib/CodeGen/CGLoopInfo.cpp @@ -507,7 +507,6 @@ MDNode *LoopInfo::createMetadata( // Setting ii attribute with an initiation interval if (Attrs.SYCLIInterval > 0) { - LLVMContext &Ctx = Header->getContext(); Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.ii.count"), ConstantAsMetadata::get(ConstantInt::get( llvm::Type::getInt32Ty(Ctx), Attrs.SYCLIInterval))}; @@ -516,7 +515,6 @@ MDNode *LoopInfo::createMetadata( // Setting max_concurrency attribute with number of threads if (Attrs.SYCLMaxConcurrencyEnable) { - LLVMContext &Ctx = Header->getContext(); Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.max_concurrency.count"), ConstantAsMetadata::get(ConstantInt::get( llvm::Type::getInt32Ty(Ctx), @@ -524,6 +522,45 @@ MDNode *LoopInfo::createMetadata( LoopProperties.push_back(MDNode::get(Ctx, Vals)); } + if (Attrs.SYCLLoopCoalesceEnable) { + Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.coalesce.enable")}; + LoopProperties.push_back(MDNode::get(Ctx, Vals)); + } + + if (Attrs.SYCLLoopCoalesceNLevels > 0) { + Metadata *Vals[] = { + MDString::get(Ctx, "llvm.loop.coalesce.count"), + ConstantAsMetadata::get(ConstantInt::get( + llvm::Type::getInt32Ty(Ctx), Attrs.SYCLLoopCoalesceNLevels))}; + LoopProperties.push_back(MDNode::get(Ctx, Vals)); + } + + // disable_loop_pipelining attribute corresponds to + // 'llvm.loop.intel.pipelining.enable, i32 0' metadata + if (Attrs.SYCLLoopPipeliningDisable) { + Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.intel.pipelining.enable"), + ConstantAsMetadata::get( + ConstantInt::get(llvm::Type::getInt32Ty(Ctx), 0))}; + LoopProperties.push_back(MDNode::get(Ctx, Vals)); + } + + if (Attrs.SYCLMaxInterleavingEnable) { + Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.max_interleaving.count"), + ConstantAsMetadata::get(ConstantInt::get( + llvm::Type::getInt32Ty(Ctx), + Attrs.SYCLMaxInterleavingNInvocations))}; + LoopProperties.push_back(MDNode::get(Ctx, Vals)); + } + + if (Attrs.SYCLSpeculatedIterationsEnable) { + Metadata *Vals[] = { + MDString::get(Ctx, "llvm.loop.intel.speculated.iterations.count"), + ConstantAsMetadata::get( + ConstantInt::get(llvm::Type::getInt32Ty(Ctx), + Attrs.SYCLSpeculatedIterationsNIterations))}; + LoopProperties.push_back(MDNode::get(Ctx, Vals)); + } + LoopProperties.insert(LoopProperties.end(), AdditionalLoopProperties.begin(), AdditionalLoopProperties.end()); return createFullUnrollMetadata(Attrs, LoopProperties, HasUserTransforms); @@ -535,9 +572,13 @@ LoopAttributes::LoopAttributes(bool IsParallel) UnrollAndJamEnable(LoopAttributes::Unspecified), VectorizePredicateEnable(LoopAttributes::Unspecified), VectorizeWidth(0), InterleaveCount(0), SYCLIInterval(0), SYCLMaxConcurrencyEnable(false), - SYCLMaxConcurrencyNThreads(0), UnrollCount(0), UnrollAndJamCount(0), - DistributeEnable(LoopAttributes::Unspecified), PipelineDisabled(false), - PipelineInitiationInterval(0) {} + SYCLMaxConcurrencyNThreads(0), SYCLLoopCoalesceEnable(false), + SYCLLoopCoalesceNLevels(0), SYCLLoopPipeliningDisable(false), + SYCLMaxInterleavingEnable(false), SYCLMaxInterleavingNInvocations(0), + SYCLSpeculatedIterationsEnable(false), + SYCLSpeculatedIterationsNIterations(0), UnrollCount(0), + UnrollAndJamCount(0), DistributeEnable(LoopAttributes::Unspecified), + PipelineDisabled(false), PipelineInitiationInterval(0) {} void LoopAttributes::clear() { IsParallel = false; @@ -547,6 +588,13 @@ void LoopAttributes::clear() { SYCLIInterval = 0; SYCLMaxConcurrencyEnable = false; SYCLMaxConcurrencyNThreads = 0; + SYCLLoopCoalesceEnable = false; + SYCLLoopCoalesceNLevels = 0; + SYCLLoopPipeliningDisable = false; + SYCLMaxInterleavingEnable = false; + SYCLMaxInterleavingNInvocations = 0; + SYCLSpeculatedIterationsEnable = false; + SYCLSpeculatedIterationsNIterations = 0; InterleaveCount = 0; UnrollCount = 0; UnrollAndJamCount = 0; @@ -574,9 +622,16 @@ LoopInfo::LoopInfo(BasicBlock *Header, const LoopAttributes &Attrs, if (!Attrs.IsParallel && Attrs.VectorizeWidth == 0 && Attrs.InterleaveCount == 0 && !Attrs.GlobalSYCLIVDepInfo.hasValue() && Attrs.ArraySYCLIVDepInfo.empty() && Attrs.SYCLIInterval == 0 && - Attrs.SYCLMaxConcurrencyEnable == false && Attrs.UnrollCount == 0 && - Attrs.UnrollAndJamCount == 0 && !Attrs.PipelineDisabled && - Attrs.PipelineInitiationInterval == 0 && + Attrs.SYCLMaxConcurrencyEnable == false && + Attrs.SYCLLoopCoalesceEnable == false && + Attrs.SYCLLoopCoalesceNLevels == 0 && + Attrs.SYCLLoopPipeliningDisable == false && + Attrs.SYCLMaxInterleavingEnable == false && + Attrs.SYCLMaxInterleavingNInvocations == 0 && + Attrs.SYCLSpeculatedIterationsEnable == false && + Attrs.SYCLSpeculatedIterationsNIterations == 0 && + Attrs.UnrollCount == 0 && Attrs.UnrollAndJamCount == 0 && + !Attrs.PipelineDisabled && Attrs.PipelineInitiationInterval == 0 && Attrs.VectorizePredicateEnable == LoopAttributes::Unspecified && Attrs.VectorizeEnable == LoopAttributes::Unspecified && Attrs.UnrollEnable == LoopAttributes::Unspecified && @@ -877,6 +932,16 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx, // n - 'llvm.loop.ii.count, i32 n' metadata will be emitted // For attribute max_concurrency: // n - 'llvm.loop.max_concurrency.count, i32 n' metadata will be emitted + // For attribute loop_coalesce: + // without parameter - 'lvm.loop.coalesce.enable' metadata will be emitted + // n - 'llvm.loop.coalesce.count, i32 n' metadata will be emitted + // For attribute disable_loop_pipelining: + // 'llvm.loop.intel.pipelining.enable, i32 0' metadata will be emitted + // For attribute max_interleaving: + // n - 'llvm.loop.max_interleaving.count, i32 n' metadata will be emitted + // For attribute speculated_iterations: + // n - 'llvm.loop.intel.speculated.iterations.count, i32 n' metadata will be + // emitted for (const auto *Attr : Attrs) { const SYCLIntelFPGAIVDepAttr *IntelFPGAIVDep = dyn_cast(Attr); @@ -884,8 +949,19 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx, dyn_cast(Attr); const SYCLIntelFPGAMaxConcurrencyAttr *IntelFPGAMaxConcurrency = dyn_cast(Attr); - - if (!IntelFPGAIVDep && !IntelFPGAII && !IntelFPGAMaxConcurrency) + const SYCLIntelFPGALoopCoalesceAttr *IntelFPGALoopCoalesce = + dyn_cast(Attr); + const SYCLIntelFPGADisableLoopPipeliningAttr + *IntelFPGADisableLoopPipelining = + dyn_cast(Attr); + const SYCLIntelFPGAMaxInterleavingAttr *IntelFPGAMaxInterleaving = + dyn_cast(Attr); + const SYCLIntelFPGASpeculatedIterationsAttr *IntelFPGASpeculatedIterations = + dyn_cast(Attr); + + if (!IntelFPGAIVDep && !IntelFPGAII && !IntelFPGAMaxConcurrency && + !IntelFPGALoopCoalesce && !IntelFPGADisableLoopPipelining && + !IntelFPGAMaxInterleaving && !IntelFPGASpeculatedIterations) continue; if (IntelFPGAIVDep) { @@ -918,6 +994,44 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx, setSYCLMaxConcurrencyEnable(); setSYCLMaxConcurrencyNThreads(ArgVal.getSExtValue()); } + + if (IntelFPGALoopCoalesce) { + llvm::APSInt ArgVal(32); + if (auto *LCE = IntelFPGALoopCoalesce->getNExpr()) { + bool IsValid = LCE->isIntegerConstantExpr(ArgVal, Ctx); + assert(IsValid && "Not an integer constant expression"); + (void)IsValid; + setSYCLLoopCoalesceNLevels(ArgVal.getSExtValue()); + } else { + setSYCLLoopCoalesceEnable(); + } + } + + if (IntelFPGADisableLoopPipelining) { + setSYCLLoopPipeliningDisable(); + } + + if (IntelFPGAMaxInterleaving) { + llvm::APSInt ArgVal(32); + bool IsValid = + IntelFPGAMaxInterleaving->getNExpr()->isIntegerConstantExpr(ArgVal, + Ctx); + assert(IsValid && "Not an integer constant expression"); + (void)IsValid; + setSYCLMaxInterleavingEnable(); + setSYCLMaxInterleavingNInvocations(ArgVal.getSExtValue()); + } + + if (IntelFPGASpeculatedIterations) { + llvm::APSInt ArgVal(32); + bool IsValid = + IntelFPGASpeculatedIterations->getNExpr()->isIntegerConstantExpr( + ArgVal, Ctx); + assert(IsValid && "Not an integer constant expression"); + (void)IsValid; + setSYCLSpeculatedIterationsEnable(); + setSYCLSpeculatedIterationsNIterations(ArgVal.getSExtValue()); + } } /// Stage the attributes. diff --git a/clang/lib/CodeGen/CGLoopInfo.h b/clang/lib/CodeGen/CGLoopInfo.h index 690c4e68df1ce..2d128b62cc6d5 100644 --- a/clang/lib/CodeGen/CGLoopInfo.h +++ b/clang/lib/CodeGen/CGLoopInfo.h @@ -113,6 +113,27 @@ struct LoopAttributes { /// Value for llvm.loop.max_concurrency.count metadata. unsigned SYCLMaxConcurrencyNThreads; + /// Flag for llvm.loop.coalesce metadata. + bool SYCLLoopCoalesceEnable; + + /// Value for llvm.loop.coalesce.count metadata. + unsigned SYCLLoopCoalesceNLevels; + + /// Flag for llvm.loop.intel.pipelining.enable, i32 0 metadata. + bool SYCLLoopPipeliningDisable; + + /// Flag for llvm.loop.max_interleaving.count metadata. + bool SYCLMaxInterleavingEnable; + + /// Value for llvm.loop.max_interleaving.count metadata. + unsigned SYCLMaxInterleavingNInvocations; + + /// Flag for llvm.loop.intel.speculated.iterations.count metadata. + bool SYCLSpeculatedIterationsEnable; + + /// Value for llvm.loop.intel.speculated.iterations.count metadata. + unsigned SYCLSpeculatedIterationsNIterations; + /// llvm.unroll. unsigned UnrollCount; @@ -333,6 +354,41 @@ class LoopInfoStack { StagedAttrs.SYCLMaxConcurrencyNThreads = C; } + /// Set flag of loop_coalesce for the next loop pushed. + void setSYCLLoopCoalesceEnable() { + StagedAttrs.SYCLLoopCoalesceEnable = true; + } + + /// Set value of coalesced levels for the next loop pushed. + void setSYCLLoopCoalesceNLevels(unsigned C) { + StagedAttrs.SYCLLoopCoalesceNLevels = C; + } + + /// Set flag of disable_loop_pipelining for the next loop pushed. + void setSYCLLoopPipeliningDisable() { + StagedAttrs.SYCLLoopPipeliningDisable = true; + } + + /// Set flag of max_interleaving for the next loop pushed. + void setSYCLMaxInterleavingEnable() { + StagedAttrs.SYCLMaxInterleavingEnable = true; + } + + /// Set value of max interleaved invocations for the next loop pushed. + void setSYCLMaxInterleavingNInvocations(unsigned C) { + StagedAttrs.SYCLMaxInterleavingNInvocations = C; + } + + /// Set flag of speculated_iterations for the next loop pushed. + void setSYCLSpeculatedIterationsEnable() { + StagedAttrs.SYCLSpeculatedIterationsEnable = true; + } + + /// Set value of concurrent speculated iterations for the next loop pushed. + void setSYCLSpeculatedIterationsNIterations(unsigned C) { + StagedAttrs.SYCLSpeculatedIterationsNIterations = C; + } + /// Set the unroll count for the next loop pushed. void setUnrollCount(unsigned C) { StagedAttrs.UnrollCount = C; } diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index cc278410d6e4f..bfeab9df9bcff 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -2519,6 +2519,12 @@ bool Parser::ParseSYCLLoopAttributes(ParsedAttributes &Attrs) { if (Attrs.begin()->getKind() != ParsedAttr::AT_SYCLIntelFPGAIVDep && Attrs.begin()->getKind() != ParsedAttr::AT_SYCLIntelFPGAII && Attrs.begin()->getKind() != ParsedAttr::AT_SYCLIntelFPGAMaxConcurrency && + Attrs.begin()->getKind() != ParsedAttr::AT_SYCLIntelFPGALoopCoalesce && + Attrs.begin()->getKind() != + ParsedAttr::AT_SYCLIntelFPGADisableLoopPipelining && + Attrs.begin()->getKind() != ParsedAttr::AT_SYCLIntelFPGAMaxInterleaving && + Attrs.begin()->getKind() != + ParsedAttr::AT_SYCLIntelFPGASpeculatedIterations && Attrs.begin()->getKind() != ParsedAttr::AT_LoopUnrollHint) return true; diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index c5f6730cf2c93..941dcdcc3d441 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -86,13 +86,31 @@ static Attr *handleIntelFPGALoopAttr(Sema &S, const ParsedAttr &A) { if (NumArgs == 0) { if (A.getKind() == ParsedAttr::AT_SYCLIntelFPGAII || - A.getKind() == ParsedAttr::AT_SYCLIntelFPGAMaxConcurrency) { + A.getKind() == ParsedAttr::AT_SYCLIntelFPGAMaxConcurrency || + A.getKind() == ParsedAttr::AT_SYCLIntelFPGAMaxInterleaving || + A.getKind() == ParsedAttr::AT_SYCLIntelFPGASpeculatedIterations) { S.Diag(A.getLoc(), diag::warn_attribute_too_few_arguments) << A << 1; return nullptr; } } - return S.BuildSYCLIntelFPGALoopAttr(A, A.getArgAsExpr(0)); + return S.BuildSYCLIntelFPGALoopAttr( + A, A.getNumArgs() ? A.getArgAsExpr(0) : nullptr); +} + +template <> +Attr *handleIntelFPGALoopAttr( + Sema &S, const ParsedAttr &A) { + if (S.LangOpts.SYCLIsHost) + return nullptr; + + unsigned NumArgs = A.getNumArgs(); + if (NumArgs > 0) { + S.Diag(A.getLoc(), diag::warn_attribute_too_many_arguments) << A << 0; + return nullptr; + } + + return new (S.Context) SYCLIntelFPGADisableLoopPipeliningAttr(S.Context, A); } static bool checkSYCLIntelFPGAIVDepSafeLen(Sema &S, llvm::APSInt &Value, @@ -177,10 +195,10 @@ Sema::BuildSYCLIntelFPGAIVDepAttr(const AttributeCommonInfo &CI, Expr *Expr1, template FPGALoopAttrT *Sema::BuildSYCLIntelFPGALoopAttr(const AttributeCommonInfo &A, Expr *E) { - if (!E) + if (!E && !(A.getParsedKind() == ParsedAttr::AT_SYCLIntelFPGALoopCoalesce)) return nullptr; - if (!E->isInstantiationDependent()) { + if (E && !E->isInstantiationDependent()) { llvm::APSInt ArgVal(32); if (!E->isIntegerConstantExpr(ArgVal, getASTContext())) { @@ -192,17 +210,22 @@ FPGALoopAttrT *Sema::BuildSYCLIntelFPGALoopAttr(const AttributeCommonInfo &A, int Val = ArgVal.getSExtValue(); - if (A.getParsedKind() == ParsedAttr::AT_SYCLIntelFPGAII) { + if (A.getParsedKind() == ParsedAttr::AT_SYCLIntelFPGAII || + A.getParsedKind() == ParsedAttr::AT_SYCLIntelFPGALoopCoalesce) { if (Val <= 0) { Diag(E->getExprLoc(), diag::err_attribute_requires_positive_integer) - << "'ii'" << /* positive */ 0; + << A.getAttrName() << /* positive */ 0; return nullptr; } } else if (A.getParsedKind() == - ParsedAttr::AT_SYCLIntelFPGAMaxConcurrency) { + ParsedAttr::AT_SYCLIntelFPGAMaxConcurrency || + A.getParsedKind() == + ParsedAttr::AT_SYCLIntelFPGAMaxInterleaving || + A.getParsedKind() == + ParsedAttr::AT_SYCLIntelFPGASpeculatedIterations) { if (Val < 0) { Diag(E->getExprLoc(), diag::err_attribute_requires_positive_integer) - << "'max_concurrency'" << /* non-negative */ 1; + << A.getAttrName() << /* non-negative */ 1; return nullptr; } } else { @@ -521,13 +544,56 @@ static void CheckForDuplicationSYCLLoopAttribute( } } +/// Diagnose mutually exclusive attributes when present on a given +/// declaration. Returns true if diagnosed. +template +static void CheckMutualExclusionSYCLLoopAttribute( + Sema &S, const SmallVectorImpl &Attrs, SourceRange Range) { + const LoopAttrT *LoopAttr = nullptr; + const LoopAttrT2 *LoopAttr2 = nullptr; + + for (const auto *I : Attrs) { + if (isa(I)) + LoopAttr = cast(I); + if (isa(I)) + LoopAttr2 = cast(I); + if (LoopAttr && LoopAttr2) { + S.Diag(Range.getBegin(), diag::err_attributes_are_not_compatible) + << LoopAttr->getSpelling() << LoopAttr2->getSpelling(); + } + } +} + static void CheckForIncompatibleSYCLLoopAttributes( Sema &S, const SmallVectorImpl &Attrs, SourceRange Range) { CheckForDuplicationSYCLLoopAttribute(S, Attrs, Range); CheckForDuplicationSYCLLoopAttribute( S, Attrs, Range); + CheckForDuplicationSYCLLoopAttribute(S, Attrs, + Range); + CheckForDuplicationSYCLLoopAttribute( + S, Attrs, Range); + CheckForDuplicationSYCLLoopAttribute( + S, Attrs, Range); + CheckForDuplicationSYCLLoopAttribute( + S, Attrs, Range); CheckForDuplicationSYCLLoopAttribute(S, Attrs, Range, false); + CheckMutualExclusionSYCLLoopAttribute( + S, Attrs, Range); + CheckMutualExclusionSYCLLoopAttribute( + S, Attrs, Range); + CheckMutualExclusionSYCLLoopAttribute(S, Attrs, Range); + CheckMutualExclusionSYCLLoopAttribute(S, Attrs, + Range); + CheckMutualExclusionSYCLLoopAttribute( + S, Attrs, Range); + CheckRedundantSYCLIntelFPGAIVDepAttrs(S, Attrs); } @@ -638,6 +704,15 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A, return handleIntelFPGALoopAttr(S, A); case ParsedAttr::AT_SYCLIntelFPGAMaxConcurrency: return handleIntelFPGALoopAttr(S, A); + case ParsedAttr::AT_SYCLIntelFPGALoopCoalesce: + return handleIntelFPGALoopAttr(S, A); + case ParsedAttr::AT_SYCLIntelFPGADisableLoopPipelining: + return handleIntelFPGALoopAttr(S, + A); + case ParsedAttr::AT_SYCLIntelFPGAMaxInterleaving: + return handleIntelFPGALoopAttr(S, A); + case ParsedAttr::AT_SYCLIntelFPGASpeculatedIterations: + return handleIntelFPGALoopAttr(S, A); case ParsedAttr::AT_OpenCLUnrollHint: case ParsedAttr::AT_LoopUnrollHint: return handleLoopUnrollHint(S, St, A, Range); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 9b6f4f4cbd2d6..fec169893d86b 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1058,6 +1058,14 @@ namespace { const SYCLIntelFPGAMaxConcurrencyAttr *MC); const LoopUnrollHintAttr * TransformLoopUnrollHintAttr(const LoopUnrollHintAttr *LU); + const SYCLIntelFPGALoopCoalesceAttr *TransformSYCLIntelFPGALoopCoalesceAttr( + const SYCLIntelFPGALoopCoalesceAttr *LC); + const SYCLIntelFPGAMaxInterleavingAttr * + TransformSYCLIntelFPGAMaxInterleavingAttr( + const SYCLIntelFPGAMaxInterleavingAttr *MI); + const SYCLIntelFPGASpeculatedIterationsAttr * + TransformSYCLIntelFPGASpeculatedIterationsAttr( + const SYCLIntelFPGASpeculatedIterationsAttr *SI); ExprResult TransformPredefinedExpr(PredefinedExpr *E); ExprResult TransformDeclRefExpr(DeclRefExpr *E); @@ -1524,6 +1532,31 @@ TemplateInstantiator::TransformSYCLIntelFPGAMaxConcurrencyAttr( *MC, TransformedExpr); } +const SYCLIntelFPGALoopCoalesceAttr * +TemplateInstantiator::TransformSYCLIntelFPGALoopCoalesceAttr( + const SYCLIntelFPGALoopCoalesceAttr *LC) { + Expr *TransformedExpr = getDerived().TransformExpr(LC->getNExpr()).get(); + return getSema().BuildSYCLIntelFPGALoopAttr( + *LC, TransformedExpr); +} + +const SYCLIntelFPGAMaxInterleavingAttr * +TemplateInstantiator::TransformSYCLIntelFPGAMaxInterleavingAttr( + const SYCLIntelFPGAMaxInterleavingAttr *MI) { + Expr *TransformedExpr = getDerived().TransformExpr(MI->getNExpr()).get(); + return getSema().BuildSYCLIntelFPGALoopAttr( + *MI, TransformedExpr); +} + +const SYCLIntelFPGASpeculatedIterationsAttr * +TemplateInstantiator::TransformSYCLIntelFPGASpeculatedIterationsAttr( + const SYCLIntelFPGASpeculatedIterationsAttr *SI) { + Expr *TransformedExpr = getDerived().TransformExpr(SI->getNExpr()).get(); + return getSema() + .BuildSYCLIntelFPGALoopAttr( + *SI, TransformedExpr); +} + const LoopUnrollHintAttr *TemplateInstantiator::TransformLoopUnrollHintAttr( const LoopUnrollHintAttr *LU) { Expr *TransformedExpr = diff --git a/clang/test/CodeGenSYCL/intel-fpga-loops.cpp b/clang/test/CodeGenSYCL/intel-fpga-loops.cpp index 4962f7200f0d4..0556feadcf7a2 100644 --- a/clang/test/CodeGenSYCL/intel-fpga-loops.cpp +++ b/clang/test/CodeGenSYCL/intel-fpga-loops.cpp @@ -1,9 +1,25 @@ // RUN: %clang_cc1 -triple spir64-unknown-unknown-sycldevice -disable-llvm-passes -fsycl-is-device -emit-llvm %s -o - | FileCheck %s -// CHECK: br label %for.cond, !llvm.loop ![[MD_II:[0-9]+]] -// CHECK: br label %for.cond2, !llvm.loop ![[MD_II_2:[0-9]+]] -// CHECK: br label %for.cond, !llvm.loop ![[MD_MC:[0-9]+]] -// CHECK: br label %for.cond2, !llvm.loop ![[MD_MC_2:[0-9]+]] +// CHECK: br label %for.cond, !llvm.loop ![[MD_DLP:[0-9]+]] +// CHECK: br label %for.cond, !llvm.loop ![[MD_II:[0-9]+]] +// CHECK: br label %for.cond2, !llvm.loop ![[MD_II_2:[0-9]+]] +// CHECK: br label %for.cond, !llvm.loop ![[MD_MC:[0-9]+]] +// CHECK: br label %for.cond2, !llvm.loop ![[MD_MC_2:[0-9]+]] +// CHECK: br label %for.cond, !llvm.loop ![[MD_LC:[0-9]+]] +// CHECK: br label %for.cond2, !llvm.loop ![[MD_LC_2:[0-9]+]] +// CHECK: br label %for.cond12, !llvm.loop ![[MD_LC_3:[0-9]+]] +// CHECK: br label %for.cond, !llvm.loop ![[MD_MI:[0-9]+]] +// CHECK: br label %for.cond2, !llvm.loop ![[MD_MI_2:[0-9]+]] +// CHECK: br label %for.cond, !llvm.loop ![[MD_SI:[0-9]+]] +// CHECK: br label %for.cond2, !llvm.loop ![[MD_SI_2:[0-9]+]] + +void disable_loop_pipelining() { + int a[10]; + // CHECK: ![[MD_DLP]] = distinct !{![[MD_DLP]], ![[MD_dlp:[0-9]+]]} + // CHECK-NEXT: ![[MD_dlp]] = !{!"llvm.loop.intel.pipelining.enable", i32 0} + [[intelfpga::disable_loop_pipelining]] for (int i = 0; i != 10; ++i) + a[i] = 0; +} template void ii() { @@ -35,6 +51,49 @@ void max_concurrency() { a[i] = 0; } +template +void loop_coalesce() { + int a[10]; + // CHECK: ![[MD_LC]] = distinct !{![[MD_LC]], ![[MD_loop_coalesce:[0-9]+]]} + // CHECK-NEXT: ![[MD_loop_coalesce]] = !{!"llvm.loop.coalesce.count", i32 2} + [[intelfpga::loop_coalesce(A)]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // CHECK: ![[MD_LC_2]] = distinct !{![[MD_LC_2]], ![[MD_loop_coalesce_2:[0-9]+]]} + // CHECK-NEXT: ![[MD_loop_coalesce_2]] = !{!"llvm.loop.coalesce.count", i32 4} + [[intelfpga::loop_coalesce(4)]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // CHECK: ![[MD_LC_3]] = distinct !{![[MD_LC_3]], ![[MD_loop_coalesce_3:[0-9]+]]} + // CHECK-NEXT: ![[MD_loop_coalesce_3]] = !{!"llvm.loop.coalesce.enable"} + [[intelfpga::loop_coalesce]] for (int i = 0; i != 10; ++i) + a[i] = 0; +} + +template +void max_interleaving() { + int a[10]; + // CHECK: ![[MD_MI]] = distinct !{![[MD_MI]], ![[MD_max_interleaving:[0-9]+]]} + // CHECK-NEXT: ![[MD_max_interleaving]] = !{!"llvm.loop.max_interleaving.count", i32 3} + [[intelfpga::max_interleaving(A)]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // CHECK: ![[MD_MI_2]] = distinct !{![[MD_MI_2]], ![[MD_max_interleaving_2:[0-9]+]]} + // CHECK-NEXT: ![[MD_max_interleaving_2]] = !{!"llvm.loop.max_interleaving.count", i32 2} + [[intelfpga::max_interleaving(2)]] for (int i = 0; i != 10; ++i) + a[i] = 0; +} + +template +void speculated_iterations() { + int a[10]; + // CHECK: ![[MD_SI]] = distinct !{![[MD_SI]], ![[MD_speculated_iterations:[0-9]+]]} + // CHECK-NEXT: ![[MD_speculated_iterations]] = !{!"llvm.loop.intel.speculated.iterations.count", i32 4} + [[intelfpga::speculated_iterations(A)]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // CHECK: ![[MD_SI_2]] = distinct !{![[MD_SI_2]], ![[MD_speculated_iterations_2:[0-9]+]]} + // CHECK-NEXT: ![[MD_speculated_iterations_2]] = !{!"llvm.loop.intel.speculated.iterations.count", i32 5} + [[intelfpga::speculated_iterations(5)]] for (int i = 0; i != 10; ++i) + a[i] = 0; +} + template __attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) { kernelFunc(); @@ -42,8 +101,12 @@ __attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) { int main() { kernel_single_task([]() { + disable_loop_pipelining(); ii<4>(); max_concurrency<0>(); + loop_coalesce<2>(); + max_interleaving<3>(); + speculated_iterations<4>(); }); return 0; } diff --git a/clang/test/SemaSYCL/intel-fpga-loops.cpp b/clang/test/SemaSYCL/intel-fpga-loops.cpp index 99150b1e63e8a..19111a163e127 100644 --- a/clang/test/SemaSYCL/intel-fpga-loops.cpp +++ b/clang/test/SemaSYCL/intel-fpga-loops.cpp @@ -16,6 +16,15 @@ void foo() { [[intelfpga::ivdep(arr)]] int e[10]; // expected-error@+1 {{intelfpga loop attributes must be applied to for, while, or do statements}} [[intelfpga::ivdep(arr, 2)]] int f[10]; + + // expected-error@+1 {{intelfpga loop attributes must be applied to for, while, or do statements}} + [[intelfpga::disable_loop_pipelining]] int g[10]; + // expected-error@+1 {{intelfpga loop attributes must be applied to for, while, or do statements}} + [[intelfpga::loop_coalesce(2)]] int h[10]; + // expected-error@+1 {{intelfpga loop attributes must be applied to for, while, or do statements}} + [[intelfpga::max_interleaving(4)]] int i[10]; + // expected-error@+1 {{intelfpga loop attributes must be applied to for, while, or do statements}} + [[intelfpga::speculated_iterations(6)]] int j[10]; } // Test for incorrect number of arguments for Intel FPGA loop attributes @@ -52,12 +61,34 @@ void boo() { // expected-error@+1 {{unknown argument to 'ivdep'. Expected integer or array variable}} [[intelfpga::ivdep(2, 3.0)]] for (int i = 0; i != 10; ++i) a[i] = 0; + + // expected-warning@+1 {{'disable_loop_pipelining' attribute takes no more than 0 arguments - attribute ignored}} + [[intelfpga::disable_loop_pipelining(0)]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // expected-warning@+1 {{'loop_coalesce' attribute takes no more than 1 argument - attribute ignored}} + [[intelfpga::loop_coalesce(2, 3)]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // expected-warning@+1 {{'max_interleaving' attribute takes at least 1 argument - attribute ignored}} + [[intelfpga::max_interleaving]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // expected-warning@+1 {{'max_interleaving' attribute takes no more than 1 argument - attribute ignored}} + [[intelfpga::max_interleaving(2, 4)]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // expected-warning@+1 {{'speculated_iterations' attribute takes at least 1 argument - attribute ignored}} + [[intelfpga::speculated_iterations]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // expected-warning@+1 {{'speculated_iterations' attribute takes no more than 1 argument - attribute ignored}} + [[intelfpga::speculated_iterations(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 + [[intelfpga::disable_loop_pipelining]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // no diagnostics are expected [[intelfpga::max_concurrency(0)]] for (int i = 0; i != 10; ++i) a[i] = 0; @@ -70,9 +101,17 @@ void goo() { for (int i = 0; i != 10; ++i) a[i] = 0; // expected-error@+1 {{'max_concurrency' attribute requires a non-negative integral compile time constant expression}} - [[intelfpga::max_concurrency(-1)]] - for (int i = 0; i != 10; ++i) - a[i] = 0; + [[intelfpga::max_concurrency(-1)]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // expected-error@+1 {{'loop_coalesce' attribute requires a positive integral compile time constant expression}} + [[intelfpga::loop_coalesce(0)]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // expected-error@+1 {{'max_interleaving' attribute requires a non-negative integral compile time constant expression}} + [[intelfpga::max_interleaving(-1)]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // expected-error@+1 {{'speculated_iterations' attribute requires a non-negative integral compile time constant expression}} + [[intelfpga::speculated_iterations(-1)]] for (int i = 0; i != 10; ++i) + a[i] = 0; // expected-error@+1 {{unknown argument to 'ivdep'. Expected integer or array variable}} [[intelfpga::ivdep("test123")]] for (int i = 0; i != 10; ++i) @@ -82,9 +121,17 @@ void goo() { for (int i = 0; i != 10; ++i) a[i] = 0; // expected-error@+1 {{'max_concurrency' attribute requires an integer constant}} - [[intelfpga::max_concurrency("test123")]] - for (int i = 0; i != 10; ++i) - a[i] = 0; + [[intelfpga::max_concurrency("test123")]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // expected-error@+1 {{'loop_coalesce' attribute requires an integer constant}} + [[intelfpga::loop_coalesce("test123")]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // expected-error@+1 {{'max_interleaving' attribute requires an integer constant}} + [[intelfpga::max_interleaving("test123")]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // expected-error@+1 {{'speculated_iterations' attribute requires an integer constant}} + [[intelfpga::speculated_iterations("test123")]] for (int i = 0; i != 10; ++i) + a[i] = 0; // expected-error@+1 {{unknown argument to 'ivdep'. Expected integer or array variable}} [[intelfpga::ivdep("test123")]] for (int i = 0; i != 10; ++i) a[i] = 0; @@ -135,9 +182,27 @@ void zoo() { [[intelfpga::ii(2)]] // expected-error@-1 {{duplicate Intel FPGA loop attribute 'ii'}} [[intelfpga::max_concurrency(2)]] - [[intelfpga::ii(2)]] - for (int i = 0; i != 10; ++i) - a[i] = 0; + [[intelfpga::ii(2)]] for (int i = 0; i != 10; ++i) + a[i] = 0; + [[intelfpga::disable_loop_pipelining]] + // expected-error@-1 {{duplicate Intel FPGA loop attribute 'disable_loop_pipelining'}} + [[intelfpga::disable_loop_pipelining]] for (int i = 0; i != 10; ++i) + a[i] = 0; + [[intelfpga::loop_coalesce(2)]] + // expected-error@-1 {{duplicate Intel FPGA loop attribute 'loop_coalesce'}} + [[intelfpga::max_interleaving(1)]] + [[intelfpga::loop_coalesce]] for (int i = 0; i != 10; ++i) + a[i] = 0; + [[intelfpga::max_interleaving(1)]] + // expected-error@-1 {{duplicate Intel FPGA loop attribute 'max_interleaving'}} + [[intelfpga::speculated_iterations(1)]] + [[intelfpga::max_interleaving(4)]] for (int i = 0; i != 10; ++i) + a[i] = 0; + [[intelfpga::speculated_iterations(1)]] + // expected-error@-1 {{duplicate Intel FPGA loop attribute 'speculated_iterations'}} + [[intelfpga::loop_coalesce]] + [[intelfpga::speculated_iterations(2)]] for (int i = 0; i != 10; ++i) + a[i] = 0; [[intelfpga::ivdep]] // expected-warning@+2 {{ignoring redundant Intel FPGA loop attribute 'ivdep': safelen INF >= safelen INF}} @@ -195,6 +260,35 @@ void zoo() { a[i] = 0; } +// Test for Intel FPGA loop attributes compatibility +void loop_attrs_compatibility() { + int a[10]; + // no diagnostics are expected + [[intelfpga::disable_loop_pipelining]] + [[intelfpga::loop_coalesce]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // expected-error@+1 {{disable_loop_pipelining and max_interleaving attributes are not compatible}} + [[intelfpga::disable_loop_pipelining]] + [[intelfpga::max_interleaving(0)]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // expected-error@+1 {{disable_loop_pipelining and speculated_iterations attributes are not compatible}} + [[intelfpga::speculated_iterations(0)]] + [[intelfpga::disable_loop_pipelining]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // expected-error@+1 {{disable_loop_pipelining and max_concurrency attributes are not compatible}} + [[intelfpga::disable_loop_pipelining]] + [[intelfpga::max_concurrency(0)]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // expected-error@+1 {{disable_loop_pipelining and ii attributes are not compatible}} + [[intelfpga::ii(10)]] + [[intelfpga::disable_loop_pipelining]] for (int i = 0; i != 10; ++i) + a[i] = 0; + // expected-error@+1 {{disable_loop_pipelining and ivdep attributes are not compatible}} + [[intelfpga::disable_loop_pipelining]] + [[intelfpga::ivdep]] for (int i = 0; i != 10; ++i) + a[i] = 0; +} + template void ivdep_dependent() { int a[10]; @@ -270,6 +364,7 @@ int main() { boo(); goo(); zoo(); + loop_attrs_compatibility(); ivdep_dependent<4, 2, 1>(); //expected-note@-1 +{{in instantiation of function template specialization}} ivdep_dependent<2, 4, -1>();