]> granicus.if.org Git - llvm/commitdiff
[WebAssembly] Don't abort on code with UB.
authorDan Gohman <dan433584@gmail.com>
Sat, 7 Jan 2017 01:50:01 +0000 (01:50 +0000)
committerDan Gohman <dan433584@gmail.com>
Sat, 7 Jan 2017 01:50:01 +0000 (01:50 +0000)
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

lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp
test/CodeGen/WebAssembly/function-bitcasts.ll
test/CodeGen/WebAssembly/unsupported-function-bitcasts.ll [new file with mode: 0644]

index 2eb4caa89eded3ac34e35db48bcd40b593dc66f1..d5474a02ce01a41d4d861de1e05dc7a65bbf344f 100644 (file)
@@ -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<Constant>(U->get()))
-      U->get()->replaceAllUsesWith(Pair.first->second);
+      U->get()->replaceAllUsesWith(Wrapper);
     else
-      U->set(Pair.first->second);
+      U->set(Wrapper);
   }
 
   return true;
index b3953c4f1008495851bac1744d22747b4f26e064..49980da6eb8fe091adbe6678af417a85df1d9652 100644 (file)
@@ -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 (file)
index 0000000..ef4318e
--- /dev/null
@@ -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
+}