Skip to content

Commit f0ae708

Browse files
kripkenradekdoulik
authored andcommitted
Precompute: Optimize array.len (WebAssembly#6299)
Arrays have immutable length, so we can optimize them like immutable fields.
1 parent 38fb82f commit f0ae708

File tree

4 files changed

+104
-22
lines changed

4 files changed

+104
-22
lines changed

src/passes/Precompute.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ class PrecomputingExpressionRunner
178178
// Otherwise, we've failed to precompute.
179179
return Flow(NONCONSTANT_FLOW);
180180
}
181-
Flow visitArrayLen(ArrayLen* curr) { return Flow(NONCONSTANT_FLOW); }
181+
// ArrayLen is not disallowed here as it is an immutable property.
182182
Flow visitArrayCopy(ArrayCopy* curr) { return Flow(NONCONSTANT_FLOW); }
183183

184184
// Generates heap info for a heap-allocating expression.

test/lit/passes/precompute-gc-immutable.wast

Lines changed: 89 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,14 @@
99
;; CHECK: (type $struct-mut (struct (field (mut i32))))
1010
(type $struct-mut (struct (mut i32)))
1111

12-
;; CHECK: (func $propagate (type $2)
12+
;; CHECK: (type $array-mut (array (mut i32)))
13+
14+
;; CHECK: (type $array-imm (array i32))
15+
(type $array-imm (array i32))
16+
17+
(type $array-mut (array (mut i32)))
18+
19+
;; CHECK: (func $propagate-struct (type $2)
1320
;; CHECK-NEXT: (local $ref-imm (ref null $struct-imm))
1421
;; CHECK-NEXT: (local $ref-mut (ref null $struct-mut))
1522
;; CHECK-NEXT: (local.set $ref-imm
@@ -31,7 +38,7 @@
3138
;; CHECK-NEXT: )
3239
;; CHECK-NEXT: )
3340
;; CHECK-NEXT: )
34-
(func $propagate
41+
(func $propagate-struct
3542
(local $ref-imm (ref null $struct-imm))
3643
(local $ref-mut (ref null $struct-mut))
3744
;; We can propagate from an immutable field of a struct created in this
@@ -59,6 +66,85 @@
5966
)
6067
)
6168

69+
;; CHECK: (func $propagate-array (type $2)
70+
;; CHECK-NEXT: (local $ref-imm (ref null $array-imm))
71+
;; CHECK-NEXT: (local $ref-mut (ref null $array-mut))
72+
;; CHECK-NEXT: (local.set $ref-imm
73+
;; CHECK-NEXT: (array.new_fixed $array-imm 3
74+
;; CHECK-NEXT: (i32.const 10)
75+
;; CHECK-NEXT: (i32.const 20)
76+
;; CHECK-NEXT: (i32.const 30)
77+
;; CHECK-NEXT: )
78+
;; CHECK-NEXT: )
79+
;; CHECK-NEXT: (call $helper
80+
;; CHECK-NEXT: (i32.const 30)
81+
;; CHECK-NEXT: )
82+
;; CHECK-NEXT: (call $helper
83+
;; CHECK-NEXT: (i32.const 3)
84+
;; CHECK-NEXT: )
85+
;; CHECK-NEXT: (local.set $ref-mut
86+
;; CHECK-NEXT: (array.new_fixed $array-mut 3
87+
;; CHECK-NEXT: (i32.const 10)
88+
;; CHECK-NEXT: (i32.const 20)
89+
;; CHECK-NEXT: (i32.const 30)
90+
;; CHECK-NEXT: )
91+
;; CHECK-NEXT: )
92+
;; CHECK-NEXT: (call $helper
93+
;; CHECK-NEXT: (array.get $array-mut
94+
;; CHECK-NEXT: (local.get $ref-mut)
95+
;; CHECK-NEXT: (i32.const 2)
96+
;; CHECK-NEXT: )
97+
;; CHECK-NEXT: )
98+
;; CHECK-NEXT: (call $helper
99+
;; CHECK-NEXT: (i32.const 3)
100+
;; CHECK-NEXT: )
101+
;; CHECK-NEXT: )
102+
(func $propagate-array
103+
(local $ref-imm (ref null $array-imm))
104+
(local $ref-mut (ref null $array-mut))
105+
;; We can propagate from a slot in an immutable array created in this
106+
;; function, and also get the length.
107+
(local.set $ref-imm
108+
(array.new_fixed $array-imm 3
109+
(i32.const 10)
110+
(i32.const 20)
111+
(i32.const 30)
112+
)
113+
)
114+
(call $helper
115+
(array.get $array-imm ;; this returns 30
116+
(local.get $ref-imm)
117+
(i32.const 2)
118+
)
119+
)
120+
(call $helper
121+
(array.len ;; this returns 3
122+
(local.get $ref-imm)
123+
)
124+
)
125+
;; But the same thing on a mutable array fails.
126+
(local.set $ref-mut
127+
(array.new_fixed $array-mut 3
128+
(i32.const 10)
129+
(i32.const 20)
130+
(i32.const 30)
131+
)
132+
)
133+
(call $helper
134+
(array.get $array-mut
135+
(local.get $ref-mut)
136+
(i32.const 2)
137+
)
138+
)
139+
;; We can, however, optimize array.len in both cases as that is an
140+
;; immutable property.
141+
(call $helper
142+
(array.len ;; this returns 3
143+
(local.get $ref-mut)
144+
)
145+
)
146+
)
147+
62148
;; CHECK: (func $non-constant (type $1) (param $param i32)
63149
;; CHECK-NEXT: (local $ref (ref null $struct-imm))
64150
;; CHECK-NEXT: (local.set $ref
@@ -118,7 +204,7 @@
118204
)
119205
)
120206

121-
;; CHECK: (func $param (type $4) (param $ref-imm (ref null $struct-imm))
207+
;; CHECK: (func $param (type $6) (param $ref-imm (ref null $struct-imm))
122208
;; CHECK-NEXT: (call $helper
123209
;; CHECK-NEXT: (struct.get $struct-imm 0
124210
;; CHECK-NEXT: (local.get $ref-imm)

test/lit/passes/precompute-gc.wast

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@
2020

2121
(type $struct_i8 (struct (field i8)))
2222

23-
(type $array16 (array (mut i16)))
24-
2523
(type $func-return-i32 (func (result i32)))
2624

2725
;; CHECK: (import "fuzzing-support" "log-i32" (func $log (type $4) (param i32)))

test/passes/Oz_fuzz-exec_all-features.txt

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -100,16 +100,15 @@
100100
)
101101
(func $arrays (type $void_func) (; has Stack IR ;)
102102
(local $0 (ref $bytes))
103-
(call $log
104-
(array.len
105-
(local.tee $0
106-
(array.new $bytes
107-
(i32.const 42)
108-
(i32.const 50)
109-
)
110-
)
103+
(local.set $0
104+
(array.new $bytes
105+
(i32.const 42)
106+
(i32.const 50)
111107
)
112108
)
109+
(call $log
110+
(i32.const 50)
111+
)
113112
(call $log
114113
(array.get_u $bytes
115114
(local.get $0)
@@ -271,16 +270,15 @@
271270
)
272271
(func $array.new_fixed (type $void_func) (; has Stack IR ;)
273272
(local $0 (ref $bytes))
274-
(call $log
275-
(array.len
276-
(local.tee $0
277-
(array.new_fixed $bytes 2
278-
(i32.const 42)
279-
(i32.const 50)
280-
)
281-
)
273+
(local.set $0
274+
(array.new_fixed $bytes 2
275+
(i32.const 42)
276+
(i32.const 50)
282277
)
283278
)
279+
(call $log
280+
(i32.const 2)
281+
)
284282
(call $log
285283
(array.get_u $bytes
286284
(local.get $0)

0 commit comments

Comments
 (0)