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.

llvm-svn: 252282
This commit is contained in:
James Molloy 2015-11-06 10:32:53 +00:00
parent 34cc3b400b
commit be569ad3b9
19 changed files with 49 additions and 14 deletions

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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.

View File

@ -616,6 +616,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(noduplicate);
KEYWORD(noimplicitfloat);
KEYWORD(noinline);
KEYWORD(norecurse);
KEYWORD(nonlazybind);
KEYWORD(nonnull);
KEYWORD(noredzone);

View File

@ -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;

View File

@ -123,6 +123,7 @@ namespace lltok {
kw_noduplicate,
kw_noimplicitfloat,
kw_noinline,
kw_norecurse,
kw_nonlazybind,
kw_nonnull,
kw_noredzone,

View File

@ -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:

View File

@ -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:

View File

@ -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;

View File

@ -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);

View File

@ -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)

View File

@ -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 }

View File

@ -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> <i1 true, i1 false>, <2 x i8> <i8 2, i8 3>, <2 x i8> <i8 3, i8 2>
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

View File

@ -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

Binary file not shown.

Binary file not shown.

View File

@ -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)