diff options
Diffstat (limited to 'test/lit/passes')
-rw-r--r-- | test/lit/passes/O4_disable-bulk-memory.wast | 142 | ||||
-rw-r--r-- | test/lit/passes/flatten_local-cse_Os.wast | 71 | ||||
-rw-r--r-- | test/lit/passes/flatten_local-cse_all-features.wast | 1139 | ||||
-rw-r--r-- | test/lit/passes/local-cse.wast | 433 | ||||
-rw-r--r-- | test/lit/passes/local-cse_all-features.wast | 272 |
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) + ) + ) + ) + ) +) |