blob: d76eeda03ba5a23a199ccafb8e9bacf6af3b705b [file] [edit]
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
;; RUN: foreach %s %t wasm-opt --generate-global-effects --simplify-globals -S -o - | filecheck %s
;; Compute function effects and then simplify globals. We must handle the case
;; of an expression that is not a global.set that sets a global - a function
;; whose effects we've computed to include some sets to globals.
(module
;; CHECK: (type $0 (func))
;; CHECK: (global $A (mut i32) (i32.const 10))
(global $A (mut i32) (i32.const 10))
;; CHECK: (global $B i32 (i32.const 20))
(global $B (mut i32) (i32.const 20))
;; CHECK: (global $C (mut i32) (i32.const 30))
(global $C (mut i32) (i32.const 30))
;; CHECK: (func $set
;; CHECK-NEXT: (global.set $A
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $set
(global.set $A
(i32.const 0)
)
)
;; CHECK: (func $test
;; CHECK-NEXT: (global.set $A
;; CHECK-NEXT: (i32.const 11)
;; CHECK-NEXT: )
;; CHECK-NEXT: (global.set $C
;; CHECK-NEXT: (i32.const 33)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 11)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 33)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $set)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (global.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 33)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test
(global.set $A
(i32.const 11)
)
(global.set $C
(i32.const 33)
)
;; We can infer $A here since we see the write to it, above.
(drop
(global.get $A)
)
;; We can infer $B since we'll prove it is immutable.
(drop
(global.get $B)
)
;; We can infer $C here since we see the write to it, above.
(drop
(global.get $C)
)
;; This call sets $A. After the call we can no longer infer $A, but we can
;; still infer the others.
(call $set)
(drop
(global.get $A)
)
(drop
(global.get $B)
)
(drop
(global.get $C)
)
)
)
;; We do not optimize here, as while we have a read-only-to-write global and
;; function, there is another get and set. This setup will be used below to
;; test for effects in calls to those other functions. Note that it is clear we
;; do not optimize by the fact that the global remains mutable and the gets and
;; sets are not modified.
(module
;; CHECK: (type $0 (func))
;; CHECK: (type $1 (func (result i32)))
;; CHECK: (global $global (mut i32) (i32.const 0))
(global $global (mut i32) (i32.const 0))
;; CHECK: (export "read-only-to-write" (func $read-only-to-write))
;; CHECK: (export "set" (func $set))
;; CHECK: (export "get" (func $get))
;; CHECK: (func $read-only-to-write
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (global.get $global)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (global.set $global
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $read-only-to-write (export "read-only-to-write")
(if
(i32.eqz
(global.get $global)
)
(then
(global.set $global
(i32.const 1)
)
)
)
)
;; CHECK: (func $set
;; CHECK-NEXT: (global.set $global
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $set (export "set")
(global.set $global
(i32.const 1)
)
)
;; CHECK: (func $get (result i32)
;; CHECK-NEXT: (global.get $global)
;; CHECK-NEXT: )
(func $get (export "get") (result i32)
(global.get $global)
)
)
(module
;; CHECK: (type $0 (func))
;; CHECK: (type $1 (func (result i32)))
;; CHECK: (global $global (mut i32) (i32.const 0))
(global $global (mut i32) (i32.const 0))
;; CHECK: (export "read-only-to-write" (func $read-only-to-write))
;; CHECK: (export "set" (func $set))
;; CHECK: (export "get" (func $get))
;; CHECK: (func $read-only-to-write
;; CHECK-NEXT: (if
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $get)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (global.set $global
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $read-only-to-write (export "read-only-to-write")
;; This looks like it reads the global only to write it: we read the global
;; through a call, then write it. However, that call is not an actual
;; global.get, so we must not miscount here. There is only one global.get in
;; the program, but it is *not* here, rather it is in a place it could be
;; read from, separately (indeed, it is an export), so we *cannot* optimize
;; the global as a read-only-to-write global: it has a read we do not
;; control, which will in fact contain 1 after the "set" global is called, so
;; we should not turn it into a constant 0 (and the global should remain
;; mutable).
(if
(block (result i32)
(drop
(call $get)
)
(i32.const 1)
)
(then
(global.set $global
(i32.const 0)
)
)
)
)
;; CHECK: (func $set
;; CHECK-NEXT: (global.set $global
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $set (export "set")
(global.set $global
(i32.const 1)
)
)
;; CHECK: (func $get (result i32)
;; CHECK-NEXT: (global.get $global)
;; CHECK-NEXT: )
(func $get (export "get") (result i32)
(global.get $global)
)
)
;; As above, but now we call out to set the global, rather than get. Again, we
;; do not optimize.
(module
;; CHECK: (type $0 (func))
;; CHECK: (type $1 (func (result i32)))
;; CHECK: (global $global (mut i32) (i32.const 0))
(global $global (mut i32) (i32.const 0))
;; CHECK: (export "read-only-to-write" (func $read-only-to-write))
;; CHECK: (export "set" (func $set))
;; CHECK: (export "get" (func $get))
;; CHECK: (func $read-only-to-write
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (global.get $global)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (call $set)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $read-only-to-write (export "read-only-to-write")
(if
(i32.eqz
(global.get $global)
)
(then
(call $set)
)
)
)
;; CHECK: (func $set
;; CHECK-NEXT: (global.set $global
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $set (export "set")
(global.set $global
(i32.const 1)
)
)
;; CHECK: (func $get (result i32)
;; CHECK-NEXT: (global.get $global)
;; CHECK-NEXT: )
(func $get (export "get") (result i32)
(global.get $global)
)
)
;; As above, but now we call out to set and get. Again, we do not optimize.
(module
;; CHECK: (type $0 (func))
;; CHECK: (type $1 (func (result i32)))
;; CHECK: (global $global (mut i32) (i32.const 0))
(global $global (mut i32) (i32.const 0))
;; CHECK: (export "read-only-to-write" (func $read-only-to-write))
;; CHECK: (export "set" (func $set))
;; CHECK: (export "get" (func $get))
;; CHECK: (func $read-only-to-write
;; CHECK-NEXT: (if
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $get)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (call $set)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $read-only-to-write (export "read-only-to-write")
(if
(block (result i32)
(drop
(call $get)
)
(i32.const 1)
)
(then
(call $set)
)
)
)
;; CHECK: (func $set
;; CHECK-NEXT: (global.set $global
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $set (export "set")
(global.set $global
(i32.const 1)
)
)
;; CHECK: (func $get (result i32)
;; CHECK-NEXT: (global.get $global)
;; CHECK-NEXT: )
(func $get (export "get") (result i32)
(global.get $global)
)
)
;; As above, but with a second global.
(module
;; CHECK: (type $0 (func))
;; CHECK: (type $1 (func (result i32)))
;; CHECK: (global $global (mut i32) (i32.const 0))
(global $global (mut i32) (i32.const 0))
;; CHECK: (global $other i32 (i32.const 0))
(global $other (mut i32) (i32.const 0))
;; CHECK: (export "read-only-to-write" (func $read-only-to-write))
;; CHECK: (export "set" (func $set))
;; CHECK: (export "get" (func $get))
;; CHECK: (func $read-only-to-write
;; CHECK-NEXT: (if
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $get)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (global.set $global
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $read-only-to-write (export "read-only-to-write")
;; We *do* have a global.get here, but it is of the wrong global, $other, so
;; we should not optimize $global (we can optimize $other to be immutable,
;; though, and apply its value of 0 here).
(if
(block (result i32)
(drop
(call $get)
)
(global.get $other)
)
(then
(global.set $global
(i32.const 0)
)
)
)
)
;; CHECK: (func $set
;; CHECK-NEXT: (global.set $global
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $set (export "set")
(global.set $global
(i32.const 1)
)
)
;; CHECK: (func $get (result i32)
;; CHECK-NEXT: (global.get $global)
;; CHECK-NEXT: )
(func $get (export "get") (result i32)
(global.get $global)
)
)