blob: a779cbe414225e3a8eb35d682706fc9a536e0065 [file] [log] [blame]
Sam Clegg5292d172018-11-06 00:31:02 +00001; RUN: llc < %s -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers -enable-emscripten-cxx-exceptions -wasm-temporary-workarounds=false | 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
Jacob Gravelle37af00e2017-10-10 16:20:18 +00008declare void @has_i32_arg(i32)
Sam Clegg88599bf2018-08-30 01:01:30 +00009declare void @has_struct_arg({i32})
Jacob Gravelle37af00e2017-10-10 16:20:18 +000010declare i32 @has_i32_ret()
11declare void @vararg(...)
12declare void @plain(i32)
13
14declare void @foo0()
15declare void @foo1()
16declare void @foo2()
17declare void @foo3()
18
Dan Gohman1b637452017-01-07 00:34:54 +000019; CHECK-LABEL: test:
Wouter van Oortmerssen49482f82018-11-19 17:10:36 +000020; CHECK: call .Lhas_i32_arg_bitcast.2@FUNCTION{{$}}
Sam Clegg88599bf2018-08-30 01:01:30 +000021; CHECK-NEXT: call .Lhas_i32_arg_bitcast.2@FUNCTION{{$}}
Sam Clegg41d70472018-08-02 17:38:06 +000022; CHECK-NEXT: call .Lhas_i32_ret_bitcast@FUNCTION{{$}}
Sam Clegg88599bf2018-08-30 01:01:30 +000023; CHECK-NEXT: i32.call $drop=, has_i32_ret@FUNCTION
Dan Gohman0e2ceb82017-01-07 01:50:01 +000024; CHECK-NEXT: i32.const $push[[L0:[0-9]+]]=, 0
Sam Clegg41d70472018-08-02 17:38:06 +000025; CHECK-NEXT: call .Lfoo0_bitcast@FUNCTION, $pop[[L0]]{{$}}
Derek Schuff7acb42a2017-01-10 21:59:53 +000026; CHECK-NEXT: i32.const $push[[L1:[0-9]+]]=, 0
Sam Clegg41d70472018-08-02 17:38:06 +000027; CHECK-NEXT: call .Lfoo0_bitcast@FUNCTION, $pop[[L1]]{{$}}
Derek Schuff7acb42a2017-01-10 21:59:53 +000028; CHECK-NEXT: i32.const $push[[L2:[0-9]+]]=, 0
Sam Clegg41d70472018-08-02 17:38:06 +000029; CHECK-NEXT: call .Lfoo0_bitcast@FUNCTION, $pop[[L2]]{{$}}
Derek Schuff7acb42a2017-01-10 21:59:53 +000030; CHECK-NEXT: call foo0@FUNCTION
Sam Clegg41d70472018-08-02 17:38:06 +000031; CHECK-NEXT: i32.call $drop=, .Lfoo1_bitcast@FUNCTION{{$}}
Dan Gohman1b637452017-01-07 00:34:54 +000032; CHECK-NEXT: call foo2@FUNCTION{{$}}
Derek Schuff7acb42a2017-01-10 21:59:53 +000033; CHECK-NEXT: call foo1@FUNCTION{{$}}
Dan Gohman1b637452017-01-07 00:34:54 +000034; CHECK-NEXT: call foo3@FUNCTION{{$}}
Dan Gohman7d7409e2017-02-28 23:37:04 +000035; CHECK-NEXT: end_function
Dan Gohman1b637452017-01-07 00:34:54 +000036define void @test() {
37entry:
38 call void bitcast (void (i32)* @has_i32_arg to void ()*)()
Derek Schuff7acb42a2017-01-10 21:59:53 +000039 call void bitcast (void (i32)* @has_i32_arg to void ()*)()
Dan Gohman1b637452017-01-07 00:34:54 +000040 call void bitcast (i32 ()* @has_i32_ret to void ()*)()
Sam Clegg88599bf2018-08-30 01:01:30 +000041 call i32 bitcast (i32 ()* @has_i32_ret to i32 ()*)()
Dan Gohman1b637452017-01-07 00:34:54 +000042 call void bitcast (void ()* @foo0 to void (i32)*)(i32 0)
Derek Schuff7acb42a2017-01-10 21:59:53 +000043 %p = bitcast void ()* @foo0 to void (i32)*
44 call void %p(i32 0)
45 %q = bitcast void ()* @foo0 to void (i32)*
46 call void %q(i32 0)
47 %r = bitcast void (i32)* %q to void ()*
48 call void %r()
Dan Gohman1b637452017-01-07 00:34:54 +000049 %t = call i32 bitcast (void ()* @foo1 to i32 ()*)()
50 call void bitcast (void ()* @foo2 to void ()*)()
Derek Schuff7acb42a2017-01-10 21:59:53 +000051 call void @foo1()
Dan Gohman1b637452017-01-07 00:34:54 +000052 call void @foo3()
Derek Schuff7acb42a2017-01-10 21:59:53 +000053
Dan Gohman1b637452017-01-07 00:34:54 +000054 ret void
55}
Dan Gohmana99b7172017-01-20 20:50:29 +000056
Sam Clegg88599bf2018-08-30 01:01:30 +000057; CHECK-LABEL: test_structs:
58; CHECK: call .Lhas_i32_arg_bitcast.1@FUNCTION, $pop{{[0-9]+}}, $pop{{[0-9]+$}}
59; CHECK: call .Lhas_i32_arg_bitcast@FUNCTION, $0, $pop2
60; CHECK: call .Lhas_struct_arg_bitcast@FUNCTION{{$}}
61define void @test_structs() {
62entry:
63 call void bitcast (void (i32)* @has_i32_arg to void (i32, {i32})*)(i32 5, {i32} {i32 6})
64 call {i32, i64} bitcast (void (i32)* @has_i32_arg to {i32, i64} (i32)*)(i32 7)
65 call void bitcast (void ({i32})* @has_struct_arg to void ()*)()
66 ret void
67}
68
69; CHECK-LABEL: test_structs_unhandled:
70; CHECK: call has_struct_arg@FUNCTION, $pop{{[0-9]+$}}
71; CHECK: call has_struct_arg@FUNCTION, $pop{{[0-9]+$}}
72; CHECK: call has_i32_ret@FUNCTION, $pop{{[0-9]+$}}
73define void @test_structs_unhandled() {
74entry:
75 call void @has_struct_arg({i32} {i32 3})
76 call void bitcast (void ({i32})* @has_struct_arg to void ({i64})*)({i64} {i64 4})
77 call {i32, i32} bitcast (i32 ()* @has_i32_ret to {i32, i32} ()*)()
78 ret void
79}
80
Jacob Gravelle37af00e2017-10-10 16:20:18 +000081; CHECK-LABEL: test_varargs:
Thomas Lively6a87dda2019-01-08 06:25:55 +000082; CHECK: global.set
Jacob Gravelle37af00e2017-10-10 16:20:18 +000083; CHECK: i32.const $push[[L3:[0-9]+]]=, 0{{$}}
Sam Clegg41d70472018-08-02 17:38:06 +000084; CHECK-NEXT: call .Lvararg_bitcast@FUNCTION, $pop[[L3]]{{$}}
Jacob Gravelle37af00e2017-10-10 16:20:18 +000085; CHECK-NEXT: i32.const $push[[L4:[0-9]+]]=, 0{{$}}
86; CHECK-NEXT: i32.store 0($[[L5:[0-9]+]]), $pop[[L4]]{{$}}
Sam Clegg41d70472018-08-02 17:38:06 +000087; CHECK-NEXT: call .Lplain_bitcast@FUNCTION, $[[L5]]{{$}}
Dan Gohmana99b7172017-01-20 20:50:29 +000088define void @test_varargs() {
89 call void bitcast (void (...)* @vararg to void (i32)*)(i32 0)
90 call void (...) bitcast (void (i32)* @plain to void (...)*)(i32 0)
91 ret void
92}
Jacob Gravelle37af00e2017-10-10 16:20:18 +000093
94; Don't use wrappers when the value is stored in memory
95
96@global_func = hidden local_unnamed_addr global void ()* null
97
98; CHECK-LABEL: test_store:
Wouter van Oortmerssen49482f82018-11-19 17:10:36 +000099; CHECK: i32.const $push[[L0:[0-9]+]]=, 0{{$}}
Jacob Gravelle37af00e2017-10-10 16:20:18 +0000100; CHECK-NEXT: i32.const $push[[L1:[0-9]+]]=, has_i32_ret@FUNCTION{{$}}
101; CHECK-NEXT: i32.store global_func($pop[[L0]]), $pop[[L1]]{{$}}
102define void @test_store() {
103 %1 = bitcast i32 ()* @has_i32_ret to void ()*
104 store void ()* %1, void ()** @global_func
105 ret void
106}
107
108; CHECK-LABEL: test_load:
Wouter van Oortmerssen49482f82018-11-19 17:10:36 +0000109; CHECK-NEXT: .functype test_load () -> (i32){{$}}
Jacob Gravelle37af00e2017-10-10 16:20:18 +0000110; CHECK-NEXT: i32.const $push[[L0:[0-9]+]]=, 0{{$}}
111; CHECK-NEXT: i32.load $push[[L1:[0-9]+]]=, global_func($pop[[L0]]){{$}}
112; CHECK-NEXT: i32.call_indirect $push{{[0-9]+}}=, $pop[[L1]]{{$}}
113define i32 @test_load() {
114 %1 = load i32 ()*, i32 ()** bitcast (void ()** @global_func to i32 ()**)
115 %2 = call i32 %1()
116 ret i32 %2
117}
118
119; Don't use wrappers when the value is passed to a function call
120
121declare void @call_func(i32 ()*)
122
123; CHECK-LABEL: test_argument:
Wouter van Oortmerssen49482f82018-11-19 17:10:36 +0000124; CHECK: i32.const $push[[L0:[0-9]+]]=, has_i32_ret@FUNCTION{{$}}
Jacob Gravelle37af00e2017-10-10 16:20:18 +0000125; CHECK-NEXT: call call_func@FUNCTION, $pop[[L0]]{{$}}
126; CHECK-NEXT: i32.const $push[[L1:[0-9]+]]=, has_i32_arg@FUNCTION{{$}}
127; CHECK-NEXT: call call_func@FUNCTION, $pop[[L1]]{{$}}
128define void @test_argument() {
129 call void @call_func(i32 ()* @has_i32_ret)
130 call void @call_func(i32 ()* bitcast (void (i32)* @has_i32_arg to i32 ()*))
131 ret void
132}
133
134; Invokes should be treated like calls
135
136; CHECK-LABEL: test_invoke:
137; CHECK: i32.const $push[[L1:[0-9]+]]=, call_func@FUNCTION{{$}}
138; CHECK-NEXT: i32.const $push[[L0:[0-9]+]]=, has_i32_ret@FUNCTION{{$}}
139; CHECK-NEXT: call "__invoke_void_i32()*"@FUNCTION, $pop[[L1]], $pop[[L0]]{{$}}
140; CHECK: i32.const $push[[L3:[0-9]+]]=, call_func@FUNCTION{{$}}
141; CHECK-NEXT: i32.const $push[[L2:[0-9]+]]=, has_i32_arg@FUNCTION{{$}}
142; CHECK-NEXT: call "__invoke_void_i32()*"@FUNCTION, $pop[[L3]], $pop[[L2]]{{$}}
Sam Clegg88599bf2018-08-30 01:01:30 +0000143; CHECK: i32.const $push[[L4:[0-9]+]]=, .Lhas_i32_arg_bitcast.2@FUNCTION{{$}}
Jacob Gravelle37af00e2017-10-10 16:20:18 +0000144; CHECK-NEXT: call __invoke_void@FUNCTION, $pop[[L4]]{{$}}
145declare i32 @personality(...)
146define void @test_invoke() personality i32 (...)* @personality {
147entry:
148 invoke void @call_func(i32 ()* @has_i32_ret)
149 to label %cont unwind label %lpad
150
151cont:
152 invoke void @call_func(i32 ()* bitcast (void (i32)* @has_i32_arg to i32 ()*))
153 to label %cont2 unwind label %lpad
154
155cont2:
156 invoke void bitcast (void (i32)* @has_i32_arg to void ()*)()
157 to label %end unwind label %lpad
158
159lpad:
160 %0 = landingpad { i8*, i32 }
161 catch i8* null
162 br label %end
163
164end:
165 ret void
166}
167
Sam Clegg41d70472018-08-02 17:38:06 +0000168; CHECK-LABEL: .Lhas_i32_arg_bitcast:
Wouter van Oortmerssen49482f82018-11-19 17:10:36 +0000169; CHECK-NEXT: .functype .Lhas_i32_arg_bitcast (i32, i32) -> ()
Sam Clegg88599bf2018-08-30 01:01:30 +0000170; CHECK-NEXT: call has_i32_arg@FUNCTION, $1{{$}}
171; CHECK-NEXT: end_function
172
173; CHECK-LABEL: .Lhas_i32_arg_bitcast.1:
Wouter van Oortmerssen49482f82018-11-19 17:10:36 +0000174; CHECK-NEXT: .functype .Lhas_i32_arg_bitcast.1 (i32, i32) -> ()
Sam Clegg88599bf2018-08-30 01:01:30 +0000175; CHECK-NEXT: call has_i32_arg@FUNCTION, $0{{$}}
176; CHECK-NEXT: end_function
177
178; CHECK-LABEL: .Lhas_i32_arg_bitcast.2:
Wouter van Oortmerssen49482f82018-11-19 17:10:36 +0000179; CHECK: call has_i32_arg@FUNCTION, $0{{$}}
Jacob Gravelle37af00e2017-10-10 16:20:18 +0000180; CHECK-NEXT: end_function
181
Sam Clegg41d70472018-08-02 17:38:06 +0000182; CHECK-LABEL: .Lhas_i32_ret_bitcast:
Wouter van Oortmerssen49482f82018-11-19 17:10:36 +0000183; CHECK: call $drop=, has_i32_ret@FUNCTION{{$}}
Jacob Gravelle37af00e2017-10-10 16:20:18 +0000184; CHECK-NEXT: end_function
185
Sam Clegg41d70472018-08-02 17:38:06 +0000186; CHECK-LABEL: .Lvararg_bitcast:
Dan Gohman3a762bf2017-12-08 21:27:00 +0000187; CHECK: call vararg@FUNCTION, $1{{$}}
188; CHECK: end_function
189
Sam Clegg41d70472018-08-02 17:38:06 +0000190; CHECK-LABEL: .Lplain_bitcast:
Dan Gohman3a762bf2017-12-08 21:27:00 +0000191; CHECK: call plain@FUNCTION, $1{{$}}
192; CHECK: end_function
193
Sam Clegg41d70472018-08-02 17:38:06 +0000194; CHECK-LABEL: .Lfoo0_bitcast:
Wouter van Oortmerssen49482f82018-11-19 17:10:36 +0000195; CHECK-NEXT: .functype .Lfoo0_bitcast (i32) -> ()
Jacob Gravelle37af00e2017-10-10 16:20:18 +0000196; CHECK-NEXT: call foo0@FUNCTION{{$}}
197; CHECK-NEXT: end_function
198
Sam Clegg41d70472018-08-02 17:38:06 +0000199; CHECK-LABEL: .Lfoo1_bitcast:
Wouter van Oortmerssen49482f82018-11-19 17:10:36 +0000200; CHECK-NEXT: .functype .Lfoo1_bitcast () -> (i32)
Jacob Gravelle37af00e2017-10-10 16:20:18 +0000201; CHECK-NEXT: call foo1@FUNCTION{{$}}
Thomas Lively6a87dda2019-01-08 06:25:55 +0000202; CHECK-NEXT: local.copy $push0=, $0
Jacob Gravelle37af00e2017-10-10 16:20:18 +0000203; CHECK-NEXT: end_function