Skip to content

Commit

Permalink
Precompute: Optimize array.len (WebAssembly#6299)
Browse files Browse the repository at this point in the history
Arrays have immutable length, so we can optimize them like immutable fields.
  • Loading branch information
kripken authored and radekdoulik committed Jul 12, 2024
1 parent 38fb82f commit f0ae708
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 22 deletions.
2 changes: 1 addition & 1 deletion src/passes/Precompute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ class PrecomputingExpressionRunner
// Otherwise, we've failed to precompute.
return Flow(NONCONSTANT_FLOW);
}
Flow visitArrayLen(ArrayLen* curr) { return Flow(NONCONSTANT_FLOW); }
// ArrayLen is not disallowed here as it is an immutable property.
Flow visitArrayCopy(ArrayCopy* curr) { return Flow(NONCONSTANT_FLOW); }

// Generates heap info for a heap-allocating expression.
Expand Down
92 changes: 89 additions & 3 deletions test/lit/passes/precompute-gc-immutable.wast
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,14 @@
;; CHECK: (type $struct-mut (struct (field (mut i32))))
(type $struct-mut (struct (mut i32)))

;; CHECK: (func $propagate (type $2)
;; CHECK: (type $array-mut (array (mut i32)))

;; CHECK: (type $array-imm (array i32))
(type $array-imm (array i32))

(type $array-mut (array (mut i32)))

;; CHECK: (func $propagate-struct (type $2)
;; CHECK-NEXT: (local $ref-imm (ref null $struct-imm))
;; CHECK-NEXT: (local $ref-mut (ref null $struct-mut))
;; CHECK-NEXT: (local.set $ref-imm
Expand All @@ -31,7 +38,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $propagate
(func $propagate-struct
(local $ref-imm (ref null $struct-imm))
(local $ref-mut (ref null $struct-mut))
;; We can propagate from an immutable field of a struct created in this
Expand Down Expand Up @@ -59,6 +66,85 @@
)
)

;; CHECK: (func $propagate-array (type $2)
;; CHECK-NEXT: (local $ref-imm (ref null $array-imm))
;; CHECK-NEXT: (local $ref-mut (ref null $array-mut))
;; CHECK-NEXT: (local.set $ref-imm
;; CHECK-NEXT: (array.new_fixed $array-imm 3
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: (i32.const 30)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $helper
;; CHECK-NEXT: (i32.const 30)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $helper
;; CHECK-NEXT: (i32.const 3)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $ref-mut
;; CHECK-NEXT: (array.new_fixed $array-mut 3
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: (i32.const 30)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $helper
;; CHECK-NEXT: (array.get $array-mut
;; CHECK-NEXT: (local.get $ref-mut)
;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $helper
;; CHECK-NEXT: (i32.const 3)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $propagate-array
(local $ref-imm (ref null $array-imm))
(local $ref-mut (ref null $array-mut))
;; We can propagate from a slot in an immutable array created in this
;; function, and also get the length.
(local.set $ref-imm
(array.new_fixed $array-imm 3
(i32.const 10)
(i32.const 20)
(i32.const 30)
)
)
(call $helper
(array.get $array-imm ;; this returns 30
(local.get $ref-imm)
(i32.const 2)
)
)
(call $helper
(array.len ;; this returns 3
(local.get $ref-imm)
)
)
;; But the same thing on a mutable array fails.
(local.set $ref-mut
(array.new_fixed $array-mut 3
(i32.const 10)
(i32.const 20)
(i32.const 30)
)
)
(call $helper
(array.get $array-mut
(local.get $ref-mut)
(i32.const 2)
)
)
;; We can, however, optimize array.len in both cases as that is an
;; immutable property.
(call $helper
(array.len ;; this returns 3
(local.get $ref-mut)
)
)
)

;; CHECK: (func $non-constant (type $1) (param $param i32)
;; CHECK-NEXT: (local $ref (ref null $struct-imm))
;; CHECK-NEXT: (local.set $ref
Expand Down Expand Up @@ -118,7 +204,7 @@
)
)

;; CHECK: (func $param (type $4) (param $ref-imm (ref null $struct-imm))
;; CHECK: (func $param (type $6) (param $ref-imm (ref null $struct-imm))
;; CHECK-NEXT: (call $helper
;; CHECK-NEXT: (struct.get $struct-imm 0
;; CHECK-NEXT: (local.get $ref-imm)
Expand Down
2 changes: 0 additions & 2 deletions test/lit/passes/precompute-gc.wast
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@

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

(type $array16 (array (mut i16)))

(type $func-return-i32 (func (result i32)))

;; CHECK: (import "fuzzing-support" "log-i32" (func $log (type $4) (param i32)))
Expand Down
30 changes: 14 additions & 16 deletions test/passes/Oz_fuzz-exec_all-features.txt
Original file line number Diff line number Diff line change
Expand Up @@ -100,16 +100,15 @@
)
(func $arrays (type $void_func) (; has Stack IR ;)
(local $0 (ref $bytes))
(call $log
(array.len
(local.tee $0
(array.new $bytes
(i32.const 42)
(i32.const 50)
)
)
(local.set $0
(array.new $bytes
(i32.const 42)
(i32.const 50)
)
)
(call $log
(i32.const 50)
)
(call $log
(array.get_u $bytes
(local.get $0)
Expand Down Expand Up @@ -271,16 +270,15 @@
)
(func $array.new_fixed (type $void_func) (; has Stack IR ;)
(local $0 (ref $bytes))
(call $log
(array.len
(local.tee $0
(array.new_fixed $bytes 2
(i32.const 42)
(i32.const 50)
)
)
(local.set $0
(array.new_fixed $bytes 2
(i32.const 42)
(i32.const 50)
)
)
(call $log
(i32.const 2)
)
(call $log
(array.get_u $bytes
(local.get $0)
Expand Down

0 comments on commit f0ae708

Please sign in to comment.