diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index ee2f7aade0092..14d7d57f19bb1 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -1475,6 +1475,13 @@ example: 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 diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h index 31018a6bed273..706addc7bf90c 100644 --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -606,7 +606,8 @@ enum AttributeKindCodes { 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 { diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td index a2452f379d318..96dd915bca024 100644 --- a/llvm/include/llvm/IR/Attributes.td +++ b/llvm/include/llvm/IR/Attributes.td @@ -196,6 +196,9 @@ def SwiftSelf : EnumAttr<"swiftself">; /// 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">; diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp index dc8ff7f131505..1f34025b660ea 100644 --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -683,6 +683,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(swifterror); KEYWORD(swiftself); KEYWORD(uwtable); + KEYWORD(willreturn); KEYWORD(writeonly); KEYWORD(zeroext); KEYWORD(immarg); diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index b6f982bc3fb9e..2bd434785069b 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -1315,6 +1315,7 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B, 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. diff --git a/llvm/lib/AsmParser/LLToken.h b/llvm/lib/AsmParser/LLToken.h index a1e7093217877..f276a39037f82 100644 --- a/llvm/lib/AsmParser/LLToken.h +++ b/llvm/lib/AsmParser/LLToken.h @@ -225,6 +225,7 @@ enum Kind { kw_swifterror, kw_swiftself, kw_uwtable, + kw_willreturn, kw_writeonly, kw_zeroext, kw_immarg, diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index 4c346176bece3..4d004dcb735fd 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1272,6 +1272,8 @@ static uint64_t getRawAttributeMask(Attribute::AttrKind Val) { 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; @@ -1510,6 +1512,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) { 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: diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index 1f39fa34a8bb9..33dbbea5f8c82 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -710,6 +710,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) { 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: diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp index 67d35def9ffdf..99fc447c5af9c 100644 --- a/llvm/lib/IR/Attributes.cpp +++ b/llvm/lib/IR/Attributes.cpp @@ -333,6 +333,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const { 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)) diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 0deb0367b42f7..0ab421e057d79 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -1486,6 +1486,7 @@ void Verifier::visitModuleFlagCGProfileEntry(const MDOperand &MDO) { static bool isFuncOnlyAttr(Attribute::AttrKind Kind) { switch (Kind) { case Attribute::NoReturn: + case Attribute::WillReturn: case Attribute::NoCfCheck: case Attribute::NoUnwind: case Attribute::NoInline: diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp index 61c1e9313c278..23a404c11a6cc 100644 --- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp +++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp @@ -801,6 +801,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs, case Attribute::StructRet: case Attribute::SwiftError: case Attribute::SwiftSelf: + case Attribute::WillReturn: case Attribute::WriteOnly: case Attribute::ZExt: case Attribute::ImmArg: diff --git a/llvm/test/Bitcode/attributes.ll b/llvm/test/Bitcode/attributes.ll index 6f149c0d3bf7b..3aac9ee64ce4a 100644 --- a/llvm/test/Bitcode/attributes.ll +++ b/llvm/test/Bitcode/attributes.ll @@ -204,7 +204,7 @@ define void @f34() ; CHECK: define void @f34() { call void @nobuiltin() nobuiltin -; CHECK: call void @nobuiltin() #36 +; CHECK: call void @nobuiltin() #37 ret void; } @@ -351,6 +351,12 @@ define void @f59() shadowcallstack ret void } +; CHECK: define void @f60() #36 +define void @f60() willreturn +{ + ret void +} + ; CHECK: attributes #0 = { noreturn } ; CHECK: attributes #1 = { nounwind } ; CHECK: attributes #2 = { readnone } @@ -387,4 +393,5 @@ define void @f59() shadowcallstack ; CHECK: attributes #33 = { speculatable } ; CHECK: attributes #34 = { sanitize_hwaddress } ; CHECK: attributes #35 = { shadowcallstack } -; CHECK: attributes #36 = { nobuiltin } +; CHECK: attributes #36 = { willreturn } +; CHECK: attributes #37 = { nobuiltin } diff --git a/llvm/test/Transforms/FunctionAttrs/willreturn.ll b/llvm/test/Transforms/FunctionAttrs/willreturn.ll new file mode 100644 index 0000000000000..878538f9de319 --- /dev/null +++ b/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 + +;