blob: 91bb1b6dbc307ea371d4ad47c9e6b4e4f6ecfff9 [file] [log] [blame]
Dan Gohman4684f822019-01-29 10:53:42 +00001; RUN: llc < %s -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers -enable-emscripten-cxx-exceptions | FileCheck %s
Dan Gohman1b637452017-01-07 00:34:54 +00002
3; Test that function pointer casts are replaced with wrappers.
4
5target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
Sam Clegga5908002018-05-10 17:49:11 +00006target triple = "wasm32-unknown-unknown"
Dan Gohman1b637452017-01-07 00:34:54 +00007
Sam Cleggdde8a252019-08-21 19:52:33 +00008define void @has_i32_arg(i32) {
9entry:
10 ret void
11}
12
Sam Clegg88599bf2018-08-30 01:01:30 +000013declare void @has_struct_arg({i32})
Jacob Gravelle37af00e2017-10-10 16:20:18 +000014declare i32 @has_i32_ret()
15declare void @vararg(...)
16declare void @plain(i32)
17
18declare void @foo0()
19declare void @foo1()
20declare void @foo2()
21declare void @foo3()
22
Dan Gohman1b637452017-01-07 00:34:54 +000023; CHECK-LABEL: test:
Sam Clegg275d15e2019-02-23 00:07:39 +000024; CHECK: call .Lhas_i32_arg_bitcast.2{{$}}
25; CHECK-NEXT: call .Lhas_i32_arg_bitcast.2{{$}}
26; CHECK-NEXT: call .Lhas_i32_ret_bitcast{{$}}
27; CHECK-NEXT: i32.call $drop=, has_i32_ret
Dan Gohman0e2ceb82017-01-07 01:50:01 +000028; CHECK-NEXT: i32.const $push[[L0:[0-9]+]]=, 0
Sam Clegg275d15e2019-02-23 00:07:39 +000029; CHECK-NEXT: call .Lfoo0_bitcast, $pop[[L0]]{{$}}
Derek Schuff7acb42a2017-01-10 21:59:53 +000030; CHECK-NEXT: i32.const $push[[L1:[0-9]+]]=, 0
Sam Clegg275d15e2019-02-23 00:07:39 +000031; CHECK-NEXT: call .Lfoo0_bitcast, $pop[[L1]]{{$}}
Derek Schuff7acb42a2017-01-10 21:59:53 +000032; CHECK-NEXT: i32.const $push[[L2:[0-9]+]]=, 0
Sam Clegg275d15e2019-02-23 00:07:39 +000033; CHECK-NEXT: call .Lfoo0_bitcast, $pop[[L2]]{{$}}
34; CHECK-NEXT: call foo0
35; CHECK-NEXT: i32.call $drop=, .Lfoo1_bitcast{{$}}
36; CHECK-NEXT: call foo2{{$}}
37; CHECK-NEXT: call foo1{{$}}
38; CHECK-NEXT: call foo3{{$}}
Dan Gohman7d7409e2017-02-28 23:37:04 +000039; CHECK-NEXT: end_function
Dan Gohman1b637452017-01-07 00:34:54 +000040define void @test() {
41entry:
42 call void bitcast (void (i32)* @has_i32_arg to void ()*)()
Derek Schuff7acb42a2017-01-10 21:59:53 +000043 call void bitcast (void (i32)* @has_i32_arg to void ()*)()
Dan Gohman1b637452017-01-07 00:34:54 +000044 call void bitcast (i32 ()* @has_i32_ret to void ()*)()
Sam Clegg88599bf2018-08-30 01:01:30 +000045 call i32 bitcast (i32 ()* @has_i32_ret to i32 ()*)()
Dan Gohman1b637452017-01-07 00:34:54 +000046 call void bitcast (void ()* @foo0 to void (i32)*)(i32 0)
Derek Schuff7acb42a2017-01-10 21:59:53 +000047 %p = bitcast void ()* @foo0 to void (i32)*
48 call void %p(i32 0)
49 %q = bitcast void ()* @foo0 to void (i32)*
50 call void %q(i32 0)
51 %r = bitcast void (i32)* %q to void ()*
52 call void %r()
Dan Gohman1b637452017-01-07 00:34:54 +000053 %t = call i32 bitcast (void ()* @foo1 to i32 ()*)()
54 call void bitcast (void ()* @foo2 to void ()*)()
Derek Schuff7acb42a2017-01-10 21:59:53 +000055 call void @foo1()
Dan Gohman1b637452017-01-07 00:34:54 +000056 call void @foo3()
Derek Schuff7acb42a2017-01-10 21:59:53 +000057
Dan Gohman1b637452017-01-07 00:34:54 +000058 ret void
59}
Dan Gohmana99b7172017-01-20 20:50:29 +000060
Sam Cleggdde8a252019-08-21 19:52:33 +000061; Calling aliases should also generate a wrapper
62
63@alias_i32_arg = weak hidden alias void (i32), void (i32)* @has_i32_arg
64
65; CHECK-LABEL: test_alias:
66; CHECK: call .Lhas_i32_arg_bitcast.2
67define void @test_alias() {
68entry:
69 call void bitcast (void (i32)* @alias_i32_arg to void ()*)()
70 ret void
71}
72
73
Sam Clegg88599bf2018-08-30 01:01:30 +000074; CHECK-LABEL: test_structs:
Sam Clegg275d15e2019-02-23 00:07:39 +000075; CHECK: call .Lhas_i32_arg_bitcast.1, $pop{{[0-9]+}}, $pop{{[0-9]+$}}
76; CHECK: call .Lhas_i32_arg_bitcast, $0, $pop2
77; CHECK: call .Lhas_struct_arg_bitcast{{$}}
Sam Clegg88599bf2018-08-30 01:01:30 +000078define void @test_structs() {
79entry:
80 call void bitcast (void (i32)* @has_i32_arg to void (i32, {i32})*)(i32 5, {i32} {i32 6})
81 call {i32, i64} bitcast (void (i32)* @has_i32_arg to {i32, i64} (i32)*)(i32 7)
82 call void bitcast (void ({i32})* @has_struct_arg to void ()*)()
83 ret void
84}
85
86; CHECK-LABEL: test_structs_unhandled:
Sam Clegg275d15e2019-02-23 00:07:39 +000087; CHECK: call has_struct_arg, $pop{{[0-9]+$}}
88; CHECK: call has_struct_arg, $pop{{[0-9]+$}}
89; CHECK: call has_i32_ret, $pop{{[0-9]+$}}
Sam Clegg88599bf2018-08-30 01:01:30 +000090define void @test_structs_unhandled() {
91entry:
92 call void @has_struct_arg({i32} {i32 3})
93 call void bitcast (void ({i32})* @has_struct_arg to void ({i64})*)({i64} {i64 4})
94 call {i32, i32} bitcast (i32 ()* @has_i32_ret to {i32, i32} ()*)()
95 ret void
96}
97
Jacob Gravelle37af00e2017-10-10 16:20:18 +000098; CHECK-LABEL: test_varargs:
Thomas Lively6a87dda2019-01-08 06:25:55 +000099; CHECK: global.set
Jacob Gravelle37af00e2017-10-10 16:20:18 +0000100; CHECK: i32.const $push[[L3:[0-9]+]]=, 0{{$}}
Sam Clegg275d15e2019-02-23 00:07:39 +0000101; CHECK-NEXT: call .Lvararg_bitcast, $pop[[L3]]{{$}}
Jacob Gravelle37af00e2017-10-10 16:20:18 +0000102; CHECK-NEXT: i32.const $push[[L4:[0-9]+]]=, 0{{$}}
103; CHECK-NEXT: i32.store 0($[[L5:[0-9]+]]), $pop[[L4]]{{$}}
Sam Clegg275d15e2019-02-23 00:07:39 +0000104; CHECK-NEXT: call .Lplain_bitcast, $[[L5]]{{$}}
Dan Gohmana99b7172017-01-20 20:50:29 +0000105define void @test_varargs() {
106 call void bitcast (void (...)* @vararg to void (i32)*)(i32 0)
107 call void (...) bitcast (void (i32)* @plain to void (...)*)(i32 0)
108 ret void
109}
Jacob Gravelle37af00e2017-10-10 16:20:18 +0000110
111; Don't use wrappers when the value is stored in memory
112
113@global_func = hidden local_unnamed_addr global void ()* null
114
115; CHECK-LABEL: test_store:
Wouter van Oortmerssen49482f82018-11-19 17:10:36 +0000116; CHECK: i32.const $push[[L0:[0-9]+]]=, 0{{$}}
Sam Clegg275d15e2019-02-23 00:07:39 +0000117; CHECK-NEXT: i32.const $push[[L1:[0-9]+]]=, has_i32_ret{{$}}
Jacob Gravelle37af00e2017-10-10 16:20:18 +0000118; CHECK-NEXT: i32.store global_func($pop[[L0]]), $pop[[L1]]{{$}}
119define void @test_store() {
120 %1 = bitcast i32 ()* @has_i32_ret to void ()*
121 store void ()* %1, void ()** @global_func
122 ret void
123}
124
125; CHECK-LABEL: test_load:
Wouter van Oortmerssen49482f82018-11-19 17:10:36 +0000126; CHECK-NEXT: .functype test_load () -> (i32){{$}}
Jacob Gravelle37af00e2017-10-10 16:20:18 +0000127; CHECK-NEXT: i32.const $push[[L0:[0-9]+]]=, 0{{$}}
128; CHECK-NEXT: i32.load $push[[L1:[0-9]+]]=, global_func($pop[[L0]]){{$}}
129; CHECK-NEXT: i32.call_indirect $push{{[0-9]+}}=, $pop[[L1]]{{$}}
130define i32 @test_load() {
131 %1 = load i32 ()*, i32 ()** bitcast (void ()** @global_func to i32 ()**)
132 %2 = call i32 %1()
133 ret i32 %2
134}
135
136; Don't use wrappers when the value is passed to a function call
137
138declare void @call_func(i32 ()*)
139
140; CHECK-LABEL: test_argument:
Sam Clegg275d15e2019-02-23 00:07:39 +0000141; CHECK: i32.const $push[[L0:[0-9]+]]=, has_i32_ret{{$}}
142; CHECK-NEXT: call call_func, $pop[[L0]]{{$}}
143; CHECK-NEXT: i32.const $push[[L1:[0-9]+]]=, has_i32_arg{{$}}
144; CHECK-NEXT: call call_func, $pop[[L1]]{{$}}
Jacob Gravelle37af00e2017-10-10 16:20:18 +0000145define void @test_argument() {
146 call void @call_func(i32 ()* @has_i32_ret)
147 call void @call_func(i32 ()* bitcast (void (i32)* @has_i32_arg to i32 ()*))
148 ret void
149}
150
151; Invokes should be treated like calls
152
153; CHECK-LABEL: test_invoke:
Sam Clegg275d15e2019-02-23 00:07:39 +0000154; CHECK: i32.const $push[[L1:[0-9]+]]=, call_func{{$}}
155; CHECK-NEXT: i32.const $push[[L0:[0-9]+]]=, has_i32_ret{{$}}
156; CHECK-NEXT: call "__invoke_void_i32()*", $pop[[L1]], $pop[[L0]]{{$}}
157; CHECK: i32.const $push[[L3:[0-9]+]]=, call_func{{$}}
158; CHECK-NEXT: i32.const $push[[L2:[0-9]+]]=, has_i32_arg{{$}}
159; CHECK-NEXT: call "__invoke_void_i32()*", $pop[[L3]], $pop[[L2]]{{$}}
160; CHECK: i32.const $push[[L4:[0-9]+]]=, .Lhas_i32_arg_bitcast.2{{$}}
161; CHECK-NEXT: call __invoke_void, $pop[[L4]]{{$}}
Jacob Gravelle37af00e2017-10-10 16:20:18 +0000162declare i32 @personality(...)
163define void @test_invoke() personality i32 (...)* @personality {
164entry:
165 invoke void @call_func(i32 ()* @has_i32_ret)
166 to label %cont unwind label %lpad
167
168cont:
169 invoke void @call_func(i32 ()* bitcast (void (i32)* @has_i32_arg to i32 ()*))
170 to label %cont2 unwind label %lpad
171
172cont2:
173 invoke void bitcast (void (i32)* @has_i32_arg to void ()*)()
174 to label %end unwind label %lpad
175
176lpad:
177 %0 = landingpad { i8*, i32 }
178 catch i8* null
179 br label %end
180
181end:
182 ret void
183}
184
Sam Clegg41d70472018-08-02 17:38:06 +0000185; CHECK-LABEL: .Lhas_i32_arg_bitcast:
Wouter van Oortmerssen49482f82018-11-19 17:10:36 +0000186; CHECK-NEXT: .functype .Lhas_i32_arg_bitcast (i32, i32) -> ()
Sam Clegg275d15e2019-02-23 00:07:39 +0000187; CHECK-NEXT: call has_i32_arg, $1{{$}}
Sam Clegg88599bf2018-08-30 01:01:30 +0000188; CHECK-NEXT: end_function
189
190; CHECK-LABEL: .Lhas_i32_arg_bitcast.1:
Wouter van Oortmerssen49482f82018-11-19 17:10:36 +0000191; CHECK-NEXT: .functype .Lhas_i32_arg_bitcast.1 (i32, i32) -> ()
Sam Clegg275d15e2019-02-23 00:07:39 +0000192; CHECK-NEXT: call has_i32_arg, $0{{$}}
Sam Clegg88599bf2018-08-30 01:01:30 +0000193; CHECK-NEXT: end_function
194
195; CHECK-LABEL: .Lhas_i32_arg_bitcast.2:
Sam Clegg275d15e2019-02-23 00:07:39 +0000196; CHECK: call has_i32_arg, $0{{$}}
Jacob Gravelle37af00e2017-10-10 16:20:18 +0000197; CHECK-NEXT: end_function
198
Sam Clegg41d70472018-08-02 17:38:06 +0000199; CHECK-LABEL: .Lhas_i32_ret_bitcast:
Sam Clegg275d15e2019-02-23 00:07:39 +0000200; CHECK: call $drop=, has_i32_ret{{$}}
Jacob Gravelle37af00e2017-10-10 16:20:18 +0000201; CHECK-NEXT: end_function
202
Sam Clegg41d70472018-08-02 17:38:06 +0000203; CHECK-LABEL: .Lvararg_bitcast:
Sam Clegg275d15e2019-02-23 00:07:39 +0000204; CHECK: call vararg, $1{{$}}
Dan Gohman3a762bf2017-12-08 21:27:00 +0000205; CHECK: end_function
206
Sam Clegg41d70472018-08-02 17:38:06 +0000207; CHECK-LABEL: .Lplain_bitcast:
Sam Clegg275d15e2019-02-23 00:07:39 +0000208; CHECK: call plain, $1{{$}}
Dan Gohman3a762bf2017-12-08 21:27:00 +0000209; CHECK: end_function
210
Sam Clegg41d70472018-08-02 17:38:06 +0000211; CHECK-LABEL: .Lfoo0_bitcast:
Wouter van Oortmerssen49482f82018-11-19 17:10:36 +0000212; CHECK-NEXT: .functype .Lfoo0_bitcast (i32) -> ()
Sam Clegg275d15e2019-02-23 00:07:39 +0000213; CHECK-NEXT: call foo0{{$}}
Jacob Gravelle37af00e2017-10-10 16:20:18 +0000214; CHECK-NEXT: end_function
215
Sam Clegg41d70472018-08-02 17:38:06 +0000216; CHECK-LABEL: .Lfoo1_bitcast:
Wouter van Oortmerssen49482f82018-11-19 17:10:36 +0000217; CHECK-NEXT: .functype .Lfoo1_bitcast () -> (i32)
Sam Clegg275d15e2019-02-23 00:07:39 +0000218; CHECK-NEXT: call foo1{{$}}
Thomas Lively6a87dda2019-01-08 06:25:55 +0000219; CHECK-NEXT: local.copy $push0=, $0
Jacob Gravelle37af00e2017-10-10 16:20:18 +0000220; CHECK-NEXT: end_function