Index: clang/docs/LanguageExtensions.rst =================================================================== --- clang/docs/LanguageExtensions.rst +++ clang/docs/LanguageExtensions.rst @@ -3028,8 +3028,18 @@ ... } -The vector width is specified by ``vectorize_width(_value_)`` and the interleave -count is specified by ``interleave_count(_value_)``, where +The vector width is specified by +``vectorize_width(_value_[, fixed|scalable])``, where _value_ is a positive +integer and the type of vectorization can be specified with an optional +second parameter. In this case 'fixed' is the default and refers to fixed width +vectorization, whereas 'scalable' indicates the compiler should use scalable +vectors instead. In another variation of ``vectorize_width(fixed|scalable)`` +the user can hint at the type of vectorization to use without specifying +the exact width. In both variants of the pragma if the target does not support +scalable vectors then the vectorizer may decide to fall back on fixed width +vectorization as the most profitable option. + +The interleave count is specified by ``interleave_count(_value_)``, where _value_ is a positive integer. This is useful for specifying the optimal width/count of the set of target architectures supported by your application. Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -3353,8 +3353,8 @@ "PipelineDisabled", "PipelineInitiationInterval", "Distribute", "VectorizePredicate"]>, EnumArgument<"State", "LoopHintState", - ["enable", "disable", "numeric", "assume_safety", "full"], - ["Enable", "Disable", "Numeric", "AssumeSafety", "Full"]>, + ["enable", "disable", "numeric", "fixed_width", "scalable_width", "assume_safety", "full"], + ["Enable", "Disable", "Numeric", "FixedWidth", "ScalableWidth", "AssumeSafety", "Full"]>, ExprArgument<"Value">]; let AdditionalMembers = [{ Index: clang/include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticParseKinds.td +++ clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1386,6 +1386,12 @@ "%select{invalid|missing}0 option%select{ %1|}0; expected vectorize, " "vectorize_width, interleave, interleave_count, unroll, unroll_count, " "pipeline, pipeline_initiation_interval, vectorize_predicate, or distribute">; +def err_pragma_loop_invalid_vectorize_option : Error< + "vectorize_width loop hint malformed; use vectorize_width(X, 'fixed' or 'scalable') " + "where X is an integer, or vectorize_width('fixed' or 'scalable')">; +def note_pragma_loop_invalid_vectorize_option : Note< + "vectorize_width loop hint malformed; use vectorize_width(X, 'fixed' or 'scalable') " + "where X is an integer, or vectorize_width('fixed' or 'scalable')">; def err_pragma_fp_invalid_option : Error< "%select{invalid|missing}0 option%select{ %1|}0; expected 'contract', 'reassociate' or 'exceptions'">; Index: clang/lib/AST/AttrImpl.cpp =================================================================== --- clang/lib/AST/AttrImpl.cpp +++ clang/lib/AST/AttrImpl.cpp @@ -42,7 +42,11 @@ OS << "("; if (state == Numeric) value->printPretty(OS, nullptr, Policy); - else if (state == Enable) + else if (state == FixedWidth || state == ScalableWidth) { + value->printPretty(OS, nullptr, Policy); + if (state == ScalableWidth) + OS << ", scalable"; + } else if (state == Enable) OS << "enable"; else if (state == Full) OS << "full"; Index: clang/lib/CodeGen/CGLoopInfo.h =================================================================== --- clang/lib/CodeGen/CGLoopInfo.h +++ clang/lib/CodeGen/CGLoopInfo.h @@ -58,6 +58,9 @@ /// Value for llvm.loop.vectorize.width metadata. unsigned VectorizeWidth; + // Value for llvm.loop.vectorize.scalable.enable + LVEnableState VectorizeScalable; + /// Value for llvm.loop.interleave.count metadata. unsigned InterleaveCount; @@ -258,6 +261,10 @@ /// Set the vectorize width for the next loop pushed. void setVectorizeWidth(unsigned W) { StagedAttrs.VectorizeWidth = W; } + void setVectorizeScalable(const LoopAttributes::LVEnableState &State) { + StagedAttrs.VectorizeScalable = State; + } + /// Set the interleave count for the next loop pushed. void setInterleaveCount(unsigned C) { StagedAttrs.InterleaveCount = C; } Index: clang/lib/CodeGen/CGLoopInfo.cpp =================================================================== --- clang/lib/CodeGen/CGLoopInfo.cpp +++ clang/lib/CodeGen/CGLoopInfo.cpp @@ -217,7 +217,8 @@ Enabled = false; else if (Attrs.VectorizeEnable != LoopAttributes::Unspecified || Attrs.VectorizePredicateEnable != LoopAttributes::Unspecified || - Attrs.InterleaveCount != 0 || Attrs.VectorizeWidth != 0) + Attrs.InterleaveCount != 0 || Attrs.VectorizeWidth != 0 || + Attrs.VectorizeScalable != LoopAttributes::Unspecified) Enabled = true; if (Enabled != true) { @@ -271,6 +272,16 @@ MDString::get(Ctx, "llvm.loop.vectorize.width"), ConstantAsMetadata::get(ConstantInt::get(llvm::Type::getInt32Ty(Ctx), Attrs.VectorizeWidth))}; + + Args.push_back(MDNode::get(Ctx, Vals)); + } + + if (Attrs.VectorizeScalable != LoopAttributes::Unspecified) { + bool IsScalable = Attrs.VectorizeScalable == LoopAttributes::Enable; + Metadata *Vals[] = { + MDString::get(Ctx, "llvm.loop.vectorize.scalable.enable"), + ConstantAsMetadata::get( + ConstantInt::get(llvm::Type::getInt1Ty(Ctx), IsScalable))}; Args.push_back(MDNode::get(Ctx, Vals)); } @@ -288,8 +299,8 @@ // 2) it is implied when vectorize.predicate is set, or // 3) it is implied when vectorize.width is set. if (Attrs.VectorizeEnable != LoopAttributes::Unspecified || - IsVectorPredicateEnabled || - Attrs.VectorizeWidth > 1 ) { + IsVectorPredicateEnabled || Attrs.VectorizeWidth > 1 || + Attrs.VectorizeScalable != LoopAttributes::Unspecified) { bool AttrVal = Attrs.VectorizeEnable != LoopAttributes::Disable; Args.push_back( MDNode::get(Ctx, {MDString::get(Ctx, "llvm.loop.vectorize.enable"), @@ -433,13 +444,15 @@ UnrollEnable(LoopAttributes::Unspecified), UnrollAndJamEnable(LoopAttributes::Unspecified), VectorizePredicateEnable(LoopAttributes::Unspecified), VectorizeWidth(0), - InterleaveCount(0), UnrollCount(0), UnrollAndJamCount(0), + VectorizeScalable(LoopAttributes::Unspecified), InterleaveCount(0), + UnrollCount(0), UnrollAndJamCount(0), DistributeEnable(LoopAttributes::Unspecified), PipelineDisabled(false), PipelineInitiationInterval(0), MustProgress(false) {} void LoopAttributes::clear() { IsParallel = false; VectorizeWidth = 0; + VectorizeScalable = LoopAttributes::Unspecified; InterleaveCount = 0; UnrollCount = 0; UnrollAndJamCount = 0; @@ -466,6 +479,7 @@ } if (!Attrs.IsParallel && Attrs.VectorizeWidth == 0 && + Attrs.VectorizeScalable == LoopAttributes::Unspecified && Attrs.InterleaveCount == 0 && Attrs.UnrollCount == 0 && Attrs.UnrollAndJamCount == 0 && !Attrs.PipelineDisabled && Attrs.PipelineInitiationInterval == 0 && @@ -501,6 +515,7 @@ BeforeJam.IsParallel = AfterJam.IsParallel = Attrs.IsParallel; BeforeJam.VectorizeWidth = Attrs.VectorizeWidth; + BeforeJam.VectorizeScalable = Attrs.VectorizeScalable; BeforeJam.InterleaveCount = Attrs.InterleaveCount; BeforeJam.VectorizeEnable = Attrs.VectorizeEnable; BeforeJam.DistributeEnable = Attrs.DistributeEnable; @@ -543,7 +558,8 @@ SmallVector BeforeLoopProperties; if (BeforeJam.VectorizeEnable != LoopAttributes::Unspecified || BeforeJam.VectorizePredicateEnable != LoopAttributes::Unspecified || - BeforeJam.InterleaveCount != 0 || BeforeJam.VectorizeWidth != 0) + BeforeJam.InterleaveCount != 0 || BeforeJam.VectorizeWidth != 0 || + BeforeJam.VectorizeScalable == LoopAttributes::Enable) BeforeLoopProperties.push_back( MDNode::get(Ctx, MDString::get(Ctx, "llvm.loop.isvectorized"))); @@ -620,6 +636,7 @@ case LoopHintAttr::Vectorize: // Disable vectorization by specifying a width of 1. setVectorizeWidth(1); + setVectorizeScalable(LoopAttributes::Unspecified); break; case LoopHintAttr::Interleave: // Disable interleaving by speciyfing a count of 1. @@ -721,11 +738,30 @@ break; } break; - case LoopHintAttr::Numeric: + case LoopHintAttr::FixedWidth: + case LoopHintAttr::ScalableWidth: switch (Option) { case LoopHintAttr::VectorizeWidth: - setVectorizeWidth(ValueInt); + setVectorizeScalable(State == LoopHintAttr::ScalableWidth + ? LoopAttributes::Enable + : LoopAttributes::Disable); + if (LH->getValue()) { + setVectorizeWidth(ValueInt); + // If the user set vectorize_width(1) or vectorize_width(1, fixed) + // they effectively want vectorization disabled. We leave the + // scalable flag unspecified in this case to avoid setting the + // vectorize.enable flag later on. + if (ValueInt == 1 && State == LoopHintAttr::FixedWidth) + setVectorizeScalable(LoopAttributes::Unspecified); + } break; + default: + llvm_unreachable("Options cannot be used with 'scalable' hint."); + break; + } + break; + case LoopHintAttr::Numeric: + switch (Option) { case LoopHintAttr::InterleaveCount: setInterleaveCount(ValueInt); break; Index: clang/lib/Parse/ParsePragma.cpp =================================================================== --- clang/lib/Parse/ParsePragma.cpp +++ clang/lib/Parse/ParsePragma.cpp @@ -1187,12 +1187,79 @@ Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << PragmaLoopHintString(Info->PragmaName, Info->Option); Hint.StateLoc = IdentifierLoc::create(Actions.Context, StateLoc, StateInfo); + } else if (OptionInfo && OptionInfo->getName() == "vectorize_width") { + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/false, + /*IsReinject=*/false); + ConsumeAnnotationToken(); + + SourceLocation StateLoc = Toks[0].getLocation(); + IdentifierInfo *StateInfo = Toks[0].getIdentifierInfo(); + StringRef IsScalableStr = StateInfo ? StateInfo->getName() : ""; + + // Look for vectorize_width(fixed|scalable) + if (IsScalableStr == "scalable" || IsScalableStr == "fixed") { + PP.Lex(Tok); // Identifier + + if (Toks.size() > 2) { + Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) + << PragmaLoopHintString(Info->PragmaName, Info->Option); + while (Tok.isNot(tok::eof)) + ConsumeAnyToken(); + } + + Hint.StateLoc = + IdentifierLoc::create(Actions.Context, StateLoc, StateInfo); + + ConsumeToken(); // Consume the constant expression eof terminator. + } else { + // Enter constant expression including eof terminator into token stream. + ExprResult R = ParseConstantExpression(); + + if (R.isInvalid() && !Tok.is(tok::comma)) + Diag(Toks[0].getLocation(), + diag::note_pragma_loop_invalid_vectorize_option); + + bool Arg2Error = false; + if (Tok.is(tok::comma)) { + PP.Lex(Tok); // , + + StateInfo = Tok.getIdentifierInfo(); + IsScalableStr = StateInfo->getName(); + + if (IsScalableStr != "scalable" && IsScalableStr != "fixed") { + Diag(Tok.getLocation(), + diag::err_pragma_loop_invalid_vectorize_option); + Arg2Error = true; + } else + Hint.StateLoc = + IdentifierLoc::create(Actions.Context, StateLoc, StateInfo); + + PP.Lex(Tok); // Identifier + } + + // Tokens following an error in an ill-formed constant expression will + // remain in the token stream and must be removed. + if (Tok.isNot(tok::eof)) { + Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) + << PragmaLoopHintString(Info->PragmaName, Info->Option); + while (Tok.isNot(tok::eof)) + ConsumeAnyToken(); + } + + ConsumeToken(); // Consume the constant expression eof terminator. + + if (Arg2Error || R.isInvalid() || + Actions.CheckLoopHintExpr(R.get(), Toks[0].getLocation())) + return false; + + // Argument is a constant expression with an integer type. + Hint.ValueExpr = R.get(); + } } else { // Enter constant expression including eof terminator into token stream. PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/false, /*IsReinject=*/false); ConsumeAnnotationToken(); - ExprResult R = ParseConstantExpression(); // Tokens following an error in an ill-formed constant expression will Index: clang/lib/Sema/SemaStmtAttr.cpp =================================================================== --- clang/lib/Sema/SemaStmtAttr.cpp +++ clang/lib/Sema/SemaStmtAttr.cpp @@ -10,13 +10,14 @@ // //===----------------------------------------------------------------------===// -#include "clang/AST/EvaluatedExprVisitor.h" -#include "clang/Sema/SemaInternal.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/EvaluatedExprVisitor.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Sema/DelayedDiagnostic.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaInternal.h" #include "llvm/ADT/StringExtras.h" using namespace clang; @@ -139,10 +140,18 @@ LoopHintAttr::PipelineInitiationInterval) .Case("distribute", LoopHintAttr::Distribute) .Default(LoopHintAttr::Vectorize); - if (Option == LoopHintAttr::VectorizeWidth || - Option == LoopHintAttr::InterleaveCount || - Option == LoopHintAttr::UnrollCount || - Option == LoopHintAttr::PipelineInitiationInterval) { + if (Option == LoopHintAttr::VectorizeWidth) { + assert((ValueExpr || (StateLoc && StateLoc->Ident)) && + "Attribute must have a valid value expression or argument."); + if (ValueExpr && S.CheckLoopHintExpr(ValueExpr, St->getBeginLoc())) + return nullptr; + if (StateLoc && StateLoc->Ident && StateLoc->Ident->isStr("scalable")) + State = LoopHintAttr::ScalableWidth; + else + State = LoopHintAttr::FixedWidth; + } else if (Option == LoopHintAttr::InterleaveCount || + Option == LoopHintAttr::UnrollCount || + Option == LoopHintAttr::PipelineInitiationInterval) { assert(ValueExpr && "Attribute must have a valid value expression."); if (S.CheckLoopHintExpr(ValueExpr, St->getBeginLoc())) return nullptr; Index: clang/test/CodeGenCXX/pragma-loop-pr27643.cpp =================================================================== --- clang/test/CodeGenCXX/pragma-loop-pr27643.cpp +++ clang/test/CodeGenCXX/pragma-loop-pr27643.cpp @@ -44,9 +44,10 @@ // CHECK: ![[VEC_WIDTH_1]] = !{!"llvm.loop.vectorize.width", i32 1} // CHECK: ![[VEC_ENABLE]] = !{!"llvm.loop.vectorize.enable", i1 true} -// CHECK: ![[LOOP2]] = distinct !{![[LOOP2]], [[MP]], ![[VEC_WIDTH_2:.*]], ![[VEC_ENABLE]]} +// CHECK: ![[LOOP2]] = distinct !{![[LOOP2]], [[MP]], ![[VEC_WIDTH_2:.*]], ![[FIXED_WIDTH:.*]], ![[VEC_ENABLE]]} // CHECK: ![[VEC_WIDTH_2]] = !{!"llvm.loop.vectorize.width", i32 2} +// CHECK: ![[FIXED_WIDTH]] = !{!"llvm.loop.vectorize.scalable.enable", i1 false} // CHECK: ![[LOOP3]] = distinct !{![[LOOP3]], [[MP]], ![[VEC_WIDTH_1]]} -// CHECK: ![[LOOP4]] = distinct !{![[LOOP4]], [[MP]], ![[VEC_WIDTH_2]], ![[VEC_ENABLE]]} +// CHECK: ![[LOOP4]] = distinct !{![[LOOP4]], [[MP]], ![[VEC_WIDTH_2]], ![[FIXED_WIDTH]], ![[VEC_ENABLE]]} Index: clang/test/CodeGenCXX/pragma-loop.cpp =================================================================== --- clang/test/CodeGenCXX/pragma-loop.cpp +++ clang/test/CodeGenCXX/pragma-loop.cpp @@ -158,51 +158,88 @@ for_template_constant_expression_test(List, Length); } +// Verify for loop is performing fixed width vectorization +void for_test_fixed_16(int *List, int Length) { +#pragma clang loop vectorize_width(16, fixed) interleave_count(4) unroll(disable) distribute(disable) + for (int i = 0; i < Length; i++) { + // CHECK: br label {{.*}}, !llvm.loop ![[LOOP_15:.*]] + List[i] = i * 2; + } +} + +// Verify for loop rejects scalable vectorization due to lack of target support +void for_test_scalable_16(int *List, int Length) { +#pragma clang loop vectorize_width(16, scalable) interleave_count(4) unroll(disable) distribute(disable) + for (int i = 0; i < Length; i++) { + // CHECK: br label {{.*}}, !llvm.loop ![[LOOP_16:.*]] + List[i] = i * 2; + } +} + +// Verify for loop is performing fixed width vectorization +void for_test_fixed(int *List, int Length) { +#pragma clang loop vectorize_width(fixed) interleave_count(4) unroll(disable) distribute(disable) + for (int i = 0; i < Length; i++) { + // CHECK: br label {{.*}}, !llvm.loop ![[LOOP_17:.*]] + List[i] = i * 2; + } +} + +// Verify for loop rejects scalable vectorization due to lack of target support +void for_test_scalable(int *List, int Length) { +#pragma clang loop vectorize_width(scalable) interleave_count(4) unroll(disable) distribute(disable) + for (int i = 0; i < Length; i++) { + // CHECK: br label {{.*}}, !llvm.loop ![[LOOP_18:.*]] + List[i] = i * 2; + } +} + // CHECK: ![[LOOP_1]] = distinct !{![[LOOP_1]], [[MP:![0-9]+]], ![[UNROLL_FULL:.*]]} // CHECK: ![[UNROLL_FULL]] = !{!"llvm.loop.unroll.full"} -// CHECK: ![[LOOP_2]] = distinct !{![[LOOP_2]], [[MP]], ![[UNROLL_DISABLE:.*]], ![[DISTRIBUTE_DISABLE:.*]], ![[WIDTH_8:.*]], ![[INTERLEAVE_4:.*]], ![[VECTORIZE_ENABLE:.*]]} +// CHECK: ![[LOOP_2]] = distinct !{![[LOOP_2]], [[MP]], ![[UNROLL_DISABLE:.*]], ![[DISTRIBUTE_DISABLE:.*]], ![[WIDTH_8:.*]], ![[FIXED_VEC:.*]], ![[INTERLEAVE_4:.*]], ![[VECTORIZE_ENABLE:.*]]} // CHECK: ![[UNROLL_DISABLE]] = !{!"llvm.loop.unroll.disable"} // CHECK: ![[DISTRIBUTE_DISABLE]] = !{!"llvm.loop.distribute.enable", i1 false} // CHECK: ![[WIDTH_8]] = !{!"llvm.loop.vectorize.width", i32 8} +// CHECK: ![[FIXED_VEC]] = !{!"llvm.loop.vectorize.scalable.enable", i1 false} // CHECK: ![[INTERLEAVE_4]] = !{!"llvm.loop.interleave.count", i32 4} // CHECK: ![[VECTORIZE_ENABLE]] = !{!"llvm.loop.vectorize.enable", i1 true} -// CHECK: ![[LOOP_3]] = distinct !{![[LOOP_3]], ![[INTERLEAVE_4:.*]], ![[VECTORIZE_ENABLE]], ![[FOLLOWUP_VECTOR_3:.*]]} +// CHECK: ![[LOOP_3]] = distinct !{![[LOOP_3]], [[MP]], ![[INTERLEAVE_4:.*]], ![[VECTORIZE_ENABLE]], ![[FOLLOWUP_VECTOR_3:.*]]} // CHECK: ![[FOLLOWUP_VECTOR_3]] = !{!"llvm.loop.vectorize.followup_all", ![[AFTER_VECTOR_3:.*]]} // CHECK: ![[AFTER_VECTOR_3]] = distinct !{![[AFTER_VECTOR_3]], [[MP]], ![[ISVECTORIZED:.*]], ![[UNROLL_8:.*]]} // CHECK: ![[ISVECTORIZED]] = !{!"llvm.loop.isvectorized"} // CHECK: ![[UNROLL_8]] = !{!"llvm.loop.unroll.count", i32 8} -// CHECK: ![[LOOP_4]] = distinct !{![[LOOP_4]], ![[WIDTH_2:.*]], ![[INTERLEAVE_2:.*]], ![[VECTORIZE_ENABLE]]} +// CHECK: ![[LOOP_4]] = distinct !{![[LOOP_4]], ![[WIDTH_2:.*]], ![[FIXED_VEC]], ![[INTERLEAVE_2:.*]], ![[VECTORIZE_ENABLE]]} // CHECK: ![[WIDTH_2]] = !{!"llvm.loop.vectorize.width", i32 2} // CHECK: ![[INTERLEAVE_2]] = !{!"llvm.loop.interleave.count", i32 2} // CHECK: ![[LOOP_5]] = distinct !{![[LOOP_5]], ![[UNROLL_DISABLE:.*]], ![[DISTRIBUTE_DISABLE:.*]], ![[WIDTH_1:.*]]} // CHECK: ![[WIDTH_1]] = !{!"llvm.loop.vectorize.width", i32 1} -// CHECK: ![[LOOP_6]] = distinct !{![[LOOP_6]], ![[WIDTH_2:.*]], ![[INTERLEAVE_2:.*]], ![[FOLLOWUP_VECTOR_6:.*]]} +// CHECK: ![[LOOP_6]] = distinct !{![[LOOP_6]], [[MP]], ![[WIDTH_2:.*]], ![[FIXED_VEC]], ![[INTERLEAVE_2:.*]], ![[FOLLOWUP_VECTOR_6:.*]]} // CHECK: ![[FOLLOWUP_VECTOR_6]] = !{!"llvm.loop.vectorize.followup_all", ![[AFTER_VECTOR_6:.*]]} // CHECK: ![[AFTER_VECTOR_6]] = distinct !{![[AFTER_VECTOR_6]], ![[ISVECTORIZED:.*]], ![[UNROLL_8:.*]]} -// CHECK: ![[LOOP_7]] = distinct !{![[LOOP_7]], [[MP]], ![[WIDTH_5:.*]], ![[VECTORIZE_ENABLE]]} +// CHECK: ![[LOOP_7]] = distinct !{![[LOOP_7]], [[MP]], ![[WIDTH_5:.*]], ![[FIXED_VEC]], ![[VECTORIZE_ENABLE]]} // CHECK: ![[WIDTH_5]] = !{!"llvm.loop.vectorize.width", i32 5} -// CHECK: ![[LOOP_8]] = distinct !{![[LOOP_8]], ![[WIDTH_5:.*]]} +// CHECK: ![[LOOP_8]] = distinct !{![[LOOP_8]], [[MP]], ![[WIDTH_5:.*]], ![[FIXED_VEC]], ![[VECTORIZE_ENABLE]]} -// CHECK: ![[LOOP_9]] = distinct !{![[LOOP_9]], ![[WIDTH_8:.*]], ![[INTERLEAVE_8:.*]], ![[FOLLOWUP_VECTOR_9:.*]]} +// CHECK: ![[LOOP_9]] = distinct !{![[LOOP_9]], ![[WIDTH_8:.*]], ![[FIXED_VEC]], ![[INTERLEAVE_8:.*]], ![[FOLLOWUP_VECTOR_9:.*]]} // CHECK: ![[FOLLOWUP_VECTOR_9]] = !{!"llvm.loop.vectorize.followup_all", ![[AFTER_VECTOR_9:.*]]} // CHECK: ![[AFTER_VECTOR_9]] = distinct !{![[AFTER_VECTOR_9]], ![[ISVECTORIZED:.*]], ![[UNROLL_8:.*]]} -// CHECK: ![[LOOP_10]] = distinct !{![[LOOP_10]], ![[WIDTH_2:.*]], ![[INTERLEAVE_2:.*]], ![[FOLLOWUP_VECTOR_10:.*]]} +// CHECK: ![[LOOP_10]] = distinct !{![[LOOP_10]], ![[WIDTH_2:.*]], ![[FIXED_VEC]], ![[INTERLEAVE_2:.*]], ![[FOLLOWUP_VECTOR_10:.*]]} // CHECK: ![[FOLLOWUP_VECTOR_10]] = !{!"llvm.loop.vectorize.followup_all", ![[AFTER_VECTOR_10:.*]]} // CHECK: ![[AFTER_VECTOR_10]] = distinct !{![[AFTER_VECTOR_10]], ![[ISVECTORIZED:.*]], ![[UNROLL_8:.*]]} -// CHECK: ![[LOOP_11]] = distinct !{![[LOOP_11]], ![[WIDTH_2:.*]], ![[INTERLEAVE_4:.*]], ![[FOLLOWUP_VECTOR_11:.*]]} +// CHECK: ![[LOOP_11]] = distinct !{![[LOOP_11]], ![[WIDTH_2:.*]], ![[FIXED_VEC]], ![[INTERLEAVE_4:.*]], ![[FOLLOWUP_VECTOR_11:.*]]} // CHECK: ![[FOLLOWUP_VECTOR_11]] = !{!"llvm.loop.vectorize.followup_all", ![[AFTER_VECTOR_11:.*]]} // CHECK: ![[AFTER_VECTOR_11]] = distinct !{![[AFTER_VECTOR_11]], ![[ISVECTORIZED:.*]], ![[UNROLL_8:.*]]} -// CHECK: ![[LOOP_12]] = distinct !{![[LOOP_12]], ![[WIDTH_6:.*]], ![[INTERLEAVE_10:.*]], ![[FOLLOWUP_VECTOR_12:.*]]} +// CHECK: ![[LOOP_12]] = distinct !{![[LOOP_12]], ![[WIDTH_6:.*]], ![[FIXED_VEC]], ![[INTERLEAVE_10:.*]], ![[FOLLOWUP_VECTOR_12:.*]]} // CHECK: ![[FOLLOWUP_VECTOR_12]] = !{!"llvm.loop.vectorize.followup_all", ![[AFTER_VECTOR_12:.*]]} // CHECK: ![[AFTER_VECTOR_12]] = distinct !{![[AFTER_VECTOR_12]], ![[ISVECTORIZED:.*]], ![[UNROLL_24:.*]]} // CHECK: ![[UNROLL_24]] = !{!"llvm.loop.unroll.count", i32 24} @@ -213,5 +250,14 @@ // CHECK: ![[AFTER_VECTOR_13]] = distinct !{![[AFTER_VECTOR_13]], ![[ISVECTORIZED:.*]], ![[UNROLL_32:.*]]} // CHECK: ![[UNROLL_32]] = !{!"llvm.loop.unroll.count", i32 32} -// CHECK: ![[LOOP_14]] = distinct !{![[LOOP_14]], [[MP]], ![[WIDTH_10:.*]], ![[VECTORIZE_ENABLE]]} +// CHECK: ![[LOOP_14]] = distinct !{![[LOOP_14]], [[MP]], ![[WIDTH_10:.*]], ![[FIXED_VEC]], ![[VECTORIZE_ENABLE]]} // CHECK: ![[WIDTH_10]] = !{!"llvm.loop.vectorize.width", i32 10} + +// CHECK: ![[LOOP_15]] = distinct !{![[LOOP_15]], ![[UNROLL_DISABLE:.*]], ![[DISTRIBUTE_DISABLE:.*]], ![[WIDTH_16:.*]], ![[FIXED_VEC]], ![[INTERLEAVE_4:.*]], ![[VECTORIZE_ENABLE:.*]]} +// CHECK: ![[WIDTH_16]] = !{!"llvm.loop.vectorize.width", i32 16} + +// CHECK: ![[LOOP_16]] = distinct !{![[LOOP_16]], ![[UNROLL_DISABLE:.*]], ![[DISTRIBUTE_DISABLE:.*]], ![[WIDTH_16]], ![[SCALABLE_VEC:.*]], ![[INTERLEAVE_4:.*]], ![[VECTORIZE_ENABLE:.*]]} +// CHECK: ![[SCALABLE_VEC]] = !{!"llvm.loop.vectorize.scalable.enable", i1 true} + +// CHECK: ![[LOOP_17]] = distinct !{![[LOOP_17]], ![[UNROLL_DISABLE:.*]], ![[DISTRIBUTE_DISABLE:.*]], ![[FIXED_VEC]], ![[INTERLEAVE_4:.*]], ![[VECTORIZE_ENABLE:.*]]} +// CHECK: ![[LOOP_18]] = distinct !{![[LOOP_18]], ![[UNROLL_DISABLE:.*]], ![[DISTRIBUTE_DISABLE:.*]], ![[SCALABLE_VEC]], ![[INTERLEAVE_4:.*]], ![[VECTORIZE_ENABLE:.*]]} Index: clang/test/Parser/pragma-loop.cpp =================================================================== --- clang/test/Parser/pragma-loop.cpp +++ clang/test/Parser/pragma-loop.cpp @@ -60,7 +60,8 @@ template void test_nontype_template_badarg(int *List, int Length) { - /* expected-error {{use of undeclared identifier 'Vec'}} */ #pragma clang loop vectorize_width(Vec) interleave_count(I) + /* expected-error {{use of undeclared identifier 'Vec'}} */ #pragma clang loop vectorize_width(Vec) interleave_count(I) /* + expected-note {{vectorize_width loop hint malformed; use vectorize_width(X, 'fixed' or 'scalable') where X is an integer, or vectorize_width('fixed' or 'scalable')}} */ /* expected-error {{use of undeclared identifier 'Int'}} */ #pragma clang loop vectorize_width(V) interleave_count(Int) for (int i = 0; i < Length; i++) { List[i] = i; @@ -189,12 +190,15 @@ /* expected-warning {{extra tokens at end of '#pragma clang loop'}} */ #pragma clang loop vectorize_width(1 +) 1 /* expected-warning {{extra tokens at end of '#pragma clang loop'}} */ #pragma clang loop vectorize_width(1) +1 const int VV = 4; -/* expected-error {{expected expression}} */ #pragma clang loop vectorize_width(VV +/ 2) -/* expected-error {{use of undeclared identifier 'undefined'}} */ #pragma clang loop vectorize_width(VV+undefined) +/* expected-error {{expected expression}} */ #pragma clang loop vectorize_width(VV +/ 2) /* + expected-note {{vectorize_width loop hint malformed; use vectorize_width(X, 'fixed' or 'scalable') where X is an integer, or vectorize_width('fixed' or 'scalable')}} */ +/* expected-error {{use of undeclared identifier 'undefined'}} */ #pragma clang loop vectorize_width(VV+undefined) /* + expected-note {{vectorize_width loop hint malformed; use vectorize_width(X, 'fixed' or 'scalable') where X is an integer, or vectorize_width('fixed' or 'scalable')}} */ /* expected-error {{expected ')'}} */ #pragma clang loop vectorize_width(1+(^*/2 * () /* expected-warning {{extra tokens at end of '#pragma clang loop' - ignored}} */ #pragma clang loop vectorize_width(1+(-0[0])))))) -/* expected-error {{use of undeclared identifier 'badvalue'}} */ #pragma clang loop vectorize_width(badvalue) +/* expected-error {{use of undeclared identifier 'badvalue'}} */ #pragma clang loop vectorize_width(badvalue) /* + expected-note {{vectorize_width loop hint malformed; use vectorize_width(X, 'fixed' or 'scalable') where X is an integer, or vectorize_width('fixed' or 'scalable')}} */ /* expected-error {{use of undeclared identifier 'badvalue'}} */ #pragma clang loop interleave_count(badvalue) /* expected-error {{use of undeclared identifier 'badvalue'}} */ #pragma clang loop unroll_count(badvalue) while (i-6 < Length) { @@ -215,7 +219,7 @@ /* expected-error {{invalid argument; expected 'enable', 'assume_safety' or 'disable'}} */ #pragma clang loop interleave(*) /* expected-error {{invalid argument; expected 'enable', 'full' or 'disable'}} */ #pragma clang loop unroll(=) /* expected-error {{invalid argument; expected 'enable' or 'disable'}} */ #pragma clang loop distribute(+) -/* expected-error {{type name requires a specifier or qualifier}} expected-error {{expected expression}} */ #pragma clang loop vectorize_width(^) +/* expected-error {{type name requires a specifier or qualifier}} expected-error {{expected expression}} */ #pragma clang loop vectorize_width(^) /* expected-note {{vectorize_width loop hint malformed; use vectorize_width(X, 'fixed' or 'scalable') where X is an integer, or vectorize_width('fixed' or 'scalable')}} */ /* expected-error {{expected expression}} expected-error {{expected expression}} */ #pragma clang loop interleave_count(/) /* expected-error {{expected expression}} expected-error {{expected expression}} */ #pragma clang loop unroll_count(==) while (i-8 < Length) {