]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - test/CodeGen/RISCV/tail-calls.ll
Vendor import of llvm trunk r338150:
[FreeBSD/FreeBSD.git] / test / CodeGen / RISCV / tail-calls.ll
1 ; RUN: llc -mtriple riscv32-unknown-linux-gnu -o - %s | FileCheck %s
2 ; RUN: llc -mtriple riscv32-unknown-elf       -o - %s | FileCheck %s
3
4 ; Perform tail call optimization for global address.
5 declare i32 @callee_tail(i32 %i)
6 define i32 @caller_tail(i32 %i) {
7 ; CHECK-LABEL: caller_tail
8 ; CHECK: tail callee_tail
9 entry:
10   %r = tail call i32 @callee_tail(i32 %i)
11   ret i32 %r
12 }
13
14 ; Perform tail call optimization for external symbol.
15 @dest = global [2 x i8] zeroinitializer
16 declare void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1)
17 define void @caller_extern(i8* %src) optsize {
18 entry:
19 ; CHECK: caller_extern
20 ; CHECK-NOT: call memcpy
21 ; CHECK: tail memcpy
22   tail call void @llvm.memcpy.p0i8.p0i8.i32(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @dest, i32 0, i32 0), i8* %src, i32 7, i1 false)
23   ret void
24 }
25
26 ; Perform indirect tail call optimization (for function pointer call).
27 declare void @callee_indirect1()
28 declare void @callee_indirect2()
29 define void @caller_indirect_tail(i32 %a) {
30 ; CHECK-LABEL: caller_indirect_tail
31 ; CHECK-NOT: call callee_indirect1
32 ; CHECK-NOT: call callee_indirect2
33 ; CHECK-NOT: tail callee_indirect1
34 ; CHECK-NOT: tail callee_indirect2
35
36 ; CHECK: lui a0, %hi(callee_indirect2)
37 ; CHECK-NEXT: addi a5, a0, %lo(callee_indirect2)
38 ; CHECK-NEXT: jr a5
39
40 ; CHECK: lui a0, %hi(callee_indirect1)
41 ; CHECK-NEXT: addi a5, a0, %lo(callee_indirect1)
42 ; CHECK-NEXT: jr a5
43 entry:
44   %tobool = icmp eq i32 %a, 0
45   %callee = select i1 %tobool, void ()* @callee_indirect1, void ()* @callee_indirect2
46   tail call void %callee()
47   ret void
48 }
49
50 ; Do not tail call optimize functions with varargs.
51 declare i32 @callee_varargs(i32, ...)
52 define void @caller_varargs(i32 %a, i32 %b) {
53 ; CHECK-LABEL: caller_varargs
54 ; CHECK-NOT: tail callee_varargs
55 ; CHECK: call callee_varargs
56 entry:
57   %call = tail call i32 (i32, ...) @callee_varargs(i32 %a, i32 %b, i32 %b, i32 %a)
58   ret void
59 }
60
61 ; Do not tail call optimize if stack is used to pass parameters.
62 declare i32 @callee_args(i32 %a, i32 %b, i32 %c, i32 %dd, i32 %e, i32 %ff, i32 %g, i32 %h, i32 %i, i32 %j, i32 %k, i32 %l, i32 %m, i32 %n)
63 define i32 @caller_args(i32 %a, i32 %b, i32 %c, i32 %dd, i32 %e, i32 %ff, i32 %g, i32 %h, i32 %i, i32 %j, i32 %k, i32 %l, i32 %m, i32 %n) {
64 ; CHECK-LABEL: caller_args
65 ; CHECK-NOT: tail callee_args
66 ; CHECK: call callee_args
67 entry:
68   %r = tail call i32 @callee_args(i32 %a, i32 %b, i32 %c, i32 %dd, i32 %e, i32 %ff, i32 %g, i32 %h, i32 %i, i32 %j, i32 %k, i32 %l, i32 %m, i32 %n)
69   ret i32 %r
70 }
71
72 ; Do not tail call optimize if parameters need to be passed indirectly.
73 declare i32 @callee_indirect_args(fp128 %a)
74 define void @caller_indirect_args() {
75 ; CHECK-LABEL: caller_indirect_args
76 ; CHECK-NOT: tail callee_indirect_args
77 ; CHECK: call callee_indirect_args
78 entry:
79   %call = tail call i32 @callee_indirect_args(fp128 0xL00000000000000003FFF000000000000)
80   ret void
81 }
82
83 ; Externally-defined functions with weak linkage should not be tail-called.
84 ; The behaviour of branch instructions in this situation (as used for tail
85 ; calls) is implementation-defined, so we cannot rely on the linker replacing
86 ; the tail call with a return.
87 declare extern_weak void @callee_weak()
88 define void @caller_weak() {
89 ; CHECK-LABEL: caller_weak
90 ; CHECK-NOT: tail callee_weak
91 ; CHECK: call callee_weak
92 entry:
93   tail call void @callee_weak()
94   ret void
95 }
96
97 ; Exception-handling functions need a special set of instructions to indicate a
98 ; return to the hardware. Tail-calling another function would probably break
99 ; this.
100 declare void @callee_irq()
101 define void @caller_irq() #0 {
102 ; CHECK-LABEL: caller_irq
103 ; CHECK-NOT: tail callee_irq
104 ; CHECK: call callee_irq
105 entry:
106   tail call void @callee_irq()
107   ret void
108 }
109 attributes #0 = { "interrupt" }
110
111 ; Byval parameters hand the function a pointer directly into the stack area
112 ; we want to reuse during a tail call. Do not tail call optimize functions with
113 ; byval parameters.
114 declare i32 @callee_byval(i32** byval %a)
115 define i32 @caller_byval() {
116 ; CHECK-LABEL: caller_byval
117 ; CHECK-NOT: tail callee_byval
118 ; CHECK: call callee_byval
119 entry:
120   %a = alloca i32*
121   %r = tail call i32 @callee_byval(i32** byval %a)
122   ret i32 %r
123 }
124
125 ; Do not tail call optimize if callee uses structret semantics.
126 %struct.A = type { i32 }
127 @a = global %struct.A zeroinitializer
128
129 declare void @callee_struct(%struct.A* sret %a)
130 define void @caller_nostruct() {
131 ; CHECK-LABEL: caller_nostruct
132 ; CHECK-NOT: tail callee_struct
133 ; CHECK: call callee_struct
134 entry:
135   tail call void @callee_struct(%struct.A* sret @a)
136   ret void
137 }
138
139 ; Do not tail call optimize if caller uses structret semantics.
140 declare void @callee_nostruct()
141 define void @caller_struct(%struct.A* sret %a) {
142 ; CHECK-LABEL: caller_struct
143 ; CHECK-NOT: tail callee_nostruct
144 ; CHECK: call callee_nostruct
145 entry:
146   tail call void @callee_nostruct()
147   ret void
148 }