Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -1276,6 +1276,10 @@ This function attribute indicates that the function never returns normally. This produces undefined behavior at runtime if the function ever does dynamically return. +``norecurse`` + This function attribute indicates that the function does not call itself + either directly or indirectly down any possible call path. This produces + undefined behavior at runtime if the function ever does recurse. ``nounwind`` This function attribute indicates that the function never raises an exception. If the function does raise an exception, its runtime Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -449,7 +449,8 @@ ATTR_KIND_SAFESTACK = 44, ATTR_KIND_ARGMEMONLY = 45, ATTR_KIND_SWIFT_SELF = 46, - ATTR_KIND_SWIFT_ERROR = 47 + ATTR_KIND_SWIFT_ERROR = 47, + ATTR_KIND_NO_RECURSE = 48 }; enum ComdatSelectionKindCodes { Index: include/llvm/IR/Attributes.h =================================================================== --- include/llvm/IR/Attributes.h +++ include/llvm/IR/Attributes.h @@ -86,6 +86,7 @@ NoDuplicate, ///< Call cannot be duplicated NoImplicitFloat, ///< Disable implicit floating point insts NoInline, ///< inline=never + NoRecurse, ///< The function does not recurse NonLazyBind, ///< Function is called early and/or ///< often, so lazy binding isn't worthwhile NonNull, ///< Pointer is known to be not null Index: include/llvm/IR/Function.h =================================================================== --- include/llvm/IR/Function.h +++ include/llvm/IR/Function.h @@ -325,6 +325,15 @@ addFnAttr(Attribute::Convergent); } + /// @brief Determine if the function is known not to recurse, directly or + /// indirectly. + bool doesNotRecurse() const { + return AttributeSets.hasAttribute(AttributeSet::FunctionIndex, + Attribute::NoRecurse); + } + void setDoesNotRecurse() { + addFnAttr(Attribute::NoRecurse); + } /// @brief True if the ABI mandates (or the user requested) that this /// function be in a unwind table. Index: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -616,6 +616,7 @@ KEYWORD(noduplicate); KEYWORD(noimplicitfloat); KEYWORD(noinline); + KEYWORD(norecurse); KEYWORD(nonlazybind); KEYWORD(nonnull); KEYWORD(noredzone); Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -998,6 +998,7 @@ case lltok::kw_nonlazybind: B.addAttribute(Attribute::NonLazyBind); break; case lltok::kw_noredzone: B.addAttribute(Attribute::NoRedZone); break; case lltok::kw_noreturn: B.addAttribute(Attribute::NoReturn); break; + case lltok::kw_norecurse: B.addAttribute(Attribute::NoRecurse); break; case lltok::kw_nounwind: B.addAttribute(Attribute::NoUnwind); break; case lltok::kw_optnone: B.addAttribute(Attribute::OptimizeNone); break; case lltok::kw_optsize: B.addAttribute(Attribute::OptimizeForSize); break; Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -123,6 +123,7 @@ kw_noduplicate, kw_noimplicitfloat, kw_noinline, + kw_norecurse, kw_nonlazybind, kw_nonnull, kw_noredzone, Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -1283,6 +1283,8 @@ return Attribute::NoImplicitFloat; case bitc::ATTR_KIND_NO_INLINE: return Attribute::NoInline; + case bitc::ATTR_KIND_NO_RECURSE: + return Attribute::NoRecurse; case bitc::ATTR_KIND_NON_LAZY_BIND: return Attribute::NonLazyBind; case bitc::ATTR_KIND_NON_NULL: Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -202,6 +202,8 @@ return bitc::ATTR_KIND_NO_IMPLICIT_FLOAT; case Attribute::NoInline: return bitc::ATTR_KIND_NO_INLINE; + case Attribute::NoRecurse: + return bitc::ATTR_KIND_NO_RECURSE; case Attribute::NonLazyBind: return bitc::ATTR_KIND_NON_LAZY_BIND; case Attribute::NonNull: Index: lib/IR/Attributes.cpp =================================================================== --- lib/IR/Attributes.cpp +++ lib/IR/Attributes.cpp @@ -232,6 +232,8 @@ return "noredzone"; if (hasAttribute(Attribute::NoReturn)) return "noreturn"; + if (hasAttribute(Attribute::NoRecurse)) + return "norecurse"; if (hasAttribute(Attribute::NoUnwind)) return "nounwind"; if (hasAttribute(Attribute::OptimizeNone)) @@ -442,6 +444,7 @@ case Attribute::JumpTable: return 1ULL << 45; case Attribute::Convergent: return 1ULL << 46; case Attribute::SafeStack: return 1ULL << 47; + case Attribute::NoRecurse: return 1ULL << 48; case Attribute::Dereferenceable: llvm_unreachable("dereferenceable attribute not supported in raw format"); break; Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -1275,7 +1275,8 @@ I->getKindAsEnum() == Attribute::OptimizeNone || I->getKindAsEnum() == Attribute::JumpTable || I->getKindAsEnum() == Attribute::Convergent || - I->getKindAsEnum() == Attribute::ArgMemOnly) { + I->getKindAsEnum() == Attribute::ArgMemOnly || + I->getKindAsEnum() == Attribute::NoRecurse) { if (!isFunction) { CheckFailed("Attribute '" + I->getAsString() + "' only applies to functions!", V); Index: test/Bindings/llvm-c/invalid-bitcode.test =================================================================== --- test/Bindings/llvm-c/invalid-bitcode.test +++ test/Bindings/llvm-c/invalid-bitcode.test @@ -1,3 +1,3 @@ ; RUN: not llvm-c-test --module-dump < %S/Inputs/invalid.ll.bc 2>&1 | FileCheck %s -CHECK: Error parsing bitcode: Unknown attribute kind (48) +CHECK: Error parsing bitcode: Unknown attribute kind (50) Index: test/Bitcode/attributes.ll =================================================================== --- test/Bitcode/attributes.ll +++ test/Bitcode/attributes.ll @@ -204,7 +204,7 @@ ; CHECK: define void @f34() { call void @nobuiltin() nobuiltin -; CHECK: call void @nobuiltin() #27 +; CHECK: call void @nobuiltin() #28 ret void; } @@ -272,6 +272,11 @@ ret void } +; CHECK: define void @f47() #27 +define void @f47() norecurse { + ret void +} + ; CHECK: attributes #0 = { noreturn } ; CHECK: attributes #1 = { nounwind } ; CHECK: attributes #2 = { readnone } @@ -299,4 +304,5 @@ ; CHECK: attributes #24 = { jumptable } ; CHECK: attributes #25 = { convergent } ; CHECK: attributes #26 = { argmemonly } -; CHECK: attributes #27 = { nobuiltin } +; CHECK: attributes #27 = { norecurse } +; CHECK: attributes #28 = { nobuiltin } Index: test/Bitcode/compatibility.ll =================================================================== --- test/Bitcode/compatibility.ll +++ test/Bitcode/compatibility.ll @@ -501,6 +501,8 @@ ; CHECK: declare void @f.uwtable() #30 declare void @f.kvpair() "cpu"="cortex-a8" ; CHECK:declare void @f.kvpair() #31 +declare void @f.norecurse() norecurse +; CHECK: declare void @f.norecurse() #32 ; Functions -- section declare void @f.section() section "80" @@ -559,7 +561,7 @@ ; Functions -- Personality constant declare void @llvm.donothing() nounwind readnone -; CHECK: declare void @llvm.donothing() #32 +; CHECK: declare void @llvm.donothing() #33 define void @f.no_personality() personality i8 3 { ; CHECK: define void @f.no_personality() personality i8 3 invoke void @llvm.donothing() to label %normal unwind label %exception @@ -1125,7 +1127,7 @@ ; CHECK: select <2 x i1> , <2 x i8> , <2 x i8> call void @f.nobuiltin() builtin - ; CHECK: call void @f.nobuiltin() #36 + ; CHECK: call void @f.nobuiltin() #37 call fastcc noalias i32* @f.noalias() noinline ; CHECK: call fastcc noalias i32* @f.noalias() #12 @@ -1497,11 +1499,12 @@ ; CHECK: attributes #29 = { "thunk" } ; CHECK: attributes #30 = { uwtable } ; CHECK: attributes #31 = { "cpu"="cortex-a8" } -; CHECK: attributes #32 = { nounwind readnone } -; CHECK: attributes #33 = { nounwind readonly argmemonly } -; CHECK: attributes #34 = { nounwind argmemonly } -; CHECK: attributes #35 = { nounwind readonly } -; CHECK: attributes #36 = { builtin } +; CHECK: attributes #32 = { norecurse } +; CHECK: attributes #33 = { nounwind readnone } +; CHECK: attributes #34 = { nounwind readonly argmemonly } +; CHECK: attributes #35 = { nounwind argmemonly } +; CHECK: attributes #36 = { nounwind readonly } +; CHECK: attributes #37 = { builtin } ;; Metadata Index: test/Bitcode/invalid.ll =================================================================== --- test/Bitcode/invalid.ll +++ test/Bitcode/invalid.ll @@ -1,6 +1,6 @@ ; RUN: not llvm-dis < %s.bc 2>&1 | FileCheck %s -; CHECK: llvm-dis{{(\.EXE|\.exe)?}}: error: Unknown attribute kind (48) +; CHECK: llvm-dis{{(\.EXE|\.exe)?}}: error: Unknown attribute kind (50) ; invalid.ll.bc has an invalid attribute number. ; The test checks that LLVM reports the error and doesn't access freed memory Index: test/LTO/X86/invalid.ll =================================================================== --- test/LTO/X86/invalid.ll +++ test/LTO/X86/invalid.ll @@ -1,4 +1,4 @@ ; RUN: not llvm-lto %S/Inputs/invalid.ll.bc 2>&1 | FileCheck %s -; CHECK: llvm-lto{{.*}}: error loading file '{{.*}}/Inputs/invalid.ll.bc': Unknown attribute kind (48) +; CHECK: llvm-lto{{.*}}: error loading file '{{.*}}/Inputs/invalid.ll.bc': Unknown attribute kind (50)