1; RUN: llc < %s -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers -enable-emscripten-cxx-exceptions | FileCheck %s --check-prefixes=CHECK,TYPED
2; RUN: llc < %s -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers -enable-emscripten-cxx-exceptions -opaque-pointers | FileCheck %s --check-prefixes=CHECK,OPAQUE
3
4; Test that function pointer casts are replaced with wrappers.
5
6; The TYPED and OPAQUE prefixes only differ in function ordering.
7
8target triple = "wasm32-unknown-unknown"
9
10define void @has_i32_arg(i32) {
11entry:
12  ret void
13}
14
15declare void @has_struct_arg({i32})
16declare i32 @has_i32_ret()
17declare void @vararg(...)
18declare void @plain(i32)
19
20declare void @foo0()
21declare void @foo1()
22declare void @foo2()
23declare void @foo3()
24
25; CHECK-LABEL: test:
26; TYPED:      call        .Lhas_i32_arg_bitcast.2{{$}}
27; TYPED-NEXT: call        .Lhas_i32_arg_bitcast.2{{$}}
28; OPAQUE:      call       .Lhas_i32_arg_bitcast{{$}}
29; OPAQUE-NEXT: call       .Lhas_i32_arg_bitcast{{$}}
30; CHECK-NEXT: call        .Lhas_i32_ret_bitcast{{$}}
31; CHECK-NEXT: call        $drop=, has_i32_ret
32; CHECK-NEXT: i32.const   $push[[L0:[0-9]+]]=, 0
33; CHECK-NEXT: call        .Lfoo0_bitcast, $pop[[L0]]{{$}}
34; CHECK-NEXT: i32.const   $push[[L1:[0-9]+]]=, 0
35; CHECK-NEXT: call        .Lfoo0_bitcast, $pop[[L1]]{{$}}
36; CHECK-NEXT: i32.const   $push[[L2:[0-9]+]]=, 0
37; CHECK-NEXT: call        .Lfoo0_bitcast, $pop[[L2]]{{$}}
38; CHECK-NEXT: call        foo0
39; CHECK-NEXT: call        $drop=, .Lfoo1_bitcast{{$}}
40; CHECK-NEXT: call        foo2{{$}}
41; CHECK-NEXT: call        foo1{{$}}
42; CHECK-NEXT: call        foo3{{$}}
43; CHECK-NEXT: end_function
44define void @test() {
45entry:
46  call void bitcast (void (i32)* @has_i32_arg to void ()*)()
47  call void bitcast (void (i32)* @has_i32_arg to void ()*)()
48  call void bitcast (i32 ()* @has_i32_ret to void ()*)()
49  call i32 bitcast (i32 ()* @has_i32_ret to i32 ()*)()
50  call void bitcast (void ()* @foo0 to void (i32)*)(i32 0)
51  %p = bitcast void ()* @foo0 to void (i32)*
52  call void %p(i32 0)
53  %q = bitcast void ()* @foo0 to void (i32)*
54  call void %q(i32 0)
55  %r = bitcast void (i32)* %q to void ()*
56  call void %r()
57  %t = call i32 bitcast (void ()* @foo1 to i32 ()*)()
58  call void bitcast (void ()* @foo2 to void ()*)()
59  call void @foo1()
60  call void @foo3()
61
62  ret void
63}
64
65; Calling aliases should also generate a wrapper
66
67@alias_i32_arg = weak hidden alias void (i32), void (i32)* @has_i32_arg
68
69; CHECK-LABEL: test_alias:
70; TYPED: call    .Lhas_i32_arg_bitcast.2
71; OPAQUE: call   .Lhas_i32_arg_bitcast
72define void @test_alias() {
73entry:
74  call void bitcast (void (i32)* @alias_i32_arg to void ()*)()
75  ret void
76}
77
78
79; CHECK-LABEL: test_structs:
80; TYPED: call     .Lhas_i32_arg_bitcast.1, $pop{{[0-9]+}}, $pop{{[0-9]+$}}
81; TYPED: call     .Lhas_i32_arg_bitcast, $0, $pop2
82; OPAQUE: call    .Lhas_i32_arg_bitcast.2, $pop{{[0-9]+}}, $pop{{[0-9]+$}}
83; OPAQUE: call    .Lhas_i32_arg_bitcast.1, $0, $pop2
84; CHECK: call     .Lhas_struct_arg_bitcast{{$}}
85define void @test_structs() {
86entry:
87  call void bitcast (void (i32)* @has_i32_arg to void (i32, {i32})*)(i32 5, {i32} {i32 6})
88  call {i32, i64} bitcast (void (i32)* @has_i32_arg to {i32, i64} (i32)*)(i32 7)
89  call void bitcast (void ({i32})* @has_struct_arg to void ()*)()
90  ret void
91}
92
93; CHECK-LABEL: test_structs_unhandled:
94; CHECK: call    has_struct_arg, $pop{{[0-9]+$}}
95; CHECK: call    has_struct_arg, $pop{{[0-9]+$}}
96; CHECK: call    has_i32_ret, $pop{{[0-9]+$}}
97define void @test_structs_unhandled() {
98entry:
99  call void @has_struct_arg({i32} {i32 3})
100  call void bitcast (void ({i32})* @has_struct_arg to void ({i64})*)({i64} {i64 4})
101  call {i32, i32} bitcast (i32 ()* @has_i32_ret to {i32, i32} ()*)()
102  ret void
103}
104
105; CHECK-LABEL: test_varargs:
106; CHECK:      global.set
107; CHECK:      i32.const   $push[[L3:[0-9]+]]=, 0{{$}}
108; CHECK-NEXT: call        .Lvararg_bitcast, $pop[[L3]]{{$}}
109; CHECK-NEXT: i32.const   $push[[L4:[0-9]+]]=, 0{{$}}
110; CHECK-NEXT: i32.store   0($[[L5:[0-9]+]]), $pop[[L4]]{{$}}
111; CHECK-NEXT: call        .Lplain_bitcast, $[[L5]]{{$}}
112define void @test_varargs() {
113  call void bitcast (void (...)* @vararg to void (i32)*)(i32 0)
114  call void (...) bitcast (void (i32)* @plain to void (...)*)(i32 0)
115  ret void
116}
117
118; Don't use wrappers when the value is stored in memory
119
120@global_func = hidden local_unnamed_addr global void ()* null
121
122; CHECK-LABEL: test_store:
123; CHECK:      i32.const   $push[[L0:[0-9]+]]=, 0{{$}}
124; CHECK-NEXT: i32.const   $push[[L1:[0-9]+]]=, has_i32_ret{{$}}
125; CHECK-NEXT: i32.store   global_func($pop[[L0]]), $pop[[L1]]{{$}}
126define void @test_store() {
127  %1 = bitcast i32 ()* @has_i32_ret to void ()*
128  store void ()* %1, void ()** @global_func
129  ret void
130}
131
132; CHECK-LABEL: test_load:
133; CHECK-NEXT: .functype test_load () -> (i32){{$}}
134; CHECK-NEXT: i32.const   $push[[L0:[0-9]+]]=, 0{{$}}
135; CHECK-NEXT: i32.load    $push[[L1:[0-9]+]]=, global_func($pop[[L0]]){{$}}
136; CHECK-NEXT: call_indirect $push{{[0-9]+}}=, $pop[[L1]]{{$}}
137define i32 @test_load() {
138  %1 = load i32 ()*, i32 ()** bitcast (void ()** @global_func to i32 ()**)
139  %2 = call i32 %1()
140  ret i32 %2
141}
142
143; Don't use wrappers when the value is passed to a function call
144
145declare void @call_func(i32 ()*)
146
147; CHECK-LABEL: test_argument:
148; CHECK:      i32.const   $push[[L0:[0-9]+]]=, has_i32_ret{{$}}
149; CHECK-NEXT: call        call_func, $pop[[L0]]{{$}}
150; CHECK-NEXT: i32.const   $push[[L1:[0-9]+]]=, has_i32_arg{{$}}
151; CHECK-NEXT: call        call_func, $pop[[L1]]{{$}}
152define void @test_argument() {
153  call void @call_func(i32 ()* @has_i32_ret)
154  call void @call_func(i32 ()* bitcast (void (i32)* @has_i32_arg to i32 ()*))
155  ret void
156}
157
158; Invokes should be treated like calls
159
160; CHECK-LABEL: test_invoke:
161; CHECK:      i32.const   $push[[L1:[0-9]+]]=, call_func{{$}}
162; CHECK-NEXT: i32.const   $push[[L0:[0-9]+]]=, has_i32_ret{{$}}
163; CHECK-NEXT: call        invoke_vi, $pop[[L1]], $pop[[L0]]{{$}}
164; CHECK:      i32.const   $push[[L3:[0-9]+]]=, call_func{{$}}
165; CHECK-NEXT: i32.const   $push[[L2:[0-9]+]]=, has_i32_arg{{$}}
166; CHECK-NEXT: call        invoke_vi, $pop[[L3]], $pop[[L2]]{{$}}
167; TYPED:      i32.const   $push[[L4:[0-9]+]]=, .Lhas_i32_arg_bitcast.2{{$}}
168; OPAQUE:     i32.const   $push[[L4:[0-9]+]]=, .Lhas_i32_arg_bitcast{{$}}
169; CHECK-NEXT: call        invoke_v, $pop[[L4]]{{$}}
170declare i32 @personality(...)
171define void @test_invoke() personality i32 (...)* @personality {
172entry:
173  invoke void @call_func(i32 ()* @has_i32_ret)
174          to label %cont unwind label %lpad
175
176cont:
177  invoke void @call_func(i32 ()* bitcast (void (i32)* @has_i32_arg to i32 ()*))
178          to label %cont2 unwind label %lpad
179
180cont2:
181  invoke void bitcast (void (i32)* @has_i32_arg to void ()*)()
182          to label %end unwind label %lpad
183
184lpad:
185  %0 = landingpad { i8*, i32 }
186          catch i8* null
187  br label %end
188
189end:
190  ret void
191}
192
193; TYPED-LABEL: .Lhas_i32_arg_bitcast:
194; TYPED-NEXT: .functype .Lhas_i32_arg_bitcast (i32, i32) -> ()
195; TYPED-NEXT: call        has_i32_arg, $1{{$}}
196; TYPED-NEXT: end_function
197
198; TYPED-LABEL: .Lhas_i32_arg_bitcast.1:
199; TYPED-NEXT: .functype .Lhas_i32_arg_bitcast.1 (i32, i32) -> ()
200; TYPED-NEXT: call        has_i32_arg, $0{{$}}
201; TYPED-NEXT: end_function
202
203; TYPED-LABEL: .Lhas_i32_arg_bitcast.2:
204; TYPED-NEXT: .functype	.Lhas_i32_arg_bitcast.2 () -> ()
205; TYPED-NEXT: call        has_i32_arg, $0{{$}}
206; TYPED-NEXT: end_function
207
208; OPAQUE-LABEL: .Lhas_i32_arg_bitcast:
209; OPAQUE-NEXT: .functype	.Lhas_i32_arg_bitcast () -> ()
210; OPAQUE-NEXT: call        has_i32_arg, $0{{$}}
211; OPAQUE-NEXT: end_function
212
213; OPAQUE-LABEL: .Lhas_i32_arg_bitcast.1:
214; OPAQUE-NEXT: .functype .Lhas_i32_arg_bitcast.1 (i32, i32) -> ()
215; OPAQUE-NEXT: call        has_i32_arg, $1{{$}}
216; OPAQUE-NEXT: end_function
217
218; OPAQUE-LABEL: .Lhas_i32_arg_bitcast.2:
219; OPAQUE-NEXT: .functype .Lhas_i32_arg_bitcast.2 (i32, i32) -> ()
220; OPAQUE-NEXT: call        has_i32_arg, $0{{$}}
221; OPAQUE-NEXT: end_function
222
223; CHECK-LABEL: .Lhas_i32_ret_bitcast:
224; CHECK:      call        $drop=, has_i32_ret{{$}}
225; CHECK-NEXT: end_function
226
227; CHECK-LABEL: .Lvararg_bitcast:
228; CHECK: call        vararg, $1{{$}}
229; CHECK: end_function
230
231; CHECK-LABEL: .Lplain_bitcast:
232; CHECK: call        plain, $1{{$}}
233; CHECK: end_function
234
235; CHECK-LABEL: .Lfoo0_bitcast:
236; CHECK-NEXT: .functype .Lfoo0_bitcast (i32) -> ()
237; CHECK-NEXT: call        foo0{{$}}
238; CHECK-NEXT: end_function
239
240; CHECK-LABEL: .Lfoo1_bitcast:
241; CHECK-NEXT: .functype .Lfoo1_bitcast () -> (i32)
242; CHECK-NEXT: call        foo1{{$}}
243; CHECK-NEXT: local.copy  $push0=, $0
244; CHECK-NEXT: end_function
245