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