[llvm] r341010 - [WebAssembly] Be a little more conservative in WebAssemblyFixFunctionBitcasts

Sam Clegg via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 29 18:01:30 PDT 2018


Author: sbc
Date: Wed Aug 29 18:01:30 2018
New Revision: 341010

URL: http://llvm.org/viewvc/llvm-project?rev=341010&view=rev
Log:
[WebAssembly] Be a little more conservative in WebAssemblyFixFunctionBitcasts

We don't have enough information to know if struct types being
bitcast will cause validation failures or not, so be conservative
and allow such cases to persist (fot now).

Fixes: https://bugs.llvm.org/show_bug.cgi?id=38711

Subscribers: dschuff, jgravelle-google, aheejin, sunfish, llvm-commits

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

Modified:
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp
    llvm/trunk/test/CodeGen/WebAssembly/function-bitcasts.ll
    llvm/trunk/test/CodeGen/WebAssembly/unsupported-function-bitcasts.ll

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp?rev=341010&r1=341009&r2=341010&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp Wed Aug 29 18:01:30 2018
@@ -107,14 +107,18 @@ static void FindUses(Value *V, Function
 // I32 vs pointer type) then we don't create a wrapper at all (return nullptr
 // instead).
 //
-// If there is a type mismatch that would result in an invalid wasm module
-// being written then generate wrapper that contains unreachable (i.e. abort
-// at runtime).  Such programs are deep into undefined behaviour territory,
+// If there is a type mismatch that we know would result in an invalid wasm
+// module then generate wrapper that contains unreachable (i.e. abort at 
+// runtime).  Such programs are deep into undefined behaviour territory,
 // but we choose to fail at runtime rather than generate and invalid module
 // or fail at compiler time.  The reason we delay the error is that we want
 // to support the CMake which expects to be able to compile and link programs
 // that refer to functions with entirely incorrect signatures (this is how
 // CMake detects the existence of a function in a toolchain).
+//
+// For bitcasts that involve struct types we don't know at this stage if they
+// would be equivalent at the wasm level and so we can't know if we need to 
+// generate a wrapper.
 static Function *CreateWrapper(Function *F, FunctionType *Ty) {
   Module *M = F->getParent();
 
@@ -132,8 +136,12 @@ static Function *CreateWrapper(Function
   bool TypeMismatch = false;
   bool WrapperNeeded = false;
 
+  Type *ExpectedRtnType = F->getFunctionType()->getReturnType();
+  Type *RtnType = Ty->getReturnType();
+
   if ((F->getFunctionType()->getNumParams() != Ty->getNumParams()) ||
-      (F->getFunctionType()->isVarArg() != Ty->isVarArg()))
+      (F->getFunctionType()->isVarArg() != Ty->isVarArg()) ||
+      (ExpectedRtnType != RtnType))
     WrapperNeeded = true;
 
   for (; AI != AE && PI != PE; ++AI, ++PI) {
@@ -148,6 +156,10 @@ static Function *CreateWrapper(Function
             CastInst::CreateBitOrPointerCast(AI, ParamType, "cast");
         BB->getInstList().push_back(PtrCast);
         Args.push_back(PtrCast);
+      } else if (ArgType->isStructTy() || ParamType->isStructTy()) {
+        LLVM_DEBUG(dbgs() << "CreateWrapper: struct param type in bitcast: "
+                          << F->getName() << "\n");
+        WrapperNeeded = false;
       } else {
         LLVM_DEBUG(dbgs() << "CreateWrapper: arg type mismatch calling: "
                           << F->getName() << "\n");
@@ -159,7 +171,7 @@ static Function *CreateWrapper(Function
     }
   }
 
-  if (!TypeMismatch) {
+  if (WrapperNeeded && !TypeMismatch) {
     for (; PI != PE; ++PI)
       Args.push_back(UndefValue::get(*PI));
     if (F->isVarArg())
@@ -173,10 +185,9 @@ static Function *CreateWrapper(Function
     // Determine what value to return.
     if (RtnType->isVoidTy()) {
       ReturnInst::Create(M->getContext(), BB);
-      WrapperNeeded = true;
     } else if (ExpectedRtnType->isVoidTy()) {
+      LLVM_DEBUG(dbgs() << "Creating dummy return: " << *RtnType << "\n");
       ReturnInst::Create(M->getContext(), UndefValue::get(RtnType), BB);
-      WrapperNeeded = true;
     } else if (RtnType == ExpectedRtnType) {
       ReturnInst::Create(M->getContext(), Call, BB);
     } else if (CastInst::isBitOrNoopPointerCastable(ExpectedRtnType, RtnType,
@@ -185,6 +196,10 @@ static Function *CreateWrapper(Function
           CastInst::CreateBitOrPointerCast(Call, RtnType, "cast");
       BB->getInstList().push_back(Cast);
       ReturnInst::Create(M->getContext(), Cast, BB);
+    } else if (RtnType->isStructTy() || ExpectedRtnType->isStructTy()) {
+      LLVM_DEBUG(dbgs() << "CreateWrapper: struct return type in bitcast: "
+                        << F->getName() << "\n");
+      WrapperNeeded = false;
     } else {
       LLVM_DEBUG(dbgs() << "CreateWrapper: return type mismatch calling: "
                         << F->getName() << "\n");
@@ -195,6 +210,10 @@ static Function *CreateWrapper(Function
   }
 
   if (TypeMismatch) {
+    // Create a new wrapper that simply contains `unreachable`.
+    Wrapper->eraseFromParent();
+    Wrapper = Function::Create(Ty, Function::PrivateLinkage, F->getName() + "_bitcast_invalid", M);
+    BasicBlock *BB = BasicBlock::Create(M->getContext(), "body", Wrapper);
     new UnreachableInst(M->getContext(), BB);
     Wrapper->setName(F->getName() + "_bitcast_invalid");
   } else if (!WrapperNeeded) {
@@ -203,6 +222,7 @@ static Function *CreateWrapper(Function
     Wrapper->eraseFromParent();
     return nullptr;
   }
+  LLVM_DEBUG(dbgs() << "CreateWrapper: " << F->getName() << "\n");
   return Wrapper;
 }
 

Modified: llvm/trunk/test/CodeGen/WebAssembly/function-bitcasts.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/function-bitcasts.ll?rev=341010&r1=341009&r2=341010&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/function-bitcasts.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/function-bitcasts.ll Wed Aug 29 18:01:30 2018
@@ -6,6 +6,7 @@ target datalayout = "e-m:e-p:32:32-i64:6
 target triple = "wasm32-unknown-unknown"
 
 declare void @has_i32_arg(i32)
+declare void @has_struct_arg({i32})
 declare i32 @has_i32_ret()
 declare void @vararg(...)
 declare void @plain(i32)
@@ -16,9 +17,10 @@ declare void @foo2()
 declare void @foo3()
 
 ; CHECK-LABEL: test:
-; CHECK-NEXT: call        .Lhas_i32_arg_bitcast at FUNCTION{{$}}
-; CHECK-NEXT: call        .Lhas_i32_arg_bitcast at FUNCTION{{$}}
+; CHECK-NEXT: call        .Lhas_i32_arg_bitcast.2 at FUNCTION{{$}}
+; CHECK-NEXT: call        .Lhas_i32_arg_bitcast.2 at FUNCTION{{$}}
 ; CHECK-NEXT: call        .Lhas_i32_ret_bitcast at FUNCTION{{$}}
+; CHECK-NEXT: i32.call     $drop=, has_i32_ret at FUNCTION
 ; CHECK-NEXT: i32.const   $push[[L0:[0-9]+]]=, 0
 ; CHECK-NEXT: call        .Lfoo0_bitcast at FUNCTION, $pop[[L0]]{{$}}
 ; CHECK-NEXT: i32.const   $push[[L1:[0-9]+]]=, 0
@@ -36,6 +38,7 @@ entry:
   call void bitcast (void (i32)* @has_i32_arg to void ()*)()
   call void bitcast (void (i32)* @has_i32_arg to void ()*)()
   call void bitcast (i32 ()* @has_i32_ret to void ()*)()
+  call i32 bitcast (i32 ()* @has_i32_ret to i32 ()*)()
   call void bitcast (void ()* @foo0 to void (i32)*)(i32 0)
   %p = bitcast void ()* @foo0 to void (i32)*
   call void %p(i32 0)
@@ -51,6 +54,30 @@ entry:
   ret void
 }
 
+; CHECK-LABEL: test_structs:
+; CHECK: call     .Lhas_i32_arg_bitcast.1 at FUNCTION, $pop{{[0-9]+}}, $pop{{[0-9]+$}}
+; CHECK: call     .Lhas_i32_arg_bitcast at FUNCTION, $0, $pop2
+; CHECK: call     .Lhas_struct_arg_bitcast at FUNCTION{{$}}
+define void @test_structs() {
+entry:
+  call void bitcast (void (i32)* @has_i32_arg to void (i32, {i32})*)(i32 5, {i32} {i32 6})
+  call {i32, i64} bitcast (void (i32)* @has_i32_arg to {i32, i64} (i32)*)(i32 7)
+  call void bitcast (void ({i32})* @has_struct_arg to void ()*)()
+  ret void
+}
+
+; CHECK-LABEL: test_structs_unhandled:
+; CHECK: call    has_struct_arg at FUNCTION, $pop{{[0-9]+$}}
+; CHECK: call    has_struct_arg at FUNCTION, $pop{{[0-9]+$}}
+; CHECK: call    has_i32_ret at FUNCTION, $pop{{[0-9]+$}}
+define void @test_structs_unhandled() {
+entry:
+  call void @has_struct_arg({i32} {i32 3})
+  call void bitcast (void ({i32})* @has_struct_arg to void ({i64})*)({i64} {i64 4})
+  call {i32, i32} bitcast (i32 ()* @has_i32_ret to {i32, i32} ()*)()
+  ret void
+}
+
 ; CHECK-LABEL: test_varargs:
 ; CHECK:      set_global
 ; CHECK:      i32.const   $push[[L3:[0-9]+]]=, 0{{$}}
@@ -113,7 +140,7 @@ define void @test_argument() {
 ; CHECK:      i32.const   $push[[L3:[0-9]+]]=, call_func at FUNCTION{{$}}
 ; CHECK-NEXT: i32.const   $push[[L2:[0-9]+]]=, has_i32_arg at FUNCTION{{$}}
 ; CHECK-NEXT: call        "__invoke_void_i32()*"@FUNCTION, $pop[[L3]], $pop[[L2]]{{$}}
-; CHECK:      i32.const   $push[[L4:[0-9]+]]=, .Lhas_i32_arg_bitcast at FUNCTION{{$}}
+; CHECK:      i32.const   $push[[L4:[0-9]+]]=, .Lhas_i32_arg_bitcast.2 at FUNCTION{{$}}
 ; CHECK-NEXT: call        __invoke_void at FUNCTION, $pop[[L4]]{{$}}
 declare i32 @personality(...)
 define void @test_invoke() personality i32 (...)* @personality {
@@ -139,6 +166,16 @@ end:
 }
 
 ; CHECK-LABEL: .Lhas_i32_arg_bitcast:
+; CHECK-NEXT: .param      i32, i32
+; CHECK-NEXT: call        has_i32_arg at FUNCTION, $1{{$}}
+; CHECK-NEXT: end_function
+
+; CHECK-LABEL: .Lhas_i32_arg_bitcast.1:
+; CHECK-NEXT: .param      i32, i32
+; CHECK-NEXT: call        has_i32_arg at FUNCTION, $0{{$}}
+; CHECK-NEXT: end_function
+
+; CHECK-LABEL: .Lhas_i32_arg_bitcast.2:
 ; CHECK-NEXT: call        has_i32_arg at FUNCTION, $0{{$}}
 ; CHECK-NEXT: end_function
 

Modified: llvm/trunk/test/CodeGen/WebAssembly/unsupported-function-bitcasts.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/unsupported-function-bitcasts.ll?rev=341010&r1=341009&r2=341010&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/unsupported-function-bitcasts.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/unsupported-function-bitcasts.ll Wed Aug 29 18:01:30 2018
@@ -9,28 +9,31 @@ target triple = "wasm32-unknown-unknown"
 declare i32 @has_i64_arg(i64)
 declare i32 @has_ptr_arg(i8*)
 
+; CHECK-LABEL: test_invalid_rtn:
+; CHECK-NEXT: i32.const   $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: i32.call $push[[L1:[0-9]+]]=, .Lhas_i64_arg_bitcast_invalid.2 at FUNCTION, $pop[[L0]]{{$}}
+; CHECK-NEXT: drop $pop[[L1]]{{$}}
+; CHECK-NEXT: i64.const   $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: i64.call $push[[L1:[0-9]+]]=, .Lhas_i64_arg_bitcast_invalid at FUNCTION, $pop[[L0]]{{$}}
+; CHECK-NEXT: drop $pop[[L1]]{{$}}
+; CHECK-NEXT: end_function
 define void @test_invalid_rtn() {
 entry:
   call i32 bitcast (i32 (i64)* @has_i64_arg to i32 (i32)*)(i32 0)
+  call [1 x i64] bitcast (i32 (i64)* @has_i64_arg to [1 x i64] (i64)*)(i64 0)
   ret void
 }
-; CHECK-LABEL: test_invalid_rtn:
-; CHECK-NEXT: i32.const   $push[[L0:[0-9]+]]=, 0{{$}}
-; CHECK-NEXT: i32.call $push1=, .Lhas_i64_arg_bitcast_invalid at FUNCTION, $pop[[L0]]{{$}}
-; CHECK-NEXT: drop $pop1
-; CHECK-NEXT: end_function
 
-define void @test_invalid_arg() {
-entry:
-  call i32 bitcast (i32 (i8*)* @has_ptr_arg to i32 (i8)*)(i8 2)
-  call i32 bitcast (i32 (i8*)* @has_ptr_arg to i32 (i32)*)(i32 2)
-  call i32 bitcast (i32 (i8*)* @has_ptr_arg to i32 (i64)*)(i64 3)
+; CHECK-LABEL: test_struct_rtn:
+; CHECK: 	call    	has_i64_arg at FUNCTION, $pop6, $pop0
+define void @test_struct_rtn() {
+  call {i32, i32} bitcast (i32 (i64)* @has_i64_arg to {i32, i32} (i64)*)(i64 0)
   ret void
 }
 
 ; CHECK-LABEL: test_invalid_arg:
 ; CHECK-NEXT: 	i32.const	$push[[L0:[0-9]+]]=, 2{{$}}
-; CHECK-NEXT: 	i32.call	$push[[L1:[0-9]+]]=, .Lhas_ptr_arg_bitcast_invalid.1 at FUNCTION, $pop[[L0]]{{$}}
+; CHECK-NEXT: 	i32.call	$push[[L1:[0-9]+]]=, .Lhas_ptr_arg_bitcast_invalid.4 at FUNCTION, $pop[[L0]]{{$}}
 ; CHECK-NEXT: 	drop	$pop[[L1]]{{$}}
 ; CHECK-NEXT: 	i32.const	$push[[L0:[0-9]+]]=, 2{{$}}
 ; CHECK-NEXT: 	i32.call	$push[[L1:[0-9]+]]=, has_ptr_arg at FUNCTION, $pop[[L0]]{{$}}
@@ -39,8 +42,21 @@ entry:
 ; CHECK-NEXT: 	i32.call	$push[[L1:[0-9]+]]=, .Lhas_ptr_arg_bitcast_invalid at FUNCTION, $pop[[L0]]{{$}}
 ; CHECK-NEXT: 	drop	$pop[[L1]]{{$}}
 ; CHECK-NEXT: 	end_function
+define void @test_invalid_arg() {
+entry:
+  call i32 bitcast (i32 (i8*)* @has_ptr_arg to i32 (i8)*)(i8 2)
+  call i32 bitcast (i32 (i8*)* @has_ptr_arg to i32 (i32)*)(i32 2)
+  call i32 bitcast (i32 (i8*)* @has_ptr_arg to i32 (i64)*)(i64 3)
+  ret void
+}
 
 ; CHECK-LABEL: .Lhas_i64_arg_bitcast_invalid:
+; CHECK-NEXT:  .param  	i64
+; CHECK-NEXT:  .result 	i64
+; CHECK-NEXT:  unreachable
+; CHECK-NEXT:  end_function
+
+; CHECK-LABEL: .Lhas_i64_arg_bitcast_invalid.2:
 ; CHECK-NEXT:  .param  	i32
 ; CHECK-NEXT:  .result 	i32
 ; CHECK-NEXT:  unreachable
@@ -52,7 +68,7 @@ entry:
 ; CHECK-NEXT: 	unreachable
 ; CHECK-NEXT: 	end_function
 
-; CHECK-LABEL: .Lhas_ptr_arg_bitcast_invalid.1:
+; CHECK-LABEL: .Lhas_ptr_arg_bitcast_invalid.4:
 ; CHECK-NEXT: 	.param  	i32
 ; CHECK-NEXT: 	.result 	i32
 ; CHECK-NEXT: 	unreachable




More information about the llvm-commits mailing list