17f058ce8SNikita Popov; RUN: llc < %s -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers -enable-emscripten-cxx-exceptions | FileCheck %s --check-prefixes=CHECK,TYPED
2*90ec6dffSNikita Popov; 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
31b637458SDan Gohman
41b637458SDan Gohman; Test that function pointer casts are replaced with wrappers.
51b637458SDan Gohman
67f058ce8SNikita Popov; The TYPED and OPAQUE prefixes only differ in function ordering.
77f058ce8SNikita Popov
8a5908009SSam Cleggtarget triple = "wasm32-unknown-unknown"
91b637458SDan Gohman
10dde8a25aSSam Cleggdefine void @has_i32_arg(i32) {
11dde8a25aSSam Cleggentry:
12dde8a25aSSam Clegg  ret void
13dde8a25aSSam Clegg}
14dde8a25aSSam Clegg
1588599bf6SSam Cleggdeclare void @has_struct_arg({i32})
1637af00e7SJacob Gravelledeclare i32 @has_i32_ret()
1737af00e7SJacob Gravelledeclare void @vararg(...)
1837af00e7SJacob Gravelledeclare void @plain(i32)
1937af00e7SJacob Gravelle
2037af00e7SJacob Gravelledeclare void @foo0()
2137af00e7SJacob Gravelledeclare void @foo1()
2237af00e7SJacob Gravelledeclare void @foo2()
2337af00e7SJacob Gravelledeclare void @foo3()
2437af00e7SJacob Gravelle
251b637458SDan Gohman; CHECK-LABEL: test:
267f058ce8SNikita Popov; TYPED:      call        .Lhas_i32_arg_bitcast.2{{$}}
277f058ce8SNikita Popov; TYPED-NEXT: call        .Lhas_i32_arg_bitcast.2{{$}}
287f058ce8SNikita Popov; OPAQUE:      call       .Lhas_i32_arg_bitcast{{$}}
297f058ce8SNikita Popov; OPAQUE-NEXT: call       .Lhas_i32_arg_bitcast{{$}}
30275d15ecSSam Clegg; CHECK-NEXT: call        .Lhas_i32_ret_bitcast{{$}}
31ca9ba764SThomas Lively; CHECK-NEXT: call        $drop=, has_i32_ret
320e2ceb81SDan Gohman; CHECK-NEXT: i32.const   $push[[L0:[0-9]+]]=, 0
33275d15ecSSam Clegg; CHECK-NEXT: call        .Lfoo0_bitcast, $pop[[L0]]{{$}}
347acb42a4SDerek Schuff; CHECK-NEXT: i32.const   $push[[L1:[0-9]+]]=, 0
35275d15ecSSam Clegg; CHECK-NEXT: call        .Lfoo0_bitcast, $pop[[L1]]{{$}}
367acb42a4SDerek Schuff; CHECK-NEXT: i32.const   $push[[L2:[0-9]+]]=, 0
37275d15ecSSam Clegg; CHECK-NEXT: call        .Lfoo0_bitcast, $pop[[L2]]{{$}}
38275d15ecSSam Clegg; CHECK-NEXT: call        foo0
39ca9ba764SThomas Lively; CHECK-NEXT: call        $drop=, .Lfoo1_bitcast{{$}}
40275d15ecSSam Clegg; CHECK-NEXT: call        foo2{{$}}
41275d15ecSSam Clegg; CHECK-NEXT: call        foo1{{$}}
42275d15ecSSam Clegg; CHECK-NEXT: call        foo3{{$}}
437d7409e5SDan Gohman; CHECK-NEXT: end_function
441b637458SDan Gohmandefine void @test() {
451b637458SDan Gohmanentry:
461b637458SDan Gohman  call void bitcast (void (i32)* @has_i32_arg to void ()*)()
477acb42a4SDerek Schuff  call void bitcast (void (i32)* @has_i32_arg to void ()*)()
481b637458SDan Gohman  call void bitcast (i32 ()* @has_i32_ret to void ()*)()
4988599bf6SSam Clegg  call i32 bitcast (i32 ()* @has_i32_ret to i32 ()*)()
501b637458SDan Gohman  call void bitcast (void ()* @foo0 to void (i32)*)(i32 0)
517acb42a4SDerek Schuff  %p = bitcast void ()* @foo0 to void (i32)*
527acb42a4SDerek Schuff  call void %p(i32 0)
537acb42a4SDerek Schuff  %q = bitcast void ()* @foo0 to void (i32)*
547acb42a4SDerek Schuff  call void %q(i32 0)
557acb42a4SDerek Schuff  %r = bitcast void (i32)* %q to void ()*
567acb42a4SDerek Schuff  call void %r()
571b637458SDan Gohman  %t = call i32 bitcast (void ()* @foo1 to i32 ()*)()
581b637458SDan Gohman  call void bitcast (void ()* @foo2 to void ()*)()
597acb42a4SDerek Schuff  call void @foo1()
601b637458SDan Gohman  call void @foo3()
617acb42a4SDerek Schuff
621b637458SDan Gohman  ret void
631b637458SDan Gohman}
64a99b717fSDan Gohman
65dde8a25aSSam Clegg; Calling aliases should also generate a wrapper
66dde8a25aSSam Clegg
67dde8a25aSSam Clegg@alias_i32_arg = weak hidden alias void (i32), void (i32)* @has_i32_arg
68dde8a25aSSam Clegg
69dde8a25aSSam Clegg; CHECK-LABEL: test_alias:
707f058ce8SNikita Popov; TYPED: call    .Lhas_i32_arg_bitcast.2
717f058ce8SNikita Popov; OPAQUE: call   .Lhas_i32_arg_bitcast
72dde8a25aSSam Cleggdefine void @test_alias() {
73dde8a25aSSam Cleggentry:
74dde8a25aSSam Clegg  call void bitcast (void (i32)* @alias_i32_arg to void ()*)()
75dde8a25aSSam Clegg  ret void
76dde8a25aSSam Clegg}
77dde8a25aSSam Clegg
78dde8a25aSSam Clegg
7988599bf6SSam Clegg; CHECK-LABEL: test_structs:
807f058ce8SNikita Popov; TYPED: call     .Lhas_i32_arg_bitcast.1, $pop{{[0-9]+}}, $pop{{[0-9]+$}}
817f058ce8SNikita Popov; TYPED: call     .Lhas_i32_arg_bitcast, $0, $pop2
827f058ce8SNikita Popov; OPAQUE: call    .Lhas_i32_arg_bitcast.2, $pop{{[0-9]+}}, $pop{{[0-9]+$}}
837f058ce8SNikita Popov; OPAQUE: call    .Lhas_i32_arg_bitcast.1, $0, $pop2
84275d15ecSSam Clegg; CHECK: call     .Lhas_struct_arg_bitcast{{$}}
8588599bf6SSam Cleggdefine void @test_structs() {
8688599bf6SSam Cleggentry:
8788599bf6SSam Clegg  call void bitcast (void (i32)* @has_i32_arg to void (i32, {i32})*)(i32 5, {i32} {i32 6})
8888599bf6SSam Clegg  call {i32, i64} bitcast (void (i32)* @has_i32_arg to {i32, i64} (i32)*)(i32 7)
8988599bf6SSam Clegg  call void bitcast (void ({i32})* @has_struct_arg to void ()*)()
9088599bf6SSam Clegg  ret void
9188599bf6SSam Clegg}
9288599bf6SSam Clegg
9388599bf6SSam Clegg; CHECK-LABEL: test_structs_unhandled:
94275d15ecSSam Clegg; CHECK: call    has_struct_arg, $pop{{[0-9]+$}}
95275d15ecSSam Clegg; CHECK: call    has_struct_arg, $pop{{[0-9]+$}}
96275d15ecSSam Clegg; CHECK: call    has_i32_ret, $pop{{[0-9]+$}}
9788599bf6SSam Cleggdefine void @test_structs_unhandled() {
9888599bf6SSam Cleggentry:
9988599bf6SSam Clegg  call void @has_struct_arg({i32} {i32 3})
10088599bf6SSam Clegg  call void bitcast (void ({i32})* @has_struct_arg to void ({i64})*)({i64} {i64 4})
10188599bf6SSam Clegg  call {i32, i32} bitcast (i32 ()* @has_i32_ret to {i32, i32} ()*)()
10288599bf6SSam Clegg  ret void
10388599bf6SSam Clegg}
10488599bf6SSam Clegg
10537af00e7SJacob Gravelle; CHECK-LABEL: test_varargs:
1066a87ddacSThomas Lively; CHECK:      global.set
10737af00e7SJacob Gravelle; CHECK:      i32.const   $push[[L3:[0-9]+]]=, 0{{$}}
108275d15ecSSam Clegg; CHECK-NEXT: call        .Lvararg_bitcast, $pop[[L3]]{{$}}
10937af00e7SJacob Gravelle; CHECK-NEXT: i32.const   $push[[L4:[0-9]+]]=, 0{{$}}
11037af00e7SJacob Gravelle; CHECK-NEXT: i32.store   0($[[L5:[0-9]+]]), $pop[[L4]]{{$}}
111275d15ecSSam Clegg; CHECK-NEXT: call        .Lplain_bitcast, $[[L5]]{{$}}
112a99b717fSDan Gohmandefine void @test_varargs() {
113a99b717fSDan Gohman  call void bitcast (void (...)* @vararg to void (i32)*)(i32 0)
114a99b717fSDan Gohman  call void (...) bitcast (void (i32)* @plain to void (...)*)(i32 0)
115a99b717fSDan Gohman  ret void
116a99b717fSDan Gohman}
11737af00e7SJacob Gravelle
11837af00e7SJacob Gravelle; Don't use wrappers when the value is stored in memory
11937af00e7SJacob Gravelle
12037af00e7SJacob Gravelle@global_func = hidden local_unnamed_addr global void ()* null
12137af00e7SJacob Gravelle
12237af00e7SJacob Gravelle; CHECK-LABEL: test_store:
12349482f82SWouter van Oortmerssen; CHECK:      i32.const   $push[[L0:[0-9]+]]=, 0{{$}}
124275d15ecSSam Clegg; CHECK-NEXT: i32.const   $push[[L1:[0-9]+]]=, has_i32_ret{{$}}
12537af00e7SJacob Gravelle; CHECK-NEXT: i32.store   global_func($pop[[L0]]), $pop[[L1]]{{$}}
12637af00e7SJacob Gravelledefine void @test_store() {
12737af00e7SJacob Gravelle  %1 = bitcast i32 ()* @has_i32_ret to void ()*
12837af00e7SJacob Gravelle  store void ()* %1, void ()** @global_func
12937af00e7SJacob Gravelle  ret void
13037af00e7SJacob Gravelle}
13137af00e7SJacob Gravelle
13237af00e7SJacob Gravelle; CHECK-LABEL: test_load:
13349482f82SWouter van Oortmerssen; CHECK-NEXT: .functype test_load () -> (i32){{$}}
13437af00e7SJacob Gravelle; CHECK-NEXT: i32.const   $push[[L0:[0-9]+]]=, 0{{$}}
13537af00e7SJacob Gravelle; CHECK-NEXT: i32.load    $push[[L1:[0-9]+]]=, global_func($pop[[L0]]){{$}}
136ca9ba764SThomas Lively; CHECK-NEXT: call_indirect $push{{[0-9]+}}=, $pop[[L1]]{{$}}
13737af00e7SJacob Gravelledefine i32 @test_load() {
13837af00e7SJacob Gravelle  %1 = load i32 ()*, i32 ()** bitcast (void ()** @global_func to i32 ()**)
13937af00e7SJacob Gravelle  %2 = call i32 %1()
14037af00e7SJacob Gravelle  ret i32 %2
14137af00e7SJacob Gravelle}
14237af00e7SJacob Gravelle
14337af00e7SJacob Gravelle; Don't use wrappers when the value is passed to a function call
14437af00e7SJacob Gravelle
14537af00e7SJacob Gravelledeclare void @call_func(i32 ()*)
14637af00e7SJacob Gravelle
14737af00e7SJacob Gravelle; CHECK-LABEL: test_argument:
148275d15ecSSam Clegg; CHECK:      i32.const   $push[[L0:[0-9]+]]=, has_i32_ret{{$}}
149275d15ecSSam Clegg; CHECK-NEXT: call        call_func, $pop[[L0]]{{$}}
150275d15ecSSam Clegg; CHECK-NEXT: i32.const   $push[[L1:[0-9]+]]=, has_i32_arg{{$}}
151275d15ecSSam Clegg; CHECK-NEXT: call        call_func, $pop[[L1]]{{$}}
15237af00e7SJacob Gravelledefine void @test_argument() {
15337af00e7SJacob Gravelle  call void @call_func(i32 ()* @has_i32_ret)
15437af00e7SJacob Gravelle  call void @call_func(i32 ()* bitcast (void (i32)* @has_i32_arg to i32 ()*))
15537af00e7SJacob Gravelle  ret void
15637af00e7SJacob Gravelle}
15737af00e7SJacob Gravelle
15837af00e7SJacob Gravelle; Invokes should be treated like calls
15937af00e7SJacob Gravelle
16037af00e7SJacob Gravelle; CHECK-LABEL: test_invoke:
161275d15ecSSam Clegg; CHECK:      i32.const   $push[[L1:[0-9]+]]=, call_func{{$}}
162275d15ecSSam Clegg; CHECK-NEXT: i32.const   $push[[L0:[0-9]+]]=, has_i32_ret{{$}}
1633bba91f6SHeejin Ahn; CHECK-NEXT: call        invoke_vi, $pop[[L1]], $pop[[L0]]{{$}}
164275d15ecSSam Clegg; CHECK:      i32.const   $push[[L3:[0-9]+]]=, call_func{{$}}
165275d15ecSSam Clegg; CHECK-NEXT: i32.const   $push[[L2:[0-9]+]]=, has_i32_arg{{$}}
1663bba91f6SHeejin Ahn; CHECK-NEXT: call        invoke_vi, $pop[[L3]], $pop[[L2]]{{$}}
1677f058ce8SNikita Popov; TYPED:      i32.const   $push[[L4:[0-9]+]]=, .Lhas_i32_arg_bitcast.2{{$}}
1687f058ce8SNikita Popov; OPAQUE:     i32.const   $push[[L4:[0-9]+]]=, .Lhas_i32_arg_bitcast{{$}}
1693bba91f6SHeejin Ahn; CHECK-NEXT: call        invoke_v, $pop[[L4]]{{$}}
17037af00e7SJacob Gravelledeclare i32 @personality(...)
17137af00e7SJacob Gravelledefine void @test_invoke() personality i32 (...)* @personality {
17237af00e7SJacob Gravelleentry:
17337af00e7SJacob Gravelle  invoke void @call_func(i32 ()* @has_i32_ret)
17437af00e7SJacob Gravelle          to label %cont unwind label %lpad
17537af00e7SJacob Gravelle
17637af00e7SJacob Gravellecont:
17737af00e7SJacob Gravelle  invoke void @call_func(i32 ()* bitcast (void (i32)* @has_i32_arg to i32 ()*))
17837af00e7SJacob Gravelle          to label %cont2 unwind label %lpad
17937af00e7SJacob Gravelle
18037af00e7SJacob Gravellecont2:
18137af00e7SJacob Gravelle  invoke void bitcast (void (i32)* @has_i32_arg to void ()*)()
18237af00e7SJacob Gravelle          to label %end unwind label %lpad
18337af00e7SJacob Gravelle
18437af00e7SJacob Gravellelpad:
18537af00e7SJacob Gravelle  %0 = landingpad { i8*, i32 }
18637af00e7SJacob Gravelle          catch i8* null
18737af00e7SJacob Gravelle  br label %end
18837af00e7SJacob Gravelle
18937af00e7SJacob Gravelleend:
19037af00e7SJacob Gravelle  ret void
19137af00e7SJacob Gravelle}
19237af00e7SJacob Gravelle
1937f058ce8SNikita Popov; TYPED-LABEL: .Lhas_i32_arg_bitcast:
1947f058ce8SNikita Popov; TYPED-NEXT: .functype .Lhas_i32_arg_bitcast (i32, i32) -> ()
1957f058ce8SNikita Popov; TYPED-NEXT: call        has_i32_arg, $1{{$}}
1967f058ce8SNikita Popov; TYPED-NEXT: end_function
19788599bf6SSam Clegg
1987f058ce8SNikita Popov; TYPED-LABEL: .Lhas_i32_arg_bitcast.1:
1997f058ce8SNikita Popov; TYPED-NEXT: .functype .Lhas_i32_arg_bitcast.1 (i32, i32) -> ()
2007f058ce8SNikita Popov; TYPED-NEXT: call        has_i32_arg, $0{{$}}
2017f058ce8SNikita Popov; TYPED-NEXT: end_function
20288599bf6SSam Clegg
2037f058ce8SNikita Popov; TYPED-LABEL: .Lhas_i32_arg_bitcast.2:
2047f058ce8SNikita Popov; TYPED-NEXT: .functype	.Lhas_i32_arg_bitcast.2 () -> ()
2057f058ce8SNikita Popov; TYPED-NEXT: call        has_i32_arg, $0{{$}}
2067f058ce8SNikita Popov; TYPED-NEXT: end_function
2077f058ce8SNikita Popov
2087f058ce8SNikita Popov; OPAQUE-LABEL: .Lhas_i32_arg_bitcast:
2097f058ce8SNikita Popov; OPAQUE-NEXT: .functype	.Lhas_i32_arg_bitcast () -> ()
2107f058ce8SNikita Popov; OPAQUE-NEXT: call        has_i32_arg, $0{{$}}
2117f058ce8SNikita Popov; OPAQUE-NEXT: end_function
2127f058ce8SNikita Popov
2137f058ce8SNikita Popov; OPAQUE-LABEL: .Lhas_i32_arg_bitcast.1:
2147f058ce8SNikita Popov; OPAQUE-NEXT: .functype .Lhas_i32_arg_bitcast.1 (i32, i32) -> ()
2157f058ce8SNikita Popov; OPAQUE-NEXT: call        has_i32_arg, $1{{$}}
2167f058ce8SNikita Popov; OPAQUE-NEXT: end_function
2177f058ce8SNikita Popov
2187f058ce8SNikita Popov; OPAQUE-LABEL: .Lhas_i32_arg_bitcast.2:
2197f058ce8SNikita Popov; OPAQUE-NEXT: .functype .Lhas_i32_arg_bitcast.2 (i32, i32) -> ()
2207f058ce8SNikita Popov; OPAQUE-NEXT: call        has_i32_arg, $0{{$}}
2217f058ce8SNikita Popov; OPAQUE-NEXT: end_function
22237af00e7SJacob Gravelle
22341d7047dSSam Clegg; CHECK-LABEL: .Lhas_i32_ret_bitcast:
224275d15ecSSam Clegg; CHECK:      call        $drop=, has_i32_ret{{$}}
22537af00e7SJacob Gravelle; CHECK-NEXT: end_function
22637af00e7SJacob Gravelle
22741d7047dSSam Clegg; CHECK-LABEL: .Lvararg_bitcast:
228275d15ecSSam Clegg; CHECK: call        vararg, $1{{$}}
2293a762bf9SDan Gohman; CHECK: end_function
2303a762bf9SDan Gohman
23141d7047dSSam Clegg; CHECK-LABEL: .Lplain_bitcast:
232275d15ecSSam Clegg; CHECK: call        plain, $1{{$}}
2333a762bf9SDan Gohman; CHECK: end_function
2343a762bf9SDan Gohman
23541d7047dSSam Clegg; CHECK-LABEL: .Lfoo0_bitcast:
23649482f82SWouter van Oortmerssen; CHECK-NEXT: .functype .Lfoo0_bitcast (i32) -> ()
237275d15ecSSam Clegg; CHECK-NEXT: call        foo0{{$}}
23837af00e7SJacob Gravelle; CHECK-NEXT: end_function
23937af00e7SJacob Gravelle
24041d7047dSSam Clegg; CHECK-LABEL: .Lfoo1_bitcast:
24149482f82SWouter van Oortmerssen; CHECK-NEXT: .functype .Lfoo1_bitcast () -> (i32)
242275d15ecSSam Clegg; CHECK-NEXT: call        foo1{{$}}
2436a87ddacSThomas Lively; CHECK-NEXT: local.copy  $push0=, $0
24437af00e7SJacob Gravelle; CHECK-NEXT: end_function
245