Index: lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp +++ lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp @@ -108,8 +108,8 @@ static Function *CreateWrapper(Function *F, FunctionType *Ty) { Module *M = F->getParent(); - Function *Wrapper = - Function::Create(Ty, Function::PrivateLinkage, "bitcast", M); + Function *Wrapper = Function::Create(Ty, Function::PrivateLinkage, + F->getName() + "_bitcast", M); BasicBlock *BB = BasicBlock::Create(M->getContext(), "body", Wrapper); // Determine what arguments to pass. @@ -120,6 +120,8 @@ FunctionType::param_iterator PE = F->getFunctionType()->param_end(); for (; AI != AE && PI != PE; ++AI, ++PI) { if (AI->getType() != *PI) { + LLVM_DEBUG(dbgs() << "CreateWrapper failed due to argument mismatch: " + << F->getName() << "\n"); Wrapper->eraseFromParent(); return nullptr; } @@ -142,8 +144,13 @@ else if (F->getFunctionType()->getReturnType() == Ty->getReturnType()) ReturnInst::Create(M->getContext(), Call, BB); else { - Wrapper->eraseFromParent(); - return nullptr; + LLVM_DEBUG(dbgs() << "CreateWrapper failed due to return type mismatch: " + << F->getName() << "\n"); + Instruction::CastOps CastOpCode = + CastInst::getCastOpcode(Call, false, Ty->getReturnType(), false); + CastInst *Cast = + CastInst::Create(CastOpCode, Call, Ty->getReturnType(), "", BB); + ReturnInst::Create(M->getContext(), Cast, BB); } return Wrapper; Index: test/CodeGen/WebAssembly/call.ll =================================================================== --- test/CodeGen/WebAssembly/call.ll +++ test/CodeGen/WebAssembly/call.ll @@ -153,7 +153,7 @@ ; CHECK-LABEL: call_constexpr: ; CHECK-NEXT: i32.const $push[[L0:[0-9]+]]=, 2{{$}} ; CHECK-NEXT: i32.const $push[[L1:[0-9]+]]=, 3{{$}} -; CHECK-NEXT: call .Lbitcast@FUNCTION, $pop[[L0]], $pop[[L1]]{{$}} +; CHECK-NEXT: call .Lvararg_func_bitcast@FUNCTION, $pop[[L0]], $pop[[L1]]{{$}} ; CHECK-NEXT: call other_void_nullary@FUNCTION{{$}} ; CHECK-NEXT: call void_nullary@FUNCTION{{$}} ; CHECK-NEXT: return{{$}} Index: test/CodeGen/WebAssembly/function-bitcasts-varargs.ll =================================================================== --- test/CodeGen/WebAssembly/function-bitcasts-varargs.ll +++ test/CodeGen/WebAssembly/function-bitcasts-varargs.ll @@ -19,13 +19,13 @@ ; CHECK: callWithArgs: ; CHECK: i32.const $push1=, 0 ; CHECK-NEXT: i32.const $push0=, 1 -; CHECK-NEXT: call .Lbitcast@FUNCTION, $pop1, $pop0 -; CHECK: call .Lbitcast.1@FUNCTION, $pop{{[0-9]+$}} +; CHECK-NEXT: call .Lunderspecified_bitcast@FUNCTION, $pop1, $pop0 +; CHECK: call .Lspecified_bitcast@FUNCTION, $pop{{[0-9]+$}} -; CHECK: .Lbitcast: +; CHECK: .Lunderspecified_bitcast: ; CHECK-NEXT: .param i32, i32{{$}} ; CHECK: call underspecified@FUNCTION, $pop{{[0-9]+$}} -; CHECK: .Lbitcast.1: +; CHECK: .Lspecified_bitcast: ; CHECK-NEXT: .param i32{{$}} ; CHECK: call specified@FUNCTION, $pop{{[0-9]+}}, $pop{{[0-9]+$}} Index: test/CodeGen/WebAssembly/function-bitcasts.ll =================================================================== --- test/CodeGen/WebAssembly/function-bitcasts.ll +++ test/CodeGen/WebAssembly/function-bitcasts.ll @@ -16,17 +16,17 @@ declare void @foo3() ; CHECK-LABEL: test: -; CHECK-NEXT: call .Lbitcast@FUNCTION{{$}} -; CHECK-NEXT: call .Lbitcast@FUNCTION{{$}} -; CHECK-NEXT: call .Lbitcast.1@FUNCTION{{$}} +; CHECK-NEXT: call .Lhas_i32_arg_bitcast@FUNCTION{{$}} +; CHECK-NEXT: call .Lhas_i32_arg_bitcast@FUNCTION{{$}} +; CHECK-NEXT: call .Lhas_i32_ret_bitcast@FUNCTION{{$}} ; CHECK-NEXT: i32.const $push[[L0:[0-9]+]]=, 0 -; CHECK-NEXT: call .Lbitcast.4@FUNCTION, $pop[[L0]]{{$}} +; CHECK-NEXT: call .Lfoo0_bitcast@FUNCTION, $pop[[L0]]{{$}} ; CHECK-NEXT: i32.const $push[[L1:[0-9]+]]=, 0 -; CHECK-NEXT: call .Lbitcast.4@FUNCTION, $pop[[L1]]{{$}} +; CHECK-NEXT: call .Lfoo0_bitcast@FUNCTION, $pop[[L1]]{{$}} ; CHECK-NEXT: i32.const $push[[L2:[0-9]+]]=, 0 -; CHECK-NEXT: call .Lbitcast.4@FUNCTION, $pop[[L2]]{{$}} +; CHECK-NEXT: call .Lfoo0_bitcast@FUNCTION, $pop[[L2]]{{$}} ; CHECK-NEXT: call foo0@FUNCTION -; CHECK-NEXT: i32.call $drop=, .Lbitcast.5@FUNCTION{{$}} +; CHECK-NEXT: i32.call $drop=, .Lfoo1_bitcast@FUNCTION{{$}} ; CHECK-NEXT: call foo2@FUNCTION{{$}} ; CHECK-NEXT: call foo1@FUNCTION{{$}} ; CHECK-NEXT: call foo3@FUNCTION{{$}} @@ -54,10 +54,10 @@ ; CHECK-LABEL: test_varargs: ; CHECK: set_global ; CHECK: i32.const $push[[L3:[0-9]+]]=, 0{{$}} -; CHECK-NEXT: call .Lbitcast.2@FUNCTION, $pop[[L3]]{{$}} +; CHECK-NEXT: call .Lvararg_bitcast@FUNCTION, $pop[[L3]]{{$}} ; CHECK-NEXT: i32.const $push[[L4:[0-9]+]]=, 0{{$}} ; CHECK-NEXT: i32.store 0($[[L5:[0-9]+]]), $pop[[L4]]{{$}} -; CHECK-NEXT: call .Lbitcast.3@FUNCTION, $[[L5]]{{$}} +; CHECK-NEXT: call .Lplain_bitcast@FUNCTION, $[[L5]]{{$}} define void @test_varargs() { call void bitcast (void (...)* @vararg to void (i32)*)(i32 0) call void (...) bitcast (void (i32)* @plain to void (...)*)(i32 0) @@ -113,7 +113,7 @@ ; CHECK: i32.const $push[[L3:[0-9]+]]=, call_func@FUNCTION{{$}} ; CHECK-NEXT: i32.const $push[[L2:[0-9]+]]=, has_i32_arg@FUNCTION{{$}} ; CHECK-NEXT: call "__invoke_void_i32()*"@FUNCTION, $pop[[L3]], $pop[[L2]]{{$}} -; CHECK: i32.const $push[[L4:[0-9]+]]=, .Lbitcast@FUNCTION{{$}} +; CHECK: i32.const $push[[L4:[0-9]+]]=, .Lhas_i32_arg_bitcast@FUNCTION{{$}} ; CHECK-NEXT: call __invoke_void@FUNCTION, $pop[[L4]]{{$}} declare i32 @personality(...) define void @test_invoke() personality i32 (...)* @personality { @@ -138,28 +138,28 @@ ret void } -; CHECK-LABEL: .Lbitcast: +; CHECK-LABEL: .Lhas_i32_arg_bitcast: ; CHECK-NEXT: call has_i32_arg@FUNCTION, $0{{$}} ; CHECK-NEXT: end_function -; CHECK-LABEL: .Lbitcast.1: +; CHECK-LABEL: .Lhas_i32_ret_bitcast: ; CHECK-NEXT: call $drop=, has_i32_ret@FUNCTION{{$}} ; CHECK-NEXT: end_function -; CHECK-LABEL: .Lbitcast.2: +; CHECK-LABEL: .Lvararg_bitcast: ; CHECK: call vararg@FUNCTION, $1{{$}} ; CHECK: end_function -; CHECK-LABEL: .Lbitcast.3: +; CHECK-LABEL: .Lplain_bitcast: ; CHECK: call plain@FUNCTION, $1{{$}} ; CHECK: end_function -; CHECK-LABEL: .Lbitcast.4: +; CHECK-LABEL: .Lfoo0_bitcast: ; CHECK-NEXT: .param i32 ; CHECK-NEXT: call foo0@FUNCTION{{$}} ; CHECK-NEXT: end_function -; CHECK-LABEL: .Lbitcast.5: +; CHECK-LABEL: .Lfoo1_bitcast: ; CHECK-NEXT: .result i32 ; CHECK-NEXT: call foo1@FUNCTION{{$}} ; CHECK-NEXT: copy_local $push0=, $0 Index: test/CodeGen/WebAssembly/unsupported-function-bitcasts.ll =================================================================== --- test/CodeGen/WebAssembly/unsupported-function-bitcasts.ll +++ test/CodeGen/WebAssembly/unsupported-function-bitcasts.ll @@ -1,8 +1,9 @@ ; RUN: llc < %s -asm-verbose=false | FileCheck %s -; Test that function pointer casts that require conversions are not converted -; to wrappers. In theory some conversions could be supported, but currently no -; conversions are implemented. +; Test that function pointer casts that require conversions of arguments +; are not converted to wrappers. +; We currently only support adding and removing of argument and conversion of +; the return type. target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" target triple = "wasm32-unknown-unknown" @@ -10,18 +11,14 @@ ; CHECK-LABEL: test: ; CHECK-NEXT: i32.const $push[[L0:[0-9]+]]=, 0{{$}} ; CHECK-NEXT: call has_i64_arg@FUNCTION, $pop[[L0]]{{$}} -; CHECK-NEXT: i32.call $push{{[0-9]+}}=, has_i64_ret@FUNCTION{{$}} -; CHECK-NEXT: drop ; CHECK-NEXT: end_function ; CHECK-NOT: .Lbitcast declare void @has_i64_arg(i64) -declare i64 @has_i64_ret() define void @test() { entry: call void bitcast (void (i64)* @has_i64_arg to void (i32)*)(i32 0) - %t = call i32 bitcast (i64 ()* @has_i64_ret to i32 ()*)() ret void }