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