Skip to content
This repository has been archived by the owner on Apr 23, 2020. It is now read-only.

Commit

Permalink
[WebAssembly] Fix broken assumption that all bitcasts are to function…
Browse files Browse the repository at this point in the history
…s types

Specifically, we can bitcast to void.

Fixes PR39591

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@346778 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
sbc100 committed Nov 13, 2018
1 parent 9d76438 commit 7d412f9
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 31 deletions.
69 changes: 43 additions & 26 deletions lib/Target/WebAssembly/WebAssemblyAddMissingPrototypes.cpp
Expand Up @@ -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());
}
}
}
}
}

Expand All @@ -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;
Expand Down
34 changes: 29 additions & 5 deletions test/CodeGen/WebAssembly/add-prototypes.ll
Expand Up @@ -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" }

0 comments on commit 7d412f9

Please sign in to comment.