;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. ;; RUN: wasm-opt %s --remove-unused-names --optimize-instructions -all -S -o - \ ;; RUN: | filecheck %s (module ;; CHECK: (tag $e (param i32)) ;; CHECK: (func $dummy (type $0) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $dummy) (tag $e (param i32)) ;; The following are the unit tests for Properties::getFallthrough for EH ;; instructions, which are used in one of binary optimizations in ;; OptimizeInstructions::visitBinary(). ;; When a pattern of (i32.add (expr) (expr with all 1s)) is detected and ;; 'expr' is guaranteed to take equal or less bits than the number of bits in ;; the second expression, the i32.add can be dropped and we can only leave ;; (expr). For example: ;; (i32.add (local.get $x) (i32.const 7)) can be just (local.get $x) when $x ;; is guaranteed to contain a value equal to or less than 7. ;; CHECK: (func $getFallthrough-try-no-throw (type $0) ;; CHECK-NEXT: (local $x i32) ;; CHECK-NEXT: (local.set $x ;; CHECK-NEXT: (try (result i32) ;; CHECK-NEXT: (do ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch_all ;; CHECK-NEXT: (i32.const 3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $getFallthrough-try-no-throw (local $x i32) (local.set $x (try (result i32) (do (i32.const 1) ) (catch_all (i32.const 3) ) ) ) ;; The 'try' above is guaranteed not to throw, so we can be sure the $x ;; contains 1 at this point, which is smaller than 7 (0b111), so we know the ;; masking with 0b111 is not ncessary and we can only leave (local.set $x). (drop (i32.and (local.get $x) (i32.const 7))) ) ;; CHECK: (func $getFallthrough-try-may-throw (type $0) ;; CHECK-NEXT: (local $x i32) ;; CHECK-NEXT: (local.set $x ;; CHECK-NEXT: (try (result i32) ;; CHECK-NEXT: (do ;; CHECK-NEXT: (call $dummy) ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch_all ;; CHECK-NEXT: (i32.const 3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.and ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: (i32.const 7) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $getFallthrough-try-may-throw (local $x i32) (local.set $x (try (result i32) (do (call $dummy) (i32.const 1) ) (catch_all (i32.const 3) ) ) ) ;; The 'try' body above may throw because of the call, so we are not sure ;; what $x contains at this point, so we can't remove the masking here. (drop (i32.and (local.get $x) (i32.const 7))) ) ;; CHECK: (func $getFallthrough-nested-try-0 (type $0) ;; CHECK-NEXT: (local $x i32) ;; CHECK-NEXT: (local.set $x ;; CHECK-NEXT: (try (result i32) ;; CHECK-NEXT: (do ;; CHECK-NEXT: (try ;; CHECK-NEXT: (do ;; CHECK-NEXT: (call $dummy) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $e ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (pop i32) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch $e ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (pop i32) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.and ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: (i32.const 7) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $getFallthrough-nested-try-0 (local $x i32) (local.set $x (try (result i32) (do (try (do (call $dummy) ) (catch $e (drop (pop i32)) ) ) (i32.const 1) ) (catch $e (drop (pop i32)) (i32.const 3) ) ) ) ;; The inner 'try' may throw and it may not be caught by both the inner and ;; outer catches, so we are not sure what $x contains at this point, which ;; prevents the masking optimization. (drop (i32.and (local.get $x) (i32.const 7))) ) ;; CHECK: (func $getFallthrough-nested-try-1 (type $0) ;; CHECK-NEXT: (local $x i32) ;; CHECK-NEXT: (local.set $x ;; CHECK-NEXT: (try (result i32) ;; CHECK-NEXT: (do ;; CHECK-NEXT: (try ;; CHECK-NEXT: (do ;; CHECK-NEXT: (call $dummy) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch_all ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch_all ;; CHECK-NEXT: (i32.const 3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $getFallthrough-nested-try-1 (local $x i32) (local.set $x (try (result i32) (do (try (do (call $dummy) ) (catch_all) ) (i32.const 1) ) (catch_all (i32.const 3) ) ) ) ;; The inner try may throw, but it will caught by the inner catch_all, and ;; $x will be set to 1. So we can do the masking optimization and remove ;; i32.and here. (drop (i32.and (local.get $x) (i32.const 7))) ) ;; CHECK: (func $getFallthrough-nested-try-2 (type $0) ;; CHECK-NEXT: (local $x i32) ;; CHECK-NEXT: (local.set $x ;; CHECK-NEXT: (try (result i32) ;; CHECK-NEXT: (do ;; CHECK-NEXT: (try ;; CHECK-NEXT: (do ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch_all ;; CHECK-NEXT: (call $dummy) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (catch_all ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.and ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: (i32.const 7) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $getFallthrough-nested-try-2 (local $x i32) (local.set $x (try (result i32) (do (try (do) (catch_all (call $dummy) ) ) (i32.const 3) ) (catch_all (i32.const 1) ) ) ) ;; Depending on whether (call $dummy) throws or not, we are not sure whether ;; $x will contain 1 or 3 at this point, which prevents the masking ;; optimization. (drop (i32.and (local.get $x) (i32.const 7))) ) )