1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
| ; RUN: opt -functionattrs -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 -S < %s | FileCheck %s
;
; Test cases specifically designed for the "no-return" function attribute.
; We use FIXME's to indicate problems and missing attributes.
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
; TEST 1, singleton SCC void return type
;
; void srec0() {
; return srec0();
; }
;
; CHECK: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; CHECK: define void @srec0()
;
define void @srec0() #0 {
entry:
call void @srec0()
ret void
}
; 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))))))))))))))));
; }
;
; CHECK: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; CHECK: define i32 @srec16(i32 %a)
;
define i32 @srec16(i32 %a) #0 {
entry:
%call = call i32 @srec16(i32 %a)
%call1 = call i32 @srec16(i32 %call)
%call2 = call i32 @srec16(i32 %call1)
%call3 = call i32 @srec16(i32 %call2)
%call4 = call i32 @srec16(i32 %call3)
%call5 = call i32 @srec16(i32 %call4)
%call6 = call i32 @srec16(i32 %call5)
%call7 = call i32 @srec16(i32 %call6)
%call8 = call i32 @srec16(i32 %call7)
%call9 = call i32 @srec16(i32 %call8)
%call10 = call i32 @srec16(i32 %call9)
%call11 = call i32 @srec16(i32 %call10)
%call12 = call i32 @srec16(i32 %call11)
%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: endless loop, no return instruction
;
; int endless_loop(int a) {
; while (1);
; }
;
; 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 {
entry:
br label %while.body
while.body: ; preds = %entry, %while.body
br label %while.body
}
; TEST 4: endless loop, dead return instruction
;
; int endless_loop(int a) {
; while (1);
; return a;
; }
;
; 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 {
entry:
br label %while.body
while.body: ; preds = %entry, %while.body
br label %while.body
return: ; No predecessors!
ret i32 %a
}
; TEST 5: all paths contain a no-return function call
;
; int multiple_noreturn_calls(int a) {
; return a == 0 ? endless_loop(a) : srec16(a);
; }
;
; 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 {
entry:
%cmp = icmp eq i32 %a, 0
br i1 %cmp, label %cond.true, label %cond.false
cond.true: ; preds = %entry
%call = call i32 @endless_loop(i32 %a)
br label %cond.end
cond.false: ; preds = %entry
%call1 = call i32 @srec16(i32 %a)
br label %cond.end
cond.end: ; preds = %cond.false, %cond.true
%cond = phi i32 [ %call, %cond.true ], [ %call1, %cond.false ]
ret i32 %cond
}
; TEST 6: willreturn means *not* no-return
; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; CHECK-NEXT: define i32 @endless_loop_but_willreturn
define i32 @endless_loop_but_willreturn(i32 %a) willreturn {
entry:
br label %while.body
while.body: ; preds = %entry, %while.body
br label %while.body
}
attributes #0 = { noinline nounwind uwtable }
|