| ;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. |
| ;; Test tail-call optimization with --traps-never-happen (-tnh). |
| |
| ;; RUN: wasm-opt %s --tail-call --enable-tail-call -S -o - | filecheck %s --check-prefix=DEFAULT |
| ;; RUN: wasm-opt %s --tail-call -tnh --enable-tail-call -S -o - | filecheck %s --check-prefix=TNH |
| |
| (module |
| (memory 1 1) |
| ;; DEFAULT: (global $g (mut i32) (i32.const 0)) |
| ;; TNH: (global $g (mut i32) (i32.const 0)) |
| (global $g (mut i32) (i32.const 0)) |
| |
| ;; DEFAULT: (func $value-callee (result i32) |
| ;; DEFAULT-NEXT: (i32.const 1) |
| ;; DEFAULT-NEXT: ) |
| ;; TNH: (func $value-callee (result i32) |
| ;; TNH-NEXT: (i32.const 1) |
| ;; TNH-NEXT: ) |
| (func $value-callee (result i32) |
| (i32.const 1) |
| ) |
| |
| ;; DEFAULT: (func $br-if-trapping-condition (param $x i32) (result i32) |
| ;; DEFAULT-NEXT: (block $out (result i32) |
| ;; DEFAULT-NEXT: (br_if $out |
| ;; DEFAULT-NEXT: (call $value-callee) |
| ;; DEFAULT-NEXT: (i32.load |
| ;; DEFAULT-NEXT: (local.get $x) |
| ;; DEFAULT-NEXT: ) |
| ;; DEFAULT-NEXT: ) |
| ;; DEFAULT-NEXT: ) |
| ;; DEFAULT-NEXT: ) |
| ;; TNH: (func $br-if-trapping-condition (param $x i32) (result i32) |
| ;; TNH-NEXT: (block $out |
| ;; TNH-NEXT: (block |
| ;; TNH-NEXT: (return_call $value-callee) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (i32.load |
| ;; TNH-NEXT: (local.get $x) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| (func $br-if-trapping-condition (param $x i32) (result i32) |
| ;; Without -tnh, the load in the condition might trap, so converting the |
| ;; call to a return_call (which skips the condition) is disallowed. With |
| ;; -tnh, the load's trap is ignored and the call becomes a return_call. |
| (block $out (result i32) |
| (br_if $out |
| (call $value-callee) |
| (i32.load |
| (local.get $x) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; DEFAULT: (func $br-table-trapping-condition (param $x i32) (result i32) |
| ;; DEFAULT-NEXT: (block $out1 (result i32) |
| ;; DEFAULT-NEXT: (block $out2 (result i32) |
| ;; DEFAULT-NEXT: (br_table $out1 $out2 |
| ;; DEFAULT-NEXT: (call $value-callee) |
| ;; DEFAULT-NEXT: (i32.div_s |
| ;; DEFAULT-NEXT: (i32.const 10) |
| ;; DEFAULT-NEXT: (local.get $x) |
| ;; DEFAULT-NEXT: ) |
| ;; DEFAULT-NEXT: ) |
| ;; DEFAULT-NEXT: ) |
| ;; DEFAULT-NEXT: ) |
| ;; DEFAULT-NEXT: ) |
| ;; TNH: (func $br-table-trapping-condition (param $x i32) (result i32) |
| ;; TNH-NEXT: (block $out1 |
| ;; TNH-NEXT: (block $out2 |
| ;; TNH-NEXT: (block |
| ;; TNH-NEXT: (return_call $value-callee) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (i32.div_s |
| ;; TNH-NEXT: (i32.const 10) |
| ;; TNH-NEXT: (local.get $x) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| (func $br-table-trapping-condition (param $x i32) (result i32) |
| ;; Similarly, a potentially trapping division in a br_table condition |
| ;; prevents tail-call conversion unless -tnh is enabled. |
| (block $out1 (result i32) |
| (block $out2 (result i32) |
| (br_table $out1 $out2 |
| (call $value-callee) |
| (i32.div_s |
| (i32.const 10) |
| (local.get $x) |
| ) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; DEFAULT: (func $br-if-non-trap-side-effect (result i32) |
| ;; DEFAULT-NEXT: (block $out (result i32) |
| ;; DEFAULT-NEXT: (br_if $out |
| ;; DEFAULT-NEXT: (call $value-callee) |
| ;; DEFAULT-NEXT: (block (result i32) |
| ;; DEFAULT-NEXT: (global.set $g |
| ;; DEFAULT-NEXT: (i32.const 1) |
| ;; DEFAULT-NEXT: ) |
| ;; DEFAULT-NEXT: (i32.const 0) |
| ;; DEFAULT-NEXT: ) |
| ;; DEFAULT-NEXT: ) |
| ;; DEFAULT-NEXT: ) |
| ;; DEFAULT-NEXT: ) |
| ;; TNH: (func $br-if-non-trap-side-effect (result i32) |
| ;; TNH-NEXT: (block $out (result i32) |
| ;; TNH-NEXT: (br_if $out |
| ;; TNH-NEXT: (call $value-callee) |
| ;; TNH-NEXT: (block (result i32) |
| ;; TNH-NEXT: (global.set $g |
| ;; TNH-NEXT: (i32.const 1) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (i32.const 0) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| (func $br-if-non-trap-side-effect (result i32) |
| ;; Non-trap side effects (like global.set) in a condition still inhibit |
| ;; optimization even when -tnh is enabled. |
| (block $out (result i32) |
| (br_if $out |
| (call $value-callee) |
| (block (result i32) |
| (global.set $g |
| (i32.const 1) |
| ) |
| (i32.const 0) |
| ) |
| ) |
| ) |
| ) |
| ) |