[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:
parent
551acf03dc
commit
f98ba05f3d
|
@ -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;
|
||||
|
|
|
@ -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" }
|
||||
|
|
Loading…
Reference in New Issue