Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyAddMissingPrototypes.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyAddMissingPrototypes.cpp +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyAddMissingPrototypes.cpp @@ -90,16 +90,23 @@ Function *NewF = nullptr; for (Use &U : F.uses()) { LLVM_DEBUG(dbgs() << "prototype-less use: " << F.getName() << "\n"); - if (BitCastOperator *BC = dyn_cast(U.getUser())) { - FunctionType *DestType = - cast(BC->getDestTy()->getPointerElementType()); - - // Create a new function with the correct type - NewType = DestType; - NewF = Function::Create(NewType, F.getLinkage(), F.getName()); - NewF->setAttributes(F.getAttributes()); - NewF->removeFnAttr("no-prototype"); - break; + if (auto *BC = dyn_cast(U.getUser())) { + if (auto *DestType = dyn_cast( + BC->getDestTy()->getPointerElementType())) { + if (!NewType) { + // Create a new function with the correct type + NewType = DestType; + NewF = Function::Create(NewType, F.getLinkage(), F.getName()); + NewF->setAttributes(F.getAttributes()); + NewF->removeFnAttr("no-prototype"); + } else { + if (NewType != DestType) { + report_fatal_error("Prototypeless function used with " + "conflicting signatures: " + + F.getName()); + } + } + } } } @@ -110,28 +117,38 @@ continue; } - for (Use &U : F.uses()) { - if (BitCastOperator *BC = dyn_cast(U.getUser())) { - FunctionType *DestType = - cast(BC->getDestTy()->getPointerElementType()); - if (NewType != DestType) { - report_fatal_error( - "Prototypeless function used with conflicting signatures: " + - F.getName()); - } - BC->replaceAllUsesWith(NewF); - Replacements.emplace_back(&F, NewF); - } else { - dbgs() << *U.getUser()->getType() << "\n"; + SmallVector DeadInsts; + + for (Use &US : F.uses()) { + User *U = US.getUser(); + if (auto *BC = dyn_cast(U)) { + if (auto *Inst = dyn_cast(U)) { + // Replace with a new bitcast + IRBuilder<> Builder(Inst); + Value *NewCast = Builder.CreatePointerCast(NewF, BC->getDestTy()); + Inst->replaceAllUsesWith(NewCast); + DeadInsts.push_back(Inst); + } else if (auto *Const = dyn_cast(U)) { + Constant *NewConst = + ConstantExpr::getPointerCast(NewF, BC->getDestTy()); + Const->replaceAllUsesWith(NewConst); + } else { + dbgs() << *U->getType() << "\n"; #ifndef NDEBUG - U.getUser()->dump(); + U->dump(); #endif - report_fatal_error( - "unexpected use of prototypeless function: " + F.getName() + "\n"); + report_fatal_error("unexpected use of prototypeless function: " + + F.getName() + "\n"); + } } } + + for (auto I : DeadInsts) + I->eraseFromParent(); + Replacements.emplace_back(&F, NewF); } + // Finally replace the old function declarations with the new ones for (auto &Pair : Replacements) { Function *Old = Pair.first; Index: llvm/trunk/test/CodeGen/WebAssembly/add-prototypes.ll =================================================================== --- llvm/trunk/test/CodeGen/WebAssembly/add-prototypes.ll +++ llvm/trunk/test/CodeGen/WebAssembly/add-prototypes.ll @@ -3,18 +3,42 @@ target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" target triple = "wasm32-unknown-unknown" +; CHECK: @foo_addr = global i64 (i32)* @foo, align 8 @foo_addr = global i64 (i32)* bitcast (i64 (...)* @foo to i64 (i32)*), align 8 -define void @bar(i32 %a) { -entry: +; CHECK: @foo_addr_i8 = global i8* bitcast (i64 (i32)* @foo to i8*), align 8 +@foo_addr_i8 = global i8* bitcast (i64 (...)* @foo to i8*), align 8 + +; CHECK-LABEL: @call_foo +; CHECK: %call = call i64 @foo(i32 42) +define void @call_foo(i32 %a) { %call = call i64 bitcast (i64 (...)* @foo to i64 (i32)*)(i32 42) ret void } -declare i64 @foo(...) #1 +; CHECK-LABEL: @call_foo_ptr +; CHECK: %call = call i64 @foo(i32 43) +define i64 @call_foo_ptr(i32 %a) { + %1 = bitcast i64 (...)* @foo to i64 (i32)* + %call = call i64 (i32) %1(i32 43) + ret i64 %call +} -attributes #1 = { "no-prototype" } +; CHECK-LABEL: @to_intptr_inst +; CHECK: ret i8* bitcast (i64 (i32)* @foo to i8*) +define i8* @to_intptr_inst() { + %1 = bitcast i64 (...)* @foo to i8* + ret i8* %1 +} + +; CHECK-LABEL: @to_intptr_constexpr +; CHECK: ret i8* bitcast (i64 (i32)* @foo to i8*) +define i8* @to_intptr_constexpr() { + ret i8* bitcast (i64 (...)* @foo to i8*) +} -; CHECK: %call = call i64 @foo(i32 42) ; CHECK: declare i64 @foo(i32) +declare i64 @foo(...) #1 + ; CHECK-NOT: attributes {{.*}} = { {{.*}}"no-prototype"{{.*}} } +attributes #1 = { "no-prototype" }