From: James Molloy Date: Fri, 6 Nov 2015 10:32:53 +0000 (+0000) Subject: Add a new attribute: norecurse X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=d001932f3a8aa1ebd1555162fdce365f011bc292;p=oota-llvm.git Add a new attribute: norecurse This attribute allows the compiler to assume that the function never recurses into itself, either directly or indirectly (transitively). This can be used among other things to demote global variables to locals. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@252282 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/docs/LangRef.rst b/docs/LangRef.rst index 507c3bfd334..d2bba5c8a74 100644 --- a/docs/LangRef.rst +++ b/docs/LangRef.rst @@ -1277,6 +1277,10 @@ example: 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 diff --git a/include/llvm/Bitcode/LLVMBitCodes.h b/include/llvm/Bitcode/LLVMBitCodes.h index 08d88a20454..b79c2785a61 100644 --- a/include/llvm/Bitcode/LLVMBitCodes.h +++ b/include/llvm/Bitcode/LLVMBitCodes.h @@ -466,7 +466,8 @@ enum { BITCODE_CURRENT_EPOCH = 0 }; 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 { diff --git a/include/llvm/IR/Attributes.h b/include/llvm/IR/Attributes.h index 15f48fa38d9..b3984330b17 100644 --- a/include/llvm/IR/Attributes.h +++ b/include/llvm/IR/Attributes.h @@ -86,6 +86,7 @@ public: 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 diff --git a/include/llvm/IR/Function.h b/include/llvm/IR/Function.h index b8e22af4bfe..71822a462da 100644 --- a/include/llvm/IR/Function.h +++ b/include/llvm/IR/Function.h @@ -329,6 +329,15 @@ public: addFnAttr(Attribute::Convergent); } + /// 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. diff --git a/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp index 2eb5f0bf45d..82d6eb7788c 100644 --- a/lib/AsmParser/LLLexer.cpp +++ b/lib/AsmParser/LLLexer.cpp @@ -616,6 +616,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(noduplicate); KEYWORD(noimplicitfloat); KEYWORD(noinline); + KEYWORD(norecurse); KEYWORD(nonlazybind); KEYWORD(nonnull); KEYWORD(noredzone); diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index 1c219ad6cd8..7feb99d555c 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -998,6 +998,7 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B, 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; diff --git a/lib/AsmParser/LLToken.h b/lib/AsmParser/LLToken.h index 06b5f9b0800..ecd6481e6fa 100644 --- a/lib/AsmParser/LLToken.h +++ b/lib/AsmParser/LLToken.h @@ -123,6 +123,7 @@ namespace lltok { kw_noduplicate, kw_noimplicitfloat, kw_noinline, + kw_norecurse, kw_nonlazybind, kw_nonnull, kw_noredzone, diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index 7c1b208c626..bc846192fcf 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1305,6 +1305,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) { 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: diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp index c73b099e27f..941e54765f5 100644 --- a/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -202,6 +202,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) { 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: diff --git a/lib/IR/Attributes.cpp b/lib/IR/Attributes.cpp index 2586cb54c3e..bdefe5917fe 100644 --- a/lib/IR/Attributes.cpp +++ b/lib/IR/Attributes.cpp @@ -232,6 +232,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const { 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 @@ uint64_t AttributeImpl::getAttrMask(Attribute::AttrKind Val) { 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; diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index 813f9ca6744..0fce50e8440 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -1233,7 +1233,8 @@ void Verifier::VerifyAttributeTypes(AttributeSet Attrs, unsigned Idx, 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); diff --git a/test/Bindings/llvm-c/Inputs/invalid.ll.bc b/test/Bindings/llvm-c/Inputs/invalid.ll.bc index a85c3644b3a..8f7474b9e46 100644 Binary files a/test/Bindings/llvm-c/Inputs/invalid.ll.bc and b/test/Bindings/llvm-c/Inputs/invalid.ll.bc differ diff --git a/test/Bindings/llvm-c/invalid-bitcode.test b/test/Bindings/llvm-c/invalid-bitcode.test index 6318a9bf13d..9219f36eb24 100644 --- a/test/Bindings/llvm-c/invalid-bitcode.test +++ b/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) diff --git a/test/Bitcode/attributes.ll b/test/Bitcode/attributes.ll index 0cf0745175e..e3eda4887b3 100644 --- a/test/Bitcode/attributes.ll +++ b/test/Bitcode/attributes.ll @@ -204,7 +204,7 @@ define void @f34() ; CHECK: define void @f34() { call void @nobuiltin() nobuiltin -; CHECK: call void @nobuiltin() #27 +; CHECK: call void @nobuiltin() #28 ret void; } @@ -272,6 +272,11 @@ define "string_attribute_with_value"="value" void @f46(i32 "string_attribute_wit 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 @@ define "string_attribute_with_value"="value" void @f46(i32 "string_attribute_wit ; CHECK: attributes #24 = { jumptable } ; CHECK: attributes #25 = { convergent } ; CHECK: attributes #26 = { argmemonly } -; CHECK: attributes #27 = { nobuiltin } +; CHECK: attributes #27 = { norecurse } +; CHECK: attributes #28 = { nobuiltin } diff --git a/test/Bitcode/compatibility.ll b/test/Bitcode/compatibility.ll index 4c6349c803c..73c24f0370a 100644 --- a/test/Bitcode/compatibility.ll +++ b/test/Bitcode/compatibility.ll @@ -501,6 +501,8 @@ declare void @f.uwtable() uwtable ; 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 @@ declare void @f.prologuearray() prologue [4 x i32] [i32 0, i32 1, i32 2, i32 3] ; 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 @@ exit: ; 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 @@ normal: ; 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 diff --git a/test/Bitcode/invalid.ll b/test/Bitcode/invalid.ll index df9fec8772d..2f2eca94321 100644 --- a/test/Bitcode/invalid.ll +++ b/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 diff --git a/test/Bitcode/invalid.ll.bc b/test/Bitcode/invalid.ll.bc index a85c3644b3a..8f7474b9e46 100644 Binary files a/test/Bitcode/invalid.ll.bc and b/test/Bitcode/invalid.ll.bc differ diff --git a/test/LTO/X86/Inputs/invalid.ll.bc b/test/LTO/X86/Inputs/invalid.ll.bc index a85c3644b3a..8f7474b9e46 100644 Binary files a/test/LTO/X86/Inputs/invalid.ll.bc and b/test/LTO/X86/Inputs/invalid.ll.bc differ diff --git a/test/LTO/X86/invalid.ll b/test/LTO/X86/invalid.ll index 5b6996d4ad3..3de11112c71 100644 --- a/test/LTO/X86/invalid.ll +++ b/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)