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,8 +1123,14 @@ 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(); + return L->getHeader()->getParent()->willReturn() || hasFinite(L); } static const char *LLVMLoopMustProgress = "llvm.loop.mustprogress"; diff --git a/llvm/test/Analysis/ScalarEvolution/lt-overflow.ll b/llvm/test/Analysis/ScalarEvolution/lt-overflow.ll --- a/llvm/test/Analysis/ScalarEvolution/lt-overflow.ll +++ b/llvm/test/Analysis/ScalarEvolution/lt-overflow.ll @@ -252,3 +252,21 @@ for.cond.cleanup: ret void } + +define void @test_finite(i32 %S, i32 %N) { +entry: + br label %for.body + +for.body: + %iv = phi i32 [ %iv.next, %for.body ], [ 0, %entry ] + %iv.next = add i32 %iv, 1024 + call void @sideeffect() nounwind willreturn + %cmp = icmp ult i32 %iv.next, %N + br i1 %cmp, label %for.body, label %for.cond.cleanup, !llvm.loop !8 + +for.cond.cleanup: + ret void +} + +!8 = distinct !{!8, !9} +!9 = !{!"llvm.loop.finite"}