blob: 6223817e59e8eeb65d0214a60ee345c1bc8ac39d [file] [edit]
;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
;; RUN: wasm-opt %s --optimize-instructions -all -S -o - | filecheck %s
;; Also verify that the "never-fold-or-reorder" flag is respected: when set, we
;; do not fold code together (important, as we keep one of the branch hints, and
;; it may be wrong, which can confuse the fuzzer), and we never reorder (which
;; can move a branch hint to execute before a trap, which can also cause the
;; fuzzer to alert).
;; RUN: wasm-opt %s --optimize-instructions -all --pass-arg=optimize-instructions-never-fold-or-reorder -S -o - \
;; RUN: | filecheck %s --check-prefix=NO_FO
(module
;; CHECK: (func $conditionals (type $1) (param $x i32) (result i32)
;; CHECK-NEXT: (@metadata.code.branch_hint "\01")
;; CHECK-NEXT: (if (result i32)
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (then
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; NO_FO: (func $conditionals (type $1) (param $x i32) (result i32)
;; NO_FO-NEXT: (@metadata.code.branch_hint "\01")
;; NO_FO-NEXT: (if (result i32)
;; NO_FO-NEXT: (local.get $x)
;; NO_FO-NEXT: (then
;; NO_FO-NEXT: (i32.const 1337)
;; NO_FO-NEXT: )
;; NO_FO-NEXT: (else
;; NO_FO-NEXT: (i32.const 42)
;; NO_FO-NEXT: )
;; NO_FO-NEXT: )
;; NO_FO-NEXT: )
(func $conditionals (param $x i32) (result i32)
;; When we flip the if, the hint should flip too.
(@metadata.code.branch_hint "\00")
(if (result i32)
(i32.eqz
(local.get $x)
)
(then
(i32.const 42)
)
(else
(i32.const 1337)
)
)
)
;; CHECK: (func $still-fold (type $0) (param $x i32) (param $y i32)
;; CHECK-NEXT: (@metadata.code.branch_hint "\00")
;; CHECK-NEXT: (if
;; CHECK-NEXT: (local.get $y)
;; CHECK-NEXT: (then
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; NO_FO: (func $still-fold (type $0) (param $x i32) (param $y i32)
;; NO_FO-NEXT: (if
;; NO_FO-NEXT: (local.get $x)
;; NO_FO-NEXT: (then
;; NO_FO-NEXT: (@metadata.code.branch_hint "\00")
;; NO_FO-NEXT: (if
;; NO_FO-NEXT: (local.get $y)
;; NO_FO-NEXT: (then
;; NO_FO-NEXT: (unreachable)
;; NO_FO-NEXT: )
;; NO_FO-NEXT: )
;; NO_FO-NEXT: )
;; NO_FO-NEXT: (else
;; NO_FO-NEXT: (@metadata.code.branch_hint "\01")
;; NO_FO-NEXT: (if
;; NO_FO-NEXT: (local.get $y)
;; NO_FO-NEXT: (then
;; NO_FO-NEXT: (unreachable)
;; NO_FO-NEXT: )
;; NO_FO-NEXT: )
;; NO_FO-NEXT: )
;; NO_FO-NEXT: )
;; NO_FO-NEXT: )
(func $still-fold (param $x i32) (param $y i32)
;; We fold if arms even if metadata differs (like LLVM). We do not fold if the
;; flag was passed, however.
(if
(local.get $x)
(then
(@metadata.code.branch_hint "\00")
(if
(local.get $y)
(then
(unreachable)
)
)
)
(else
(@metadata.code.branch_hint "\01")
(if
(local.get $y)
(then
(unreachable)
)
)
)
)
)
;; CHECK: (func $yes-fold (type $0) (param $x i32) (param $y i32)
;; CHECK-NEXT: (@metadata.code.branch_hint "\01")
;; CHECK-NEXT: (if
;; CHECK-NEXT: (local.get $y)
;; CHECK-NEXT: (then
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; NO_FO: (func $yes-fold (type $0) (param $x i32) (param $y i32)
;; NO_FO-NEXT: (if
;; NO_FO-NEXT: (local.get $x)
;; NO_FO-NEXT: (then
;; NO_FO-NEXT: (@metadata.code.branch_hint "\01")
;; NO_FO-NEXT: (if
;; NO_FO-NEXT: (local.get $y)
;; NO_FO-NEXT: (then
;; NO_FO-NEXT: (unreachable)
;; NO_FO-NEXT: )
;; NO_FO-NEXT: )
;; NO_FO-NEXT: )
;; NO_FO-NEXT: (else
;; NO_FO-NEXT: (@metadata.code.branch_hint "\01")
;; NO_FO-NEXT: (if
;; NO_FO-NEXT: (local.get $y)
;; NO_FO-NEXT: (then
;; NO_FO-NEXT: (unreachable)
;; NO_FO-NEXT: )
;; NO_FO-NEXT: )
;; NO_FO-NEXT: )
;; NO_FO-NEXT: )
;; NO_FO-NEXT: )
(func $yes-fold (param $x i32) (param $y i32)
;; Now the hints match, so we definitely fold (without the flag).
(if
(local.get $x)
(then
(@metadata.code.branch_hint "\01")
(if
(local.get $y)
(then
(unreachable)
)
)
)
(else
(@metadata.code.branch_hint "\01")
(if
(local.get $y)
(then
(unreachable)
)
)
)
)
)
;; CHECK: (func $always-fold-select (type $2) (param $x i32) (param $y i32) (result i32)
;; CHECK-NEXT: (@metadata.code.branch_hint "\00")
;; CHECK-NEXT: (if (result i32)
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (then
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; NO_FO: (func $always-fold-select (type $2) (param $x i32) (param $y i32) (result i32)
;; NO_FO-NEXT: (@metadata.code.branch_hint "\00")
;; NO_FO-NEXT: (if (result i32)
;; NO_FO-NEXT: (local.get $x)
;; NO_FO-NEXT: (then
;; NO_FO-NEXT: (i32.const 10)
;; NO_FO-NEXT: )
;; NO_FO-NEXT: (else
;; NO_FO-NEXT: (i32.const 20)
;; NO_FO-NEXT: )
;; NO_FO-NEXT: )
;; NO_FO-NEXT: )
(func $always-fold-select (param $x i32) (param $y i32) (result i32)
;; A select with different metadata is still foldable: the code was executed
;; anyhow, so it's fine if we execute just one of the two (we pick the first,
;; arbitrarily). We do so even with the flag.
(select
(@metadata.code.branch_hint "\00")
(if (result i32)
(local.get $x)
(then
(i32.const 10)
)
(else
(i32.const 20)
)
)
(@metadata.code.branch_hint "\01")
(if (result i32)
(local.get $x)
(then
(i32.const 10)
)
(else
(i32.const 20)
)
)
(local.get $y)
)
)
;; CHECK: (func $ordering (type $3) (param $x i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.add
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.add
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; NO_FO: (func $ordering (type $3) (param $x i32)
;; NO_FO-NEXT: (drop
;; NO_FO-NEXT: (i32.add
;; NO_FO-NEXT: (local.get $x)
;; NO_FO-NEXT: (i32.const 42)
;; NO_FO-NEXT: )
;; NO_FO-NEXT: )
;; NO_FO-NEXT: (drop
;; NO_FO-NEXT: (i32.add
;; NO_FO-NEXT: (i32.const 42)
;; NO_FO-NEXT: (local.get $x)
;; NO_FO-NEXT: )
;; NO_FO-NEXT: )
;; NO_FO-NEXT: )
(func $ordering (param $x i32)
;; Normally we canonicalize the sides of a binary like this (so after the
;; pass, both the below expressions would be identical), but we refrain from
;; doing so with the flag.
(drop
(i32.add
(local.get $x)
(i32.const 42)
)
)
(drop
(i32.add
(i32.const 42)
(local.get $x)
)
)
)
)