[llvm] r364555 - [Attr] Add "willreturn" function attribute

Johannes Doerfert via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 27 08:51:41 PDT 2019


Author: jdoerfert
Date: Thu Jun 27 08:51:40 2019
New Revision: 364555

URL: http://llvm.org/viewvc/llvm-project?rev=364555&view=rev
Log:
[Attr] Add "willreturn" function attribute

This patch introduces a new function attribute, willreturn, to indicate
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.

This attribute guarantees that the function does not have any endless
loops, endless recursion, or terminating functions like abort or exit.

Patch by Hideto Ueno (@uenoku)

Reviewers: jdoerfert

Subscribers: mehdi_amini, hiraditya, steven_wu, dexonsmith, lebedev.ri, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D62801

Added:
    llvm/trunk/test/Transforms/FunctionAttrs/willreturn.ll
Modified:
    llvm/trunk/docs/LangRef.rst
    llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h
    llvm/trunk/include/llvm/IR/Attributes.td
    llvm/trunk/lib/AsmParser/LLLexer.cpp
    llvm/trunk/lib/AsmParser/LLParser.cpp
    llvm/trunk/lib/AsmParser/LLToken.h
    llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp
    llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp
    llvm/trunk/lib/IR/Attributes.cpp
    llvm/trunk/lib/IR/Verifier.cpp
    llvm/trunk/lib/Transforms/Utils/CodeExtractor.cpp
    llvm/trunk/test/Bitcode/attributes.ll

Modified: llvm/trunk/docs/LangRef.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/LangRef.rst?rev=364555&r1=364554&r2=364555&view=diff
==============================================================================
--- llvm/trunk/docs/LangRef.rst (original)
+++ llvm/trunk/docs/LangRef.rst Thu Jun 27 08:51:40 2019
@@ -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

Modified: llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h?rev=364555&r1=364554&r2=364555&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h (original)
+++ llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h Thu Jun 27 08:51:40 2019
@@ -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 {

Modified: llvm/trunk/include/llvm/IR/Attributes.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Attributes.td?rev=364555&r1=364554&r2=364555&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/Attributes.td (original)
+++ llvm/trunk/include/llvm/IR/Attributes.td Thu Jun 27 08:51:40 2019
@@ -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">;
 

Modified: llvm/trunk/lib/AsmParser/LLLexer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLLexer.cpp?rev=364555&r1=364554&r2=364555&view=diff
==============================================================================
--- llvm/trunk/lib/AsmParser/LLLexer.cpp (original)
+++ llvm/trunk/lib/AsmParser/LLLexer.cpp Thu Jun 27 08:51:40 2019
@@ -683,6 +683,7 @@ lltok::Kind LLLexer::LexIdentifier() {
   KEYWORD(swifterror);
   KEYWORD(swiftself);
   KEYWORD(uwtable);
+  KEYWORD(willreturn);
   KEYWORD(writeonly);
   KEYWORD(zeroext);
   KEYWORD(immarg);

Modified: llvm/trunk/lib/AsmParser/LLParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLParser.cpp?rev=364555&r1=364554&r2=364555&view=diff
==============================================================================
--- llvm/trunk/lib/AsmParser/LLParser.cpp (original)
+++ llvm/trunk/lib/AsmParser/LLParser.cpp Thu Jun 27 08:51:40 2019
@@ -1315,6 +1315,7 @@ bool LLParser::ParseFnAttributeValuePair
       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.

Modified: llvm/trunk/lib/AsmParser/LLToken.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLToken.h?rev=364555&r1=364554&r2=364555&view=diff
==============================================================================
--- llvm/trunk/lib/AsmParser/LLToken.h (original)
+++ llvm/trunk/lib/AsmParser/LLToken.h Thu Jun 27 08:51:40 2019
@@ -225,6 +225,7 @@ enum Kind {
   kw_swifterror,
   kw_swiftself,
   kw_uwtable,
+  kw_willreturn,
   kw_writeonly,
   kw_zeroext,
   kw_immarg,

Modified: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp?rev=364555&r1=364554&r2=364555&view=diff
==============================================================================
--- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp (original)
+++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp Thu Jun 27 08:51:40 2019
@@ -1272,6 +1272,8 @@ static uint64_t getRawAttributeMask(Attr
     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 getAttrFromCo
     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:

Modified: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp?rev=364555&r1=364554&r2=364555&view=diff
==============================================================================
--- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp (original)
+++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp Thu Jun 27 08:51:40 2019
@@ -710,6 +710,8 @@ static uint64_t getAttrKindEncoding(Attr
     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:

Modified: llvm/trunk/lib/IR/Attributes.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Attributes.cpp?rev=364555&r1=364554&r2=364555&view=diff
==============================================================================
--- llvm/trunk/lib/IR/Attributes.cpp (original)
+++ llvm/trunk/lib/IR/Attributes.cpp Thu Jun 27 08:51:40 2019
@@ -333,6 +333,8 @@ std::string Attribute::getAsString(bool
     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))

Modified: llvm/trunk/lib/IR/Verifier.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Verifier.cpp?rev=364555&r1=364554&r2=364555&view=diff
==============================================================================
--- llvm/trunk/lib/IR/Verifier.cpp (original)
+++ llvm/trunk/lib/IR/Verifier.cpp Thu Jun 27 08:51:40 2019
@@ -1486,6 +1486,7 @@ void Verifier::visitModuleFlagCGProfileE
 static bool isFuncOnlyAttr(Attribute::AttrKind Kind) {
   switch (Kind) {
   case Attribute::NoReturn:
+  case Attribute::WillReturn:
   case Attribute::NoCfCheck:
   case Attribute::NoUnwind:
   case Attribute::NoInline:

Modified: llvm/trunk/lib/Transforms/Utils/CodeExtractor.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/CodeExtractor.cpp?rev=364555&r1=364554&r2=364555&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Utils/CodeExtractor.cpp (original)
+++ llvm/trunk/lib/Transforms/Utils/CodeExtractor.cpp Thu Jun 27 08:51:40 2019
@@ -801,6 +801,7 @@ Function *CodeExtractor::constructFuncti
       case Attribute::StructRet:
       case Attribute::SwiftError:
       case Attribute::SwiftSelf:
+      case Attribute::WillReturn:
       case Attribute::WriteOnly:
       case Attribute::ZExt:
       case Attribute::ImmArg:

Modified: llvm/trunk/test/Bitcode/attributes.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/attributes.ll?rev=364555&r1=364554&r2=364555&view=diff
==============================================================================
--- llvm/trunk/test/Bitcode/attributes.ll (original)
+++ llvm/trunk/test/Bitcode/attributes.ll Thu Jun 27 08:51:40 2019
@@ -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 }

Added: llvm/trunk/test/Transforms/FunctionAttrs/willreturn.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/willreturn.ll?rev=364555&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/willreturn.ll (added)
+++ llvm/trunk/test/Transforms/FunctionAttrs/willreturn.ll Thu Jun 27 08:51:40 2019
@@ -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
+
+; <label>:3:                                      ; preds = %1
+  %4 = add nsw i32 %0, -1
+  %5 = tail call i32 @fib(i32 %4)
+  %6 = add nsw i32 %0, -2
+  %7 = tail call i32 @fib(i32 %6)
+  %8 = add nsw i32 %7, %5
+  ret i32 %8
+
+; <label>:9:                                      ; preds = %1
+  ret i32 %0
+}
+
+; 2.2 (negative case)
+; recursive function which doesn't stop for some input.
+; int fact_maybe_not_halt(int n) {
+;   if (n==0) {
+;     return 1;
+;   }
+;   return fact_maybe_not_halt( n > 0 ? n-1 : n) * n;
+; }
+; fact_maybe_not(-1) doesn't stop.
+
+; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable
+; FNATTR-NOT: willreturn
+; FNATTR-NEXT: define i32 @fact_maybe_not_halt(i32) local_unnamed_addr
+define i32 @fact_maybe_not_halt(i32) local_unnamed_addr #0 {
+  %2 = icmp eq i32 %0, 0
+  br i1 %2, label %11, label %3
+
+; <label>:3:                                      ; preds = %1, %3
+  %4 = phi i32 [ %8, %3 ], [ %0, %1 ]
+  %5 = phi i32 [ %9, %3 ], [ 1, %1 ]
+  %6 = icmp sgt i32 %4, 0
+  %7 = sext i1 %6 to i32
+  %8 = add nsw i32 %4, %7
+  %9 = mul nsw i32 %4, %5
+  %10 = icmp eq i32 %8, 0
+  br i1 %10, label %11, label %3
+
+; <label>:11:                                     ; preds = %3, %1
+  %12 = phi i32 [ 1, %1 ], [ %9, %3 ]
+  ret i32 %12
+}
+
+
+; TEST 3 (positive case)
+; loop
+; int fact_loop(int n ){
+;   int ans = 1;
+;   for(int i = 1;i<=n;i++){
+;     ans *= i;
+;   }
+;   return ans;
+; }
+
+; FIXME: missing willreturn
+; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable
+; FNATTR-NEXT: define i32 @fact_loop(i32)
+define i32 @fact_loop(i32) local_unnamed_addr #0 {
+  %2 = icmp slt i32 %0, 1
+  br i1 %2, label %3, label %5
+
+; <label>:3:                                      ; preds = %5, %1
+  %4 = phi i32 [ 1, %1 ], [ %8, %5 ]
+  ret i32 %4
+
+; <label>:5:                                      ; preds = %1, %5
+  %6 = phi i32 [ %9, %5 ], [ 1, %1 ]
+  %7 = phi i32 [ %8, %5 ], [ 1, %1 ]
+  %8 = mul nsw i32 %6, %7
+  %9 = add nuw nsw i32 %6, 1
+  %10 = icmp eq i32 %6, %0
+  br i1 %10, label %3, label %5
+}
+
+; TEST 4 (negative case)
+; mutual recursion
+; void mutual_recursion1(){
+;    mutual_recursion2();
+; }
+; void mutual_recursion2(){
+;     mutual_recursion1();
+; }
+
+; FNATTR: Function Attrs: noinline nounwind readnone uwtable
+; FNATTR-NOT: willreturn
+; FNATTR-NEXT: define void @mutual_recursion1()
+define void @mutual_recursion1() #0 {
+  call void @mutual_recursion2()
+  ret void
+}
+
+
+; FNATTR: Function Attrs: noinline nounwind readnone uwtable
+; FNATTR-NOT: willreturn
+; FNATTR-NEXT: define void @mutual_recursion2()
+define void @mutual_recursion2() #0 {
+  call void @mutual_recursion1()
+  ret void
+}
+
+
+; TEST 5 (negative case)
+; call exit/abort (has noreturn attribute)
+; FNATTR: Function Attrs: noreturn
+; FNATTR-NEXT: declare void @exit(i32) local_unnamed_addr
+declare void @exit(i32) local_unnamed_addr noreturn
+
+; FNATTR: Function Attrs: noinline nounwind uwtable
+; FNATTR-NOT: willreturn
+; FNATTR-NEXT: define void @only_exit()
+define void @only_exit() local_unnamed_addr #0 {
+  tail call void @exit(i32 0)
+  unreachable
+}
+
+; conditional exit
+; void conditional_exit(int cond, int *p){
+;     if(cond){
+;       exit(0);
+;     }
+;     if(*p){
+;       exit(1);
+;     }
+;     return;
+; }
+; FNATTR: Function Attrs: noinline nounwind uwtable
+; FNATTR-NOT: willreturn
+; FNATTR-NEXT: define void @conditional_exit(i32, i32* nocapture readonly) local_unnamed_addr
+define void @conditional_exit(i32, i32* nocapture readonly) local_unnamed_addr #0 {
+  %3 = icmp eq i32 %0, 0
+  br i1 %3, label %5, label %4
+
+; <label>:4:                                      ; preds = %2
+  tail call void @exit(i32 0)
+  unreachable
+
+; <label>:5:                                      ; preds = %2
+  %6 = load i32, i32* %1, align 4
+  %7 = icmp eq i32 %6, 0
+  br i1 %7, label %9, label %8
+
+; <label>:8:                                      ; preds = %5
+  tail call void @exit(i32 1)
+  unreachable
+
+; <label>:9:                                      ; preds = %5
+  ret void
+}
+
+; TEST 6 (positive case)
+; Call intrinsic function
+; FNATTRS: Function Attrs: noinline readnone speculatable
+; FNATTRS-NEXT: declare float @llvm.floor.f32(float)
+declare float @llvm.floor.f32(float)
+
+; FIXME: missing willreturn
+; FNATTRS: Function Attrs: noinline nounwind uwtable
+; FNATTRS-NEXT: define void @call_floor(float %a)
+define void @call_floor(float %a) #0 {
+    tail call float @llvm.floor.f32(float %a)
+    ret void
+}
+
+
+; TEST 7 (negative case)
+; Call function declaration without willreturn
+
+; FNATTR: Function Attrs: noinline nounwind uwtable
+; FNATTR-NOT: willreturn
+; FNATTR-NEXT: declare void @maybe_noreturn()
+declare void @maybe_noreturn() #0
+
+; FNATTR: Function Attrs: noinline nounwind uwtable
+; FNATTR-NOT: willreturn
+; FNATTR-NEXT: define void @call_maybe_noreturn()
+define void @call_maybe_noreturn() #0 {
+    tail call void @maybe_noreturn()
+    ret void
+}
+
+
+; TEST 8 (positive case)
+; Check propagation.
+
+; FNATTR: Function Attrs: willreturn
+; FNATTR-NEXT: declare void @will_return()
+declare void @will_return() willreturn
+
+; FIXME: missing willreturn
+; FNATTR: Function Attrs: noinline nounwind uwtable
+; FNATTR-NEXT: define void @f1()
+define void @f1() #0 {
+    tail call void @will_return()
+    ret void
+}
+
+; FIXME: missing willreturn
+; FNATTR: Function Attrs: noinline nounwind uwtable
+; FNATTR-NEXT: define void @f2()
+define void @f2() #0 {
+    tail call void @f1()
+    ret void
+}
+
+
+; TEST 9 (negative case)
+; call willreturn function in endless loop.
+
+; FNATTR: Function Attrs: noinline nounwind uwtable
+; FNATTR-NOT: willreturn
+; FNATTR-NEXT: define void @call_will_return_but_has_loop()
+define void @call_will_return_but_has_loop() #0 {
+  br label %label1
+label1:
+  tail call void @will_return()
+  br label %label2
+label2:
+  br label %label1
+}
+
+
+; TEST 10 (positive case)
+; invoke a function with willreturn
+
+; FNATTR: Function Attrs: noinline uwtable willreturn
+; FNATTR-NEXT: declare i1 @maybe_raise_exception()
+declare i1 @maybe_raise_exception() #1 willreturn
+
+; FIXME: missing willreturn
+; FNATTR: Function Attrs: nounwind
+; FNATTR-NEXT: define void @invoke_test()
+define void @invoke_test() personality i32 (...)* @__gxx_personality_v0 {
+  invoke i1 @maybe_raise_exception()
+			to label %N unwind label %F
+  N:
+    ret void
+  F:
+    %val = landingpad { i8*, i32 }
+                  catch i8* null
+    ret void
+}
+
+declare i32 @__gxx_personality_v0(...)
+
+
+; TEST 11 (positive case)
+; counstant trip count
+; int loop_constant_trip_count(int*p){
+;    int ans = 0;
+;    for(int i = 0;i<10;i++){
+;        ans += p[i];
+;    }
+;    return ans;
+; }
+
+; FIXME: missing willreturn
+; FNATTR: Function Attrs: noinline norecurse nounwind readonly uwtable
+; FNATTR-NEXT: define i32 @loop_constant_trip_count(i32* nocapture readonly)
+define i32 @loop_constant_trip_count(i32* nocapture readonly) #0 {
+  br label %3
+
+; <label>:2:                                      ; preds = %3
+  ret i32 %8
+
+; <label>:3:                                      ; preds = %3, %1
+  %4 = phi i64 [ 0, %1 ], [ %9, %3 ]
+  %5 = phi i32 [ 0, %1 ], [ %8, %3 ]
+  %6 = getelementptr inbounds i32, i32* %0, i64 %4
+  %7 = load i32, i32* %6, align 4
+  %8 = add nsw i32 %7, %5
+  %9 = add nuw nsw i64 %4, 1
+  %10 = icmp eq i64 %9, 10
+  br i1 %10, label %2, label %3
+}
+
+
+; TEST 12 (negative case)
+; unbounded trip count
+
+; int loop_trip_count_unbound(unsigned s,unsigned e, int *p, int offset){
+;     int ans = 0;
+;     for(unsigned i = s;i != e;i+=offset){
+;         ans += p[i];
+;     }
+;     return ans;
+; }
+; FNATTR: Function Attrs: noinline norecurse nounwind readonly uwtable
+; FNATTR-NOT: willreturn
+; FNATTR-NEXT: define i32 @loop_trip_count_unbound(i32, i32, i32* nocapture readonly, i32) local_unnamed_addr
+define i32 @loop_trip_count_unbound(i32, i32, i32* nocapture readonly, i32) local_unnamed_addr #0 {
+  %5 = icmp eq i32 %0, %1
+  br i1 %5, label %6, label %8
+
+; <label>:6:                                      ; preds = %8, %4
+  %7 = phi i32 [ 0, %4 ], [ %14, %8 ]
+  ret i32 %7
+
+; <label>:8:                                      ; preds = %4, %8
+  %9 = phi i32 [ %15, %8 ], [ %0, %4 ]
+  %10 = phi i32 [ %14, %8 ], [ 0, %4 ]
+  %11 = zext i32 %9 to i64
+  %12 = getelementptr inbounds i32, i32* %2, i64 %11
+  %13 = load i32, i32* %12, align 4
+  %14 = add nsw i32 %13, %10
+  %15 = add i32 %9, %3
+  %16 = icmp eq i32 %15, %1
+  br i1 %16, label %6, label %8
+}
+
+
+; TEST 13 (positive case)
+; Function Attrs: norecurse nounwind readonly uwtable
+;  int loop_trip_dec(int n, int *p){
+;    int ans = 0;
+;    for(;n >= 0;n--){
+;        ans += p[n];
+;    }
+;    return ans;
+;  }
+
+
+; FIXME: missing willreturn
+; FNATTR: Function Attrs: noinline norecurse nounwind readonly uwtable
+; FNATTR-NEXT: define i32 @loop_trip_dec(i32, i32* nocapture readonly)
+
+define i32 @loop_trip_dec(i32, i32* nocapture readonly) local_unnamed_addr #0 {
+  %3 = icmp sgt i32 %0, -1
+  br i1 %3, label %4, label %14
+
+; <label>:4:                                      ; preds = %2
+  %5 = sext i32 %0 to i64
+  br label %6
+
+; <label>:6:                                      ; preds = %4, %6
+  %7 = phi i64 [ %5, %4 ], [ %12, %6 ]
+  %8 = phi i32 [ 0, %4 ], [ %11, %6 ]
+  %9 = getelementptr inbounds i32, i32* %1, i64 %7
+  %10 = load i32, i32* %9, align 4
+  %11 = add nsw i32 %10, %8
+  %12 = add nsw i64 %7, -1
+  %13 = icmp sgt i64 %7, 0
+  br i1 %13, label %6, label %14
+
+; <label>:14:                                     ; preds = %6, %2
+  %15 = phi i32 [ 0, %2 ], [ %11, %6 ]
+  ret i32 %15
+}
+
+; TEST 14 (positive case)
+; multiple return
+
+; FIXME: missing willreturn
+; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable
+; FNATTR-NEXT: define i32 @multiple_return(i32 %a)
+define i32 @multiple_return(i32 %a) #0 {
+  %b =  icmp eq i32 %a, 0
+  br i1 %b, label %t, label %f
+
+t:
+  ret i32 1
+f:
+  ret i32 0
+}
+
+; TEST 15 (positive & negative case)
+; unreachable exit
+
+; 15.1 (positive case)
+; FIXME: missing willreturn
+; FNATTR: Function Attrs: noinline nounwind uwtable
+; FNATTR-NEXT: define void @unreachable_exit_positive1()
+define void @unreachable_exit_positive1() #0 {
+  tail call void @will_return()
+  ret void
+
+unreachable_label:
+  tail call void @exit(i32 0)
+  unreachable
+}
+
+; FIXME: missing willreturn
+; FNATTR: Function Attrs: noinline nounwind uwtable
+; FNATTR-NEXT: define i32 @unreachable_exit_positive2(i32)
+define i32 @unreachable_exit_positive2(i32) local_unnamed_addr #0 {
+  %2 = icmp slt i32 %0, 1
+  br i1 %2, label %3, label %5
+
+; <label>:3:                                      ; preds = %5, %1
+  %4 = phi i32 [ 1, %1 ], [ %8, %5 ]
+  ret i32 %4
+
+; <label>:5:                                      ; preds = %1, %5
+  %6 = phi i32 [ %9, %5 ], [ 1, %1 ]
+  %7 = phi i32 [ %8, %5 ], [ 1, %1 ]
+  %8 = mul nsw i32 %6, %7
+  %9 = add nuw nsw i32 %6, 1
+  %10 = icmp eq i32 %6, %0
+  br i1 %10, label %3, label %5
+
+unreachable_label:
+  tail call void @exit(i32 0)
+  unreachable
+}
+
+;15.2
+
+; FNATTR: Function Attrs: noinline nounwind uwtable
+; FNATTR-NOT: willreturn
+; FNATTR-NEXT: define void @unreachable_exit_negative1()
+define void @unreachable_exit_negative1() #0 {
+  tail call void @exit(i32 0)
+  ret void
+
+unreachable_label:
+  tail call void @exit(i32 0)
+  unreachable
+}
+
+; FNATTR: Function Attrs: noinline nounwind uwtable
+; FNATTR-NOT: willreturn
+; FNATTR-NEXT: define void @unreachable_exit_negative2()
+define void @unreachable_exit_negative2() #0 {
+
+  br label %L1
+L1:
+  br label %L2
+L2:
+  br label %L1
+
+unreachable_label:
+  tail call void @exit(i32 0)
+  unreachable
+}
+
+
+attributes #0 = { nounwind uwtable noinline }
+attributes #1 = { uwtable noinline }




More information about the llvm-commits mailing list