summaryrefslogtreecommitdiff
path: root/test/lit/passes
diff options
context:
space:
mode:
Diffstat (limited to 'test/lit/passes')
-rw-r--r--test/lit/passes/O4_disable-bulk-memory.wast142
-rw-r--r--test/lit/passes/flatten_local-cse_Os.wast71
-rw-r--r--test/lit/passes/flatten_local-cse_all-features.wast1139
-rw-r--r--test/lit/passes/local-cse.wast433
-rw-r--r--test/lit/passes/local-cse_all-features.wast272
5 files changed, 775 insertions, 1282 deletions
diff --git a/test/lit/passes/O4_disable-bulk-memory.wast b/test/lit/passes/O4_disable-bulk-memory.wast
index aec1030bb..4ab403159 100644
--- a/test/lit/passes/O4_disable-bulk-memory.wast
+++ b/test/lit/passes/O4_disable-bulk-memory.wast
@@ -231,13 +231,10 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.gt_u
- ;; CHECK-NEXT: (local.tee $0
+ ;; CHECK-NEXT: (local.tee $2
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.add
;; CHECK-NEXT: (i32.add
- ;; CHECK-NEXT: (local.tee $1
- ;; CHECK-NEXT: (global.get $global$1)
- ;; CHECK-NEXT: )
;; CHECK-NEXT: (select
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: (i32.const 1)
@@ -246,6 +243,9 @@
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.tee $0
+ ;; CHECK-NEXT: (global.get $global$1)
+ ;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 7)
;; CHECK-NEXT: )
@@ -253,7 +253,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.shl
- ;; CHECK-NEXT: (local.tee $2
+ ;; CHECK-NEXT: (local.tee $1
;; CHECK-NEXT: (memory.size)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 16)
@@ -263,14 +263,14 @@
;; CHECK-NEXT: (i32.lt_s
;; CHECK-NEXT: (memory.grow
;; CHECK-NEXT: (select
- ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: (local.tee $3
;; CHECK-NEXT: (i32.shr_u
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.add
;; CHECK-NEXT: (i32.sub
+ ;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: (local.get $0)
- ;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 65535)
;; CHECK-NEXT: )
@@ -280,7 +280,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.gt_s
- ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: (local.get $3)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
@@ -299,9 +299,9 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (global.set $global$1
- ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
(func $~lib/allocator/arena/__memory_allocate (; 6 ;) (type $3) (param $0 i32) (result i32)
(local $1 i32)
@@ -1920,56 +1920,67 @@
;; CHECK-NEXT: (local.get $13)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
- ;; CHECK-NEXT: (local.set $11
- ;; CHECK-NEXT: (f64.sqrt
+ ;; CHECK-NEXT: (local.set $2
+ ;; CHECK-NEXT: (f64.mul
+ ;; CHECK-NEXT: (local.get $17)
;; CHECK-NEXT: (local.tee $8
- ;; CHECK-NEXT: (f64.add
- ;; CHECK-NEXT: (f64.add
- ;; CHECK-NEXT: (f64.mul
- ;; CHECK-NEXT: (local.tee $2
- ;; CHECK-NEXT: (f64.sub
- ;; CHECK-NEXT: (local.get $14)
- ;; CHECK-NEXT: (f64.load
- ;; CHECK-NEXT: (local.tee $1
- ;; CHECK-NEXT: (i32.load offset=8
- ;; CHECK-NEXT: (i32.add
- ;; CHECK-NEXT: (i32.load
- ;; CHECK-NEXT: (local.get $12)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.shl
- ;; CHECK-NEXT: (local.get $7)
- ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: (f64.div
+ ;; CHECK-NEXT: (f64.const 0.01)
+ ;; CHECK-NEXT: (f64.mul
+ ;; CHECK-NEXT: (local.tee $2
+ ;; CHECK-NEXT: (f64.add
+ ;; CHECK-NEXT: (f64.add
+ ;; CHECK-NEXT: (f64.mul
+ ;; CHECK-NEXT: (local.tee $9
+ ;; CHECK-NEXT: (f64.sub
+ ;; CHECK-NEXT: (local.get $14)
+ ;; CHECK-NEXT: (f64.load
+ ;; CHECK-NEXT: (local.tee $1
+ ;; CHECK-NEXT: (i32.load offset=8
+ ;; CHECK-NEXT: (i32.add
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (local.get $12)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.shl
+ ;; CHECK-NEXT: (local.get $7)
+ ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $9)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (f64.mul
+ ;; CHECK-NEXT: (local.tee $10
+ ;; CHECK-NEXT: (f64.sub
+ ;; CHECK-NEXT: (local.get $15)
+ ;; CHECK-NEXT: (f64.load offset=8
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (f64.mul
- ;; CHECK-NEXT: (local.tee $9
- ;; CHECK-NEXT: (f64.sub
- ;; CHECK-NEXT: (local.get $15)
- ;; CHECK-NEXT: (f64.load offset=8
- ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: (f64.mul
+ ;; CHECK-NEXT: (local.tee $11
+ ;; CHECK-NEXT: (f64.sub
+ ;; CHECK-NEXT: (local.get $16)
+ ;; CHECK-NEXT: (f64.load offset=16
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $11)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.get $9)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (f64.mul
- ;; CHECK-NEXT: (local.tee $10
- ;; CHECK-NEXT: (f64.sub
- ;; CHECK-NEXT: (local.get $16)
- ;; CHECK-NEXT: (f64.load offset=16
- ;; CHECK-NEXT: (local.get $1)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (f64.sqrt
+ ;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.get $10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
@@ -1979,21 +1990,13 @@
;; CHECK-NEXT: (f64.sub
;; CHECK-NEXT: (local.get $4)
;; CHECK-NEXT: (f64.mul
- ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: (local.get $9)
;; CHECK-NEXT: (local.tee $8
;; CHECK-NEXT: (f64.mul
;; CHECK-NEXT: (f64.load offset=48
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.tee $11
- ;; CHECK-NEXT: (f64.div
- ;; CHECK-NEXT: (f64.const 0.01)
- ;; CHECK-NEXT: (f64.mul
- ;; CHECK-NEXT: (local.get $8)
- ;; CHECK-NEXT: (local.get $11)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $8)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
@@ -2003,7 +2006,7 @@
;; CHECK-NEXT: (f64.sub
;; CHECK-NEXT: (local.get $5)
;; CHECK-NEXT: (f64.mul
- ;; CHECK-NEXT: (local.get $9)
+ ;; CHECK-NEXT: (local.get $10)
;; CHECK-NEXT: (local.get $8)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
@@ -2012,7 +2015,7 @@
;; CHECK-NEXT: (f64.sub
;; CHECK-NEXT: (local.get $6)
;; CHECK-NEXT: (f64.mul
- ;; CHECK-NEXT: (local.get $10)
+ ;; CHECK-NEXT: (local.get $11)
;; CHECK-NEXT: (local.get $8)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
@@ -2024,13 +2027,8 @@
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (f64.mul
+ ;; CHECK-NEXT: (local.get $9)
;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: (local.tee $2
- ;; CHECK-NEXT: (f64.mul
- ;; CHECK-NEXT: (local.get $17)
- ;; CHECK-NEXT: (local.get $11)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
@@ -2041,7 +2039,7 @@
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (f64.mul
- ;; CHECK-NEXT: (local.get $9)
+ ;; CHECK-NEXT: (local.get $10)
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
@@ -2053,7 +2051,7 @@
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (f64.mul
- ;; CHECK-NEXT: (local.get $10)
+ ;; CHECK-NEXT: (local.get $11)
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
@@ -2943,7 +2941,8 @@
;; CHECK: (func $assembly/index/getBody (; has Stack IR ;) (param $0 i32) (result i32)
;; CHECK-NEXT: (local $1 i32)
;; CHECK-NEXT: (if (result i32)
- ;; CHECK-NEXT: (i32.gt_u
+ ;; CHECK-NEXT: (i32.lt_u
+ ;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: (i32.load offset=4
;; CHECK-NEXT: (local.tee $1
;; CHECK-NEXT: (i32.load
@@ -2951,10 +2950,10 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (if (result i32)
- ;; CHECK-NEXT: (i32.gt_u
+ ;; CHECK-NEXT: (i32.lt_u
+ ;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: (i32.shr_u
;; CHECK-NEXT: (i32.load
;; CHECK-NEXT: (local.tee $1
@@ -2965,7 +2964,6 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.load offset=8
;; CHECK-NEXT: (i32.add
diff --git a/test/lit/passes/flatten_local-cse_Os.wast b/test/lit/passes/flatten_local-cse_Os.wast
deleted file mode 100644
index 1f315cd2c..000000000
--- a/test/lit/passes/flatten_local-cse_Os.wast
+++ /dev/null
@@ -1,71 +0,0 @@
-;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
-;; NOTE: This test was ported using port_test.py and could be cleaned up.
-
-;; RUN: foreach %s %t wasm-opt --flatten --local-cse -Os -S -o - | filecheck %s
-
-(module
- ;; testcase from AssemblyScript
- (func "div16_internal" (param $0 i32) (param $1 i32) (result i32)
- (i32.add
- (i32.xor
- (i32.shr_s
- (i32.shl
- (local.get $0)
- (i32.const 16)
- )
- (i32.const 16)
- )
- (i32.shr_s
- (i32.shl
- (local.get $1)
- (i32.const 16)
- )
- (i32.const 16)
- )
- )
- (i32.xor
- (i32.shr_s
- (i32.shl
- (local.get $0)
- (i32.const 16)
- )
- (i32.const 16)
- )
- (i32.shr_s
- (i32.shl
- (local.get $1)
- (i32.const 16)
- )
- (i32.const 16)
- )
- )
- )
- )
-)
-;; CHECK: (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
-
-;; CHECK: (export "div16_internal" (func $0))
-
-;; CHECK: (func $0 (; has Stack IR ;) (param $0 i32) (param $1 i32) (result i32)
-;; CHECK-NEXT: (i32.add
-;; CHECK-NEXT: (local.tee $0
-;; CHECK-NEXT: (i32.xor
-;; CHECK-NEXT: (i32.shr_s
-;; CHECK-NEXT: (i32.shl
-;; CHECK-NEXT: (local.get $0)
-;; CHECK-NEXT: (i32.const 16)
-;; CHECK-NEXT: )
-;; CHECK-NEXT: (i32.const 16)
-;; CHECK-NEXT: )
-;; CHECK-NEXT: (i32.shr_s
-;; CHECK-NEXT: (i32.shl
-;; CHECK-NEXT: (local.get $1)
-;; CHECK-NEXT: (i32.const 16)
-;; CHECK-NEXT: )
-;; CHECK-NEXT: (i32.const 16)
-;; CHECK-NEXT: )
-;; CHECK-NEXT: )
-;; CHECK-NEXT: )
-;; CHECK-NEXT: (local.get $0)
-;; CHECK-NEXT: )
-;; CHECK-NEXT: )
diff --git a/test/lit/passes/flatten_local-cse_all-features.wast b/test/lit/passes/flatten_local-cse_all-features.wast
deleted file mode 100644
index 243c8a96c..000000000
--- a/test/lit/passes/flatten_local-cse_all-features.wast
+++ /dev/null
@@ -1,1139 +0,0 @@
-;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
-;; NOTE: This test was ported using port_test.py and could be cleaned up.
-
-;; RUN: foreach %s %t wasm-opt --flatten --local-cse --all-features -S -o - | filecheck %s
-
-(module
- (memory 100 100)
- ;; CHECK: (type $none_=>_none (func))
-
- ;; CHECK: (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
-
- ;; CHECK: (type $i32_=>_i32 (func (param i32) (result i32)))
-
- ;; CHECK: (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
-
- ;; CHECK: (type $f64_f64_i32_=>_f32 (func (param f64 f64 i32) (result f32)))
-
- ;; CHECK: (memory $0 100 100)
-
- ;; CHECK: (func $basics
- ;; CHECK-NEXT: (local $x i32)
- ;; CHECK-NEXT: (local $y i32)
- ;; CHECK-NEXT: (local $2 i32)
- ;; CHECK-NEXT: (local $3 i32)
- ;; CHECK-NEXT: (local $4 i32)
- ;; CHECK-NEXT: (local $5 i32)
- ;; CHECK-NEXT: (local $6 i32)
- ;; CHECK-NEXT: (local $7 i32)
- ;; CHECK-NEXT: (local $8 i32)
- ;; CHECK-NEXT: (local $9 i32)
- ;; CHECK-NEXT: (local $10 i32)
- ;; CHECK-NEXT: (local $11 i32)
- ;; CHECK-NEXT: (local $12 i32)
- ;; CHECK-NEXT: (local $13 i32)
- ;; CHECK-NEXT: (local $14 i32)
- ;; CHECK-NEXT: (local $15 i32)
- ;; CHECK-NEXT: (local $16 i32)
- ;; CHECK-NEXT: (local $17 i32)
- ;; CHECK-NEXT: (local $18 i32)
- ;; CHECK-NEXT: (local $19 i32)
- ;; CHECK-NEXT: (local.set $2
- ;; CHECK-NEXT: (i32.add
- ;; CHECK-NEXT: (i32.const 1)
- ;; CHECK-NEXT: (i32.const 2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $3
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (if
- ;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: (nop)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $4
- ;; CHECK-NEXT: (i32.add
- ;; CHECK-NEXT: (i32.const 1)
- ;; CHECK-NEXT: (i32.const 2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (local.get $4)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $5
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $6
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $7
- ;; CHECK-NEXT: (i32.add
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (local.get $7)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $8
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $9
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $10
- ;; CHECK-NEXT: (local.get $7)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (local.get $7)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $11
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $12
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $13
- ;; CHECK-NEXT: (local.get $7)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (local.get $7)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (call $basics)
- ;; CHECK-NEXT: (local.set $14
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $15
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $16
- ;; CHECK-NEXT: (local.get $7)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (local.get $7)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $x
- ;; CHECK-NEXT: (i32.const 100)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $17
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $18
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $19
- ;; CHECK-NEXT: (i32.add
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (local.get $19)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- (func $basics
- (local $x i32)
- (local $y i32)
- (drop
- (i32.add (i32.const 1) (i32.const 2))
- )
- (drop
- (i32.add (i32.const 1) (i32.const 2))
- )
- (if (i32.const 0) (nop))
- (drop ;; we can't do this yet, non-linear
- (i32.add (i32.const 1) (i32.const 2))
- )
- (drop
- (i32.add (local.get $x) (local.get $y))
- )
- (drop
- (i32.add (local.get $x) (local.get $y))
- )
- (drop
- (i32.add (local.get $x) (local.get $y))
- )
- (call $basics) ;; side effects, but no matter for our locals
- (drop
- (i32.add (local.get $x) (local.get $y))
- )
- (local.set $x (i32.const 100))
- (drop ;; x was changed!
- (i32.add (local.get $x) (local.get $y))
- )
- )
- ;; CHECK: (func $recursive1
- ;; CHECK-NEXT: (local $x i32)
- ;; CHECK-NEXT: (local $y i32)
- ;; CHECK-NEXT: (local $2 i32)
- ;; CHECK-NEXT: (local $3 i32)
- ;; CHECK-NEXT: (local $4 i32)
- ;; CHECK-NEXT: (local $5 i32)
- ;; CHECK-NEXT: (local $6 i32)
- ;; CHECK-NEXT: (local.set $2
- ;; CHECK-NEXT: (i32.add
- ;; CHECK-NEXT: (i32.const 2)
- ;; CHECK-NEXT: (i32.const 3)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $3
- ;; CHECK-NEXT: (i32.add
- ;; CHECK-NEXT: (i32.const 1)
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (local.get $3)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $4
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $5
- ;; CHECK-NEXT: (local.get $3)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (local.get $3)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $6
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- (func $recursive1
- (local $x i32)
- (local $y i32)
- (drop
- (i32.add
- (i32.const 1)
- (i32.add
- (i32.const 2)
- (i32.const 3)
- )
- )
- )
- (drop
- (i32.add
- (i32.const 1)
- (i32.add
- (i32.const 2)
- (i32.const 3)
- )
- )
- )
- (drop
- (i32.add
- (i32.const 2)
- (i32.const 3)
- )
- )
- )
- ;; CHECK: (func $recursive2
- ;; CHECK-NEXT: (local $x i32)
- ;; CHECK-NEXT: (local $y i32)
- ;; CHECK-NEXT: (local $2 i32)
- ;; CHECK-NEXT: (local $3 i32)
- ;; CHECK-NEXT: (local $4 i32)
- ;; CHECK-NEXT: (local $5 i32)
- ;; CHECK-NEXT: (local $6 i32)
- ;; CHECK-NEXT: (local.set $2
- ;; CHECK-NEXT: (i32.add
- ;; CHECK-NEXT: (i32.const 2)
- ;; CHECK-NEXT: (i32.const 3)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $3
- ;; CHECK-NEXT: (i32.add
- ;; CHECK-NEXT: (i32.const 1)
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (local.get $3)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $4
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $5
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $6
- ;; CHECK-NEXT: (local.get $3)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (local.get $3)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- (func $recursive2
- (local $x i32)
- (local $y i32)
- (drop
- (i32.add
- (i32.const 1)
- (i32.add
- (i32.const 2)
- (i32.const 3)
- )
- )
- )
- (drop
- (i32.add
- (i32.const 2)
- (i32.const 3)
- )
- )
- (drop
- (i32.add
- (i32.const 1)
- (i32.add
- (i32.const 2)
- (i32.const 3)
- )
- )
- )
- )
- ;; CHECK: (func $self
- ;; CHECK-NEXT: (local $x i32)
- ;; CHECK-NEXT: (local $y i32)
- ;; CHECK-NEXT: (local $2 i32)
- ;; CHECK-NEXT: (local $3 i32)
- ;; CHECK-NEXT: (local $4 i32)
- ;; CHECK-NEXT: (local $5 i32)
- ;; CHECK-NEXT: (local.set $2
- ;; CHECK-NEXT: (i32.add
- ;; CHECK-NEXT: (i32.const 2)
- ;; CHECK-NEXT: (i32.const 3)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $3
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $4
- ;; CHECK-NEXT: (i32.add
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (local.get $4)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $5
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- (func $self
- (local $x i32)
- (local $y i32)
- (drop
- (i32.add
- (i32.add
- (i32.const 2)
- (i32.const 3)
- )
- (i32.add
- (i32.const 2)
- (i32.const 3)
- )
- )
- )
- (drop
- (i32.add
- (i32.const 2)
- (i32.const 3)
- )
- )
- )
- ;; CHECK: (func $loads
- ;; CHECK-NEXT: (local $0 i32)
- ;; CHECK-NEXT: (local $1 i32)
- ;; CHECK-NEXT: (local.set $0
- ;; CHECK-NEXT: (i32.load
- ;; CHECK-NEXT: (i32.const 10)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (local.get $0)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $1
- ;; CHECK-NEXT: (i32.load
- ;; CHECK-NEXT: (i32.const 10)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (local.get $1)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- (func $loads
- (drop
- (i32.load (i32.const 10))
- )
- (drop
- (i32.load (i32.const 10)) ;; implicit traps, sad
- )
- )
- ;; CHECK: (func $8 (param $var$0 i32) (result i32)
- ;; CHECK-NEXT: (local $var$1 i32)
- ;; CHECK-NEXT: (local $var$2 i32)
- ;; CHECK-NEXT: (local $var$3 i32)
- ;; CHECK-NEXT: (local $4 i32)
- ;; CHECK-NEXT: (local $5 i32)
- ;; CHECK-NEXT: (local $6 i32)
- ;; CHECK-NEXT: (local $7 i32)
- ;; CHECK-NEXT: (local $8 i32)
- ;; CHECK-NEXT: (local $9 i32)
- ;; CHECK-NEXT: (local $10 i32)
- ;; CHECK-NEXT: (local $11 i32)
- ;; CHECK-NEXT: (local $12 i32)
- ;; CHECK-NEXT: (local $13 i32)
- ;; CHECK-NEXT: (local $14 i32)
- ;; CHECK-NEXT: (local $15 i32)
- ;; CHECK-NEXT: (local $16 i32)
- ;; CHECK-NEXT: (local $17 i32)
- ;; CHECK-NEXT: (local $18 i32)
- ;; CHECK-NEXT: (local $19 i32)
- ;; CHECK-NEXT: (local $20 i32)
- ;; CHECK-NEXT: (local $21 i32)
- ;; CHECK-NEXT: (block $label$0
- ;; CHECK-NEXT: (local.set $4
- ;; CHECK-NEXT: (local.get $var$1)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $5
- ;; CHECK-NEXT: (i32.add
- ;; CHECK-NEXT: (local.get $var$1)
- ;; CHECK-NEXT: (i32.const 4)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $var$2
- ;; CHECK-NEXT: (local.get $5)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $6
- ;; CHECK-NEXT: (local.get $var$2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $7
- ;; CHECK-NEXT: (local.get $var$2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $8
- ;; CHECK-NEXT: (i32.load
- ;; CHECK-NEXT: (local.get $var$2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $var$2
- ;; CHECK-NEXT: (i32.const 74)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $9
- ;; CHECK-NEXT: (local.get $var$2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $10
- ;; CHECK-NEXT: (i32.xor
- ;; CHECK-NEXT: (local.get $var$2)
- ;; CHECK-NEXT: (i32.const -1)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $11
- ;; CHECK-NEXT: (i32.and
- ;; CHECK-NEXT: (local.get $8)
- ;; CHECK-NEXT: (local.get $10)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.store
- ;; CHECK-NEXT: (local.get $5)
- ;; CHECK-NEXT: (local.get $11)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $12
- ;; CHECK-NEXT: (local.get $var$1)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $13
- ;; CHECK-NEXT: (local.get $5)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $var$1
- ;; CHECK-NEXT: (local.get $5)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $14
- ;; CHECK-NEXT: (local.get $var$1)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $15
- ;; CHECK-NEXT: (local.get $var$1)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $16
- ;; CHECK-NEXT: (i32.load
- ;; CHECK-NEXT: (local.get $var$1)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $17
- ;; CHECK-NEXT: (local.get $var$2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $18
- ;; CHECK-NEXT: (i32.and
- ;; CHECK-NEXT: (local.get $var$2)
- ;; CHECK-NEXT: (i32.const 8)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $19
- ;; CHECK-NEXT: (i32.or
- ;; CHECK-NEXT: (local.get $16)
- ;; CHECK-NEXT: (local.get $18)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.store
- ;; CHECK-NEXT: (local.get $var$1)
- ;; CHECK-NEXT: (local.get $19)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $20
- ;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $21
- ;; CHECK-NEXT: (local.get $20)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (return
- ;; CHECK-NEXT: (local.get $20)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- (func $8 (param $var$0 i32) (result i32)
- (local $var$1 i32)
- (local $var$2 i32)
- (local $var$3 i32)
- (block $label$0 (result i32)
- (i32.store
- (local.tee $var$2
- (i32.add
- (local.get $var$1)
- (i32.const 4)
- )
- )
- (i32.and
- (i32.load
- (local.get $var$2)
- )
- (i32.xor
- (local.tee $var$2
- (i32.const 74)
- )
- (i32.const -1)
- )
- )
- )
- (i32.store
- (local.tee $var$1
- (i32.add
- (local.get $var$1)
- (i32.const 4)
- )
- )
- (i32.or
- (i32.load
- (local.get $var$1)
- )
- (i32.and
- (local.get $var$2)
- (i32.const 8)
- )
- )
- )
- (i32.const 0)
- )
- )
- ;; CHECK: (func $loop1 (param $x i32) (param $y i32) (result i32)
- ;; CHECK-NEXT: (local $2 i32)
- ;; CHECK-NEXT: (local $3 i32)
- ;; CHECK-NEXT: (local $4 i32)
- ;; CHECK-NEXT: (local $5 i32)
- ;; CHECK-NEXT: (local $6 i32)
- ;; CHECK-NEXT: (local $7 i32)
- ;; CHECK-NEXT: (local $8 i32)
- ;; CHECK-NEXT: (block
- ;; CHECK-NEXT: (local.set $2
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $x
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $3
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $y
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $4
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $x
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $5
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $y
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $6
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (return
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (unreachable)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $8
- ;; CHECK-NEXT: (local.get $7)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (return
- ;; CHECK-NEXT: (local.get $7)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- (func $loop1 (param $x i32) (param $y i32) (result i32)
- (local.set $x (local.get $y))
- (local.set $y (local.get $x))
- (local.set $x (local.get $y))
- (local.set $y (local.get $x))
- (return (local.get $y))
- )
- ;; CHECK: (func $loop2 (param $x i32) (param $y i32) (param $z i32) (result i32)
- ;; CHECK-NEXT: (local $3 i32)
- ;; CHECK-NEXT: (local $4 i32)
- ;; CHECK-NEXT: (local $5 i32)
- ;; CHECK-NEXT: (local $6 i32)
- ;; CHECK-NEXT: (local $7 i32)
- ;; CHECK-NEXT: (local $8 i32)
- ;; CHECK-NEXT: (local $9 i32)
- ;; CHECK-NEXT: (local $10 i32)
- ;; CHECK-NEXT: (local $11 i32)
- ;; CHECK-NEXT: (block
- ;; CHECK-NEXT: (local.set $3
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $x
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $4
- ;; CHECK-NEXT: (local.get $z)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $y
- ;; CHECK-NEXT: (local.get $z)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $5
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $z
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $6
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $x
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $7
- ;; CHECK-NEXT: (local.get $z)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $y
- ;; CHECK-NEXT: (local.get $z)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $8
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $z
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $9
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (return
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (unreachable)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $11
- ;; CHECK-NEXT: (local.get $10)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (return
- ;; CHECK-NEXT: (local.get $10)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- (func $loop2 (param $x i32) (param $y i32) (param $z i32) (result i32)
- (local.set $x (local.get $y))
- (local.set $y (local.get $z))
- (local.set $z (local.get $x))
- (local.set $x (local.get $y))
- (local.set $y (local.get $z))
- (local.set $z (local.get $x))
- (return (local.get $x))
- )
- ;; CHECK: (func $loop3 (param $x i32) (param $y i32) (param $z i32) (result i32)
- ;; CHECK-NEXT: (local $3 i32)
- ;; CHECK-NEXT: (local $4 i32)
- ;; CHECK-NEXT: (local $5 i32)
- ;; CHECK-NEXT: (local $6 i32)
- ;; CHECK-NEXT: (local $7 i32)
- ;; CHECK-NEXT: (local $8 i32)
- ;; CHECK-NEXT: (local $9 i32)
- ;; CHECK-NEXT: (local $10 i32)
- ;; CHECK-NEXT: (block
- ;; CHECK-NEXT: (local.set $3
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $x
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $4
- ;; CHECK-NEXT: (local.get $z)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $y
- ;; CHECK-NEXT: (local.get $z)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $5
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $z
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $6
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $y
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $7
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $z
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $8
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (return
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (unreachable)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $10
- ;; CHECK-NEXT: (local.get $9)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (return
- ;; CHECK-NEXT: (local.get $9)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- (func $loop3 (param $x i32) (param $y i32) (param $z i32) (result i32)
- (local.set $x (local.get $y))
- (local.set $y (local.get $z))
- (local.set $z (local.get $y))
- (local.set $y (local.get $z))
- (local.set $z (local.get $y))
- (return (local.get $y))
- )
- ;; CHECK: (func $handle-removing (param $var$0 f64) (param $var$1 f64) (param $var$2 i32) (result f32)
- ;; CHECK-NEXT: (local $3 i32)
- ;; CHECK-NEXT: (local $4 i32)
- ;; CHECK-NEXT: (local $5 i32)
- ;; CHECK-NEXT: (local $6 f32)
- ;; CHECK-NEXT: (local $7 f32)
- ;; CHECK-NEXT: (block
- ;; CHECK-NEXT: (local.set $var$2
- ;; CHECK-NEXT: (i32.const 32767)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $3
- ;; CHECK-NEXT: (local.get $var$2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $var$2
- ;; CHECK-NEXT: (i32.const 1024)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $4
- ;; CHECK-NEXT: (local.get $var$2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $5
- ;; CHECK-NEXT: (select
- ;; CHECK-NEXT: (local.get $3)
- ;; CHECK-NEXT: (local.get $var$2)
- ;; CHECK-NEXT: (i32.const -2147483648)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $var$2
- ;; CHECK-NEXT: (local.get $5)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $6
- ;; CHECK-NEXT: (f32.const 1)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $7
- ;; CHECK-NEXT: (local.get $6)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (return
- ;; CHECK-NEXT: (local.get $6)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- (func $handle-removing (param $var$0 f64) (param $var$1 f64) (param $var$2 i32) (result f32)
- (local.set $var$2
- (select
- (local.tee $var$2
- (i32.const 32767)
- )
- (local.tee $var$2
- (i32.const 1024)
- )
- (i32.const -2147483648)
- )
- )
- (f32.const 1)
- )
-)
-;; a testcase that fails if we don't handle equivalent local canonicalization properly
-(module
- ;; CHECK: (type $2 (func (param i64 f32 i32)))
-
- ;; CHECK: (type $0 (func))
- (type $0 (func))
- ;; CHECK: (type $1 (func (param i32 f64) (result i32)))
- (type $1 (func (param i32 f64) (result i32)))
- (type $2 (func (param i64 f32 i32)))
- ;; CHECK: (global $global$0 (mut i32) (i32.const 10))
- (global $global$0 (mut i32) (i32.const 10))
- (table 23 23 funcref)
- ;; CHECK: (table $0 23 23 funcref)
-
- ;; CHECK: (export "func_1_invoker" (func $1))
- (export "func_1_invoker" (func $1))
- ;; CHECK: (export "func_6" (func $2))
- (export "func_6" (func $2))
- ;; CHECK: (func $0 (param $var$0 i64) (param $var$1 f32) (param $var$2 i32)
- ;; CHECK-NEXT: (local $3 i32)
- ;; CHECK-NEXT: (local $4 i32)
- ;; CHECK-NEXT: (local $5 i32)
- ;; CHECK-NEXT: (local $6 i32)
- ;; CHECK-NEXT: (block $label$1
- ;; CHECK-NEXT: (local.set $3
- ;; CHECK-NEXT: (i32.const 128)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (br_if $label$1
- ;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $4
- ;; CHECK-NEXT: (local.get $3)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $3
- ;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (br_if $label$1
- ;; CHECK-NEXT: (local.get $4)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $5
- ;; CHECK-NEXT: (local.get $3)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (local.get $3)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $3
- ;; CHECK-NEXT: (i32.const -14051)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $6
- ;; CHECK-NEXT: (local.get $3)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (if
- ;; CHECK-NEXT: (local.get $3)
- ;; CHECK-NEXT: (global.set $global$0
- ;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- (func $0 (; 0 ;) (type $2) (param $var$0 i64) (param $var$1 f32) (param $var$2 i32)
- (if
- (block $label$1 (result i32)
- (drop
- (br_if $label$1
- (i32.const 0)
- (br_if $label$1
- (i32.const 128)
- (i32.const 0)
- )
- )
- )
- (i32.const -14051)
- )
- (global.set $global$0
- (i32.const 0)
- )
- )
- )
- ;; CHECK: (func $1
- ;; CHECK-NEXT: (call $0
- ;; CHECK-NEXT: (i64.const 1125899906842624)
- ;; CHECK-NEXT: (f32.const -nan:0x7fc91a)
- ;; CHECK-NEXT: (i32.const -46)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- (func $1 (; 1 ;) (type $0)
- (call $0
- (i64.const 1125899906842624)
- (f32.const -nan:0x7fc91a)
- (i32.const -46)
- )
- )
- ;; CHECK: (func $2 (param $var$0 i32) (param $var$1 f64) (result i32)
- ;; CHECK-NEXT: (local $2 i32)
- ;; CHECK-NEXT: (local $3 i32)
- ;; CHECK-NEXT: (local $4 i32)
- ;; CHECK-NEXT: (block
- ;; CHECK-NEXT: (block
- ;; CHECK-NEXT: (local.set $2
- ;; CHECK-NEXT: (global.get $global$0)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (if
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: (block
- ;; CHECK-NEXT: (unreachable)
- ;; CHECK-NEXT: (unreachable)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $3
- ;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $4
- ;; CHECK-NEXT: (local.get $3)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (return
- ;; CHECK-NEXT: (local.get $3)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- (func $2 (; 2 ;) (type $1) (param $var$0 i32) (param $var$1 f64) (result i32)
- (if
- (global.get $global$0)
- (unreachable)
- )
- (i32.const 0)
- )
-)
-(module
- ;; CHECK: (type $i32_=>_none (func (param i32)))
-
- ;; CHECK: (import "env" "out" (func $out (param i32)))
- (import "env" "out" (func $out (param i32)))
- ;; CHECK: (func $each-pass-must-clear (param $var$0 i32)
- ;; CHECK-NEXT: (local $1 i32)
- ;; CHECK-NEXT: (local $2 i32)
- ;; CHECK-NEXT: (local $3 i32)
- ;; CHECK-NEXT: (local $4 i32)
- ;; CHECK-NEXT: (local.set $1
- ;; CHECK-NEXT: (local.get $var$0)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $2
- ;; CHECK-NEXT: (i32.eqz
- ;; CHECK-NEXT: (local.get $var$0)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (call $out
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $3
- ;; CHECK-NEXT: (local.get $var$0)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $4
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (call $out
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- (func $each-pass-must-clear (param $var$0 i32)
- (call $out
- (i32.eqz
- (local.get $var$0)
- )
- )
- (call $out
- (i32.eqz
- (local.get $var$0)
- )
- )
- )
-)
-(module
- ;; CHECK: (type $none_=>_i64 (func (result i64)))
-
- ;; CHECK: (type $none_=>_none (func))
-
- ;; CHECK: (global $glob (mut i32) (i32.const 1))
- (global $glob (mut i32) (i32.const 1))
- ;; CHECK: (func $i64-shifts (result i64)
- ;; CHECK-NEXT: (local $temp i64)
- ;; CHECK-NEXT: (local $1 i64)
- ;; CHECK-NEXT: (local $2 i64)
- ;; CHECK-NEXT: (local $3 i64)
- ;; CHECK-NEXT: (local $4 i64)
- ;; CHECK-NEXT: (local $5 i64)
- ;; CHECK-NEXT: (block
- ;; CHECK-NEXT: (local.set $1
- ;; CHECK-NEXT: (i64.add
- ;; CHECK-NEXT: (i64.const 1)
- ;; CHECK-NEXT: (i64.const 2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $temp
- ;; CHECK-NEXT: (local.get $1)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $temp
- ;; CHECK-NEXT: (i64.const 9999)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $2
- ;; CHECK-NEXT: (local.get $1)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $temp
- ;; CHECK-NEXT: (local.get $1)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $3
- ;; CHECK-NEXT: (local.get $temp)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $4
- ;; CHECK-NEXT: (local.get $temp)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $5
- ;; CHECK-NEXT: (local.get $temp)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (return
- ;; CHECK-NEXT: (local.get $temp)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- (func $i64-shifts (result i64)
- (local $temp i64)
- (local.set $temp
- (i64.add
- (i64.const 1)
- (i64.const 2)
- )
- )
- (local.set $temp
- (i64.const 9999)
- )
- (local.set $temp
- (i64.add
- (i64.const 1)
- (i64.const 2)
- )
- )
- (local.get $temp)
- )
- ;; CHECK: (func $global
- ;; CHECK-NEXT: (local $x i32)
- ;; CHECK-NEXT: (local $y i32)
- ;; CHECK-NEXT: (local $2 i32)
- ;; CHECK-NEXT: (local $3 i32)
- ;; CHECK-NEXT: (local $4 i32)
- ;; CHECK-NEXT: (local.set $2
- ;; CHECK-NEXT: (global.get $glob)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $x
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $3
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $y
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $4
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $y
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- (func $global
- (local $x i32)
- (local $y i32)
- (local.set $x (global.get $glob))
- (local.set $y (global.get $glob))
- (local.set $y (global.get $glob))
- )
-)
-
-(module
- ;; After --flatten, there will be a series of chain copies between multiple
- ;; locals, but some of the locals will be funcref type and others anyref
- ;; type. We cannot make locals of different types a common subexpression.
- ;; CHECK: (type $none_=>_anyref (func (result anyref)))
-
- ;; CHECK: (type $none_=>_none (func))
-
- ;; CHECK: (func $subtype-test (result anyref)
- ;; CHECK-NEXT: (local $0 funcref)
- ;; CHECK-NEXT: (local $1 funcref)
- ;; CHECK-NEXT: (local $2 anyref)
- ;; CHECK-NEXT: (local $3 anyref)
- ;; CHECK-NEXT: (block
- ;; CHECK-NEXT: (nop)
- ;; CHECK-NEXT: (loop $label$1
- ;; CHECK-NEXT: (local.set $0
- ;; CHECK-NEXT: (ref.null func)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $1
- ;; CHECK-NEXT: (local.get $0)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $2
- ;; CHECK-NEXT: (local.get $0)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $3
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (return
- ;; CHECK-NEXT: (local.get $2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- (func $subtype-test (result anyref)
- (nop)
- (loop $label$1 (result funcref)
- (ref.null func)
- )
- )
-
- ;; CHECK: (func $test
- ;; CHECK-NEXT: (local $0 anyref)
- ;; CHECK-NEXT: (local $1 funcref)
- ;; CHECK-NEXT: (local $2 funcref)
- ;; CHECK-NEXT: (block $label$1
- ;; CHECK-NEXT: (local.set $0
- ;; CHECK-NEXT: (ref.null func)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $1
- ;; CHECK-NEXT: (ref.null func)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (local.set $2
- ;; CHECK-NEXT: (local.get $1)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (local.get $1)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- (func $test
- (local $0 anyref)
- (drop
- (block $label$1 (result funcref)
- (local.set $0
- (ref.null func)
- )
- ;; After --flatten, this will be assigned to a local of funcref type. After
- ;; --local-cse, even if we set (ref.null func) to local $0 above, this
- ;; should not be replaced with $0, because it is of type anyref.
- (ref.null func)
- )
- )
- )
-)
diff --git a/test/lit/passes/local-cse.wast b/test/lit/passes/local-cse.wast
new file mode 100644
index 000000000..5cdf712f8
--- /dev/null
+++ b/test/lit/passes/local-cse.wast
@@ -0,0 +1,433 @@
+;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
+;; NOTE: This test was ported using port_test.py and could be cleaned up.
+
+;; RUN: foreach %s %t wasm-opt --local-cse -S -o - | filecheck %s
+
+(module
+ (memory 100 100)
+ ;; CHECK: (type $none_=>_none (func))
+
+ ;; CHECK: (type $i32_=>_i32 (func (param i32) (result i32)))
+
+ ;; CHECK: (type $none_=>_i64 (func (result i64)))
+
+ ;; CHECK: (memory $0 100 100)
+
+ ;; CHECK: (func $basics
+ ;; CHECK-NEXT: (local $x i32)
+ ;; CHECK-NEXT: (local $y i32)
+ ;; CHECK-NEXT: (local $2 i32)
+ ;; CHECK-NEXT: (local $3 i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.tee $2
+ ;; CHECK-NEXT: (i32.add
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (nop)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.add
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.tee $3
+ ;; CHECK-NEXT: (i32.add
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (local.get $y)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (call $basics)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $x
+ ;; CHECK-NEXT: (i32.const 100)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.add
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (local.get $y)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $basics
+ (local $x i32)
+ (local $y i32)
+ ;; These two adds can be optimized.
+ (drop
+ (i32.add (i32.const 1) (i32.const 2))
+ )
+ (drop
+ (i32.add (i32.const 1) (i32.const 2))
+ )
+ (if (i32.const 0) (nop))
+ ;; This add is after an if, which means we are no longer in the same basic
+ ;; block - which means we cannot optimize it with the previous identical
+ ;; adds.
+ (drop
+ (i32.add (i32.const 1) (i32.const 2))
+ )
+ ;; More adds with different contents than the previous, but all three are
+ ;; identical.
+ (drop
+ (i32.add (local.get $x) (local.get $y))
+ )
+ (drop
+ (i32.add (local.get $x) (local.get $y))
+ )
+ (drop
+ (i32.add (local.get $x) (local.get $y))
+ )
+ ;; Calls have side effects, but that is not a problem for these adds which
+ ;; only use locals, so we can optimize the add after the call.
+ (call $basics)
+ (drop
+ (i32.add (local.get $x) (local.get $y))
+ )
+ ;; Modify $x, which means we cannot optimize the add after the set.
+ (local.set $x (i32.const 100))
+ (drop
+ (i32.add (local.get $x) (local.get $y))
+ )
+ )
+
+ ;; CHECK: (func $recursive1
+ ;; CHECK-NEXT: (local $x i32)
+ ;; CHECK-NEXT: (local $y i32)
+ ;; CHECK-NEXT: (local $2 i32)
+ ;; CHECK-NEXT: (local $3 i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.tee $3
+ ;; CHECK-NEXT: (i32.add
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: (local.tee $2
+ ;; CHECK-NEXT: (i32.add
+ ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: (i32.const 3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $recursive1
+ (local $x i32)
+ (local $y i32)
+ ;; The first two dropped things are identical and can be optimized.
+ (drop
+ (i32.add
+ (i32.const 1)
+ (i32.add
+ (i32.const 2)
+ (i32.const 3)
+ )
+ )
+ )
+ (drop
+ (i32.add
+ (i32.const 1)
+ (i32.add
+ (i32.const 2)
+ (i32.const 3)
+ )
+ )
+ )
+ ;; The last thing here appears inside the previous pattern, and can still
+ ;; be optimized, with another local.
+ (drop
+ (i32.add
+ (i32.const 2)
+ (i32.const 3)
+ )
+ )
+ )
+
+ ;; CHECK: (func $recursive2
+ ;; CHECK-NEXT: (local $x i32)
+ ;; CHECK-NEXT: (local $y i32)
+ ;; CHECK-NEXT: (local $2 i32)
+ ;; CHECK-NEXT: (local $3 i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.tee $3
+ ;; CHECK-NEXT: (i32.add
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: (local.tee $2
+ ;; CHECK-NEXT: (i32.add
+ ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: (i32.const 3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $recursive2
+ (local $x i32)
+ (local $y i32)
+ ;; As before, but the order is different, with the sub-pattern in the
+ ;; middle.
+ (drop
+ (i32.add
+ (i32.const 1)
+ (i32.add
+ (i32.const 2)
+ (i32.const 3)
+ )
+ )
+ )
+ (drop
+ (i32.add
+ (i32.const 2)
+ (i32.const 3)
+ )
+ )
+ (drop
+ (i32.add
+ (i32.const 1)
+ (i32.add
+ (i32.const 2)
+ (i32.const 3)
+ )
+ )
+ )
+ )
+
+ ;; CHECK: (func $self
+ ;; CHECK-NEXT: (local $x i32)
+ ;; CHECK-NEXT: (local $y i32)
+ ;; CHECK-NEXT: (local $2 i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.add
+ ;; CHECK-NEXT: (local.tee $2
+ ;; CHECK-NEXT: (i32.add
+ ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: (i32.const 3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $self
+ (local $x i32)
+ (local $y i32)
+ ;; As before, with just the large pattern and the sub pattern, but no
+ ;; repeats of the large pattern.
+ (drop
+ (i32.add
+ (i32.add
+ (i32.const 2)
+ (i32.const 3)
+ )
+ (i32.add
+ (i32.const 2)
+ (i32.const 3)
+ )
+ )
+ )
+ (drop
+ (i32.add
+ (i32.const 2)
+ (i32.const 3)
+ )
+ )
+ )
+
+ ;; CHECK: (func $loads
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (i32.const 10)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.load
+ ;; CHECK-NEXT: (i32.const 10)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $loads
+ ;; The possible trap on loads prevents optimization.
+ ;; TODO: optimize that too
+ (drop
+ (i32.load (i32.const 10))
+ )
+ (drop
+ (i32.load (i32.const 10))
+ )
+ )
+
+ ;; CHECK: (func $calls (param $x i32) (result i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (call $calls
+ ;; CHECK-NEXT: (i32.const 10)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (call $calls
+ ;; CHECK-NEXT: (i32.const 10)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 10)
+ ;; CHECK-NEXT: )
+ (func $calls (param $x i32) (result i32)
+ ;; The side effects of calls prevent optimization.
+ (drop
+ (call $calls (i32.const 10))
+ )
+ (drop
+ (call $calls (i32.const 10))
+ )
+ (i32.const 10)
+ )
+
+ ;; CHECK: (func $many-sets (result i64)
+ ;; CHECK-NEXT: (local $temp i64)
+ ;; CHECK-NEXT: (local $1 i64)
+ ;; CHECK-NEXT: (local.set $temp
+ ;; CHECK-NEXT: (local.tee $1
+ ;; CHECK-NEXT: (i64.add
+ ;; CHECK-NEXT: (i64.const 1)
+ ;; CHECK-NEXT: (i64.const 2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $temp
+ ;; CHECK-NEXT: (i64.const 9999)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $temp
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $temp)
+ ;; CHECK-NEXT: )
+ (func $many-sets (result i64)
+ (local $temp i64)
+ ;; Assign to $temp three times here. We can optimize the add regardless of
+ ;; that, and should not be confused by the sets themselves having effects
+ ;; that are in conflict (the value is what matters).
+ (local.set $temp
+ (i64.add
+ (i64.const 1)
+ (i64.const 2)
+ )
+ )
+ (local.set $temp
+ (i64.const 9999)
+ )
+ (local.set $temp
+ (i64.add
+ (i64.const 1)
+ (i64.const 2)
+ )
+ )
+ (local.get $temp)
+ )
+
+ ;; CHECK: (func $switch-children (param $x i32) (result i32)
+ ;; CHECK-NEXT: (local $1 i32)
+ ;; CHECK-NEXT: (block $label$1 (result i32)
+ ;; CHECK-NEXT: (br_table $label$1 $label$1
+ ;; CHECK-NEXT: (local.tee $1
+ ;; CHECK-NEXT: (i32.and
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (i32.const 3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $switch-children (param $x i32) (result i32)
+ (block $label$1 (result i32)
+ ;; We can optimize the two children of this switch. This test verifies
+ ;; that we do so properly and do not hit an assertion involving the
+ ;; ordering of the switch's children, which was incorrect in the past.
+ (br_table $label$1 $label$1
+ (i32.and
+ (local.get $x)
+ (i32.const 3)
+ )
+ (i32.and
+ (local.get $x)
+ (i32.const 3)
+ )
+ )
+ )
+ )
+)
+
+(module
+ ;; CHECK: (type $none_=>_none (func))
+
+ ;; CHECK: (global $glob (mut i32) (i32.const 1))
+ (global $glob (mut i32) (i32.const 1))
+
+ ;; CHECK: (global $other-glob (mut i32) (i32.const 1))
+ (global $other-glob (mut i32) (i32.const 1))
+
+ ;; CHECK: (func $global
+ ;; CHECK-NEXT: (local $0 i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.tee $0
+ ;; CHECK-NEXT: (global.get $glob)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (global.set $other-glob
+ ;; CHECK-NEXT: (i32.const 100)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (global.set $glob
+ ;; CHECK-NEXT: (i32.const 200)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (global.get $glob)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $global
+ ;; We should optimize redundant global.get operations.
+ (drop (global.get $glob))
+ (drop (global.get $glob))
+ ;; We can do it past a write to another global
+ (global.set $other-glob (i32.const 100))
+ (drop (global.get $glob))
+ ;; But we can't do it past a write to our global.
+ (global.set $glob (i32.const 200))
+ (drop (global.get $glob))
+ )
+)
diff --git a/test/lit/passes/local-cse_all-features.wast b/test/lit/passes/local-cse_all-features.wast
new file mode 100644
index 000000000..b51240c50
--- /dev/null
+++ b/test/lit/passes/local-cse_all-features.wast
@@ -0,0 +1,272 @@
+;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
+;; NOTE: This test was ported using port_test.py and could be cleaned up.
+
+;; RUN: foreach %s %t wasm-opt --local-cse --all-features -S -o - | filecheck %s
+
+(module
+ ;; CHECK: (type $i32_=>_i32 (func (param i32) (result i32)))
+
+ ;; CHECK: (type $none_=>_none (func))
+
+ ;; CHECK: (elem declare func $calls $ref.func)
+
+ ;; CHECK: (func $calls (param $x i32) (result i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (call_ref
+ ;; CHECK-NEXT: (i32.const 10)
+ ;; CHECK-NEXT: (ref.func $calls)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (call_ref
+ ;; CHECK-NEXT: (i32.const 10)
+ ;; CHECK-NEXT: (ref.func $calls)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 20)
+ ;; CHECK-NEXT: )
+ (func $calls (param $x i32) (result i32)
+ ;; The side effects of calls prevent optimization.
+ (drop
+ (call_ref (i32.const 10) (ref.func $calls))
+ )
+ (drop
+ (call_ref (i32.const 10) (ref.func $calls))
+ )
+ (i32.const 20)
+ )
+
+ ;; CHECK: (func $ref.func
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.func $ref.func)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.func $ref.func)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $ref.func
+ ;; RefFunc and other constants should be ignored - don't undo the effects
+ ;; of constant propagation.
+ (drop
+ (ref.func $ref.func)
+ )
+ (drop
+ (ref.func $ref.func)
+ )
+ )
+)
+
+(module
+ ;; CHECK: (type $A (struct (field i32)))
+ (type $A (struct (field i32)))
+
+ ;; CHECK: (type $ref|$A|_=>_none (func (param (ref $A))))
+
+ ;; CHECK: (type $B (array (mut i32)))
+ (type $B (array (mut i32)))
+
+ ;; CHECK: (type $none_=>_none (func))
+
+ ;; CHECK: (func $struct-gets (param $ref (ref $A))
+ ;; CHECK-NEXT: (local $1 i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.tee $1
+ ;; CHECK-NEXT: (struct.get $A 0
+ ;; CHECK-NEXT: (local.get $ref)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $struct-gets (param $ref (ref $A))
+ ;; Repeated loads from a struct can be optimized.
+ ;;
+ ;; Note that these struct.gets cannot trap as the reference is non-nullable,
+ ;; so there are no side effects here, and we can optimize.
+ (drop
+ (struct.get $A 0
+ (local.get $ref)
+ )
+ )
+ (drop
+ (struct.get $A 0
+ (local.get $ref)
+ )
+ )
+ (drop
+ (struct.get $A 0
+ (local.get $ref)
+ )
+ )
+ )
+
+ ;; CHECK: (func $non-nullable-value (param $ref (ref $A))
+ ;; CHECK-NEXT: (local $1 (ref null $A))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.as_non_null
+ ;; CHECK-NEXT: (local.tee $1
+ ;; CHECK-NEXT: (select (result (ref $A))
+ ;; CHECK-NEXT: (local.get $ref)
+ ;; CHECK-NEXT: (local.get $ref)
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.as_non_null
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $non-nullable-value (param $ref (ref $A))
+ ;; The value that is repeated is non-nullable, which we must do some fixups
+ ;; for after creating a local of that type.
+ (drop
+ (select (result (ref $A))
+ (local.get $ref)
+ (local.get $ref)
+ (i32.const 1)
+ )
+ )
+ (drop
+ (select (result (ref $A))
+ (local.get $ref)
+ (local.get $ref)
+ (i32.const 1)
+ )
+ )
+ )
+
+ ;; CHECK: (func $creations
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.new_with_rtt $A
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: (rtt.canon $A)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.new_with_rtt $A
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: (rtt.canon $A)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (array.new_with_rtt $B
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: (rtt.canon $B)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (array.new_with_rtt $B
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: (rtt.canon $B)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $creations
+ ;; Allocating GC data has no side effects, but each allocation is unique
+ ;; and so we cannot replace separate allocations with a single one.
+ (drop
+ (struct.new_with_rtt $A
+ (i32.const 1)
+ (rtt.canon $A)
+ )
+ )
+ (drop
+ (struct.new_with_rtt $A
+ (i32.const 1)
+ (rtt.canon $A)
+ )
+ )
+ (drop
+ (array.new_with_rtt $B
+ (i32.const 1)
+ (i32.const 1)
+ (rtt.canon $B)
+ )
+ )
+ (drop
+ (array.new_with_rtt $B
+ (i32.const 1)
+ (i32.const 1)
+ (rtt.canon $B)
+ )
+ )
+ )
+)
+
+(module
+ ;; Real-world testcase from AssemblyScript, containing multiple nested things
+ ;; that can be optimized. The inputs to the add (the xors) are identical, and
+ ;; we can avoid repeating them.
+ ;; CHECK: (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+
+ ;; CHECK: (func $div16_internal (param $0 i32) (param $1 i32) (result i32)
+ ;; CHECK-NEXT: (local $2 i32)
+ ;; CHECK-NEXT: (i32.add
+ ;; CHECK-NEXT: (local.tee $2
+ ;; CHECK-NEXT: (i32.xor
+ ;; CHECK-NEXT: (i32.shr_s
+ ;; CHECK-NEXT: (i32.shl
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (i32.const 16)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 16)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.shr_s
+ ;; CHECK-NEXT: (i32.shl
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: (i32.const 16)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 16)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $div16_internal (param $0 i32) (param $1 i32) (result i32)
+ (i32.add
+ (i32.xor
+ (i32.shr_s
+ (i32.shl
+ (local.get $0)
+ (i32.const 16)
+ )
+ (i32.const 16)
+ )
+ (i32.shr_s
+ (i32.shl
+ (local.get $1)
+ (i32.const 16)
+ )
+ (i32.const 16)
+ )
+ )
+ (i32.xor
+ (i32.shr_s
+ (i32.shl
+ (local.get $0)
+ (i32.const 16)
+ )
+ (i32.const 16)
+ )
+ (i32.shr_s
+ (i32.shl
+ (local.get $1)
+ (i32.const 16)
+ )
+ (i32.const 16)
+ )
+ )
+ )
+ )
+)