Index: llvm/docs/LangRef.rst =================================================================== --- llvm/docs/LangRef.rst +++ llvm/docs/LangRef.rst @@ -1478,6 +1478,13 @@ 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. +``willreturn`` + This function attribute indicates that a call of this function will + either exhibit undefined behavior or comes back and continues execution + at a point in the existing call stack that includes the current invocation. + Annotated functions may still raise an exception, i.a., ``nounwind`` is not implied. + If an invocation of an annotated function does not return control back + to a point in the call stack, the behavior is undefined. ``nounwind`` This function attribute indicates that the function never raises an exception. If the function does raise an exception, its runtime Index: llvm/include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -606,7 +606,8 @@ ATTR_KIND_OPT_FOR_FUZZING = 57, ATTR_KIND_SHADOWCALLSTACK = 58, ATTR_KIND_SPECULATIVE_LOAD_HARDENING = 59, - ATTR_KIND_IMMARG = 60 + ATTR_KIND_IMMARG = 60, + ATTR_KIND_WILLRETURN = 61, }; enum ComdatSelectionKindCodes { Index: llvm/include/llvm/IR/Attributes.td =================================================================== --- llvm/include/llvm/IR/Attributes.td +++ llvm/include/llvm/IR/Attributes.td @@ -196,6 +196,9 @@ /// Function must be in a unwind table. def UWTable : EnumAttr<"uwtable">; +/// Function always comes back to callsite. +def WillReturn : EnumAttr<"willreturn">; + /// Function only writes to memory. def WriteOnly : EnumAttr<"writeonly">; Index: llvm/lib/AsmParser/LLLexer.cpp =================================================================== --- llvm/lib/AsmParser/LLLexer.cpp +++ llvm/lib/AsmParser/LLLexer.cpp @@ -683,6 +683,7 @@ KEYWORD(swifterror); KEYWORD(swiftself); KEYWORD(uwtable); + KEYWORD(willreturn); KEYWORD(writeonly); KEYWORD(zeroext); KEYWORD(immarg); Index: llvm/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/lib/AsmParser/LLParser.cpp +++ llvm/lib/AsmParser/LLParser.cpp @@ -1315,6 +1315,7 @@ break; case lltok::kw_strictfp: B.addAttribute(Attribute::StrictFP); break; case lltok::kw_uwtable: B.addAttribute(Attribute::UWTable); break; + case lltok::kw_willreturn: B.addAttribute(Attribute::WillReturn); break; case lltok::kw_writeonly: B.addAttribute(Attribute::WriteOnly); break; // Error handling. Index: llvm/lib/AsmParser/LLToken.h =================================================================== --- llvm/lib/AsmParser/LLToken.h +++ llvm/lib/AsmParser/LLToken.h @@ -226,6 +226,7 @@ kw_swifterror, kw_swiftself, kw_uwtable, + kw_willreturn, kw_writeonly, kw_zeroext, kw_immarg, Index: llvm/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1195,6 +1195,8 @@ return 1ULL << 60; case Attribute::ImmArg: return 1ULL << 61; + case Attribute::WillReturn: + return 1ULL << 62; case Attribute::Dereferenceable: llvm_unreachable("dereferenceable attribute not supported in raw format"); break; @@ -1427,6 +1429,8 @@ return Attribute::SwiftSelf; case bitc::ATTR_KIND_UW_TABLE: return Attribute::UWTable; + case bitc::ATTR_KIND_WILLRETURN: + return Attribute::WillReturn; case bitc::ATTR_KIND_WRITEONLY: return Attribute::WriteOnly; case bitc::ATTR_KIND_Z_EXT: Index: llvm/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -710,6 +710,8 @@ return bitc::ATTR_KIND_SWIFT_SELF; case Attribute::UWTable: return bitc::ATTR_KIND_UW_TABLE; + case Attribute::WillReturn: + return bitc::ATTR_KIND_WILLRETURN; case Attribute::WriteOnly: return bitc::ATTR_KIND_WRITEONLY; case Attribute::ZExt: Index: llvm/lib/IR/Attributes.cpp =================================================================== --- llvm/lib/IR/Attributes.cpp +++ llvm/lib/IR/Attributes.cpp @@ -333,6 +333,8 @@ return "noredzone"; if (hasAttribute(Attribute::NoReturn)) return "noreturn"; + if (hasAttribute(Attribute::WillReturn)) + return "willreturn"; if (hasAttribute(Attribute::NoCfCheck)) return "nocf_check"; if (hasAttribute(Attribute::NoRecurse)) Index: llvm/lib/IR/Verifier.cpp =================================================================== --- llvm/lib/IR/Verifier.cpp +++ llvm/lib/IR/Verifier.cpp @@ -1521,6 +1521,7 @@ static bool isFuncOnlyAttr(Attribute::AttrKind Kind) { switch (Kind) { case Attribute::NoReturn: + case Attribute::WillReturn: case Attribute::NoCfCheck: case Attribute::NoUnwind: case Attribute::NoInline: Index: llvm/lib/Transforms/Utils/CodeExtractor.cpp =================================================================== --- llvm/lib/Transforms/Utils/CodeExtractor.cpp +++ llvm/lib/Transforms/Utils/CodeExtractor.cpp @@ -801,6 +801,7 @@ case Attribute::StructRet: case Attribute::SwiftError: case Attribute::SwiftSelf: + case Attribute::WillReturn: case Attribute::WriteOnly: case Attribute::ZExt: case Attribute::ImmArg: Index: llvm/test/Transforms/FunctionAttrs/willreturn.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/FunctionAttrs/willreturn.ll @@ -0,0 +1,469 @@ +; RUN: opt -functionattrs -S < %s | FileCheck %s --check-prefix=FNATTR + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +; Test cases specifically designed for the "willreturn" function attribute. +; We use FIXME's to indicate problems and missing attributes. + + +; TEST 1 (positive case) +; FIXME: missing willreturn +; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable +; FNATTR-NEXT: define void @only_return() +define void @only_return() #0 { + ret void +} + + +; TEST 2 (positive & negative case) +; 2.1 (positive case) +; recursive function which will halt +; int fib(int n){ +; return n<=1? n : fib(n-1) + fib(n-2); +; } + +; FIXME: missing willreturn +; FNATTR: Function Attrs: noinline nounwind readnone uwtable +; FNATTR-NEXT: define i32 @fib(i32) +define i32 @fib(i32) local_unnamed_addr #0 { + %2 = icmp slt i32 %0, 2 + br i1 %2, label %9, label %3 + +;