blob: a211e7e7d0f39498ee66a35258c638e3a9492642 [file] [edit]
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
;; NOTE: This test was ported using port_passes_tests_to_lit.py and could be cleaned up.
;; RUN: foreach %s %t wasm-opt --local-cse -all -S -o - | filecheck %s
(module
;; CHECK: (type $0 (func))
;; CHECK: (type $1 (func (param i32) (result i32)))
;; CHECK: (import "a" "b" (func $import (type $0)))
(import "a" "b" (func $import))
;; CHECK: (global $mutable (mut i32) (i32.const 42))
(global $mutable (mut i32) (i32.const 42))
;; CHECK: (global $immutable i32 (i32.const 1337))
(global $immutable i32 (i32.const 1337))
;; CHECK: (@binaryen.idempotent)
;; CHECK-NEXT: (func $idempotent (type $1) (param $0 i32) (result i32)
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
(@binaryen.idempotent)
(func $idempotent (param i32) (result i32)
;; This function has side effects, but is marked idempotent.
(call $import)
(i32.const 42)
)
;; CHECK: (func $potent (type $1) (param $0 i32) (result i32)
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: )
(func $potent (param i32) (result i32)
;; As above, but not marked as idempotent.
(call $import)
(i32.const 1337)
)
;; CHECK: (func $yes (type $0)
;; CHECK-NEXT: (local $0 i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.tee $0
;; CHECK-NEXT: (call $idempotent
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $yes
;; We can optimize here.
(drop
(call $idempotent
(i32.const 10)
)
)
(drop
(call $idempotent
(i32.const 10)
)
)
)
;; CHECK: (func $no (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $potent
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $potent
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $no
;; Without idempotency we cannot optimize.
(drop
(call $potent
(i32.const 10)
)
)
(drop
(call $potent
(i32.const 10)
)
)
)
;; CHECK: (func $different-input (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $idempotent
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $idempotent
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $different-input
;; We cannot optimize here.
(drop
(call $idempotent
(i32.const 10)
)
)
(drop
(call $idempotent
(i32.const 20)
)
)
)
;; CHECK: (func $idem-effects (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $idempotent
;; CHECK-NEXT: (global.get $mutable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $idempotent
;; CHECK-NEXT: (global.get $mutable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $idem-effects
;; An idempotent function still has effects on the first call. Those effects
;; can invalidate the global.get here.
(drop
(call $idempotent
(global.get $mutable)
)
)
(drop
(call $idempotent
(global.get $mutable)
)
)
)
;; CHECK: (func $idem-effects-immutable (type $0)
;; CHECK-NEXT: (local $0 i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.tee $0
;; CHECK-NEXT: (call $idempotent
;; CHECK-NEXT: (global.get $immutable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $idem-effects-immutable
;; But here we read an immutable value, so we can optimize.
(drop
(call $idempotent
(global.get $immutable)
)
)
(drop
(call $idempotent
(global.get $immutable)
)
)
)
;; CHECK: (func $idem-effects-interact (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.add
;; CHECK-NEXT: (global.get $mutable)
;; CHECK-NEXT: (global.get $mutable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $idempotent
;; CHECK-NEXT: (global.get $immutable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.add
;; CHECK-NEXT: (global.get $mutable)
;; CHECK-NEXT: (global.get $mutable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $idempotent
;; CHECK-NEXT: (global.get $immutable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $idem-effects-interact
;; An idempotent function still has effects on the first call. That
;; prevents optimizing the i32.add, as the first call might alter $mutable.
(drop
(i32.add
(global.get $mutable)
(global.get $mutable)
)
)
(drop
(call $idempotent
(global.get $immutable)
)
)
(drop
(i32.add
(global.get $mutable)
(global.get $mutable)
)
)
(drop
(call $idempotent
(global.get $immutable)
)
)
)
;; CHECK: (func $idem-effects-interact-2 (type $0)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $idempotent
;; CHECK-NEXT: (global.get $immutable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.add
;; CHECK-NEXT: (global.get $mutable)
;; CHECK-NEXT: (global.get $mutable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $idempotent
;; CHECK-NEXT: (global.get $immutable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.add
;; CHECK-NEXT: (global.get $mutable)
;; CHECK-NEXT: (global.get $mutable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $idem-effects-interact-2
;; As above, but interleaved differently. The first i32.add is now between
;; the two idempotent calls. Here we could optimize, but do not atm, as the
;; mutable reads invalidate the first call (only the reverse is true, but
;; our check is symmetrical atm), and the second call - which we fail to
;; optimize out - invalidates the later mutable reads. TODO
(drop
(call $idempotent
(global.get $immutable)
)
)
(drop
(i32.add
(global.get $mutable)
(global.get $mutable)
)
)
(drop
(call $idempotent
(global.get $immutable)
)
)
(drop
(i32.add
(global.get $mutable)
(global.get $mutable)
)
)
)
)