From 4643f26e113476ebb273ee4f69e89c61801c7c2f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 28 Mar 2022 09:44:00 -0700 Subject: Generalize PossibleConstantValues for immutable globals (#4549) This moves more logic from ConstantFieldPropagation into PossibleConstantValues, that is, instead of handling the two cases of a Literal or a Name before calling PossibleConstantValues, move that code into the helper class. That way all users of PossibleConstantValues can benefit from it. In particular, this makes DeadArgumentElimination now support optimizing immutable globals, as well as ref.func and ref.null. (Changes to test/lit/passes/dae-gc-refine-params.wast are to avoid the new optimizations from kicking in, so that it still tests what it tested before.) --- test/lit/passes/dae-gc.wast | 161 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 159 insertions(+), 2 deletions(-) (limited to 'test/lit/passes/dae-gc.wast') diff --git a/test/lit/passes/dae-gc.wast b/test/lit/passes/dae-gc.wast index bcf177f74..1d12150eb 100644 --- a/test/lit/passes/dae-gc.wast +++ b/test/lit/passes/dae-gc.wast @@ -1,6 +1,6 @@ ;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. -;; RUN: wasm-opt %s -all --dae -S -o - | filecheck %s -;; RUN: wasm-opt %s -all --dae --nominal -S -o - | filecheck %s --check-prefix=NOMNL +;; RUN: foreach %s %t wasm-opt -all --dae -S -o - | filecheck %s +;; RUN: foreach %s %t wasm-opt -all --dae --nominal -S -o - | filecheck %s --check-prefix=NOMNL (module ;; CHECK: (type ${} (struct )) @@ -96,3 +96,160 @@ ) ) ) + +;; Test ref.func and ref.null optimization of constant parameter values. +(module + ;; CHECK: (func $foo (param $0 (ref $none_=>_none)) + ;; CHECK-NEXT: (local $1 (ref null $none_=>_none)) + ;; CHECK-NEXT: (local.set $1 + ;; CHECK-NEXT: (ref.func $a) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; NOMNL: (func $foo (type $ref|none_->_none|_=>_none) (param $0 (ref $none_=>_none)) + ;; NOMNL-NEXT: (local $1 (ref null $none_=>_none)) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (ref.func $a) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (block + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.as_non_null + ;; NOMNL-NEXT: (local.get $1) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (local.get $0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + (func $foo (param $x (ref func)) (param $y (ref func)) + ;; "Use" the params to avoid other optimizations kicking in. + (drop (local.get $x)) + (drop (local.get $y)) + ) + + ;; CHECK: (func $call-foo + ;; CHECK-NEXT: (call $foo + ;; CHECK-NEXT: (ref.func $b) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $foo + ;; CHECK-NEXT: (ref.func $c) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; NOMNL: (func $call-foo (type $none_=>_none) + ;; NOMNL-NEXT: (call $foo + ;; NOMNL-NEXT: (ref.func $b) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (call $foo + ;; NOMNL-NEXT: (ref.func $c) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + (func $call-foo + ;; Call $foo with a constant function in the first param, which we + ;; can optimize, but different ones in the second. + (call $foo + (ref.func $a) + (ref.func $b) + ) + (call $foo + (ref.func $a) + (ref.func $c) + ) + ) + + ;; CHECK: (func $bar (param $0 (ref null $none_=>_none)) + ;; CHECK-NEXT: (local $1 anyref) + ;; CHECK-NEXT: (local.set $1 + ;; CHECK-NEXT: (ref.null func) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; NOMNL: (func $bar (type $ref?|none_->_none|_=>_none) (param $0 (ref null $none_=>_none)) + ;; NOMNL-NEXT: (local $1 anyref) + ;; NOMNL-NEXT: (local.set $1 + ;; NOMNL-NEXT: (ref.null func) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (block + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (local.get $1) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (local.get $0) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + (func $bar (param $x (ref null any)) (param $y (ref null any)) + ;; "Use" the params to avoid other optimizations kicking in. + (drop (local.get $x)) + (drop (local.get $y)) + ) + + ;; CHECK: (func $call-bar + ;; CHECK-NEXT: (call $bar + ;; CHECK-NEXT: (ref.null $none_=>_none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $bar + ;; CHECK-NEXT: (ref.func $a) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; NOMNL: (func $call-bar (type $none_=>_none) + ;; NOMNL-NEXT: (call $bar + ;; NOMNL-NEXT: (ref.null $none_=>_none) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (call $bar + ;; NOMNL-NEXT: (ref.func $a) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) + (func $call-bar + ;; Call with nulls. Mixing nulls is fine as they all have the same value, and + ;; we can optimize. However, mixing a null with a reference stops us in the + ;; second param. + (call $bar + (ref.null func) + (ref.null func) + ) + (call $bar + (ref.null any) + (ref.func $a) + ) + ) + + ;; Helper functions so we have something to take the reference of. + ;; CHECK: (func $a + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; NOMNL: (func $a (type $none_=>_none) + ;; NOMNL-NEXT: (nop) + ;; NOMNL-NEXT: ) + (func $a) + ;; CHECK: (func $b + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; NOMNL: (func $b (type $none_=>_none) + ;; NOMNL-NEXT: (nop) + ;; NOMNL-NEXT: ) + (func $b) + ;; CHECK: (func $c + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; NOMNL: (func $c (type $none_=>_none) + ;; NOMNL-NEXT: (nop) + ;; NOMNL-NEXT: ) + (func $c) +) -- cgit v1.2.3