[WebAssembly] Fix broken assumption that all bitcasts are to functions types

Specifically, we can bitcast to void.

Fixes PR39591

Differential Revision: https://reviews.llvm.org/D54447

llvm-svn: 346778
This commit is contained in:
Sam Clegg 2018-11-13 19:14:02 +00:00
parent 551acf03dc
commit f98ba05f3d
2 changed files with 73 additions and 32 deletions

View File

@ -90,16 +90,23 @@ bool WebAssemblyAddMissingPrototypes::runOnModule(Module &M) {
Function *NewF = nullptr;
for (Use &U : F.uses()) {
LLVM_DEBUG(dbgs() << "prototype-less use: " << F.getName() << "\n");
if (BitCastOperator *BC = dyn_cast<BitCastOperator>(U.getUser())) {
FunctionType *DestType =
cast<FunctionType>(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<BitCastOperator>(U.getUser())) {
if (auto *DestType = dyn_cast<FunctionType>(
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 @@ bool WebAssemblyAddMissingPrototypes::runOnModule(Module &M) {
continue;
}
for (Use &U : F.uses()) {
if (BitCastOperator *BC = dyn_cast<BitCastOperator>(U.getUser())) {
FunctionType *DestType =
cast<FunctionType>(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<Instruction *, 4> DeadInsts;
for (Use &US : F.uses()) {
User *U = US.getUser();
if (auto *BC = dyn_cast<BitCastOperator>(U)) {
if (auto *Inst = dyn_cast<BitCastInst>(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<ConstantExpr>(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;

View File

@ -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
}
; 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
}
; 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: declare i64 @foo(i32)
declare i64 @foo(...) #1
attributes #1 = { "no-prototype" }
; CHECK: %call = call i64 @foo(i32 42)
; CHECK: declare i64 @foo(i32)
; CHECK-NOT: attributes {{.*}} = { {{.*}}"no-prototype"{{.*}} }
attributes #1 = { "no-prototype" }