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
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 {
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
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.
KEYWORD(noduplicate);
KEYWORD(noimplicitfloat);
KEYWORD(noinline);
+ KEYWORD(norecurse);
KEYWORD(nonlazybind);
KEYWORD(nonnull);
KEYWORD(noredzone);
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;
kw_noduplicate,
kw_noimplicitfloat,
kw_noinline,
+ kw_norecurse,
kw_nonlazybind,
kw_nonnull,
kw_noredzone,
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:
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:
return "noredzone";
if (hasAttribute(Attribute::NoReturn))
return "noreturn";
+ if (hasAttribute(Attribute::NoRecurse))
+ return "norecurse";
if (hasAttribute(Attribute::NoUnwind))
return "nounwind";
if (hasAttribute(Attribute::OptimizeNone))
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;
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);
; 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)
; CHECK: define void @f34()
{
call void @nobuiltin() nobuiltin
-; CHECK: call void @nobuiltin() #27
+; CHECK: call void @nobuiltin() #28
ret void;
}
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 }
; CHECK: attributes #24 = { jumptable }
; CHECK: attributes #25 = { convergent }
; CHECK: attributes #26 = { argmemonly }
-; CHECK: attributes #27 = { nobuiltin }
+; CHECK: attributes #27 = { norecurse }
+; CHECK: attributes #28 = { nobuiltin }
; 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"
; 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
; 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
; 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
; 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
; 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)