Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -2975,16 +2975,17 @@ let Spellings = [Pragma<"clang", "loop">, Pragma<"", "unroll">, Pragma<"", "nounroll">, Pragma<"", "unroll_and_jam">, - Pragma<"", "nounroll_and_jam">]; + Pragma<"", "nounroll_and_jam">, + Pragma<"", "tail_predicate">]; /// State of the loop optimization specified by the spelling. let Args = [EnumArgument<"Option", "OptionType", ["vectorize", "vectorize_width", "interleave", "interleave_count", "unroll", "unroll_count", "unroll_and_jam", "unroll_and_jam_count", - "pipeline", "pipeline_initiation_interval", "distribute"], + "pipeline", "pipeline_initiation_interval", "distribute", "tail_predicate"], ["Vectorize", "VectorizeWidth", "Interleave", "InterleaveCount", "Unroll", "UnrollCount", "UnrollAndJam", "UnrollAndJamCount", - "PipelineDisabled", "PipelineInitiationInterval", "Distribute"]>, + "PipelineDisabled", "PipelineInitiationInterval", "Distribute", "TailPredicate"]>, EnumArgument<"State", "LoopHintState", ["enable", "disable", "numeric", "assume_safety", "full"], ["Enable", "Disable", "Numeric", "AssumeSafety", "Full"]>, @@ -3004,6 +3005,7 @@ case PipelineDisabled: return "pipeline"; case PipelineInitiationInterval: return "pipeline_initiation_interval"; case Distribute: return "distribute"; + case TailPredicate: return "tail_predicate"; } llvm_unreachable("Unhandled LoopHint option."); } Index: clang/include/clang/Parse/Parser.h =================================================================== --- clang/include/clang/Parse/Parser.h +++ clang/include/clang/Parse/Parser.h @@ -191,6 +191,7 @@ std::unique_ptr CUDAForceHostDeviceHandler; std::unique_ptr OptimizeHandler; std::unique_ptr LoopHintHandler; + std::unique_ptr TailPredicateHintHandler; std::unique_ptr UnrollHintHandler; std::unique_ptr NoUnrollHintHandler; std::unique_ptr UnrollAndJamHintHandler; Index: clang/lib/CodeGen/CGLoopInfo.h =================================================================== --- clang/lib/CodeGen/CGLoopInfo.h +++ clang/lib/CodeGen/CGLoopInfo.h @@ -51,6 +51,9 @@ /// Value for llvm.loop.unroll_and_jam.* metadata (enable, disable, or full). LVEnableState UnrollAndJamEnable; + /// Value for llvm.loop.tailpredicate metadata + LVEnableState TailPredicateEnable; + /// Value for llvm.loop.vectorize.width metadata. unsigned VectorizeWidth; @@ -162,6 +165,11 @@ createFullUnrollMetadata(const LoopAttributes &Attrs, llvm::ArrayRef LoopProperties, bool &HasUserTransforms); + + llvm::MDNode * + createTailPredicateMetadata(const LoopAttributes &Attrs, + llvm::ArrayRef LoopProperties, + bool &HasUserTransforms); /// @} /// Create a LoopID for this loop, including transformation-unspecific @@ -237,6 +245,12 @@ StagedAttrs.UnrollEnable = State; } + + void setTailPredicateState(const LoopAttributes::LVEnableState &State) { + StagedAttrs.TailPredicateEnable = State; + } + + /// Set the next pushed loop unroll_and_jam state. void setUnrollAndJamState(const LoopAttributes::LVEnableState &State) { StagedAttrs.UnrollAndJamEnable = State; Index: clang/lib/CodeGen/CGLoopInfo.cpp =================================================================== --- clang/lib/CodeGen/CGLoopInfo.cpp +++ clang/lib/CodeGen/CGLoopInfo.cpp @@ -342,6 +342,22 @@ return LoopID; } +MDNode *LoopInfo::createTailPredicateMetadata(const LoopAttributes &Attrs, + ArrayRef LoopProperties, + bool &HasUserTransforms) { + LLVMContext &Ctx = Header->getContext(); + + if (Attrs.TailPredicateEnable != LoopAttributes::Enable) + return nullptr; + + SmallVector NewLoopProperties; + NewLoopProperties.append(LoopProperties.begin(), LoopProperties.end()); + NewLoopProperties.push_back( + MDNode::get(Ctx, MDString::get(Ctx, "llvm.loop.tailpredicate"))); + LoopProperties = NewLoopProperties; + return createLoopPropertiesMetadata(LoopProperties); +} + MDNode *LoopInfo::createFullUnrollMetadata(const LoopAttributes &Attrs, ArrayRef LoopProperties, bool &HasUserTransforms) { @@ -405,13 +421,20 @@ LoopProperties.insert(LoopProperties.end(), AdditionalLoopProperties.begin(), AdditionalLoopProperties.end()); + + MDNode *N = + createTailPredicateMetadata(Attrs, LoopProperties, HasUserTransforms); + if(N) + LoopProperties.push_back(N); + return createFullUnrollMetadata(Attrs, LoopProperties, HasUserTransforms); } LoopAttributes::LoopAttributes(bool IsParallel) : IsParallel(IsParallel), VectorizeEnable(LoopAttributes::Unspecified), UnrollEnable(LoopAttributes::Unspecified), - UnrollAndJamEnable(LoopAttributes::Unspecified), VectorizeWidth(0), + UnrollAndJamEnable(LoopAttributes::Unspecified), + TailPredicateEnable(LoopAttributes::Unspecified), VectorizeWidth(0), InterleaveCount(0), UnrollCount(0), UnrollAndJamCount(0), DistributeEnable(LoopAttributes::Unspecified), PipelineDisabled(false), PipelineInitiationInterval(0) {} @@ -425,6 +448,7 @@ VectorizeEnable = LoopAttributes::Unspecified; UnrollEnable = LoopAttributes::Unspecified; UnrollAndJamEnable = LoopAttributes::Unspecified; + TailPredicateEnable = LoopAttributes::Unspecified; DistributeEnable = LoopAttributes::Unspecified; PipelineDisabled = false; PipelineInitiationInterval = 0; @@ -446,6 +470,7 @@ Attrs.InterleaveCount == 0 && Attrs.UnrollCount == 0 && Attrs.UnrollAndJamCount == 0 && !Attrs.PipelineDisabled && Attrs.PipelineInitiationInterval == 0 && + Attrs.TailPredicateEnable == LoopAttributes::Unspecified && Attrs.VectorizeEnable == LoopAttributes::Unspecified && Attrs.UnrollEnable == LoopAttributes::Unspecified && Attrs.UnrollAndJamEnable == LoopAttributes::Unspecified && @@ -603,6 +628,9 @@ case LoopHintAttr::UnrollAndJam: setUnrollAndJamState(LoopAttributes::Disable); break; + case LoopHintAttr::TailPredicate: + setTailPredicateState(LoopAttributes::Disable); + break; case LoopHintAttr::Distribute: setDistributeState(false); break; @@ -630,6 +658,9 @@ case LoopHintAttr::UnrollAndJam: setUnrollAndJamState(LoopAttributes::Enable); break; + case LoopHintAttr::TailPredicate: + setTailPredicateState(LoopAttributes::Enable); + break; case LoopHintAttr::Distribute: setDistributeState(true); break; @@ -653,6 +684,7 @@ break; case LoopHintAttr::Unroll: case LoopHintAttr::UnrollAndJam: + case LoopHintAttr::TailPredicate: case LoopHintAttr::UnrollCount: case LoopHintAttr::UnrollAndJamCount: case LoopHintAttr::VectorizeWidth: @@ -681,6 +713,7 @@ case LoopHintAttr::Distribute: case LoopHintAttr::PipelineDisabled: case LoopHintAttr::PipelineInitiationInterval: + case LoopHintAttr::TailPredicate: llvm_unreachable("Options cannot be used with 'full' hint."); break; } @@ -704,6 +737,7 @@ break; case LoopHintAttr::Unroll: case LoopHintAttr::UnrollAndJam: + case LoopHintAttr::TailPredicate: case LoopHintAttr::Vectorize: case LoopHintAttr::Interleave: case LoopHintAttr::Distribute: Index: clang/lib/Parse/ParsePragma.cpp =================================================================== --- clang/lib/Parse/ParsePragma.cpp +++ clang/lib/Parse/ParsePragma.cpp @@ -372,6 +372,10 @@ llvm::make_unique("unroll_and_jam"); PP.AddPragmaHandler(UnrollAndJamHintHandler.get()); + TailPredicateHintHandler = + llvm::make_unique("tail_predicate"); + PP.AddPragmaHandler(TailPredicateHintHandler.get()); + NoUnrollAndJamHintHandler = llvm::make_unique("nounroll_and_jam"); PP.AddPragmaHandler(NoUnrollAndJamHintHandler.get()); @@ -479,6 +483,9 @@ PP.RemovePragmaHandler(UnrollAndJamHintHandler.get()); UnrollAndJamHintHandler.reset(); + PP.RemovePragmaHandler(TailPredicateHintHandler.get()); + TailPredicateHintHandler.reset(); + PP.RemovePragmaHandler(NoUnrollAndJamHintHandler.get()); NoUnrollAndJamHintHandler.reset(); @@ -1006,17 +1013,13 @@ } // end anonymous namespace static std::string PragmaLoopHintString(Token PragmaName, Token Option) { - std::string PragmaString; - 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"); - PragmaString = "unroll"; - } + std::string PragmaString = PragmaName.getIdentifierInfo()->getName(); + PragmaString = llvm::StringSwitch(PragmaString) + .Case("loop", std::string("clang loop ") + PragmaString) + .Case("unroll_and_jam", PragmaString) + .Case("unroll", PragmaString) + .Default(""); + assert(PragmaString.size() && "Unexpected pragma name"); return PragmaString; } @@ -1041,12 +1044,12 @@ // Return a valid hint if pragma unroll or nounroll were specified // without an argument. - bool PragmaUnroll = PragmaNameInfo->getName() == "unroll"; - bool PragmaNoUnroll = PragmaNameInfo->getName() == "nounroll"; - bool PragmaUnrollAndJam = PragmaNameInfo->getName() == "unroll_and_jam"; - bool PragmaNoUnrollAndJam = PragmaNameInfo->getName() == "nounroll_and_jam"; - if (Toks.empty() && (PragmaUnroll || PragmaNoUnroll || PragmaUnrollAndJam || - PragmaNoUnrollAndJam)) { + const bool LoopHint = llvm::StringSwitch(PragmaNameInfo->getName()) + .Cases("unroll", "nounroll", "unroll_and_jam", + "nounroll_and_jam", "tail_predicate", true) + .Default(false); + + if (Toks.empty() && LoopHint) { ConsumeAnnotationToken(); Hint.Range = Info->PragmaName.getLocation(); return true; Index: clang/lib/Sema/SemaStmtAttr.cpp =================================================================== --- clang/lib/Sema/SemaStmtAttr.cpp +++ clang/lib/Sema/SemaStmtAttr.cpp @@ -85,6 +85,7 @@ StringRef PragmaName = llvm::StringSwitch(PragmaNameLoc->Ident->getName()) .Cases("unroll", "nounroll", "unroll_and_jam", "nounroll_and_jam", + "tail_predicate", PragmaNameLoc->Ident->getName()) .Default("clang loop"); @@ -118,6 +119,8 @@ SetHints(LoopHintAttr::Unroll, LoopHintAttr::Enable); } else if (PragmaName == "nounroll_and_jam") { SetHints(LoopHintAttr::UnrollAndJam, LoopHintAttr::Disable); + } else if (PragmaName == "tail_predicate") { + SetHints(LoopHintAttr::TailPredicate, LoopHintAttr::Enable); } else if (PragmaName == "unroll_and_jam") { // #pragma unroll_and_jam N if (ValueExpr) @@ -189,7 +192,8 @@ const LoopHintAttr *StateAttr; const LoopHintAttr *NumericAttr; } HintAttrs[] = {{nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}, - {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}}; + {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}, + {nullptr, nullptr}}; for (const auto *I : Attrs) { const LoopHintAttr *LH = dyn_cast(I); @@ -205,7 +209,8 @@ Unroll, UnrollAndJam, Distribute, - Pipeline + Pipeline, + TailPredicate } Category; switch (Option) { case LoopHintAttr::Vectorize: @@ -232,6 +237,9 @@ case LoopHintAttr::PipelineInitiationInterval: Category = Pipeline; break; + case LoopHintAttr::TailPredicate: + Category = TailPredicate; + break; }; assert(Category < sizeof(HintAttrs) / sizeof(HintAttrs[0])); @@ -240,6 +248,7 @@ if (Option == LoopHintAttr::Vectorize || Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll || Option == LoopHintAttr::UnrollAndJam || + Option == LoopHintAttr::TailPredicate || Option == LoopHintAttr::PipelineDisabled || Option == LoopHintAttr::Distribute) { // Enable|Disable|AssumeSafety hint. For example, vectorize(enable). Index: clang/test/CodeGenCXX/pragma-tail-predicate.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/pragma-tail-predicate.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -triple arm-none-eabi -std=c++11 -emit-llvm -o - %s | FileCheck %s + +// CHECK: !{!"llvm.loop.tailpredicate"} + +int foo(int *a, int N) { + int sum = 0; + + #pragma tail_predicate + for (int i = 0; i < N; i++) + sum += a[i]; + + return sum; +} Index: clang/test/Parser/pragma-tail-predicate.cpp =================================================================== --- /dev/null +++ clang/test/Parser/pragma-tail-predicate.cpp @@ -0,0 +1,18 @@ +// 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. + +int foo(int *a, int N) { + int sum = 0; + + #pragma tail_predicate + for (int i = 0; i < N; i++) + sum += a[i]; + + + #pragma tail_predicate + /* expected-error {{expected a for, while, or do-while loop to follow '#pragma tail_predicate'}} */ int b; + + return sum; +}