| ;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. | |
| ;; RUN: foreach %s %t wasm-opt --optimize-j2cl -all -S -o - | filecheck %s | |
| ;; Simple primitives are hoisted. | |
| (module | |
| ;; CHECK: (type $0 (func)) | |
| ;; CHECK: (global $field-i32@Foo i32 (i32.const 1)) | |
| (global $field-i32@Foo (mut i32) (i32.const 0)) | |
| ;; CHECK: (global $field-f64@Foo f64 (f64.const 1)) | |
| (global $field-f64@Foo (mut f64) (f64.const 0)) | |
| ;; CHECK: (func $clinit_<once>_@Foo (type $0) | |
| ;; CHECK-NEXT: (nop) | |
| ;; CHECK-NEXT: ) | |
| (func $clinit_<once>_@Foo | |
| (global.set $field-i32@Foo (i32.const 1)) | |
| (global.set $field-f64@Foo (f64.const 1)) | |
| ) | |
| ) | |
| ;; Fields with more complex constant initialization are hoisted. | |
| (module | |
| ;; CHECK: (type $A (struct (field i32))) | |
| (type $A (struct (field i32))) | |
| ;; CHECK: (type $1 (func)) | |
| ;; CHECK: (global $referredField@Foo i32 (i32.const 42)) | |
| (global $referredField@Foo i32 (i32.const 42)) | |
| ;; CHECK: (global $referredFieldMut@Foo (mut i32) (i32.const 42)) | |
| (global $referredFieldMut@Foo (mut i32) (i32.const 42)) | |
| ;; CHECK: (global $field1@Foo anyref (struct.new $A | |
| ;; CHECK-NEXT: (global.get $referredField@Foo) | |
| ;; CHECK-NEXT: )) | |
| (global $field1@Foo (mut anyref) (ref.null none)) | |
| ;; CHECK: (global $field2@Foo (mut anyref) (ref.null none)) | |
| (global $field2@Foo (mut anyref) (ref.null none)) | |
| ;; CHECK: (global $field3@Foo anyref (global.get $field1@Foo)) | |
| (global $field3@Foo (mut anyref) (ref.null none)) | |
| ;; CHECK: (func $clinit_<once>_@Foo (type $1) | |
| ;; CHECK-NEXT: (global.set $field2@Foo | |
| ;; CHECK-NEXT: (struct.new $A | |
| ;; CHECK-NEXT: (global.get $referredFieldMut@Foo) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| (func $clinit_<once>_@Foo | |
| ;; Referred field is immutable, should hoist | |
| (global.set $field1@Foo (struct.new $A ( | |
| global.get $referredField@Foo) | |
| )) | |
| ;; Referred field is mutable, should not hoist | |
| (global.set $field2@Foo (struct.new $A | |
| (global.get $referredFieldMut@Foo) | |
| )) | |
| ;; Referred field is mutable but hoistable hence also this one. | |
| ;; (Note that requires multiple iterations in a single run) | |
| (global.set $field3@Foo (global.get $field1@Foo)) | |
| ) | |
| ) | |
| ;; Fields initialized to a non-default value shouldn't be hoisted. | |
| (module | |
| ;; CHECK: (type $A (struct)) | |
| (type $A (struct)) | |
| ;; CHECK: (type $1 (func)) | |
| ;; CHECK: (global $field-i32@Foo (mut i32) (i32.const 2)) | |
| (global $field-i32@Foo (mut i32) (i32.const 2)) | |
| ;; CHECK: (global $field-any@Foo (mut anyref) (struct.new_default $A)) | |
| (global $field-any@Foo (mut anyref) (struct.new $A)) | |
| ;; CHECK: (func $clinit_<once>_@Foo (type $1) | |
| ;; CHECK-NEXT: (global.set $field-i32@Foo | |
| ;; CHECK-NEXT: (i32.const 1) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: (global.set $field-any@Foo | |
| ;; CHECK-NEXT: (struct.new_default $A) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| (func $clinit_<once>_@Foo | |
| (global.set $field-i32@Foo (i32.const 1)) | |
| (global.set $field-any@Foo (struct.new $A)) | |
| ) | |
| ) | |
| ;; Non-block body is optimized | |
| (module | |
| ;; CHECK: (type $0 (func)) | |
| ;; CHECK: (global $field@Foo i32 (i32.const 1)) | |
| (global $field@Foo (mut i32) (i32.const 0)) | |
| ;; CHECK: (func $clinit_<once>_@Foo (type $0) | |
| ;; CHECK-NEXT: (nop) | |
| ;; CHECK-NEXT: ) | |
| (func $clinit_<once>_@Foo | |
| (global.set $field@Foo (i32.const 1)) | |
| ) | |
| ) | |
| ;; $$class-initialized are not hoisted | |
| (module | |
| ;; CHECK: (type $0 (func)) | |
| ;; CHECK: (global $$class-initialized@Foo (mut i32) (i32.const 0)) | |
| (global $$class-initialized@Foo (mut i32) (i32.const 0)) | |
| ;; CHECK: (func $clinit_<once>_@Foo (type $0) | |
| ;; CHECK-NEXT: (global.set $$class-initialized@Foo | |
| ;; CHECK-NEXT: (i32.const 1) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| (func $clinit_<once>_@Foo | |
| (global.set $$class-initialized@Foo (i32.const 1)) | |
| ) | |
| ) | |
| ;; Fields from different classes are not hoisted. | |
| (module | |
| ;; CHECK: (type $0 (func)) | |
| ;; CHECK: (global $field@Foo (mut i32) (i32.const 0)) | |
| (global $field@Foo (mut i32) (i32.const 0)) | |
| ;; CHECK: (func $clinit_<once>_@Bar (type $0) | |
| ;; CHECK-NEXT: (global.set $field@Foo | |
| ;; CHECK-NEXT: (i32.const 1) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| (func $clinit_<once>_@Bar | |
| ;; Note that $clinit is @Bar and field is @Foo. | |
| (global.set $field@Foo (i32.const 1)) | |
| ) | |
| ) | |
| ;; Getters are transitively inlined and their constants hoisted. | |
| (module | |
| ;; CHECK: (type $0 (func (result i32))) | |
| ;; CHECK: (global $$var1@Zoo i32 (i32.const 2)) | |
| (global $$var1@Zoo (mut i32) (i32.const 0)) | |
| ;; CHECK: (global $$var2@Zoo i32 (i32.const 2)) | |
| (global $$var2@Zoo (mut i32) (i32.const 0)) | |
| ;; CHECK: (global $$var3@Zoo i32 (i32.const 2)) | |
| (global $$var3@Zoo (mut i32) (i32.const 0)) | |
| ;; CHECK: (func $getVar1_<once>_@Zoo (type $0) (result i32) | |
| ;; CHECK-NEXT: (i32.const 2) | |
| ;; CHECK-NEXT: ) | |
| (func $getVar1_<once>_@Zoo (result i32) | |
| (if (global.get $$var1@Zoo) | |
| (then | |
| (return (global.get $$var1@Zoo)) | |
| ) | |
| ) | |
| (global.set $$var1@Zoo (i32.const 2)) | |
| (return (global.get $$var1@Zoo)) | |
| ) | |
| ;; CHECK: (func $getVar2_<once>_@Zoo (type $0) (result i32) | |
| ;; CHECK-NEXT: (i32.const 2) | |
| ;; CHECK-NEXT: ) | |
| (func $getVar2_<once>_@Zoo (result i32) | |
| (if (global.get $$var2@Zoo) | |
| (then | |
| (return (global.get $$var2@Zoo)) | |
| ) | |
| ) | |
| (global.set $$var2@Zoo (call $getVar1_<once>_@Zoo)) | |
| (return (global.get $$var2@Zoo)) | |
| ) | |
| ;; CHECK: (func $getVar3_<once>_@Zoo (type $0) (result i32) | |
| ;; CHECK-NEXT: (i32.const 2) | |
| ;; CHECK-NEXT: ) | |
| (func $getVar3_<once>_@Zoo (result i32) | |
| (if (global.get $$var3@Zoo) | |
| (then | |
| (return (global.get $$var3@Zoo)) | |
| ) | |
| ) | |
| (global.set $$var3@Zoo (call $getVar2_<once>_@Zoo)) | |
| (return (global.get $$var3@Zoo)) | |
| ) | |
| ) | |
| ;; Simple once functions are inlined | |
| (module | |
| ;; CHECK: (type $0 (func)) | |
| ;; CHECK: (type $1 (func (result i32))) | |
| ;; CHECK: (global $$var1@Zoo (mut i32) (i32.const 2)) | |
| (global $$var1@Zoo (mut i32) (i32.const 2)) | |
| ;; CHECK: (global $$var2@Zoo (mut i32) (i32.const 3)) | |
| (global $$var2@Zoo (mut i32) (i32.const 3)) | |
| ;; CHECK: (func $notOnceFunction@Zoo (type $0) | |
| ;; CHECK-NEXT: ) | |
| (func $notOnceFunction@Zoo | |
| ) | |
| ;; CHECK: (func $nop_<once>_@Zoo (type $0) | |
| ;; CHECK-NEXT: (nop) | |
| ;; CHECK-NEXT: ) | |
| (func $nop_<once>_@Zoo | |
| (nop) | |
| ) | |
| ;; CHECK: (func $empty_<once>_@Zoo (type $0) | |
| ;; CHECK-NEXT: ) | |
| (func $empty_<once>_@Zoo | |
| ) | |
| ;; CHECK: (func $simpleCall_<once>_@Zoo (type $0) | |
| ;; CHECK-NEXT: (call $notOnceFunction@Zoo) | |
| ;; CHECK-NEXT: ) | |
| (func $simpleCall_<once>_@Zoo | |
| (call $notOnceFunction@Zoo) | |
| ) | |
| ;; CHECK: (func $globalGet_<once>_@Zoo (type $1) (result i32) | |
| ;; CHECK-NEXT: (global.get $$var1@Zoo) | |
| ;; CHECK-NEXT: ) | |
| (func $globalGet_<once>_@Zoo (result i32) | |
| (global.get $$var1@Zoo) | |
| ) | |
| ;; CHECK: (func $globalSet_<once>_@Zoo (type $0) | |
| ;; CHECK-NEXT: (global.set $$var2@Zoo | |
| ;; CHECK-NEXT: (i32.const 3) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| (func $globalSet_<once>_@Zoo | |
| (global.set $$var2@Zoo (i32.const 3)) | |
| ) | |
| ;; CHECK: (func $caller_@Zoo (type $1) (result i32) | |
| ;; CHECK-NEXT: (nop) | |
| ;; CHECK-NEXT: (block | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: (call $notOnceFunction@Zoo) | |
| ;; CHECK-NEXT: (global.set $$var2@Zoo | |
| ;; CHECK-NEXT: (i32.const 3) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: (global.get $$var1@Zoo) | |
| ;; CHECK-NEXT: ) | |
| (func $caller_@Zoo (result i32) | |
| (call $nop_<once>_@Zoo) | |
| (call $empty_<once>_@Zoo) | |
| (call $simpleCall_<once>_@Zoo) | |
| (call $globalSet_<once>_@Zoo) | |
| (call $globalGet_<once>_@Zoo) | |
| ) | |
| ) | |
| ;; Simple once functions that would be inlined if cleaned up. | |
| (module | |
| ;; CHECK: (type $0 (func (result i32))) | |
| ;; CHECK: (type $1 (func)) | |
| ;; CHECK: (global $$var1@Zoo (mut i32) (i32.const 2)) | |
| (global $$var1@Zoo (mut i32) (i32.const 2)) | |
| ;; CHECK: (func $justReturn_<once>_@Zoo (type $1) | |
| ;; CHECK-NEXT: (return) | |
| ;; CHECK-NEXT: ) | |
| (func $justReturn_<once>_@Zoo | |
| (return) | |
| ) | |
| ;; CHECK: (func $returnGlobalGet_<once>_@Zoo (type $0) (result i32) | |
| ;; CHECK-NEXT: (return | |
| ;; CHECK-NEXT: (global.get $$var1@Zoo) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| (func $returnGlobalGet_<once>_@Zoo (result i32) | |
| (return (global.get $$var1@Zoo)) | |
| ) | |
| ;; CHECK: (func $caller_@Zoo (type $0) (result i32) | |
| ;; CHECK-NEXT: (call $justReturn_<once>_@Zoo) | |
| ;; CHECK-NEXT: (call $returnGlobalGet_<once>_@Zoo) | |
| ;; CHECK-NEXT: ) | |
| (func $caller_@Zoo (result i32) | |
| (call $justReturn_<once>_@Zoo) | |
| (call $returnGlobalGet_<once>_@Zoo) | |
| ) | |
| ) | |
| ;; Hoist constants for getters that have transitive dependencies. | |
| (module | |
| ;; CHECK: (type $A (struct (field i32))) | |
| (type $A (struct (field i32))) | |
| ;; CHECK: (type $1 (func (result (ref null $A)))) | |
| ;; CHECK: (global $$class@X (ref null $A) (struct.new $A | |
| ;; CHECK-NEXT: (i32.const 2) | |
| ;; CHECK-NEXT: )) | |
| (global $$class@X (mut (ref null $A)) (ref.null $A)) | |
| ;; CHECK: (global $$class@Y (ref null $A) (global.get $$class@X)) | |
| (global $$class@Y (mut (ref null $A)) (ref.null $A)) | |
| ;; CHECK: (func $f_<once>_@X (type $1) (result (ref null $A)) | |
| ;; CHECK-NEXT: (global.get $$class@X) | |
| ;; CHECK-NEXT: ) | |
| (func $f_<once>_@X (result (ref null $A)) | |
| (block (result (ref null $A)) | |
| (if (i32.eqz (ref.is_null (global.get $$class@X))) | |
| (then | |
| (return (global.get $$class@X)) | |
| ) | |
| ) | |
| (global.set $$class@X (struct.new $A (i32.const 2))) | |
| (global.get $$class@X) | |
| ) | |
| ) | |
| ;; CHECK: (func $f_<once>_@Y (type $1) (result (ref null $A)) | |
| ;; CHECK-NEXT: (global.get $$class@Y) | |
| ;; CHECK-NEXT: ) | |
| (func $f_<once>_@Y (result (ref null $A)) | |
| (block (result (ref null $A)) | |
| (if | |
| (i32.eqz (ref.is_null (global.get $$class@Y))) | |
| (then | |
| (return (global.get $$class@Y)) | |
| ) | |
| ) | |
| (global.set $$class@Y (call $f_<once>_@X)) | |
| (global.get $$class@Y) | |
| ) | |
| ) | |
| ) | |
| ;; Imported globals are ignored. | |
| (module | |
| ;; CHECK: (import "a" "b" (global $a.b (ref func))) | |
| (import "a" "b" (global $a.b (ref func))) | |
| ) | |