diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -6873,6 +6873,17 @@ not found to interact with the environment in an observable way, the loop may be removed. This corresponds to the ``mustprogress`` function attribute. +'``llvm.loop.finite``' Metadata +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``llvm.loop.finite`` metadata indicates that this loop is finite. The loop, +to which this attribute is attached, must terminate and continue exection at some +instruction outside this loop. The reason for termination is unspecified and may +come from an exception (i.a, nounwind is not implied). This is a stronger form +of ``llvm.loop.mustprogress`` which simply says that the loop either may terminate, +unwind or interact with the environment. All loops within a function marked with +the attribute ``willreturn`` are finite by definition. + '``irr_loop``' Metadata ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/llvm/include/llvm/Analysis/LoopInfo.h b/llvm/include/llvm/Analysis/LoopInfo.h --- a/llvm/include/llvm/Analysis/LoopInfo.h +++ b/llvm/include/llvm/Analysis/LoopInfo.h @@ -853,6 +853,9 @@ /// Add llvm.loop.mustprogress to this loop's loop id metadata. void setLoopMustProgress(); + /// Add llvm.loop.finite to this loop's loop id metadata. + void setLoopFinite(); + void dump() const; void dumpVerbose() const; @@ -1332,6 +1335,14 @@ /// the containing function attribute too. bool hasMustProgress(const Loop *L); +/// Look for the loop attribute that requires the loop to be finite. +/// Note: Most consumers probably want "isFinite" which checks +/// the containing function attribute `willreturn` too. +bool hasFinite(const Loop *L); + +/// Look for the loop attribute that requires the loop to be finite. +bool isFinite(const Loop *L); + /// Return true if this loop can be assumed to make progress. (i.e. can't /// be infinite without side effects without also being undefined) bool isMustProgress(const Loop *L); diff --git a/llvm/lib/Analysis/LoopInfo.cpp b/llvm/lib/Analysis/LoopInfo.cpp --- a/llvm/lib/Analysis/LoopInfo.cpp +++ b/llvm/lib/Analysis/LoopInfo.cpp @@ -564,6 +564,22 @@ setLoopID(NewLoopID); } +void Loop::setLoopFinite() { + LLVMContext &Context = getHeader()->getContext(); + + MDNode *Finite = findOptionMDForLoop(this, "llvm.loop.finite"); + + if (Finite) + return; + + MDNode *FiniteMD = + MDNode::get(Context, MDString::get(Context, "llvm.loop.finite")); + MDNode *LoopID = getLoopID(); + MDNode *NewLoopID = + makePostTransformationMetadata(Context, LoopID, {}, {FiniteMD}); + setLoopID(NewLoopID); +} + bool Loop::isAnnotatedParallel() const { MDNode *DesiredLoopIdMetadata = getLoopID(); @@ -1107,6 +1123,16 @@ return getOptionalIntLoopAttribute(TheLoop, Name).getValueOr(Default); } +static const char *LLVMLoopFinite = "llvm.loop.finite"; + +bool llvm::hasFinite(const Loop *L) { + return getBooleanLoopAttribute(L, LLVMLoopFinite); +} + +bool llvm::isFinite(const Loop *L) { + return L->getHeader()->getParent()->willReturn() || hasFinite(L); +} + static const char *LLVMLoopMustProgress = "llvm.loop.mustprogress"; bool llvm::hasMustProgress(const Loop *L) { @@ -1114,7 +1140,8 @@ } bool llvm::isMustProgress(const Loop *L) { - return L->getHeader()->getParent()->mustProgress() || hasMustProgress(L); + return L->getHeader()->getParent()->mustProgress() || hasMustProgress(L) || + isFinite(L); } bool llvm::isValidAsAccessGroup(MDNode *Node) {