Add a new attribute: norecurse
authorJames Molloy <james.molloy@arm.com>
Fri, 6 Nov 2015 10:32:53 +0000 (10:32 +0000)
committerJames Molloy <james.molloy@arm.com>
Fri, 6 Nov 2015 10:32:53 +0000 (10:32 +0000)
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

19 files changed:
docs/LangRef.rst
include/llvm/Bitcode/LLVMBitCodes.h
include/llvm/IR/Attributes.h
include/llvm/IR/Function.h
lib/AsmParser/LLLexer.cpp
lib/AsmParser/LLParser.cpp
lib/AsmParser/LLToken.h
lib/Bitcode/Reader/BitcodeReader.cpp
lib/Bitcode/Writer/BitcodeWriter.cpp
lib/IR/Attributes.cpp
lib/IR/Verifier.cpp
test/Bindings/llvm-c/Inputs/invalid.ll.bc
test/Bindings/llvm-c/invalid-bitcode.test
test/Bitcode/attributes.ll
test/Bitcode/compatibility.ll
test/Bitcode/invalid.ll
test/Bitcode/invalid.ll.bc
test/LTO/X86/Inputs/invalid.ll.bc
test/LTO/X86/invalid.ll

index 507c3bfd334e6f003ed16ba560ef21e772a1281a..d2bba5c8a74310e22567cf78417c7b70e305463d 100644 (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
index 08d88a20454327930b08f44d283d7e6a18e99d99..b79c2785a61dad1bb40fbf3b5818d45af47edcff 100644 (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 {
index 15f48fa38d93c386345857ea11f5357526f9641e..b3984330b171193087e1e7d53bc9cff358dcf485 100644 (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
index b8e22af4bfe3d72f92cc5e781986c18a62df0851..71822a462daa68da562c178c4932d99ac321966a 100644 (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.
index 2eb5f0bf45d5bfc6941999dc5ff8608e48404762..82d6eb7788cc3844f413328c9f9703cfd54aa5a6 100644 (file)
@@ -616,6 +616,7 @@ lltok::Kind LLLexer::LexIdentifier() {
   KEYWORD(noduplicate);
   KEYWORD(noimplicitfloat);
   KEYWORD(noinline);
+  KEYWORD(norecurse);
   KEYWORD(nonlazybind);
   KEYWORD(nonnull);
   KEYWORD(noredzone);
index 1c219ad6cd8ec22017695f1a074ae286b25f36c2..7feb99d555c5e5a99c5bf1b5fd55c89a091fdfe3 100644 (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;
index 06b5f9b0800f90a335095ef9a4b4adaa92ab18e5..ecd6481e6faafdbe5fedf712e7afcecf2bc17c5a 100644 (file)
@@ -123,6 +123,7 @@ namespace lltok {
     kw_noduplicate,
     kw_noimplicitfloat,
     kw_noinline,
+    kw_norecurse,
     kw_nonlazybind,
     kw_nonnull,
     kw_noredzone,
index 7c1b208c62610b92980527c87fe3594de52ae995..bc846192fcfd02674000237aacfaf7020cc977d9 100644 (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:
index c73b099e27f92c4e27f4fb8719eadccb52db6491..941e54765f5bb3803b0eb408cae81e1575a443a5 100644 (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:
index 2586cb54c3ee892b91407e41a521e5269f068e3d..bdefe5917feffbb467011247076122e72901a407 100644 (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;
index 813f9ca6744852847d9358d50835abed6c75d4c3..0fce50e8440191612b911aba3be579fd819d6b80 100644 (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);
index a85c3644b3abb93a450b18dcfa20b5fbf01ed143..8f7474b9e468a12c9a0719386bf9e9eda12cdd85 100644 (file)
Binary files a/test/Bindings/llvm-c/Inputs/invalid.ll.bc and b/test/Bindings/llvm-c/Inputs/invalid.ll.bc differ
index 6318a9bf13d93bf7af3f25815698aeb40e7835e3..9219f36eb2428dc3007ca3d8d7b300dfcc378859 100644 (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)
index 0cf0745175ef68e5fe65aa98bae694f1b547c719..e3eda4887b36171fa17de9e5cae943b2e1f99180 100644 (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 }
index 4c6349c803cf2ddfc6cfb712b592d99507a6f14f..73c24f0370a6528c45acab2537fae5f058a010e5 100644 (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
 
index df9fec8772d1f429d55d44f4d725872476d980cd..2f2eca94321e5336fe2647ae2fcf5659b1083e6f 100644 (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
index a85c3644b3abb93a450b18dcfa20b5fbf01ed143..8f7474b9e468a12c9a0719386bf9e9eda12cdd85 100644 (file)
Binary files a/test/Bitcode/invalid.ll.bc and b/test/Bitcode/invalid.ll.bc differ
index a85c3644b3abb93a450b18dcfa20b5fbf01ed143..8f7474b9e468a12c9a0719386bf9e9eda12cdd85 100644 (file)
Binary files a/test/LTO/X86/Inputs/invalid.ll.bc and b/test/LTO/X86/Inputs/invalid.ll.bc differ
index 5b6996d4ad35073f69adcf22e03f0326081fe238..3de11112c71d6e706f3d487dc086915a5e73027e 100644 (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)