;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. ;; RUN: foreach %s %t wasm-opt -all --inlining -S -o - | filecheck %s ;; Test that we inline functions with unreachable bodies. This is important to ;; propagate the trap to the caller (where it might lead to DCE). (module (func $trap (unreachable) ) ;; CHECK: (type $0 (func)) ;; CHECK: (type $1 (func (result i32))) ;; CHECK: (func $call-trap (type $0) ;; CHECK-NEXT: (block $__inlined_func$trap ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $call-trap ;; In this case the call had type none, but the inlined code is unreachable, ;; so we'll add a br to the new block to keep the type as none (the br is ;; not actually reached, and other opts will remove it). (call $trap) ) (func $trap-result (result i32) ;; As above, but now there is a declared result. (unreachable) ) ;; CHECK: (func $call-trap-result (type $1) (result i32) ;; CHECK-NEXT: (block $__inlined_func$trap-result$1 ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $call-trap-result (result i32) (call $trap-result) ) (func $contents-then-trap ;; Add some contents in addition to the trap. (nop) (drop (i32.const 1337) ) (nop) (unreachable) ) ;; CHECK: (func $call-contents-then-trap (type $0) ;; CHECK-NEXT: (block $__inlined_func$contents-then-trap$2 ;; CHECK-NEXT: (block ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 1337) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $call-contents-then-trap (call $contents-then-trap) ) ) (module ;; CHECK: (type $0 (func (param i32) (result i32))) ;; CHECK: (type $1 (func)) ;; CHECK: (import "env" "imported" (func $imported (type $0) (param i32) (result i32))) (import "env" "imported" (func $imported (param i32) (result i32))) ;; CHECK: (func $caller (type $1) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$callee ;; CHECK-NEXT: (call $imported ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $caller (drop (call $callee) ) ) ;; After inlining, this return_call will turn into a call, but should still be ;; unreachable. Validation will fail if it is not. (func $callee (result i32) (return_call $imported (unreachable) ) ) ) (module ;; CHECK: (type $A (func)) (type $A (func)) (func $0 (nop) (call_ref $A (ref.null nofunc) ;; In Binaryen IR this makes the call_ref unreachable. ) ) ;; CHECK: (func $1 (type $A) ;; CHECK-NEXT: (block $__inlined_func$0 ;; CHECK-NEXT: (block ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $1 (type $A) ;; After inlining, this function body will become unreachable. (call $0) ) ) (module ;; CHECK: (type $0 (func (result f64))) ;; CHECK: (func $0 (type $0) (result f64) ;; CHECK-NEXT: (block $block ;; CHECK-NEXT: (br_if $block ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (return ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$1 ;; CHECK-NEXT: (block $block0 ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $0 (result f64) (block $block (br_if $block (i32.const 0) ) ) (return ;; The inlined function has the same label, $block. We should not be ;; confused by that when we inline the unreachable code (an error can ;; occur if we mix up the two blocks or think they are identical; to avoid ;; that we should fix up the duplicate labels before doing anything that ;; depends on valid label names, like refinalization). (call $1) ) ) (func $1 (result f64) (block $block (unreachable) ) ) )