Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -2686,6 +2686,8 @@ /// interleave_count: interleaves 'Value' loop iterations. /// unroll: fully unroll loop if State == Enable. /// unroll_count: unrolls loop 'Value' times. + /// unroll_and_jam: attempt to unroll and jam loop if State == Enable. + /// unroll_and_jam_count: unroll and jams loop 'Value' times. /// distribute: attempt to distribute loop if State == Enable /// #pragma unroll directive @@ -2694,14 +2696,17 @@ /// expression: unrolls loop 'Value' times. let Spellings = [Pragma<"clang", "loop">, Pragma<"", "unroll">, - Pragma<"", "nounroll">]; + Pragma<"", "nounroll">, Pragma<"", "unroll_and_jam">, + Pragma<"", "nounroll_and_jam">]; /// State of the loop optimization specified by the spelling. let Args = [EnumArgument<"Option", "OptionType", ["vectorize", "vectorize_width", "interleave", "interleave_count", - "unroll", "unroll_count", "distribute"], + "unroll", "unroll_count", "unroll_and_jam", "unroll_and_jam_count", + "distribute"], ["Vectorize", "VectorizeWidth", "Interleave", "InterleaveCount", - "Unroll", "UnrollCount", "Distribute"]>, + "Unroll", "UnrollCount", "UnrollAndJam", "UnrollAndJamCount", + "Distribute"]>, EnumArgument<"State", "LoopHintState", ["enable", "disable", "numeric", "assume_safety", "full"], ["Enable", "Disable", "Numeric", "AssumeSafety", "Full"]>, @@ -2716,6 +2721,8 @@ case InterleaveCount: return "interleave_count"; case Unroll: return "unroll"; case UnrollCount: return "unroll_count"; + case UnrollAndJam: return "unroll_and_jam"; + case UnrollAndJamCount: return "unroll_and_jam_count"; case Distribute: return "distribute"; } llvm_unreachable("Unhandled LoopHint option."); @@ -2725,9 +2732,9 @@ unsigned SpellingIndex = getSpellingListIndex(); // For "#pragma unroll" and "#pragma nounroll" the string "unroll" or // "nounroll" is already emitted as the pragma name. - if (SpellingIndex == Pragma_nounroll) + if (SpellingIndex == Pragma_nounroll || SpellingIndex == Pragma_nounroll_and_jam) return; - else if (SpellingIndex == Pragma_unroll) { + else if (SpellingIndex == Pragma_unroll || SpellingIndex == Pragma_unroll_and_jam) { OS << ' ' << getValueString(Policy); return; } @@ -2763,6 +2770,11 @@ return "#pragma nounroll"; else if (SpellingIndex == Pragma_unroll) return "#pragma unroll" + (option == UnrollCount ? getValueString(Policy) : ""); + else if (SpellingIndex == Pragma_nounroll_and_jam) + return "#pragma nounroll_and_jam"; + else if (SpellingIndex == Pragma_unroll_and_jam) + return "#pragma unroll_and_jam" + + (option == UnrollAndJamCount ? getValueString(Policy) : ""); assert(SpellingIndex == Pragma_clang_loop && "Unexpected spelling"); return getOptionName(option) + getValueString(Policy); Index: include/clang/Parse/Parser.h =================================================================== --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -185,6 +185,8 @@ std::unique_ptr LoopHintHandler; std::unique_ptr UnrollHintHandler; std::unique_ptr NoUnrollHintHandler; + std::unique_ptr UnrollAndJamHintHandler; + std::unique_ptr NoUnrollAndJamHintHandler; std::unique_ptr FPHandler; std::unique_ptr STDCFENVHandler; std::unique_ptr STDCCXLIMITHandler; Index: lib/CodeGen/CGLoopInfo.h =================================================================== --- lib/CodeGen/CGLoopInfo.h +++ lib/CodeGen/CGLoopInfo.h @@ -49,6 +49,9 @@ /// Value for llvm.loop.unroll.* metadata (enable, disable, or full). LVEnableState UnrollEnable; + /// Value for llvm.loop.unroll_and_jam.* metadata (enable, disable, or full). + LVEnableState UnrollAndJamEnable; + /// Value for llvm.loop.vectorize.width metadata. unsigned VectorizeWidth; @@ -58,6 +61,9 @@ /// llvm.unroll. unsigned UnrollCount; + /// llvm.unroll. + unsigned UnrollAndJamCount; + /// Value for llvm.loop.distribute.enable metadata. LVEnableState DistributeEnable; }; @@ -143,6 +149,11 @@ StagedAttrs.UnrollEnable = State; } + /// Set the next pushed loop unroll_and_jam state. + void setUnrollAndJamState(const LoopAttributes::LVEnableState &State) { + StagedAttrs.UnrollAndJamEnable = State; + } + /// Set the vectorize width for the next loop pushed. void setVectorizeWidth(unsigned W) { StagedAttrs.VectorizeWidth = W; } @@ -152,6 +163,9 @@ /// Set the unroll count for the next loop pushed. void setUnrollCount(unsigned C) { StagedAttrs.UnrollCount = C; } + /// \brief Set the unroll count for the next loop pushed. + void setUnrollAndJamCount(unsigned C) { StagedAttrs.UnrollAndJamCount = C; } + private: /// Returns true if there is LoopInfo on the stack. bool hasInfo() const { return !Active.empty(); } Index: lib/CodeGen/CGLoopInfo.cpp =================================================================== --- lib/CodeGen/CGLoopInfo.cpp +++ lib/CodeGen/CGLoopInfo.cpp @@ -25,10 +25,12 @@ if (!Attrs.IsParallel && Attrs.VectorizeWidth == 0 && Attrs.InterleaveCount == 0 && Attrs.UnrollCount == 0 && + Attrs.UnrollAndJamCount == 0 && Attrs.VectorizeEnable == LoopAttributes::Unspecified && Attrs.UnrollEnable == LoopAttributes::Unspecified && - Attrs.DistributeEnable == LoopAttributes::Unspecified && - !StartLoc && !EndLoc) + Attrs.UnrollAndJamEnable == LoopAttributes::Unspecified && + Attrs.DistributeEnable == LoopAttributes::Unspecified && !StartLoc && + !EndLoc) return nullptr; SmallVector Args; @@ -61,7 +63,7 @@ Args.push_back(MDNode::get(Ctx, Vals)); } - // Setting interleave.count + // Setting unroll.count if (Attrs.UnrollCount > 0) { Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.unroll.count"), ConstantAsMetadata::get(ConstantInt::get( @@ -69,6 +71,14 @@ Args.push_back(MDNode::get(Ctx, Vals)); } + // Setting unroll_and_jam.count + if (Attrs.UnrollAndJamCount > 0) { + Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.unroll_and_jam.count"), + ConstantAsMetadata::get(ConstantInt::get( + Type::getInt32Ty(Ctx), Attrs.UnrollAndJamCount))}; + Args.push_back(MDNode::get(Ctx, Vals)); + } + // Setting vectorize.enable if (Attrs.VectorizeEnable != LoopAttributes::Unspecified) { Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.vectorize.enable"), @@ -91,6 +101,19 @@ Args.push_back(MDNode::get(Ctx, Vals)); } + // Setting unroll_and_jam.full or unroll_and_jam.disable + if (Attrs.UnrollAndJamEnable != LoopAttributes::Unspecified) { + std::string Name; + if (Attrs.UnrollAndJamEnable == LoopAttributes::Enable) + Name = "llvm.loop.unroll_and_jam.enable"; + else if (Attrs.UnrollAndJamEnable == LoopAttributes::Full) + Name = "llvm.loop.unroll_and_jam.full"; + else + Name = "llvm.loop.unroll_and_jam.disable"; + Metadata *Vals[] = {MDString::get(Ctx, Name)}; + Args.push_back(MDNode::get(Ctx, Vals)); + } + if (Attrs.DistributeEnable != LoopAttributes::Unspecified) { Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.distribute.enable"), ConstantAsMetadata::get(ConstantInt::get( @@ -107,8 +130,9 @@ LoopAttributes::LoopAttributes(bool IsParallel) : IsParallel(IsParallel), VectorizeEnable(LoopAttributes::Unspecified), - UnrollEnable(LoopAttributes::Unspecified), VectorizeWidth(0), - InterleaveCount(0), UnrollCount(0), + UnrollEnable(LoopAttributes::Unspecified), + UnrollAndJamEnable(LoopAttributes::Unspecified), VectorizeWidth(0), + InterleaveCount(0), UnrollCount(0), UnrollAndJamCount(0), DistributeEnable(LoopAttributes::Unspecified) {} void LoopAttributes::clear() { @@ -116,8 +140,10 @@ VectorizeWidth = 0; InterleaveCount = 0; UnrollCount = 0; + UnrollAndJamCount = 0; VectorizeEnable = LoopAttributes::Unspecified; UnrollEnable = LoopAttributes::Unspecified; + UnrollAndJamEnable = LoopAttributes::Unspecified; DistributeEnable = LoopAttributes::Unspecified; } @@ -191,10 +217,14 @@ case LoopHintAttr::Unroll: setUnrollState(LoopAttributes::Disable); break; + case LoopHintAttr::UnrollAndJam: + setUnrollAndJamState(LoopAttributes::Disable); + break; case LoopHintAttr::Distribute: setDistributeState(false); break; case LoopHintAttr::UnrollCount: + case LoopHintAttr::UnrollAndJamCount: case LoopHintAttr::VectorizeWidth: case LoopHintAttr::InterleaveCount: llvm_unreachable("Options cannot be disabled."); @@ -210,10 +240,14 @@ case LoopHintAttr::Unroll: setUnrollState(LoopAttributes::Enable); break; + case LoopHintAttr::UnrollAndJam: + setUnrollAndJamState(LoopAttributes::Enable); + break; case LoopHintAttr::Distribute: setDistributeState(true); break; case LoopHintAttr::UnrollCount: + case LoopHintAttr::UnrollAndJamCount: case LoopHintAttr::VectorizeWidth: case LoopHintAttr::InterleaveCount: llvm_unreachable("Options cannot enabled."); @@ -229,7 +263,9 @@ setVectorizeEnable(true); break; case LoopHintAttr::Unroll: + case LoopHintAttr::UnrollAndJam: case LoopHintAttr::UnrollCount: + case LoopHintAttr::UnrollAndJamCount: case LoopHintAttr::VectorizeWidth: case LoopHintAttr::InterleaveCount: case LoopHintAttr::Distribute: @@ -242,9 +278,13 @@ case LoopHintAttr::Unroll: setUnrollState(LoopAttributes::Full); break; + case LoopHintAttr::UnrollAndJam: + setUnrollAndJamState(LoopAttributes::Full); + break; case LoopHintAttr::Vectorize: case LoopHintAttr::Interleave: case LoopHintAttr::UnrollCount: + case LoopHintAttr::UnrollAndJamCount: case LoopHintAttr::VectorizeWidth: case LoopHintAttr::InterleaveCount: case LoopHintAttr::Distribute: @@ -263,7 +303,11 @@ case LoopHintAttr::UnrollCount: setUnrollCount(ValueInt); break; + case LoopHintAttr::UnrollAndJamCount: + setUnrollAndJamCount(ValueInt); + break; case LoopHintAttr::Unroll: + case LoopHintAttr::UnrollAndJam: case LoopHintAttr::Vectorize: case LoopHintAttr::Interleave: case LoopHintAttr::Distribute: Index: lib/Parse/ParsePragma.cpp =================================================================== --- lib/Parse/ParsePragma.cpp +++ lib/Parse/ParsePragma.cpp @@ -352,6 +352,13 @@ NoUnrollHintHandler.reset(new PragmaUnrollHintHandler("nounroll")); PP.AddPragmaHandler(NoUnrollHintHandler.get()); + UnrollAndJamHintHandler.reset(new PragmaUnrollHintHandler("unroll_and_jam")); + PP.AddPragmaHandler(UnrollAndJamHintHandler.get()); + + NoUnrollAndJamHintHandler.reset( + new PragmaUnrollHintHandler("nounroll_and_jam")); + PP.AddPragmaHandler(NoUnrollAndJamHintHandler.get()); + FPHandler.reset(new PragmaFPHandler()); PP.AddPragmaHandler("clang", FPHandler.get()); @@ -451,6 +458,12 @@ PP.RemovePragmaHandler(NoUnrollHintHandler.get()); NoUnrollHintHandler.reset(); + PP.RemovePragmaHandler(UnrollAndJamHintHandler.get()); + UnrollAndJamHintHandler.reset(); + + PP.RemovePragmaHandler(NoUnrollAndJamHintHandler.get()); + NoUnrollAndJamHintHandler.reset(); + PP.RemovePragmaHandler("clang", FPHandler.get()); FPHandler.reset(); @@ -955,6 +968,8 @@ if (PragmaName.getIdentifierInfo()->getName() == "loop") { PragmaString = "clang loop "; PragmaString += Option.getIdentifierInfo()->getName(); + } else if (PragmaName.getIdentifierInfo()->getName() == "unroll_and_jam") { + PragmaString = "unroll_and_jam"; } else { assert(PragmaName.getIdentifierInfo()->getName() == "unroll" && "Unexpected pragma name"); @@ -986,7 +1001,10 @@ // without an argument. bool PragmaUnroll = PragmaNameInfo->getName() == "unroll"; bool PragmaNoUnroll = PragmaNameInfo->getName() == "nounroll"; - if (Toks.empty() && (PragmaUnroll || PragmaNoUnroll)) { + bool PragmaUnrollAndJam = PragmaNameInfo->getName() == "unroll_and_jam"; + bool PragmaNoUnrollAndJam = PragmaNameInfo->getName() == "nounroll_and_jam"; + if (Toks.empty() && (PragmaUnroll || PragmaNoUnroll || PragmaUnrollAndJam || + PragmaNoUnrollAndJam)) { ConsumeAnnotationToken(); Hint.Range = Info->PragmaName.getLocation(); return true; @@ -999,24 +1017,28 @@ // If no option is specified the argument is assumed to be a constant expr. bool OptionUnroll = false; + bool OptionUnrollAndJam = false; bool OptionDistribute = false; bool StateOption = false; if (OptionInfo) { // Pragma Unroll does not specify an option. OptionUnroll = OptionInfo->isStr("unroll"); + OptionUnrollAndJam = OptionInfo->isStr("unroll_and_jam"); OptionDistribute = OptionInfo->isStr("distribute"); StateOption = llvm::StringSwitch(OptionInfo->getName()) .Case("vectorize", true) .Case("interleave", true) .Default(false) || - OptionUnroll || OptionDistribute; + OptionUnroll || OptionUnrollAndJam || OptionDistribute; } - bool AssumeSafetyArg = !OptionUnroll && !OptionDistribute; + bool AssumeSafetyArg = + !OptionUnroll && !OptionUnrollAndJam && !OptionDistribute; // Verify loop hint has an argument. if (Toks[0].is(tok::eof)) { ConsumeAnnotationToken(); Diag(Toks[0].getLocation(), diag::err_pragma_loop_missing_argument) - << /*StateArgument=*/StateOption << /*FullKeyword=*/OptionUnroll + << /*StateArgument=*/StateOption + << /*FullKeyword=*/(OptionUnroll || OptionUnrollAndJam) << /*AssumeSafetyKeyword=*/AssumeSafetyArg; return false; } @@ -1027,15 +1049,15 @@ SourceLocation StateLoc = Toks[0].getLocation(); IdentifierInfo *StateInfo = Toks[0].getIdentifierInfo(); - bool Valid = StateInfo && - llvm::StringSwitch(StateInfo->getName()) - .Cases("enable", "disable", true) - .Case("full", OptionUnroll) - .Case("assume_safety", AssumeSafetyArg) - .Default(false); + bool Valid = + StateInfo && llvm::StringSwitch(StateInfo->getName()) + .Cases("enable", "disable", true) + .Case("full", OptionUnroll || OptionUnrollAndJam) + .Case("assume_safety", AssumeSafetyArg) + .Default(false); if (!Valid) { Diag(Toks[0].getLocation(), diag::err_pragma_invalid_keyword) - << /*FullKeyword=*/OptionUnroll + << /*FullKeyword=*/(OptionUnroll || OptionUnrollAndJam) << /*AssumeSafetyKeyword=*/AssumeSafetyArg; return false; } @@ -2845,6 +2867,10 @@ /// #pragma unroll unroll-hint-value /// #pragma unroll '(' unroll-hint-value ')' /// #pragma nounroll +/// #pragma unroll_and_jam +/// #pragma unroll_and_jam unroll-hint-value +/// #pragma unroll_and_jam '(' unroll-hint-value ')' +/// #pragma nounroll_and_jam /// /// unroll-hint-value: /// constant-expression @@ -2869,9 +2895,10 @@ // nounroll or unroll pragma without an argument. Info->PragmaName = PragmaName; Info->Option.startToken(); - } else if (PragmaName.getIdentifierInfo()->getName() == "nounroll") { + } else if (PragmaName.getIdentifierInfo()->getName() == "nounroll" || + PragmaName.getIdentifierInfo()->getName() == "nounroll_and_jam") { PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) - << "nounroll"; + << PragmaName.getIdentifierInfo()->getName(); return; } else { // Unroll pragma with an argument: "#pragma unroll N" or Index: lib/Sema/SemaStmtAttr.cpp =================================================================== --- lib/Sema/SemaStmtAttr.cpp +++ lib/Sema/SemaStmtAttr.cpp @@ -87,6 +87,9 @@ bool PragmaUnroll = PragmaNameLoc->Ident->getName() == "unroll"; bool PragmaNoUnroll = PragmaNameLoc->Ident->getName() == "nounroll"; + bool PragmaUnrollAndJam = PragmaNameLoc->Ident->getName() == "unroll_and_jam"; + bool PragmaNoUnrollAndJam = + PragmaNameLoc->Ident->getName() == "nounroll_and_jam"; if (St->getStmtClass() != Stmt::DoStmtClass && St->getStmtClass() != Stmt::ForStmtClass && St->getStmtClass() != Stmt::CXXForRangeStmtClass && @@ -95,6 +98,8 @@ llvm::StringSwitch(PragmaNameLoc->Ident->getName()) .Case("unroll", "#pragma unroll") .Case("nounroll", "#pragma nounroll") + .Case("unroll_and_jam", "#pragma unroll_and_jam") + .Case("nounroll_and_jam", "#pragma nounroll_and_jam") .Default("#pragma clang loop"); S.Diag(St->getLocStart(), diag::err_pragma_loop_precedes_nonloop) << Pragma; return nullptr; @@ -118,6 +123,20 @@ Option = LoopHintAttr::Unroll; State = LoopHintAttr::Enable; } + } else if (PragmaNoUnrollAndJam) { + // #pragma nounroll_and_jam + Option = LoopHintAttr::UnrollAndJam; + State = LoopHintAttr::Disable; + } else if (PragmaUnrollAndJam) { + if (ValueExpr) { + // #pragma unroll_and_jam N + Option = LoopHintAttr::UnrollAndJamCount; + State = LoopHintAttr::Numeric; + } else { + // #pragma unroll_and_jam + Option = LoopHintAttr::UnrollAndJam; + State = LoopHintAttr::Enable; + } } else { // #pragma clang loop ... assert(OptionLoc && OptionLoc->Ident && @@ -165,22 +184,23 @@ static void CheckForIncompatibleAttributes(Sema &S, const SmallVectorImpl &Attrs) { - // There are 4 categories of loop hints attributes: vectorize, interleave, - // unroll and distribute. Except for distribute they come in two variants: a - // state form and a numeric form. The state form selectively - // defaults/enables/disables the transformation for the loop (for unroll, - // default indicates full unrolling rather than enabling the transformation). - // The numeric form form provides an integer hint (for example, unroll count) - // to the transformer. The following array accumulates the hints encountered - // while iterating through the attributes to check for compatibility. + // There are 5 categories of loop hints attributes: vectorize, interleave, + // unroll, unroll_and_jam and distribute. Except for distribute they come + // in two variants: a state form and a numeric form. The state form + // selectively defaults/enables/disables the transformation for the loop + // (for unroll, default indicates full unrolling rather than enabling the + // transformation). The numeric form form provides an integer hint (for + // example, unroll count) to the transformer. The following array accumulates + // the hints encountered while iterating through the attributes to check for + // compatibility. struct { const LoopHintAttr *StateAttr; const LoopHintAttr *NumericAttr; } HintAttrs[] = {{nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}, + {nullptr, nullptr}, {nullptr, nullptr}}; - for (const auto *I : Attrs) { const LoopHintAttr *LH = dyn_cast(I); @@ -189,7 +209,7 @@ continue; LoopHintAttr::OptionType Option = LH->getOption(); - enum { Vectorize, Interleave, Unroll, Distribute } Category; + enum { Vectorize, Interleave, Unroll, UnrollAndJam, Distribute } Category; switch (Option) { case LoopHintAttr::Vectorize: case LoopHintAttr::VectorizeWidth: @@ -203,16 +223,22 @@ case LoopHintAttr::UnrollCount: Category = Unroll; break; + case LoopHintAttr::UnrollAndJam: + case LoopHintAttr::UnrollAndJamCount: + Category = UnrollAndJam; + break; case LoopHintAttr::Distribute: // Perform the check for duplicated 'distribute' hints. Category = Distribute; break; }; + assert(Category < sizeof(HintAttrs) / sizeof(HintAttrs[0])); auto &CategoryState = HintAttrs[Category]; const LoopHintAttr *PrevAttr; if (Option == LoopHintAttr::Vectorize || Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll || + Option == LoopHintAttr::UnrollAndJam || Option == LoopHintAttr::Distribute) { // Enable|Disable|AssumeSafety hint. For example, vectorize(enable). PrevAttr = CategoryState.StateAttr; @@ -232,7 +258,7 @@ << LH->getDiagnosticName(Policy); if (CategoryState.StateAttr && CategoryState.NumericAttr && - (Category == Unroll || + (Category == Unroll || Category == UnrollAndJam || CategoryState.StateAttr->getState() == LoopHintAttr::Disable)) { // Disable hints are not compatible with numeric hints of the same // category. As a special case, numeric unroll hints are also not Index: test/CodeGenCXX/pragma-unroll-and-jam.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/pragma-unroll-and-jam.cpp @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 -triple arm-none-eabi -std=c++11 -emit-llvm -o - %s | FileCheck %s + +void unroll_and_jam(int *List, int Length, int Value) { + // CHECK: define {{.*}} @_Z14unroll_and_jam +#pragma unroll_and_jam + for (int i = 0; i < Length; i++) { + for (int j = 0; j < Length; j++) { + // CHECK: br label {{.*}}, !llvm.loop ![[LOOP_1:.*]] + List[i * Length + j] = Value; + } + } +} + +void unroll_and_jam_count(int *List, int Length, int Value) { + // CHECK: define {{.*}} @_Z20unroll_and_jam_count +#pragma unroll_and_jam(4) + for (int i = 0; i < Length; i++) { + for (int j = 0; j < Length; j++) { + // CHECK: br label {{.*}}, !llvm.loop ![[LOOP_2:.*]] + List[i * Length + j] = Value; + } + } +} + +void nounroll_and_jam(int *List, int Length, int Value) { + // CHECK: define {{.*}} @_Z16nounroll_and_jam +#pragma nounroll_and_jam + for (int i = 0; i < Length; i++) { + for (int j = 0; j < Length; j++) { + // CHECK: br label {{.*}}, !llvm.loop ![[LOOP_3:.*]] + List[i * Length + j] = Value; + } + } +} + +void clang_unroll_plus_nounroll_and_jam(int *List, int Length, int Value) { + // CHECK: define {{.*}} @_Z34clang_unroll_plus_nounroll_and_jam +#pragma nounroll_and_jam +#pragma unroll(4) + for (int i = 0; i < Length; i++) { + for (int j = 0; j < Length; j++) { + // CHECK: br label {{.*}}, !llvm.loop ![[LOOP_7:.*]] + List[i * Length + j] = Value; + } + } +} + +// CHECK: ![[LOOP_1]] = distinct !{![[LOOP_1]], ![[UNJ_ENABLE:.*]]} +// CHECK: ![[UNJ_ENABLE]] = !{!"llvm.loop.unroll_and_jam.enable"} +// CHECK: ![[LOOP_2]] = distinct !{![[LOOP_2]], ![[UNJ_4:.*]]} +// CHECK: ![[UNJ_4]] = !{!"llvm.loop.unroll_and_jam.count", i32 4} +// CHECK: ![[LOOP_3]] = distinct !{![[LOOP_3]], ![[UNJ_DISABLE:.*]]} +// CHECK: ![[UNJ_DISABLE]] = !{!"llvm.loop.unroll_and_jam.disable"} +// CHECK: ![[LOOP_7]] = distinct !{![[LOOP_7]], ![[UNROLL_4:.*]], ![[UNJ_DISABLE:.*]]} +// CHECK: ![[UNROLL_4]] = !{!"llvm.loop.unroll.count", i32 4} Index: test/Parser/pragma-unroll-and-jam.cpp =================================================================== --- /dev/null +++ test/Parser/pragma-unroll-and-jam.cpp @@ -0,0 +1,78 @@ +// RUN: %clang_cc1 -std=c++11 -verify %s + +// Note that this puts the expected lines before the directives to work around +// limitations in the -verify mode. + +void test(int *List, int Length, int Value) { + int i = 0; + +#pragma unroll_and_jam + for (int i = 0; i < Length; i++) { + for (int j = 0; j < Length; j++) { + List[i * Length + j] = Value; + } + } + +#pragma nounroll_and_jam + for (int i = 0; i < Length; i++) { + for (int j = 0; j < Length; j++) { + List[i * Length + j] = Value; + } + } + +#pragma unroll_and_jam 4 + for (int i = 0; i < Length; i++) { + for (int j = 0; j < Length; j++) { + List[i * Length + j] = Value; + } + } + +/* expected-error {{expected ')'}} */ #pragma unroll_and_jam(4 +/* expected-error {{missing argument; expected an integer value}} */ #pragma unroll_and_jam() +/* expected-warning {{extra tokens at end of '#pragma unroll_and_jam'}} */ #pragma unroll_and_jam 1 2 + for (int i = 0; i < Length; i++) { + for (int j = 0; j < Length; j++) { + List[i * Length + j] = Value; + } + } + +/* expected-warning {{extra tokens at end of '#pragma nounroll_and_jam'}} */ #pragma nounroll_and_jam 1 + for (int i = 0; i < Length; i++) { + for (int j = 0; j < Length; j++) { + List[i * Length + j] = Value; + } + } + +#pragma unroll_and_jam +/* expected-error {{expected a for, while, or do-while loop to follow '#pragma unroll_and_jam'}} */ int j = Length; +#pragma unroll_and_jam 4 +/* expected-error {{expected a for, while, or do-while loop to follow '#pragma unroll_and_jam'}} */ int k = Length; +#pragma nounroll_and_jam +/* expected-error {{expected a for, while, or do-while loop to follow '#pragma nounroll_and_jam'}} */ int l = Length; + +/* expected-error {{incompatible directives '#pragma nounroll_and_jam' and '#pragma unroll_and_jam(4)'}} */ #pragma unroll_and_jam 4 +#pragma nounroll_and_jam + for (int i = 0; i < Length; i++) { + for (int j = 0; j < Length; j++) { + List[i * Length + j] = Value; + } + } + +#pragma nounroll_and_jam +#pragma unroll(4) + for (int i = 0; i < Length; i++) { + for (int j = 0; j < Length; j++) { + List[i * Length + j] = Value; + } + } + +// pragma clang unroll_and_jam is disabled for the moment +/* expected-error {{invalid option 'unroll_and_jam'; expected vectorize, vectorize_width, interleave, interleave_count, unroll, unroll_count, or distribute}} */ #pragma clang loop unroll_and_jam(4) + for (int i = 0; i < Length; i++) { + for (int j = 0; j < Length; j++) { + List[i * Length + j] = Value; + } + } + +#pragma unroll_and_jam +/* expected-error {{expected statement}} */ }