diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp @@ -64,29 +64,21 @@ // Recursively descend the def-use lists from V to find non-bitcast users of // bitcasts of V. static void findUses(Value *V, Function &F, - SmallVectorImpl> &Uses, - SmallPtrSetImpl &ConstantBCs) { - for (Use &U : V->uses()) { - if (auto *BC = dyn_cast(U.getUser())) - findUses(BC, F, Uses, ConstantBCs); - else if (auto *A = dyn_cast(U.getUser())) - findUses(A, F, Uses, ConstantBCs); - else if (U.get()->getType() != F.getType()) { - CallBase *CB = dyn_cast(U.getUser()); - if (!CB) - // Skip uses that aren't immediately called - continue; + SmallVectorImpl> &Uses) { + for (User *U : V->users()) { + if (auto *BC = dyn_cast(U)) + findUses(BC, F, Uses); + else if (auto *A = dyn_cast(U)) + findUses(A, F, Uses); + else if (auto *CB = dyn_cast(U)) { Value *Callee = CB->getCalledOperand(); if (Callee != V) // Skip calls where the function isn't the callee continue; - if (isa(U.get())) { - // Only add constant bitcasts to the list once; they get RAUW'd - auto C = ConstantBCs.insert(cast(U.get())); - if (!C.second) - continue; - } - Uses.push_back(std::make_pair(&U, &F)); + if (CB->getFunctionType() == F.getValueType()) + // Skip uses that are immediately called + continue; + Uses.push_back(std::make_pair(CB, &F)); } } } @@ -238,8 +230,7 @@ Function *Main = nullptr; CallInst *CallMain = nullptr; - SmallVector, 0> Uses; - SmallPtrSet ConstantBCs; + SmallVector, 0> Uses; // Collect all the places that need wrappers. for (Function &F : M) { @@ -247,7 +238,7 @@ // bitcast type difference for swiftself and swifterror. if (F.getCallingConv() == CallingConv::Swift) continue; - findUses(&F, F, Uses, ConstantBCs); + findUses(&F, F, Uses); // If we have a "main" function, and its type isn't // "int main(int argc, char *argv[])", create an artificial call with it @@ -268,8 +259,7 @@ Value *Casted = ConstantExpr::getBitCast(Main, PointerType::get(MainTy, 0)); CallMain = CallInst::Create(MainTy, Casted, Args, "call_main"); - Use *UseMain = &CallMain->getOperandUse(2); - Uses.push_back(std::make_pair(UseMain, &F)); + Uses.push_back(std::make_pair(CallMain, &F)); } } } @@ -277,16 +267,9 @@ DenseMap, Function *> Wrappers; for (auto &UseFunc : Uses) { - Use *U = UseFunc.first; + CallBase *CB = UseFunc.first; Function *F = UseFunc.second; - auto *PTy = cast(U->get()->getType()); - auto *Ty = dyn_cast(PTy->getElementType()); - - // If the function is casted to something like i8* as a "generic pointer" - // to be later casted to something else, we can't generate a wrapper for it. - // Just ignore such casts for now. - if (!Ty) - continue; + FunctionType *Ty = CB->getFunctionType(); auto Pair = Wrappers.insert(std::make_pair(std::make_pair(F, Ty), nullptr)); if (Pair.second) @@ -296,10 +279,7 @@ if (!Wrapper) continue; - if (isa(U->get())) - U->get()->replaceAllUsesWith(Wrapper); - else - U->set(Wrapper); + CB->setCalledOperand(Wrapper); } // If we created a wrapper for main, rename the wrapper so that it's the diff --git a/llvm/test/CodeGen/WebAssembly/function-bitcasts.ll b/llvm/test/CodeGen/WebAssembly/function-bitcasts.ll --- a/llvm/test/CodeGen/WebAssembly/function-bitcasts.ll +++ b/llvm/test/CodeGen/WebAssembly/function-bitcasts.ll @@ -1,7 +1,10 @@ -; RUN: llc < %s -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers -enable-emscripten-cxx-exceptions | FileCheck %s +; RUN: llc < %s -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers -enable-emscripten-cxx-exceptions | FileCheck %s --check-prefixes=CHECK,TYPED +; RUN: llc < %s -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers -enable-emscripten-cxx-exceptions -force-opaque-pointers | FileCheck %s --check-prefixes=CHECK,OPAQUE ; Test that function pointer casts are replaced with wrappers. +; The TYPED and OPAQUE prefixes only differ in function ordering. + target triple = "wasm32-unknown-unknown" define void @has_i32_arg(i32) { @@ -20,8 +23,10 @@ declare void @foo3() ; CHECK-LABEL: test: -; CHECK: call .Lhas_i32_arg_bitcast.2{{$}} -; CHECK-NEXT: call .Lhas_i32_arg_bitcast.2{{$}} +; TYPED: call .Lhas_i32_arg_bitcast.2{{$}} +; TYPED-NEXT: call .Lhas_i32_arg_bitcast.2{{$}} +; OPAQUE: call .Lhas_i32_arg_bitcast{{$}} +; OPAQUE-NEXT: call .Lhas_i32_arg_bitcast{{$}} ; CHECK-NEXT: call .Lhas_i32_ret_bitcast{{$}} ; CHECK-NEXT: call $drop=, has_i32_ret ; CHECK-NEXT: i32.const $push[[L0:[0-9]+]]=, 0 @@ -62,7 +67,8 @@ @alias_i32_arg = weak hidden alias void (i32), void (i32)* @has_i32_arg ; CHECK-LABEL: test_alias: -; CHECK: call .Lhas_i32_arg_bitcast.2 +; TYPED: call .Lhas_i32_arg_bitcast.2 +; OPAQUE: call .Lhas_i32_arg_bitcast define void @test_alias() { entry: call void bitcast (void (i32)* @alias_i32_arg to void ()*)() @@ -71,8 +77,10 @@ ; CHECK-LABEL: test_structs: -; CHECK: call .Lhas_i32_arg_bitcast.1, $pop{{[0-9]+}}, $pop{{[0-9]+$}} -; CHECK: call .Lhas_i32_arg_bitcast, $0, $pop2 +; TYPED: call .Lhas_i32_arg_bitcast.1, $pop{{[0-9]+}}, $pop{{[0-9]+$}} +; TYPED: call .Lhas_i32_arg_bitcast, $0, $pop2 +; OPAQUE: call .Lhas_i32_arg_bitcast.2, $pop{{[0-9]+}}, $pop{{[0-9]+$}} +; OPAQUE: call .Lhas_i32_arg_bitcast.1, $0, $pop2 ; CHECK: call .Lhas_struct_arg_bitcast{{$}} define void @test_structs() { entry: @@ -156,7 +164,8 @@ ; CHECK: i32.const $push[[L3:[0-9]+]]=, call_func{{$}} ; CHECK-NEXT: i32.const $push[[L2:[0-9]+]]=, has_i32_arg{{$}} ; CHECK-NEXT: call invoke_vi, $pop[[L3]], $pop[[L2]]{{$}} -; CHECK: i32.const $push[[L4:[0-9]+]]=, .Lhas_i32_arg_bitcast.2{{$}} +; TYPED: i32.const $push[[L4:[0-9]+]]=, .Lhas_i32_arg_bitcast.2{{$}} +; OPAQUE: i32.const $push[[L4:[0-9]+]]=, .Lhas_i32_arg_bitcast{{$}} ; CHECK-NEXT: call invoke_v, $pop[[L4]]{{$}} declare i32 @personality(...) define void @test_invoke() personality i32 (...)* @personality { @@ -181,19 +190,35 @@ ret void } -; CHECK-LABEL: .Lhas_i32_arg_bitcast: -; CHECK-NEXT: .functype .Lhas_i32_arg_bitcast (i32, i32) -> () -; CHECK-NEXT: call has_i32_arg, $1{{$}} -; CHECK-NEXT: end_function - -; CHECK-LABEL: .Lhas_i32_arg_bitcast.1: -; CHECK-NEXT: .functype .Lhas_i32_arg_bitcast.1 (i32, i32) -> () -; CHECK-NEXT: call has_i32_arg, $0{{$}} -; CHECK-NEXT: end_function - -; CHECK-LABEL: .Lhas_i32_arg_bitcast.2: -; CHECK: call has_i32_arg, $0{{$}} -; CHECK-NEXT: end_function +; TYPED-LABEL: .Lhas_i32_arg_bitcast: +; TYPED-NEXT: .functype .Lhas_i32_arg_bitcast (i32, i32) -> () +; TYPED-NEXT: call has_i32_arg, $1{{$}} +; TYPED-NEXT: end_function + +; TYPED-LABEL: .Lhas_i32_arg_bitcast.1: +; TYPED-NEXT: .functype .Lhas_i32_arg_bitcast.1 (i32, i32) -> () +; TYPED-NEXT: call has_i32_arg, $0{{$}} +; TYPED-NEXT: end_function + +; TYPED-LABEL: .Lhas_i32_arg_bitcast.2: +; TYPED-NEXT: .functype .Lhas_i32_arg_bitcast.2 () -> () +; TYPED-NEXT: call has_i32_arg, $0{{$}} +; TYPED-NEXT: end_function + +; OPAQUE-LABEL: .Lhas_i32_arg_bitcast: +; OPAQUE-NEXT: .functype .Lhas_i32_arg_bitcast () -> () +; OPAQUE-NEXT: call has_i32_arg, $0{{$}} +; OPAQUE-NEXT: end_function + +; OPAQUE-LABEL: .Lhas_i32_arg_bitcast.1: +; OPAQUE-NEXT: .functype .Lhas_i32_arg_bitcast.1 (i32, i32) -> () +; OPAQUE-NEXT: call has_i32_arg, $1{{$}} +; OPAQUE-NEXT: end_function + +; OPAQUE-LABEL: .Lhas_i32_arg_bitcast.2: +; OPAQUE-NEXT: .functype .Lhas_i32_arg_bitcast.2 (i32, i32) -> () +; OPAQUE-NEXT: call has_i32_arg, $0{{$}} +; OPAQUE-NEXT: end_function ; CHECK-LABEL: .Lhas_i32_ret_bitcast: ; CHECK: call $drop=, has_i32_ret{{$}} diff --git a/llvm/test/CodeGen/WebAssembly/main-declaration.ll b/llvm/test/CodeGen/WebAssembly/main-declaration.ll --- a/llvm/test/CodeGen/WebAssembly/main-declaration.ll +++ b/llvm/test/CodeGen/WebAssembly/main-declaration.ll @@ -1,4 +1,5 @@ ; RUN: llc < %s -asm-verbose=false | FileCheck %s +; RUN: llc < %s -asm-verbose=false -force-opaque-pointers | FileCheck %s ; Test main functions with alternate signatures.