summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/lit/passes/heap2local.wast1097
1 files changed, 1096 insertions, 1 deletions
diff --git a/test/lit/passes/heap2local.wast b/test/lit/passes/heap2local.wast
index be6538a94..6bdfa0be8 100644
--- a/test/lit/passes/heap2local.wast
+++ b/test/lit/passes/heap2local.wast
@@ -1,4 +1,4 @@
-;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
+;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
;; (remove-unused-names allows the pass to see that blocks flow values)
;; RUN: foreach %s %t wasm-opt -all --remove-unused-names --heap2local -S -o - | filecheck %s
@@ -7,8 +7,18 @@
;; CHECK: (type $struct.A (struct (field (mut i32)) (field (mut f64))))
(type $struct.A (struct (field (mut i32)) (field (mut f64))))
+ ;; CHECK: (type $1 (func))
+
+ ;; CHECK: (type $2 (func (result f64)))
+
;; CHECK: (type $struct.recursive (struct (field (mut (ref null $struct.recursive)))))
+ ;; CHECK: (type $4 (func (param (ref null $struct.A))))
+
+ ;; CHECK: (type $5 (func (result i32)))
+
+ ;; CHECK: (type $6 (func (result anyref)))
+
;; CHECK: (type $struct.packed (struct (field (mut i8))))
(type $struct.packed (struct (field (mut i8))))
@@ -18,6 +28,14 @@
(type $struct.nonnullable (struct (field (ref $struct.A))))
+ ;; CHECK: (type $8 (func (param i32) (result f64)))
+
+ ;; CHECK: (type $9 (func (param (ref null $struct.recursive))))
+
+ ;; CHECK: (type $10 (func (param (ref $struct.A))))
+
+ ;; CHECK: (type $11 (func (param i32)))
+
;; CHECK: (func $simple (type $1)
;; CHECK-NEXT: (local $0 i32)
;; CHECK-NEXT: (local $1 f64)
@@ -1957,6 +1975,8 @@
(module
;; CHECK: (type $A (sub (struct (field (ref null $A)))))
(type $A (sub (struct (field (ref null $A)))))
+ ;; CHECK: (type $1 (func (result anyref)))
+
;; CHECK: (type $B (sub $A (struct (field (ref $A)))))
(type $B (sub $A (struct (field (ref $A)))))
@@ -2062,6 +2082,8 @@
(type $A (sub (struct (field (mut i32)))))
(type $B (sub $A (struct (field (mut i32)))))
+ ;; CHECK: (type $0 (func))
+
;; CHECK: (func $func (type $0)
;; CHECK-NEXT: (local $0 i32)
;; CHECK-NEXT: (local $1 i32)
@@ -2105,6 +2127,10 @@
;; CHECK: (type $struct (struct (field (mut anyref))))
(type $struct (struct (field (mut anyref))))
+ ;; CHECK: (type $1 (func))
+
+ ;; CHECK: (type $2 (func (result anyref)))
+
;; CHECK: (func $multiple-interactions (type $1)
;; CHECK-NEXT: (local $temp (ref $struct))
;; CHECK-NEXT: (local $1 anyref)
@@ -2216,3 +2242,1072 @@
(local.get $temp2)
)
)
+
+;; Arrays.
+(module
+ ;; CHECK: (type $array (array (mut i32)))
+ (type $array (array (mut i32)))
+
+ ;; CHECK: (type $1 (struct (field (mut i32))))
+
+ ;; CHECK: (type $2 (func (result i32)))
+
+ ;; CHECK: (type $3 (func))
+
+ ;; CHECK: (type $4 (func (param i32) (result i32)))
+
+ ;; CHECK: (type $5 (struct (field (mut i32)) (field (mut i32))))
+
+ ;; CHECK: (type $6 (func (param i32)))
+
+ ;; CHECK: (type $7 (struct (field (mut i32)) (field (mut i32)) (field (mut i32)) (field (mut i32)) (field (mut i32)) (field (mut i32)) (field (mut i32))))
+
+ ;; CHECK: (type $8 (struct ))
+
+ ;; CHECK: (type $9 (struct (field (mut i32)) (field (mut i32)) (field (mut i32)) (field (mut i32)) (field (mut i32)) (field (mut i32)) (field (mut i32)) (field (mut i32)) (field (mut i32)) (field (mut i32)) (field (mut i32)) (field (mut i32)) (field (mut i32)) (field (mut i32)) (field (mut i32)) (field (mut i32)) (field (mut i32)) (field (mut i32)) (field (mut i32))))
+
+ ;; CHECK: (func $array.new_default (type $3)
+ ;; CHECK-NEXT: (local $temp (ref $array))
+ ;; CHECK-NEXT: (local $1 i32)
+ ;; CHECK-NEXT: (local $2 i32)
+ ;; CHECK-NEXT: (local $3 i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result nullref)
+ ;; CHECK-NEXT: (local.set $1
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $2
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $3
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $1
+ ;; CHECK-NEXT: (i32.const 10)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $2
+ ;; CHECK-NEXT: (i32.const 20)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $3
+ ;; CHECK-NEXT: (i32.const 30)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 40)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array.new_default
+ (local $temp (ref $array))
+ ;; This fixed-size array can be replaced with locals.
+ (local.set $temp
+ (array.new_default $array
+ (i32.const 3)
+ )
+ )
+ (array.set $array
+ (local.get $temp)
+ (i32.const 0)
+ (i32.const 10)
+ )
+ (array.set $array
+ (local.get $temp)
+ (i32.const 1)
+ (i32.const 20)
+ )
+ (array.set $array
+ (local.get $temp)
+ (i32.const 2)
+ (i32.const 30)
+ )
+ (drop
+ (array.get $array
+ (local.get $temp)
+ (i32.const 0)
+ )
+ )
+ (drop
+ (array.get $array
+ (local.get $temp)
+ (i32.const 1)
+ )
+ )
+ (drop
+ (array.get $array
+ (local.get $temp)
+ (i32.const 2)
+ )
+ )
+ ;; OOB operations trap at runtime.
+ (array.set $array
+ (local.get $temp)
+ (i32.const 3)
+ (i32.const 40)
+ )
+ (drop
+ (array.get $array
+ (local.get $temp)
+ (i32.const 3)
+ )
+ )
+ )
+
+ ;; CHECK: (func $array.new (type $2) (result i32)
+ ;; CHECK-NEXT: (local $temp (ref $array))
+ ;; CHECK-NEXT: (local $1 i32)
+ ;; CHECK-NEXT: (local $2 i32)
+ ;; CHECK-NEXT: (local $3 i32)
+ ;; CHECK-NEXT: (local $4 i32)
+ ;; CHECK-NEXT: (local $5 i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result (ref null $5))
+ ;; CHECK-NEXT: (local.set $1
+ ;; CHECK-NEXT: (i32.const 1337)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block (result nullref)
+ ;; CHECK-NEXT: (local.set $4
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $5
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $2
+ ;; CHECK-NEXT: (local.get $4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $3
+ ;; CHECK-NEXT: (local.get $5)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array.new (result i32)
+ (local $temp (ref $array))
+ ;; This is also optimizable.
+ (local.set $temp
+ (array.new $array
+ (i32.const 1337)
+ (i32.const 2)
+ )
+ )
+ (array.get $array
+ (local.get $temp)
+ (i32.const 1)
+ )
+ )
+
+ ;; CHECK: (func $array.new_fixed (type $4) (param $x i32) (result i32)
+ ;; CHECK-NEXT: (local $temp (ref $array))
+ ;; CHECK-NEXT: (local $2 i32)
+ ;; CHECK-NEXT: (local $3 i32)
+ ;; CHECK-NEXT: (local $4 i32)
+ ;; CHECK-NEXT: (local $5 i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result nullref)
+ ;; CHECK-NEXT: (local.set $4
+ ;; CHECK-NEXT: (call $get-i32)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $5
+ ;; CHECK-NEXT: (i32.const 1337)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $2
+ ;; CHECK-NEXT: (local.get $4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $3
+ ;; CHECK-NEXT: (local.get $5)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array.new_fixed (param $x i32) (result i32)
+ (local $temp (ref $array))
+ ;; This is also optimizable.
+ (local.set $temp
+ (array.new_fixed $array 2
+ (call $get-i32) ;; test side effects in a value
+ (i32.const 1337)
+ )
+ )
+ (array.get $array
+ (local.get $temp)
+ (i32.const 0)
+ )
+ )
+
+ ;; CHECK: (func $array.nonconstant_size (type $4) (param $x i32) (result i32)
+ ;; CHECK-NEXT: (local $temp (ref $array))
+ ;; CHECK-NEXT: (local.set $temp
+ ;; CHECK-NEXT: (array.new $array
+ ;; CHECK-NEXT: (i32.const 42)
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (array.get $array
+ ;; CHECK-NEXT: (local.get $temp)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array.nonconstant_size (param $x i32) (result i32)
+ (local $temp (ref $array))
+ (local.set $temp
+ (array.new $array
+ (i32.const 42)
+ ;; We cannot optimize a nonconstant size.
+ (local.get $x)
+ )
+ )
+ (array.get $array
+ (local.get $temp)
+ (i32.const 0)
+ )
+ )
+
+ ;; CHECK: (func $array.nonconstant_get (type $4) (param $x i32) (result i32)
+ ;; CHECK-NEXT: (local $temp (ref $array))
+ ;; CHECK-NEXT: (local.set $temp
+ ;; CHECK-NEXT: (array.new $array
+ ;; CHECK-NEXT: (i32.const 42)
+ ;; CHECK-NEXT: (i32.const 3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (array.get $array
+ ;; CHECK-NEXT: (local.get $temp)
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array.nonconstant_get (param $x i32) (result i32)
+ (local $temp (ref $array))
+ (local.set $temp
+ (array.new $array
+ (i32.const 42)
+ (i32.const 3)
+ )
+ )
+ (array.get $array
+ (local.get $temp)
+ ;; We cannot optimize a nonconstant get.
+ (local.get $x)
+ )
+ )
+
+ ;; CHECK: (func $array.nonconstant_set (type $6) (param $x i32)
+ ;; CHECK-NEXT: (local $temp (ref $array))
+ ;; CHECK-NEXT: (local.set $temp
+ ;; CHECK-NEXT: (array.new $array
+ ;; CHECK-NEXT: (i32.const 42)
+ ;; CHECK-NEXT: (i32.const 3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (array.set $array
+ ;; CHECK-NEXT: (local.get $temp)
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (i32.const 100)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array.nonconstant_set (param $x i32)
+ (local $temp (ref $array))
+ (local.set $temp
+ (array.new $array
+ (i32.const 42)
+ (i32.const 3)
+ )
+ )
+ (array.set $array
+ (local.get $temp)
+ ;; We cannot optimize a nonconstant set.
+ (local.get $x)
+ (i32.const 100)
+ )
+ )
+
+ ;; CHECK: (func $array.local.super (type $3)
+ ;; CHECK-NEXT: (local $temp anyref)
+ ;; CHECK-NEXT: (local $1 i32)
+ ;; CHECK-NEXT: (local $2 i32)
+ ;; CHECK-NEXT: (local $3 i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result nullref)
+ ;; CHECK-NEXT: (local.set $1
+ ;; CHECK-NEXT: (i32.const 42)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block (result nullref)
+ ;; CHECK-NEXT: (local.set $3
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $2
+ ;; CHECK-NEXT: (local.get $3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $2
+ ;; CHECK-NEXT: (i32.const 100)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array.local.super
+ ;; This local is a supertype, and the allocation flows through a cast, all
+ ;; of which we handle.
+ (local $temp (ref null any))
+ (local.set $temp
+ (array.new $array
+ (i32.const 42)
+ (i32.const 1)
+ )
+ )
+ (array.set $array
+ (ref.cast (ref $array)
+ (local.get $temp)
+ )
+ (i32.const 0)
+ (i32.const 100)
+ )
+ )
+
+ ;; CHECK: (func $array.folded (type $2) (result i32)
+ ;; CHECK-NEXT: (local $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 $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: (drop
+ ;; CHECK-NEXT: (block (result (ref null $7))
+ ;; CHECK-NEXT: (local.set $0
+ ;; CHECK-NEXT: (call $get-i32)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block (result nullref)
+ ;; CHECK-NEXT: (local.set $8
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $9
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $10
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $11
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $12
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $13
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $14
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $1
+ ;; CHECK-NEXT: (local.get $8)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $2
+ ;; CHECK-NEXT: (local.get $9)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $3
+ ;; CHECK-NEXT: (local.get $10)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $4
+ ;; CHECK-NEXT: (local.get $11)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $5
+ ;; CHECK-NEXT: (local.get $12)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $6
+ ;; CHECK-NEXT: (local.get $13)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $7
+ ;; CHECK-NEXT: (local.get $14)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $7)
+ ;; CHECK-NEXT: )
+ (func $array.folded (result i32)
+ ;; Test a form without local.get/set operations.
+ (array.get $array
+ (array.new $array
+ (call $get-i32)
+ (i32.const 7)
+ )
+ (i32.const 6)
+ )
+ )
+
+ ;; CHECK: (func $array.folded.multiple (type $3)
+ ;; CHECK-NEXT: (local $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 $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: (local $22 i32)
+ ;; CHECK-NEXT: (local $23 i32)
+ ;; CHECK-NEXT: (local $24 i32)
+ ;; CHECK-NEXT: (local $25 i32)
+ ;; CHECK-NEXT: (local $26 i32)
+ ;; CHECK-NEXT: (local $27 i32)
+ ;; CHECK-NEXT: (local $28 i32)
+ ;; CHECK-NEXT: (local $29 i32)
+ ;; CHECK-NEXT: (local $30 i32)
+ ;; CHECK-NEXT: (local $31 i32)
+ ;; CHECK-NEXT: (local $32 i32)
+ ;; CHECK-NEXT: (local $33 i32)
+ ;; CHECK-NEXT: (local $34 i32)
+ ;; CHECK-NEXT: (local $35 i32)
+ ;; CHECK-NEXT: (local $36 i32)
+ ;; CHECK-NEXT: (local $37 i32)
+ ;; CHECK-NEXT: (local $38 i32)
+ ;; CHECK-NEXT: (local $39 i32)
+ ;; CHECK-NEXT: (local $40 i32)
+ ;; CHECK-NEXT: (local $41 i32)
+ ;; CHECK-NEXT: (local $42 i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result (ref null $8))
+ ;; CHECK-NEXT: (local.set $0
+ ;; CHECK-NEXT: (call $get-i32)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block (result nullref)
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result (ref null $1))
+ ;; CHECK-NEXT: (local.set $1
+ ;; CHECK-NEXT: (call $get-i32)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block (result nullref)
+ ;; CHECK-NEXT: (local.set $3
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $2
+ ;; CHECK-NEXT: (local.get $3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result (ref null $9))
+ ;; CHECK-NEXT: (local.set $4
+ ;; CHECK-NEXT: (call $get-i32)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block (result nullref)
+ ;; CHECK-NEXT: (local.set $24
+ ;; CHECK-NEXT: (local.get $4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $25
+ ;; CHECK-NEXT: (local.get $4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $26
+ ;; CHECK-NEXT: (local.get $4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $27
+ ;; CHECK-NEXT: (local.get $4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $28
+ ;; CHECK-NEXT: (local.get $4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $29
+ ;; CHECK-NEXT: (local.get $4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $30
+ ;; CHECK-NEXT: (local.get $4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $31
+ ;; CHECK-NEXT: (local.get $4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $32
+ ;; CHECK-NEXT: (local.get $4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $33
+ ;; CHECK-NEXT: (local.get $4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $34
+ ;; CHECK-NEXT: (local.get $4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $35
+ ;; CHECK-NEXT: (local.get $4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $36
+ ;; CHECK-NEXT: (local.get $4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $37
+ ;; CHECK-NEXT: (local.get $4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $38
+ ;; CHECK-NEXT: (local.get $4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $39
+ ;; CHECK-NEXT: (local.get $4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $40
+ ;; CHECK-NEXT: (local.get $4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $41
+ ;; CHECK-NEXT: (local.get $4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $42
+ ;; CHECK-NEXT: (local.get $4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $5
+ ;; CHECK-NEXT: (local.get $24)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $6
+ ;; CHECK-NEXT: (local.get $25)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $7
+ ;; CHECK-NEXT: (local.get $26)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $8
+ ;; CHECK-NEXT: (local.get $27)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $9
+ ;; CHECK-NEXT: (local.get $28)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $10
+ ;; CHECK-NEXT: (local.get $29)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $11
+ ;; CHECK-NEXT: (local.get $30)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $12
+ ;; CHECK-NEXT: (local.get $31)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $13
+ ;; CHECK-NEXT: (local.get $32)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $14
+ ;; CHECK-NEXT: (local.get $33)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $15
+ ;; CHECK-NEXT: (local.get $34)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $16
+ ;; CHECK-NEXT: (local.get $35)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $17
+ ;; CHECK-NEXT: (local.get $36)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $18
+ ;; CHECK-NEXT: (local.get $37)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $19
+ ;; CHECK-NEXT: (local.get $38)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $20
+ ;; CHECK-NEXT: (local.get $39)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $21
+ ;; CHECK-NEXT: (local.get $40)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $22
+ ;; CHECK-NEXT: (local.get $41)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $23
+ ;; CHECK-NEXT: (local.get $42)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $11)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (array.get $array
+ ;; CHECK-NEXT: (array.new $array
+ ;; CHECK-NEXT: (call $get-i32)
+ ;; CHECK-NEXT: (i32.const 20)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 6)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array.folded.multiple
+ ;; We allow sizes 0-19, so these will be optimized.
+ (drop
+ (array.new $array
+ (call $get-i32)
+ (i32.const 0)
+ )
+ )
+ (drop
+ (array.get $array
+ (array.new $array
+ (call $get-i32)
+ (i32.const 1)
+ )
+ (i32.const 0)
+ )
+ )
+ (drop
+ (array.get $array
+ (array.new $array
+ (call $get-i32)
+ (i32.const 19)
+ )
+ (i32.const 6)
+ )
+ )
+
+ ;; 20 is too much, however.
+ (drop
+ (array.get $array
+ (array.new $array
+ (call $get-i32)
+ (i32.const 20)
+ )
+ (i32.const 6)
+ )
+ )
+ )
+
+ ;; CHECK: (func $array.nested.refinalize.get (type $2) (result i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result nullref)
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ (func $array.nested.refinalize.get (result i32)
+ ;; The get here is of an index that is out of bounds, and will trap. We
+ ;; should refinalize so the unreachability is propagated and we do not
+ ;; error on validation.
+ (array.get $array
+ (array.new_default $array
+ (i32.const 0)
+ )
+ (i32.const 0)
+ )
+ )
+
+ ;; CHECK: (func $array.nested.refinalize.set (type $3)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result nullref)
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 42)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ (func $array.nested.refinalize.set
+ ;; As above, but with a set.
+ (array.set $array
+ (array.new_default $array
+ (i32.const 0)
+ )
+ (i32.const 0)
+ (i32.const 42)
+ )
+ )
+
+ ;; CHECK: (func $array.flowing.type (type $2) (result i32)
+ ;; CHECK-NEXT: (local $temp (ref $array))
+ ;; CHECK-NEXT: (local $1 i32)
+ ;; CHECK-NEXT: (local $2 i32)
+ ;; CHECK-NEXT: (local $3 i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result (ref null $1))
+ ;; CHECK-NEXT: (local.set $1
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block (result nullref)
+ ;; CHECK-NEXT: (local.set $3
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $2
+ ;; CHECK-NEXT: (local.get $3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result (ref null $1))
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result (ref null $1))
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result (ref null $1))
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result (ref null $1))
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array.flowing.type (result i32)
+ (local $temp (ref $array))
+ ;; The array reference here flows through some places that need to be
+ ;; updated when we optimize. In particular the blocks' types will change.
+ (local.set $temp
+ (array.new $array
+ (i32.const 1)
+ (i32.const 1)
+ )
+ )
+ (drop
+ (block $nullable (result (ref null $array))
+ (local.get $temp)
+ )
+ )
+ (drop
+ (block $non-nullable (result (ref $array))
+ (local.get $temp)
+ )
+ )
+ ;; Test supertypes too.
+ (drop
+ (block $non-nullable (result (ref array))
+ (local.get $temp)
+ )
+ )
+ (drop
+ (block $non-nullable (result (ref null array))
+ (local.get $temp)
+ )
+ )
+ ;; Read from the array as well.
+ (array.get $array
+ (local.get $temp)
+ (i32.const 0)
+ )
+ )
+
+ ;; CHECK: (func $get-i32 (type $2) (result i32)
+ ;; CHECK-NEXT: (i32.const 1337)
+ ;; CHECK-NEXT: )
+ (func $get-i32 (result i32)
+ ;; Helper for the above.
+ (i32.const 1337)
+ )
+)
+
+;; Arrays with reference values.
+(module
+ ;; CHECK: (type $array (array (ref null $array)))
+ (type $array (array (ref null $array)))
+
+
+ ;; CHECK: (type $1 (struct (field (ref null $array))))
+
+ ;; CHECK: (type $2 (func))
+
+ ;; CHECK: (type $3 (struct (field (ref null $array)) (field (ref null $array)) (field (ref null $array))))
+
+ ;; CHECK: (type $4 (func (result anyref)))
+
+ ;; CHECK: (func $nested (type $2)
+ ;; CHECK-NEXT: (local $0 (ref null $array))
+ ;; CHECK-NEXT: (local $1 (ref null $array))
+ ;; CHECK-NEXT: (local $2 (ref null $array))
+ ;; CHECK-NEXT: (local $3 (ref null $array))
+ ;; CHECK-NEXT: (local $4 (ref null $array))
+ ;; CHECK-NEXT: (local $5 (ref null $array))
+ ;; CHECK-NEXT: (local $6 (ref null $array))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result (ref null $3))
+ ;; CHECK-NEXT: (local.set $0
+ ;; CHECK-NEXT: (array.new $array
+ ;; CHECK-NEXT: (array.new_default $array
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block (result nullref)
+ ;; CHECK-NEXT: (local.set $4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $5
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $6
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $1
+ ;; CHECK-NEXT: (local.get $4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $2
+ ;; CHECK-NEXT: (local.get $5)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $3
+ ;; CHECK-NEXT: (local.get $6)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $nested
+ ;; Nested array.new operations, all of whom can be optimized away in
+ ;; principle. We do only a single iteration here for now, which optimizes
+ ;; away the outermost array.new (see TODO in the pass about iterations).
+ (drop
+ (array.new $array
+ (array.new $array
+ (array.new_default $array
+ (i32.const 1)
+ )
+ (i32.const 2)
+ )
+ (i32.const 3)
+ )
+ )
+ )
+
+ ;; CHECK: (func $nested-unreachable (type $2)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block ;; (replaces unreachable ArrayNew we can't emit)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result nullref)
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $nested-unreachable
+ ;; The array.get in the middle is out of bounds, and will cause the outer
+ ;; array.new to become unreachable.
+ (drop
+ (array.new $array
+ (array.get $array
+ (array.new_default $array
+ (i32.const 0)
+ )
+ (i32.const 0)
+ )
+ (i32.const 0)
+ )
+ )
+ )
+
+ ;; CHECK: (func $array.flowing.type (type $4) (result anyref)
+ ;; CHECK-NEXT: (local $temp (ref $array))
+ ;; CHECK-NEXT: (local $1 (ref null $array))
+ ;; CHECK-NEXT: (local $2 (ref null $array))
+ ;; CHECK-NEXT: (local $3 (ref null $array))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result (ref null $1))
+ ;; CHECK-NEXT: (local.set $1
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block (result nullref)
+ ;; CHECK-NEXT: (local.set $3
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $2
+ ;; CHECK-NEXT: (local.get $3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result (ref null $1))
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result (ref null $1))
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result (ref null $1))
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result (ref null $1))
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block (result (ref null $array))
+ ;; CHECK-NEXT: (block (result (ref null $array))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array.flowing.type (result anyref)
+ (local $temp (ref $array))
+ ;; This is similar to $array.flowing.type from above, but now the array's
+ ;; values are references.
+ (local.set $temp
+ (array.new $array
+ (ref.null $array)
+ (i32.const 1)
+ )
+ )
+ (drop
+ (block $nullable (result (ref null $array))
+ (local.get $temp)
+ )
+ )
+ (drop
+ (block $non-nullable (result (ref $array))
+ (local.get $temp)
+ )
+ )
+ ;; Test supertypes too.
+ (drop
+ (block $non-nullable (result (ref array))
+ (local.get $temp)
+ )
+ )
+ (drop
+ (block $non-nullable (result (ref null array))
+ (local.get $temp)
+ )
+ )
+ ;; This block's type should end up valid. In particular this test checks
+ ;; that we do not get confused by the array's type, which we rewrite to the
+ ;; struct type in Array2Struct - this array.get's type is the array type,
+ ;; but only because the value we read is the array type, and not because the
+ ;; allocation reaches here.
+ (block (result anyref)
+ (array.get $array
+ (local.get $temp)
+ (i32.const 0)
+ )
+ )
+ )
+)