summaryrefslogtreecommitdiffstats
path: root/llvm/test
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/test')
-rw-r--r--llvm/test/Transforms/FunctionAttrs/arg_nocapture.ll12
-rw-r--r--llvm/test/Transforms/FunctionAttrs/arg_returned.ll10
-rw-r--r--llvm/test/Transforms/FunctionAttrs/fn_noreturn.ll38
-rw-r--r--llvm/test/Transforms/FunctionAttrs/liveness.ll2
-rw-r--r--llvm/test/Transforms/FunctionAttrs/nofree-attributor.ll13
-rw-r--r--llvm/test/Transforms/FunctionAttrs/nonnull.ll24
-rw-r--r--llvm/test/Transforms/FunctionAttrs/noreturn_async.ll142
-rw-r--r--llvm/test/Transforms/FunctionAttrs/noreturn_sync.ll138
-rw-r--r--llvm/test/Transforms/FunctionAttrs/nosync.ll10
-rw-r--r--llvm/test/Transforms/FunctionAttrs/nounwind.ll4
-rw-r--r--llvm/test/Transforms/FunctionAttrs/willreturn.ll30
11 files changed, 356 insertions, 67 deletions
diff --git a/llvm/test/Transforms/FunctionAttrs/arg_nocapture.ll b/llvm/test/Transforms/FunctionAttrs/arg_nocapture.ll
index 94d692e1d79..917d037ab3a 100644
--- a/llvm/test/Transforms/FunctionAttrs/arg_nocapture.ll
+++ b/llvm/test/Transforms/FunctionAttrs/arg_nocapture.ll
@@ -1,5 +1,4 @@
; RUN: opt -functionattrs -attributor -attributor-disable=false -S < %s | FileCheck %s
-; RUN: opt -functionattrs -attributor -attributor-disable=false -attributor-verify=true -S < %s | FileCheck %s
;
; Test cases specifically designed for the "no-capture" argument attribute.
; We use FIXME's to indicate problems and missing attributes.
@@ -87,11 +86,12 @@ entry:
;
; Other arguments are possible here due to the no-return behavior.
;
-; FIXME: no-return missing
; CHECK: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @srec16(i32* nocapture readnone %a)
define i32* @srec16(i32* %a) #0 {
entry:
%call = call i32* @srec16(i32* %a)
+; CHECK: %call = call i32* @srec16(i32* %a)
+; CHECK-NEXT: unreachable
%call1 = call i32* @srec16(i32* %call)
%call2 = call i32* @srec16(i32* %call1)
%call3 = call i32* @srec16(i32* %call2)
@@ -131,7 +131,7 @@ entry:
; }
;
; void *scc_C(short *a) {
-; return scc_A((int*)(scc_C(a) ? scc_B((double*)a) : scc_C(a)));
+; return scc_A((int*)(scc_A(a) ? scc_B((double*)a) : scc_C(a)));
; }
define float* @scc_A(i32* %a) {
entry:
@@ -183,8 +183,10 @@ cond.end: ; preds = %cond.false, %cond.t
define i8* @scc_C(i16* %a) {
entry:
- %call = call i8* @scc_C(i16* %a)
- %tobool = icmp ne i8* %call, null
+ %bc = bitcast i16* %a to i32*
+ %call = call float* @scc_A(i32* %bc)
+ %bc2 = bitcast float* %call to i8*
+ %tobool = icmp ne i8* %bc2, null
br i1 %tobool, label %cond.true, label %cond.false
cond.true: ; preds = %entry
diff --git a/llvm/test/Transforms/FunctionAttrs/arg_returned.ll b/llvm/test/Transforms/FunctionAttrs/arg_returned.ll
index f7d1de0f5d9..1cd01a7a340 100644
--- a/llvm/test/Transforms/FunctionAttrs/arg_returned.ll
+++ b/llvm/test/Transforms/FunctionAttrs/arg_returned.ll
@@ -259,10 +259,9 @@ return: ; preds = %cond.end, %if.then3
; return *a ? a : rt0(a);
; }
;
-; FIXME: no-return missing
; FNATTR: define i32* @rt0(i32* readonly %a)
-; BOTH: Function Attrs: nofree noinline nosync nounwind readonly uwtable
-; BOTH-NEXT: define i32* @rt0(i32* readonly returned %a)
+; BOTH: Function Attrs: nofree noinline noreturn nosync nounwind readonly uwtable
+; BOTH-NEXT: define i32* @rt0(i32* readonly %a)
define i32* @rt0(i32* %a) #0 {
entry:
%v = load i32, i32* %a, align 4
@@ -278,9 +277,8 @@ entry:
; return *a ? undef : rt1(a);
; }
;
-; FIXME: no-return missing
; FNATTR: define noalias i32* @rt1(i32* nocapture readonly %a)
-; BOTH: Function Attrs: nofree noinline nosync nounwind readonly uwtable
+; BOTH: Function Attrs: nofree noinline noreturn nosync nounwind readonly uwtable
; BOTH-NEXT: define noalias i32* @rt1(i32* nocapture readonly %a)
define i32* @rt1(i32* %a) #0 {
entry:
@@ -746,7 +744,7 @@ attributes #0 = { noinline nounwind uwtable }
; BOTH-NOT: attributes #
; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noinline norecurse nosync nounwind readnone uwtable willreturn }
; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noinline nosync nounwind readnone uwtable }
-; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noinline nosync nounwind readonly uwtable }
+; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noinline noreturn nosync nounwind readonly uwtable }
; BOTH-DAG: attributes #{{[0-9]*}} = { noinline nounwind uwtable }
; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noinline nosync nounwind readnone uwtable willreturn }
; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noinline nosync nounwind uwtable willreturn }
diff --git a/llvm/test/Transforms/FunctionAttrs/fn_noreturn.ll b/llvm/test/Transforms/FunctionAttrs/fn_noreturn.ll
index 9513ef8222a..885c5af4527 100644
--- a/llvm/test/Transforms/FunctionAttrs/fn_noreturn.ll
+++ b/llvm/test/Transforms/FunctionAttrs/fn_noreturn.ll
@@ -1,26 +1,18 @@
; RUN: opt -functionattrs -attributor -attributor-disable=false -S < %s | FileCheck %s
-; RUN: opt -functionattrs -attributor -attributor-disable=false -attributor-verify=true -S < %s | FileCheck %s
;
; Test cases specifically designed for the "no-return" function attribute.
; We use FIXME's to indicate problems and missing attributes.
-;
-; TEST 1: singleton SCC void return type
-; TEST 2: singleton SCC int return type with a lot of recursive calls
-; TEST 3: endless loop, no return instruction
-; TEST 4: endless loop, dead return instruction
-; TEST 5: all paths contain a no-return function call
-;
+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
-; TEST 1
+; TEST 1, singleton SCC void return type
;
; void srec0() {
; return srec0();
; }
;
-; FIXME: no-return missing
-; CHECK: Function Attrs: nofree noinline nosync nounwind readnone uwtable
+; CHECK: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; CHECK: define void @srec0()
;
define void @srec0() #0 {
@@ -30,14 +22,13 @@ entry:
}
-; TEST 2
+; TEST 2: singleton SCC int return type with a lot of recursive calls
;
; int srec16(int a) {
; return srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(a))))))))))))))));
; }
;
-; FIXME: no-return missing
-; CHECK: Function Attrs: nofree noinline nosync nounwind readnone uwtable
+; CHECK: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; CHECK: define i32 @srec16(i32 %a)
;
define i32 @srec16(i32 %a) #0 {
@@ -58,18 +49,20 @@ entry:
%call13 = call i32 @srec16(i32 %call12)
%call14 = call i32 @srec16(i32 %call13)
%call15 = call i32 @srec16(i32 %call14)
+ br label %exit
+
+exit:
ret i32 %call15
}
-; TEST 3
+; TEST 3: endless loop, no return instruction
;
; int endless_loop(int a) {
; while (1);
; }
;
-; FIXME: no-return missing
-; CHECK: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
+; CHECK: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable
; CHECK: define i32 @endless_loop(i32 %a)
;
define i32 @endless_loop(i32 %a) #0 {
@@ -81,15 +74,15 @@ while.body: ; preds = %entry, %while.body
}
-; TEST 4
+; TEST 4: endless loop, dead return instruction
;
; int endless_loop(int a) {
; while (1);
; return a;
; }
;
-; FIXME: no-return missing
-; CHECK: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
+; FIXME: no-return missing (D65243 should fix this)
+; CHECK: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable
; CHECK: define i32 @dead_return(i32 returned %a)
;
define i32 @dead_return(i32 %a) #0 {
@@ -104,14 +97,13 @@ return: ; No predecessors!
}
-; TEST 5
+; TEST 5: all paths contain a no-return function call
;
; int multiple_noreturn_calls(int a) {
; return a == 0 ? endless_loop(a) : srec16(a);
; }
;
-; FIXME: no-return missing
-; CHECK: Function Attrs: nofree noinline nosync nounwind readnone uwtable
+; CHECK: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; CHECK: define i32 @multiple_noreturn_calls(i32 %a)
;
define i32 @multiple_noreturn_calls(i32 %a) #0 {
diff --git a/llvm/test/Transforms/FunctionAttrs/liveness.ll b/llvm/test/Transforms/FunctionAttrs/liveness.ll
index 166b15441e4..535ba8779e3 100644
--- a/llvm/test/Transforms/FunctionAttrs/liveness.ll
+++ b/llvm/test/Transforms/FunctionAttrs/liveness.ll
@@ -26,7 +26,7 @@ define internal i32 @internal_load(i32*) norecurse nounwind uwtable {
}
; TEST 1: Only first block is live.
-; CHECK: Function Attrs: nofree nosync nounwind
+; CHECK: Function Attrs: nofree noreturn nosync nounwind
; CHECK-NEXT: define i32 @first_block_no_return(i32 %a, i32* nonnull %ptr1, i32* %ptr2)
define i32 @first_block_no_return(i32 %a, i32* nonnull %ptr1, i32* %ptr2) #0 {
entry:
diff --git a/llvm/test/Transforms/FunctionAttrs/nofree-attributor.ll b/llvm/test/Transforms/FunctionAttrs/nofree-attributor.ll
index ceb49d4a347..8ccb52fac6d 100644
--- a/llvm/test/Transforms/FunctionAttrs/nofree-attributor.ll
+++ b/llvm/test/Transforms/FunctionAttrs/nofree-attributor.ll
@@ -67,8 +67,15 @@ define void @free_in_scc1(i8* nocapture %0) local_unnamed_addr #0 {
; ATTRIBUTOR-NOT: nofree
; ATTRIBUTOR: define void @free_in_scc2(i8* nocapture %0) local_unnamed_addr
define void @free_in_scc2(i8* nocapture %0) local_unnamed_addr #0 {
- tail call void @free_in_scc1(i8* %0)
+ %cmp = icmp eq i8* %0, null
+ br i1 %cmp, label %rec, label %call
+call:
tail call void @free(i8* %0) #1
+ br label %end
+rec:
+ tail call void @free_in_scc1(i8* %0)
+ br label %end
+end:
ret void
}
@@ -85,7 +92,7 @@ define void @free_in_scc2(i8* nocapture %0) local_unnamed_addr #0 {
; FNATTR: Function Attrs: noinline nounwind readnone uwtable
; FNATTR-NEXT: define void @mutual_recursion1()
-; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
+; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind uwtable
; ATTRIBUTOR-NEXT: define void @mutual_recursion1()
define void @mutual_recursion1() #0 {
call void @mutual_recursion2()
@@ -94,7 +101,7 @@ define void @mutual_recursion1() #0 {
; FNATTR: Function Attrs: noinline nounwind readnone uwtable
; FNATTR-NEXT: define void @mutual_recursion2()
-; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
+; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind uwtable
; ATTRIBUTOR-NEXT: define void @mutual_recursion2()
define void @mutual_recursion2() #0 {
call void @mutual_recursion1()
diff --git a/llvm/test/Transforms/FunctionAttrs/nonnull.ll b/llvm/test/Transforms/FunctionAttrs/nonnull.ll
index a236aeab8ac..466276a062d 100644
--- a/llvm/test/Transforms/FunctionAttrs/nonnull.ll
+++ b/llvm/test/Transforms/FunctionAttrs/nonnull.ll
@@ -21,16 +21,20 @@ define i8* @test2(i8* nonnull %p) {
; Given an SCC where one of the functions can not be marked nonnull,
; can we still mark the other one which is trivially nonnull
-define i8* @scc_binder() {
+define i8* @scc_binder(i1 %c) {
; FNATTR: define i8* @scc_binder
; ATTRIBUTOR: define noalias i8* @scc_binder
- call i8* @test3()
+ br i1 %c, label %rec, label %end
+rec:
+ call i8* @test3(i1 %c)
+ br label %end
+end:
ret i8* null
}
-define i8* @test3() {
+define i8* @test3(i1 %c) {
; BOTH: define nonnull i8* @test3
- call i8* @scc_binder()
+ call i8* @scc_binder(i1 %c)
%ret = call i8* @ret_nonnull()
ret i8* %ret
}
@@ -54,17 +58,21 @@ define i8* @test4() {
; Given a mutual recursive set of functions which *can* return null
; make sure we haven't marked them as nonnull.
-define i8* @test5_helper() {
+define i8* @test5_helper(i1 %c) {
; FNATTR: define noalias i8* @test5_helper
; ATTRIBUTOR: define noalias i8* @test5_helper
- %ret = call i8* @test5()
+ br i1 %c, label %rec, label %end
+rec:
+ %ret = call i8* @test5(i1 %c)
+ br label %end
+end:
ret i8* null
}
-define i8* @test5() {
+define i8* @test5(i1 %c) {
; FNATTR: define noalias i8* @test5
; ATTRIBUTOR: define noalias i8* @test5
- %ret = call i8* @test5_helper()
+ %ret = call i8* @test5_helper(i1 %c)
ret i8* %ret
}
diff --git a/llvm/test/Transforms/FunctionAttrs/noreturn_async.ll b/llvm/test/Transforms/FunctionAttrs/noreturn_async.ll
new file mode 100644
index 00000000000..44de35e4b08
--- /dev/null
+++ b/llvm/test/Transforms/FunctionAttrs/noreturn_async.ll
@@ -0,0 +1,142 @@
+; RUN: opt -functionattrs -attributor -attributor-disable=false -S < %s | FileCheck %s
+;
+; This file is the same as noreturn_sync.ll but with a personality which
+; indicates that the exception handler *can* catch asynchronous exceptions. As
+; a consequence, invokes to noreturn and nounwind functions are not translated
+; to calls followed by an unreachable but the unwind edge is considered live.
+;
+; https://reviews.llvm.org/D59978#inline-586873
+;
+; Make sure we handle invoke of a noreturn function correctly.
+;
+; This test is also a reminder of how we handle (=ignore) stackoverflow exception handling.
+;
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc19.16.27032"
+
+@"??_C@_0BG@CMNEKHOP@Exception?5NOT?5caught?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [22 x i8] c"Exception NOT caught\0A\00", align 1
+@"??_C@_0BC@NKPAGFFJ@Exception?5caught?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [18 x i8] c"Exception caught\0A\00", align 1
+@"??_C@_0BK@JHJLGDKL@Done?5execution?5result?$DN?$CFi?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [26 x i8] c"Done execution result=%i\0A\00", align 1
+@"?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA" = linkonce_odr dso_local global i64 0, align 8
+
+
+define dso_local void @"?overflow@@YAXXZ"() {
+entry:
+; CHECK: Function Attrs: nofree noreturn nosync nounwind
+; CHECK-NEXT: define
+; CHECK-NEXT: entry:
+; CHECK-NEXT: call void @"?overflow@@YAXXZ"()
+; CHECK-NEXT: unreachable
+ call void @"?overflow@@YAXXZ"()
+ %call3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @"??_C@_0BC@NKPAGFFJ@Exception?5caught?6?$AA@", i64 0, i64 0))
+ ret void
+}
+
+
+; CHECK-NOT: nounwind
+; CHECK-NOT: noreturn
+; CHECK: define
+; CHECK-SAME: @"?catchoverflow@@YAHXZ"()
+define dso_local i32 @"?catchoverflow@@YAHXZ"() personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) {
+entry:
+ %retval = alloca i32, align 4
+ %__exception_code = alloca i32, align 4
+; CHECK: invoke void @"?overflow@@YAXXZ"()
+; CHECK: to label %invoke.cont unwind label %catch.dispatch
+ invoke void @"?overflow@@YAXXZ"()
+ to label %invoke.cont unwind label %catch.dispatch
+
+invoke.cont: ; preds = %entry
+; CHECK: invoke.cont:
+; CHECK-NEXT: unreachable
+ br label %invoke.cont1
+
+catch.dispatch: ; preds = %invoke.cont, %entry
+ %0 = catchswitch within none [label %__except] unwind to caller
+
+__except: ; preds = %catch.dispatch
+ %1 = catchpad within %0 [i8* null]
+ catchret from %1 to label %__except2
+
+__except2: ; preds = %__except
+ %2 = call i32 @llvm.eh.exceptioncode(token %1)
+ store i32 1, i32* %retval, align 4
+ br label %return
+
+invoke.cont1: ; preds = %invoke.cont
+ store i32 0, i32* %retval, align 4
+ br label %return
+
+__try.cont: ; No predecessors!
+ store i32 2, i32* %retval, align 4
+ br label %return
+
+return: ; preds = %__try.cont, %__except2, %invoke.cont1
+ %3 = load i32, i32* %retval, align 4
+ ret i32 %3
+}
+
+
+define dso_local void @"?overflow@@YAXXZ_may_throw"() {
+entry:
+; CHECK: Function Attrs: noreturn
+; CHECK-NOT: nounwind
+; CHECK-NEXT: define
+; CHECK-NEXT: entry:
+; CHECK-NEXT: %call3 = call i32 (i8*, ...) @printf(i8* dereferenceable_or_null(18) getelementptr inbounds ([18 x i8], [18 x i8]* @"??_C@_0BC@NKPAGFFJ@Exception?5caught?6?$AA@", i64 0, i64 0))
+; CHECK-NEXT: call void @"?overflow@@YAXXZ_may_throw"()
+; CHECK-NEXT: unreachable
+ %call3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @"??_C@_0BC@NKPAGFFJ@Exception?5caught?6?$AA@", i64 0, i64 0))
+ call void @"?overflow@@YAXXZ_may_throw"()
+ ret void
+}
+
+
+; CHECK-NOT: nounwind
+; CHECK-NOT: noreturn
+; CHECK: define
+; CHECK-SAME: @"?catchoverflow@@YAHXZ_may_throw"()
+define dso_local i32 @"?catchoverflow@@YAHXZ_may_throw"() personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) {
+entry:
+ %retval = alloca i32, align 4
+ %__exception_code = alloca i32, align 4
+; CHECK: invoke void @"?overflow@@YAXXZ_may_throw"()
+; CHECK: to label %invoke.cont unwind label %catch.dispatch
+ invoke void @"?overflow@@YAXXZ_may_throw"()
+ to label %invoke.cont unwind label %catch.dispatch
+
+invoke.cont: ; preds = %entry
+; CHECK: invoke.cont:
+; CHECK-NEXT: unreachable
+ br label %invoke.cont1
+
+catch.dispatch: ; preds = %invoke.cont, %entry
+ %0 = catchswitch within none [label %__except] unwind to caller
+
+__except: ; preds = %catch.dispatch
+ %1 = catchpad within %0 [i8* null]
+ catchret from %1 to label %__except2
+
+__except2: ; preds = %__except
+ %2 = call i32 @llvm.eh.exceptioncode(token %1)
+ store i32 1, i32* %retval, align 4
+ br label %return
+
+invoke.cont1: ; preds = %invoke.cont
+ store i32 0, i32* %retval, align 4
+ br label %return
+
+__try.cont: ; No predecessors!
+ store i32 2, i32* %retval, align 4
+ br label %return
+
+return: ; preds = %__try.cont, %__except2, %invoke.cont1
+ %3 = load i32, i32* %retval, align 4
+ ret i32 %3
+}
+
+declare dso_local i32 @__C_specific_handler(...)
+
+declare dso_local i32 @printf(i8* %_Format, ...)
+
+declare i32 @llvm.eh.exceptioncode(token)
diff --git a/llvm/test/Transforms/FunctionAttrs/noreturn_sync.ll b/llvm/test/Transforms/FunctionAttrs/noreturn_sync.ll
new file mode 100644
index 00000000000..44d3a7b3fee
--- /dev/null
+++ b/llvm/test/Transforms/FunctionAttrs/noreturn_sync.ll
@@ -0,0 +1,138 @@
+; RUN: opt -functionattrs -attributor -attributor-disable=false -S < %s | FileCheck %s
+;
+; This file is the same as noreturn_async.ll but with a personality which
+; indicates that the exception handler *cannot* catch asynchronous exceptions.
+; As a consequence, invokes to noreturn and nounwind functions are translated
+; to calls followed by an unreachable.
+;
+; https://reviews.llvm.org/D59978#inline-586873
+;
+; Make sure we handle invoke of a noreturn function correctly.
+;
+; This test is also a reminder of how we handle (=ignore) stackoverflow exception handling.
+;
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-linux-gnu"
+
+@"??_C@_0BG@CMNEKHOP@Exception?5NOT?5caught?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [22 x i8] c"Exception NOT caught\0A\00", align 1
+@"??_C@_0BC@NKPAGFFJ@Exception?5caught?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [18 x i8] c"Exception caught\0A\00", align 1
+@"??_C@_0BK@JHJLGDKL@Done?5execution?5result?$DN?$CFi?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [26 x i8] c"Done execution result=%i\0A\00", align 1
+@"?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA" = linkonce_odr dso_local global i64 0, align 8
+
+
+define dso_local void @"?overflow@@YAXXZ"() {
+entry:
+; CHECK: Function Attrs: nofree noreturn nosync nounwind
+; CHECK-NEXT: define
+; CHECK-NEXT: entry:
+; CHECK-NEXT: call void @"?overflow@@YAXXZ"()
+; CHECK-NEXT: unreachable
+ call void @"?overflow@@YAXXZ"()
+ %call3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @"??_C@_0BC@NKPAGFFJ@Exception?5caught?6?$AA@", i64 0, i64 0))
+ ret void
+}
+
+
+; CHECK: Function Attrs: nofree noreturn nosync nounwind
+; CHECK-NEXT: @"?catchoverflow@@YAHXZ"()
+define dso_local i32 @"?catchoverflow@@YAHXZ"() personality i8* bitcast (i32 (...)* @__gcc_personality_v0 to i8*) {
+entry:
+ %retval = alloca i32, align 4
+ %__exception_code = alloca i32, align 4
+ invoke void @"?overflow@@YAXXZ"()
+ to label %invoke.cont unwind label %catch.dispatch
+; CHECK: call void @"?overflow@@YAXXZ"()
+; CHECK-NEXT: unreachable
+
+invoke.cont: ; preds = %entry
+ br label %invoke.cont1
+
+catch.dispatch: ; preds = %invoke.cont, %entry
+ %0 = catchswitch within none [label %__except] unwind to caller
+
+__except: ; preds = %catch.dispatch
+ %1 = catchpad within %0 [i8* null]
+ catchret from %1 to label %__except2
+
+__except2: ; preds = %__except
+ %2 = call i32 @llvm.eh.exceptioncode(token %1)
+ store i32 1, i32* %retval, align 4
+ br label %return
+
+invoke.cont1: ; preds = %invoke.cont
+ store i32 0, i32* %retval, align 4
+ br label %return
+
+__try.cont: ; No predecessors!
+ store i32 2, i32* %retval, align 4
+ br label %return
+
+return: ; preds = %__try.cont, %__except2, %invoke.cont1
+ %3 = load i32, i32* %retval, align 4
+ ret i32 %3
+}
+
+
+define dso_local void @"?overflow@@YAXXZ_may_throw"() {
+entry:
+; CHECK: Function Attrs: noreturn
+; CHECK-NOT: nounwind
+; CHECK-NEXT: define
+; CHECK-NEXT: entry:
+; CHECK-NEXT: %call3 = call i32 (i8*, ...) @printf(i8* dereferenceable_or_null(18) getelementptr inbounds ([18 x i8], [18 x i8]* @"??_C@_0BC@NKPAGFFJ@Exception?5caught?6?$AA@", i64 0, i64 0))
+; CHECK-NEXT: call void @"?overflow@@YAXXZ_may_throw"()
+; CHECK-NEXT: unreachable
+ %call3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @"??_C@_0BC@NKPAGFFJ@Exception?5caught?6?$AA@", i64 0, i64 0))
+ call void @"?overflow@@YAXXZ_may_throw"()
+ ret void
+}
+
+
+; CHECK-NOT: nounwind
+; CHECK-NOT: noreturn
+; CHECK: define
+; CHECK-SAME: @"?catchoverflow@@YAHXZ_may_throw"()
+define dso_local i32 @"?catchoverflow@@YAHXZ_may_throw"() personality i8* bitcast (i32 (...)* @__gcc_personality_v0 to i8*) {
+entry:
+ %retval = alloca i32, align 4
+ %__exception_code = alloca i32, align 4
+; CHECK: invoke void @"?overflow@@YAXXZ_may_throw"()
+; CHECK: to label %invoke.cont unwind label %catch.dispatch
+ invoke void @"?overflow@@YAXXZ_may_throw"()
+ to label %invoke.cont unwind label %catch.dispatch
+
+invoke.cont: ; preds = %entry
+; CHECK: invoke.cont:
+; CHECK-NEXT: unreachable
+ br label %invoke.cont1
+
+catch.dispatch: ; preds = %invoke.cont, %entry
+ %0 = catchswitch within none [label %__except] unwind to caller
+
+__except: ; preds = %catch.dispatch
+ %1 = catchpad within %0 [i8* null]
+ catchret from %1 to label %__except2
+
+__except2: ; preds = %__except
+ %2 = call i32 @llvm.eh.exceptioncode(token %1)
+ store i32 1, i32* %retval, align 4
+ br label %return
+
+invoke.cont1: ; preds = %invoke.cont
+ store i32 0, i32* %retval, align 4
+ br label %return
+
+__try.cont: ; No predecessors!
+ store i32 2, i32* %retval, align 4
+ br label %return
+
+return: ; preds = %__try.cont, %__except2, %invoke.cont1
+ %3 = load i32, i32* %retval, align 4
+ ret i32 %3
+}
+
+declare dso_local i32 @__gcc_personality_v0(...)
+
+declare dso_local i32 @printf(i8* %_Format, ...)
+
+declare i32 @llvm.eh.exceptioncode(token)
diff --git a/llvm/test/Transforms/FunctionAttrs/nosync.ll b/llvm/test/Transforms/FunctionAttrs/nosync.ll
index 1d7f46af203..c86facb8192 100644
--- a/llvm/test/Transforms/FunctionAttrs/nosync.ll
+++ b/llvm/test/Transforms/FunctionAttrs/nosync.ll
@@ -180,13 +180,12 @@ define void @call_might_sync() nounwind uwtable noinline {
ret void
}
-; TEST 11 - negative, should not deduce nosync
-; volatile operation in same scc. Call volatile_load defined in TEST 8.
+; TEST 11 - positive, should deduce nosync
+; volatile operation in same scc but dead. Call volatile_load defined in TEST 8.
; FNATTR: Function Attrs: nofree noinline nounwind uwtable
; FNATTR-NEXT: define i32 @scc1(i32* %0)
-; ATTRIBUTOR: Function Attrs: nofree noinline nounwind uwtable
-; ATTRIBUTOR-NOT: nosync
+; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind uwtable
; ATTRIBUTOR-NEXT: define i32 @scc1(i32* %0)
define i32 @scc1(i32* %0) noinline nounwind uwtable {
tail call void @scc2(i32* %0);
@@ -196,8 +195,7 @@ define i32 @scc1(i32* %0) noinline nounwind uwtable {
; FNATTR: Function Attrs: nofree noinline nounwind uwtable
; FNATTR-NEXT: define void @scc2(i32* %0)
-; ATTRIBUTOR: Function Attrs: nofree noinline nounwind uwtable
-; ATTRIBUTOR-NOT: nosync
+; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind uwtable
; ATTRIBUTOR-NEXT: define void @scc2(i32* %0)
define void @scc2(i32* %0) noinline nounwind uwtable {
tail call i32 @scc1(i32* %0);
diff --git a/llvm/test/Transforms/FunctionAttrs/nounwind.ll b/llvm/test/Transforms/FunctionAttrs/nounwind.ll
index fa2dddd31ae..1c9d019960c 100644
--- a/llvm/test/Transforms/FunctionAttrs/nounwind.ll
+++ b/llvm/test/Transforms/FunctionAttrs/nounwind.ll
@@ -13,7 +13,7 @@ define i32 @foo1() {
; TEST 2
; CHECK: Function Attrs: nounwind readnone
; CHECK-NEXT: define i32 @scc1_foo()
-; ATTRIBUTOR: Function Attrs: nofree nosync nounwind
+; ATTRIBUTOR: Function Attrs: nofree noreturn nosync nounwind
; ATTRIBUTOR-NEXT: define i32 @scc1_foo()
define i32 @scc1_foo() {
%1 = call i32 @scc1_bar()
@@ -24,7 +24,7 @@ define i32 @scc1_foo() {
; TEST 3
; CHECK: Function Attrs: nounwind readnone
; CHECK-NEXT: define i32 @scc1_bar()
-; ATTRIBUTOR: Function Attrs: nofree nosync nounwind
+; ATTRIBUTOR: Function Attrs: nofree noreturn nosync nounwind
; ATTRIBUTOR-NEXT: define i32 @scc1_bar()
define i32 @scc1_bar() {
%1 = call i32 @scc1_foo()
diff --git a/llvm/test/Transforms/FunctionAttrs/willreturn.ll b/llvm/test/Transforms/FunctionAttrs/willreturn.ll
index 6d7d35a5108..8ddcf7e7e15 100644
--- a/llvm/test/Transforms/FunctionAttrs/willreturn.ll
+++ b/llvm/test/Transforms/FunctionAttrs/willreturn.ll
@@ -125,24 +125,28 @@ define i32 @fact_loop(i32 %0) local_unnamed_addr #0 {
; FNATTR: Function Attrs: noinline nounwind readnone uwtable
; FNATTR-NOT: willreturn
-; FNATTR-NEXT: define void @mutual_recursion1()
+; FNATTR-NEXT: define void @mutual_recursion1(i1 %c)
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
; ATTRIBUTOR-NOT: willreturn
-; ATTRIBUTOR-NEXT: define void @mutual_recursion1()
-define void @mutual_recursion1() #0 {
- call void @mutual_recursion2()
+; ATTRIBUTOR-NEXT: define void @mutual_recursion1(i1 %c)
+define void @mutual_recursion1(i1 %c) #0 {
+ br i1 %c, label %rec, label %end
+rec:
+ call void @mutual_recursion2(i1 %c)
+ br label %end
+end:
ret void
}
; FNATTR: Function Attrs: noinline nounwind readnone uwtable
; FNATTR-NOT: willreturn
-; FNATTR-NEXT: define void @mutual_recursion2()
+; FNATTR-NEXT: define void @mutual_recursion2(i1 %c)
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
; ATTRIBUTOR-NOT: willreturn
-; ATTRIBUTOR-NEXT: define void @mutual_recursion2()
-define void @mutual_recursion2() #0 {
- call void @mutual_recursion1()
+; ATTRIBUTOR-NEXT: define void @mutual_recursion2(i1 %c)
+define void @mutual_recursion2(i1 %c) #0 {
+ call void @mutual_recursion1(i1 %c)
ret void
}
@@ -158,7 +162,7 @@ declare void @exit(i32 %0) local_unnamed_addr noreturn
; FNATTR: Function Attrs: noinline nounwind uwtable
; FNATTR-NOT: willreturn
; FNATTR-NEXT: define void @only_exit()
-; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR: Function Attrs: noinline noreturn nounwind uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define void @only_exit() local_unnamed_addr
define void @only_exit() local_unnamed_addr #0 {
@@ -283,7 +287,7 @@ define void @f2() #0 {
; FNATTR: Function Attrs: noinline nounwind uwtable
; FNATTR-NOT: willreturn
; FNATTR-NEXT: define void @call_will_return_but_has_loop()
-; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR: Function Attrs: noinline noreturn nounwind uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define void @call_will_return_but_has_loop()
define void @call_will_return_but_has_loop() #0 {
@@ -499,7 +503,7 @@ unreachable_label:
; FNATTR: Function Attrs: noinline nounwind uwtable
; FNATTR-NOT: willreturn
; FNATTR-NEXT: define void @unreachable_exit_negative1()
-; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR: Function Attrs: noinline noreturn nounwind uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define void @unreachable_exit_negative1()
define void @unreachable_exit_negative1() #0 {
@@ -514,7 +518,7 @@ unreachable_label:
; FNATTR: Function Attrs: noinline nounwind uwtable
; FNATTR-NOT: willreturn
; FNATTR-NEXT: define void @unreachable_exit_negative2()
-; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
+; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define void @unreachable_exit_negative2()
define void @unreachable_exit_negative2() #0 {
@@ -539,7 +543,7 @@ declare void @llvm.eh.sjlj.longjmp(i8*)
; FNATTR: Function Attrs: noinline nounwind uwtable
; FNATTR-NOT: willreturn
; FNATTR-NEXT: define void @call_longjmp(i8* nocapture readnone %0) local_unnamed_addr #3 {
-; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR: Function Attrs: noinline noreturn nounwind uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define void @call_longjmp(i8* nocapture readnone %0) local_unnamed_addr
define void @call_longjmp(i8* nocapture readnone %0) local_unnamed_addr #0 {
OpenPOWER on IntegriCloud