summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2022-04-21 10:44:26 -0700
committerGitHub <noreply@github.com>2022-04-21 10:44:26 -0700
commit793eabd785716247949ce6a4e6ab31c008711d08 (patch)
treeb03eddec631dc3930bffb293882d34509d4e3419
parent65f09f262e00348462e3371fbc89c6c1d398fba1 (diff)
downloadbinaryen-793eabd785716247949ce6a4e6ab31c008711d08.tar.gz
binaryen-793eabd785716247949ce6a4e6ab31c008711d08.tar.bz2
binaryen-793eabd785716247949ce6a4e6ab31c008711d08.zip
[NominalFuzzing] MergeSimilarFunctions: handle nominal types properly (#4602)
This fixes two bugs: First, we need to compare the nominal types of function constants when looking for constants to "merge", not just their structure. Second, when creating the new function we must use the proper type of those constants, and not just another type.
-rw-r--r--src/passes/MergeSimilarFunctions.cpp4
-rw-r--r--test/lit/passes/merge-similar-functions_types.wast323
2 files changed, 325 insertions, 2 deletions
diff --git a/src/passes/MergeSimilarFunctions.cpp b/src/passes/MergeSimilarFunctions.cpp
index d6e616c10..9edf327fc 100644
--- a/src/passes/MergeSimilarFunctions.cpp
+++ b/src/passes/MergeSimilarFunctions.cpp
@@ -118,7 +118,7 @@ struct ParamInfo {
return (*literals)[0].type;
} else if (auto callees = std::get_if<std::vector<Name>>(&values)) {
auto* callee = module->getFunction((*callees)[0]);
- return Type(callee->getSig(), NonNullable);
+ return Type(callee->type, NonNullable);
} else {
WASM_UNREACHABLE("unexpected const value type");
}
@@ -246,7 +246,7 @@ bool MergeSimilarFunctions::areInEquvalentClass(Function* lhs,
}
auto* lhsCallee = module->getFunction(lhsCast->target);
auto* rhsCallee = module->getFunction(rhsCast->target);
- if (lhsCallee->getSig() != rhsCallee->getSig()) {
+ if (lhsCallee->type != rhsCallee->type) {
return false;
}
diff --git a/test/lit/passes/merge-similar-functions_types.wast b/test/lit/passes/merge-similar-functions_types.wast
new file mode 100644
index 000000000..497c734e1
--- /dev/null
+++ b/test/lit/passes/merge-similar-functions_types.wast
@@ -0,0 +1,323 @@
+;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
+;; RUN: foreach %s %t wasm-opt --merge-similar-functions -all -S -o - \
+;; RUN: | filecheck %s
+;; RUN: foreach %s %t wasm-opt --merge-similar-functions -all --nominal -S -o - \
+;; RUN: | filecheck %s --check-prefix=NOMNL
+
+;; Calls to functions $2 and $3 are the only differences between the contents
+;; of $0 and $1, so we want to merge them and pass ref.funcs of $2 and $3.
+;; However, their nominal types differ, so in nominal typing we cannot do so.
+(module
+ ;; CHECK: (type $type$0 (func))
+ ;; NOMNL: (type $type$0 (func_subtype func))
+ (type $type$0 (func_subtype func))
+ ;; NOMNL: (type $type$1 (func_subtype func))
+ (type $type$1 (func_subtype func))
+ ;; NOMNL: (type $type$2 (func_subtype func))
+ (type $type$2 (func_subtype func))
+ (type $type$3 (func_subtype (param f32) (result f32) func))
+ (type $type$4 (func_subtype (param f64) (result f64) func))
+ ;; CHECK: (type $ref|$type$0|_=>_none (func (param (ref $type$0))))
+
+ ;; CHECK: (elem declare func $2 $3)
+
+ ;; CHECK: (func $0
+ ;; CHECK-NEXT: (call $byn$mgfn-shared$0
+ ;; CHECK-NEXT: (ref.func $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; NOMNL: (func $0 (type $type$0)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (call $2)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: )
+ (func $0 (type $type$0)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (call $2)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ )
+ ;; CHECK: (func $1
+ ;; CHECK-NEXT: (call $byn$mgfn-shared$0
+ ;; CHECK-NEXT: (ref.func $3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; NOMNL: (func $1 (type $type$0)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (call $3)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: (nop)
+ ;; NOMNL-NEXT: )
+ (func $1 (type $type$0)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (call $3)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ )
+ ;; CHECK: (func $2
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 17)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; NOMNL: (func $2 (type $type$1)
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (i32.const 17)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ (func $2 (type $type$1)
+ (drop
+ (i32.const 17)
+ )
+ )
+ ;; CHECK: (func $3
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 999)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; NOMNL: (func $3 (type $type$2)
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (i32.const 999)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ (func $3 (type $type$2)
+ (drop
+ (i32.const 999)
+ )
+ )
+)
+
+
+
+
+;; CHECK: (func $byn$mgfn-shared$0 (param $0 (ref $type$0))
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (call_ref
+;; CHECK-NEXT: (local.get $0)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: )
+(module
+ ;; As above, but now the nominal types do match, so we can optimize in all
+ ;; modes.
+
+ ;; CHECK: (type $type$0 (func))
+ ;; NOMNL: (type $type$1 (func_subtype func))
+
+ ;; NOMNL: (type $type$0 (func_subtype func))
+ (type $type$0 (func_subtype func))
+ (type $type$1 (func_subtype func))
+ (type $type$3 (func_subtype (param f32) (result f32) func))
+ (type $type$4 (func_subtype (param f64) (result f64) func))
+ ;; CHECK: (type $ref|$type$0|_=>_none (func (param (ref $type$0))))
+
+ ;; CHECK: (global $global$0 (mut i32) (i32.const 10))
+ ;; NOMNL: (type $ref|$type$1|_=>_none (func_subtype (param (ref $type$1)) func))
+
+ ;; NOMNL: (global $global$0 (mut i32) (i32.const 10))
+ (global $global$0 (mut i32) (i32.const 10))
+ ;; CHECK: (memory $0 (shared 16 17))
+ ;; NOMNL: (memory $0 (shared 16 17))
+ (memory $0 (shared 16 17))
+ ;; CHECK: (elem declare func $2 $3)
+
+ ;; CHECK: (func $0
+ ;; CHECK-NEXT: (call $byn$mgfn-shared$0
+ ;; CHECK-NEXT: (ref.func $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; NOMNL: (elem declare func $2 $3)
+
+ ;; NOMNL: (func $0 (type $type$0)
+ ;; NOMNL-NEXT: (call $byn$mgfn-shared$0
+ ;; NOMNL-NEXT: (ref.func $2)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ (func $0 (type $type$0)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (call $2)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ )
+ ;; CHECK: (func $1
+ ;; CHECK-NEXT: (call $byn$mgfn-shared$0
+ ;; CHECK-NEXT: (ref.func $3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; NOMNL: (func $1 (type $type$0)
+ ;; NOMNL-NEXT: (call $byn$mgfn-shared$0
+ ;; NOMNL-NEXT: (ref.func $3)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ (func $1 (type $type$0)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (call $3)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ (nop)
+ )
+ ;; CHECK: (func $2
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 17)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; NOMNL: (func $2 (type $type$1)
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (i32.const 17)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ (func $2 (type $type$1)
+ (drop
+ (i32.const 17)
+ )
+ )
+ ;; CHECK: (func $3
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 999)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; NOMNL: (func $3 (type $type$1)
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (i32.const 999)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ (func $3 (type $type$1)
+ (drop
+ (i32.const 999)
+ )
+ )
+)
+;; CHECK: (func $byn$mgfn-shared$0 (param $0 (ref $type$0))
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (call_ref
+;; CHECK-NEXT: (local.get $0)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: (nop)
+;; CHECK-NEXT: )
+
+;; NOMNL: (func $byn$mgfn-shared$0 (type $ref|$type$1|_=>_none) (param $0 (ref $type$1))
+;; NOMNL-NEXT: (nop)
+;; NOMNL-NEXT: (nop)
+;; NOMNL-NEXT: (nop)
+;; NOMNL-NEXT: (nop)
+;; NOMNL-NEXT: (nop)
+;; NOMNL-NEXT: (nop)
+;; NOMNL-NEXT: (nop)
+;; NOMNL-NEXT: (nop)
+;; NOMNL-NEXT: (call_ref
+;; NOMNL-NEXT: (local.get $0)
+;; NOMNL-NEXT: )
+;; NOMNL-NEXT: (nop)
+;; NOMNL-NEXT: (nop)
+;; NOMNL-NEXT: (nop)
+;; NOMNL-NEXT: (nop)
+;; NOMNL-NEXT: (nop)
+;; NOMNL-NEXT: (nop)
+;; NOMNL-NEXT: (nop)
+;; NOMNL-NEXT: (nop)
+;; NOMNL-NEXT: )