blob: 145a18deccb5717d78a214fcfa6182490268be9f [file] [edit]
;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
;; RUN: wasm-opt %s --remove-unused-brs -all -S -o - \
;; RUN: | filecheck %s
;; RUN: wasm-opt %s --remove-unused-brs --pass-arg=remove-unused-brs-never-unconditionalize -all -S -o - \
;; RUN: | filecheck %s --check-prefix=NO_UN
;; Verify that the "never-unconditionalize" flag is respected: when set, we do
;; not run code unconditionally that previously might not have run. This is
;; important as the branch hint in un-executed code may be right or wrong, which
;; can confuse the fuzzer.
(module
;; CHECK: (func $selectify (type $0) (param $x i32) (param $y i32) (result i32)
;; CHECK-NEXT: (select
;; CHECK-NEXT: (local.get $y)
;; CHECK-NEXT: (@metadata.code.branch_hint "\01")
;; CHECK-NEXT: (if (result i32)
;; CHECK-NEXT: (local.get $y)
;; CHECK-NEXT: (then
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (block $out (result i32)
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; NO_UN: (func $selectify (type $0) (param $x i32) (param $y i32) (result i32)
;; NO_UN-NEXT: (if (result i32)
;; NO_UN-NEXT: (local.get $x)
;; NO_UN-NEXT: (then
;; NO_UN-NEXT: (local.get $y)
;; NO_UN-NEXT: )
;; NO_UN-NEXT: (else
;; NO_UN-NEXT: (@metadata.code.branch_hint "\01")
;; NO_UN-NEXT: (if (result i32)
;; NO_UN-NEXT: (local.get $y)
;; NO_UN-NEXT: (then
;; NO_UN-NEXT: (i32.const 10)
;; NO_UN-NEXT: )
;; NO_UN-NEXT: (else
;; NO_UN-NEXT: (block $out (result i32)
;; NO_UN-NEXT: (nop)
;; NO_UN-NEXT: (i32.const 20)
;; NO_UN-NEXT: )
;; NO_UN-NEXT: )
;; NO_UN-NEXT: )
;; NO_UN-NEXT: )
;; NO_UN-NEXT: )
;; NO_UN-NEXT: )
(func $selectify (param $x i32) (param $y i32) (result i32)
;; This if can be a select, but the nested if's branch hint will then
;; always execute, which we should avoid when the flag is passed.
(if (result i32)
(local.get $x)
(then
(local.get $y)
)
(else
(block $out (result i32)
(@metadata.code.branch_hint "\01")
(if
(local.get $y)
(then
(br $out
(i32.const 10)
)
)
)
(i32.const 20)
)
)
)
)
;; CHECK: (func $if-select (type $1) (param $x i32) (param $y i32)
;; CHECK-NEXT: (block $out
;; CHECK-NEXT: (br_if $out
;; CHECK-NEXT: (select
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (local.get $y)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; NO_UN: (func $if-select (type $1) (param $x i32) (param $y i32)
;; NO_UN-NEXT: (if
;; NO_UN-NEXT: (local.get $x)
;; NO_UN-NEXT: (then
;; NO_UN-NEXT: (block $out
;; NO_UN-NEXT: (br_if $out
;; NO_UN-NEXT: (local.get $y)
;; NO_UN-NEXT: )
;; NO_UN-NEXT: )
;; NO_UN-NEXT: )
;; NO_UN-NEXT: )
;; NO_UN-NEXT: )
(func $if-select (param $x i32) (param $y i32)
;; The br_if can be combined with the if using a select, but not when the
;; flag is passed.
(block $out
(if
(local.get $x)
(then
(br_if $out
(local.get $y)
)
)
)
)
)
;; CHECK: (func $if-select-2 (type $1) (param $x i32) (param $y i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (select
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (local.get $y)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; NO_UN: (func $if-select-2 (type $1) (param $x i32) (param $y i32)
;; NO_UN-NEXT: (if
;; NO_UN-NEXT: (local.get $x)
;; NO_UN-NEXT: (then
;; NO_UN-NEXT: (if
;; NO_UN-NEXT: (local.get $y)
;; NO_UN-NEXT: (then
;; NO_UN-NEXT: (nop)
;; NO_UN-NEXT: )
;; NO_UN-NEXT: )
;; NO_UN-NEXT: )
;; NO_UN-NEXT: )
;; NO_UN-NEXT: )
(func $if-select-2 (param $x i32) (param $y i32)
;; The if conditions can be combined into one if with a select, but not when
;; the flag is passed.
(if
(local.get $x)
(then
(if
(local.get $y)
(then
(nop)
)
)
)
)
)
;; CHECK: (func $nothing (type $2)
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
;; NO_UN: (func $nothing (type $2)
;; NO_UN-NEXT: (nop)
;; NO_UN-NEXT: )
(func $nothing
;; Helper for below.
(nop)
)
;; CHECK: (func $restructure-br_if-value-effectful (type $0) (param $x i32) (param $y i32) (result i32)
;; CHECK-NEXT: (select
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (call $nothing)
;; CHECK-NEXT: (local.get $y)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block $x (result i32)
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; NO_UN: (func $restructure-br_if-value-effectful (type $0) (param $x i32) (param $y i32) (result i32)
;; NO_UN-NEXT: (block $x (result i32)
;; NO_UN-NEXT: (drop
;; NO_UN-NEXT: (br_if $x
;; NO_UN-NEXT: (block (result i32)
;; NO_UN-NEXT: (call $nothing)
;; NO_UN-NEXT: (local.get $y)
;; NO_UN-NEXT: )
;; NO_UN-NEXT: (local.get $x)
;; NO_UN-NEXT: )
;; NO_UN-NEXT: )
;; NO_UN-NEXT: (i32.const 0)
;; NO_UN-NEXT: )
;; NO_UN-NEXT: )
(func $restructure-br_if-value-effectful (param $x i32) (param $y i32) (result i32)
;; We can restructure this to a select, but not when the flag is passed.
(block $x (result i32)
(drop
(br_if $x
(block (result i32)
(call $nothing)
(local.get $y)
)
(local.get $x)
)
)
(i32.const 0)
)
)
)