From: Dan Gohman Date: Sat, 7 Jan 2017 01:50:01 +0000 (+0000) Subject: [WebAssembly] Don't abort on code with UB. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e877be12b24de8ade7136cca9fcc3075dc61c39a;p=llvm [WebAssembly] Don't abort on code with UB. Gracefully leave code that performs function-pointer bitcasts implying non-trivial pointer conversions alone, rather than aborting, since it's just undefined behavior. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@291326 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp b/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp index 2eb4caa89ed..d5474a02ce0 100644 --- a/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp +++ b/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp @@ -77,6 +77,9 @@ static void FindUses(Value *V, Function &F, // - Call with fewer arguments than needed: arguments are filled in with undef // - Return value is not needed: drop it // - Return value needed but not present: supply an undef +// +// For now, return nullptr without creating a wrapper if the wrapper cannot +// be generated due to incompatible types. static Function *CreateWrapper(Function *F, FunctionType *Ty) { Module *M = F->getParent(); @@ -90,8 +93,10 @@ static Function *CreateWrapper(Function *F, FunctionType *Ty) { FunctionType::param_iterator PI = F->getFunctionType()->param_begin(); FunctionType::param_iterator PE = F->getFunctionType()->param_end(); for (; AI != Wrapper->arg_end() && PI != PE; ++AI, ++PI) { - assert(AI->getType() == *PI && - "mismatched argument types not supported yet"); + if (AI->getType() != *PI) { + Wrapper->eraseFromParent(); + return nullptr; + } Args.push_back(&*AI); } for (; PI != PE; ++PI) @@ -107,8 +112,10 @@ static Function *CreateWrapper(Function *F, FunctionType *Ty) { BB); else if (F->getFunctionType()->getReturnType() == Ty->getReturnType()) ReturnInst::Create(M->getContext(), Call, BB); - else - llvm_unreachable("mismatched return types not supported yet"); + else { + Wrapper->eraseFromParent(); + return nullptr; + } return Wrapper; } @@ -138,10 +145,14 @@ bool FixFunctionBitcasts::runOnModule(Module &M) { if (Pair.second) Pair.first->second = CreateWrapper(F, Ty); + Function *Wrapper = Pair.first->second; + if (!Wrapper) + continue; + if (isa(U->get())) - U->get()->replaceAllUsesWith(Pair.first->second); + U->get()->replaceAllUsesWith(Wrapper); else - U->set(Pair.first->second); + U->set(Wrapper); } return true; diff --git a/test/CodeGen/WebAssembly/function-bitcasts.ll b/test/CodeGen/WebAssembly/function-bitcasts.ll index b3953c4f100..49980da6eb8 100644 --- a/test/CodeGen/WebAssembly/function-bitcasts.ll +++ b/test/CodeGen/WebAssembly/function-bitcasts.ll @@ -8,7 +8,7 @@ target triple = "wasm32-unknown-unknown" ; CHECK-LABEL: test: ; CHECK-NEXT: call .Lbitcast@FUNCTION{{$}} ; CHECK-NEXT: call .Lbitcast.1@FUNCTION{{$}} -; CHECK-NEXT: i32.const $push[[L0:[0-9]*]]=, 0 +; CHECK-NEXT: i32.const $push[[L0:[0-9]+]]=, 0 ; CHECK-NEXT: call .Lbitcast.2@FUNCTION, $pop[[L0]]{{$}} ; CHECK-NEXT: i32.call $drop=, .Lbitcast.3@FUNCTION{{$}} ; CHECK-NEXT: call foo2@FUNCTION{{$}} diff --git a/test/CodeGen/WebAssembly/unsupported-function-bitcasts.ll b/test/CodeGen/WebAssembly/unsupported-function-bitcasts.ll new file mode 100644 index 00000000000..ef4318ec299 --- /dev/null +++ b/test/CodeGen/WebAssembly/unsupported-function-bitcasts.ll @@ -0,0 +1,26 @@ +; RUN: llc < %s -asm-verbose=false | FileCheck %s + +; Test that function pointer casts that require conversions are not converted +; to wrappers. In theory some conversions could be supported, but currently no +; conversions are implemented. + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +; CHECK-LABEL: test: +; CHECK-NEXT: i32.const $push[[L0:[0-9]+]]=, 0{{$}} +; CHECK-NEXT: call has_i64_arg@FUNCTION, $pop[[L0]]{{$}} +; CHECK-NEXT: i32.call $drop=, has_i64_ret@FUNCTION{{$}} +; CHECK-NEXT: .endfunc + +; CHECK-NOT: .Lbitcast + +declare void @has_i64_arg(i64) +declare i64 @has_i64_ret() + +define void @test() { +entry: + call void bitcast (void (i64)* @has_i64_arg to void (i32)*)(i32 0) + %t = call i32 bitcast (i64 ()* @has_i64_ret to i32 ()*)() + ret void +}