diff options
-rw-r--r-- | src/passes/SignaturePruning.cpp | 14 | ||||
-rw-r--r-- | test/lit/passes/signature-pruning.wast | 39 |
2 files changed, 50 insertions, 3 deletions
diff --git a/src/passes/SignaturePruning.cpp b/src/passes/SignaturePruning.cpp index 168ef8454..292feeca5 100644 --- a/src/passes/SignaturePruning.cpp +++ b/src/passes/SignaturePruning.cpp @@ -31,6 +31,7 @@ #include "ir/intrinsics.h" #include "ir/lubs.h" #include "ir/module-utils.h" +#include "ir/subtypes.h" #include "ir/type-updating.h" #include "param-utils.h" #include "pass.h" @@ -149,6 +150,13 @@ struct SignaturePruning : public Pass { } } + // A type must have the same number of parameters and results as its + // supertypes and subtypes, so we only attempt to modify types without + // supertypes or subtypes. + // TODO We could handle "cycles" where we remove fields from a group of + // types with subtyping relations at once. + SubTypes subTypes(*module); + // Find parameters to prune. for (auto& [type, funcs] : sigFuncs) { auto sig = type.getSignature(); @@ -160,9 +168,9 @@ struct SignaturePruning : public Pass { continue; } - // A type with a signature supertype cannot be optimized: we'd need to - // remove the field from the super as well, which atm we don't attempt to - // do. TODO + if (!subTypes.getStrictSubTypes(type).empty()) { + continue; + } if (auto super = type.getSuperType()) { if (super->isSignature()) { continue; diff --git a/test/lit/passes/signature-pruning.wast b/test/lit/passes/signature-pruning.wast index c3d6567f7..76a2666ab 100644 --- a/test/lit/passes/signature-pruning.wast +++ b/test/lit/passes/signature-pruning.wast @@ -849,3 +849,42 @@ ) ) ) + +;; Due to function subtyping, we cannot prune fields from $func.B without also +;; pruning them in $func.A, and vice versa, if they have a subtyping +;; relationship. Atm we do not prune such "cycles" so we do not optimize here. +;; TODO +(module + ;; CHECK: (type $array.A (array (ref $struct.A))) + + ;; CHECK: (type $array.B (array_subtype (ref $struct.B) $array.A)) + + ;; CHECK: (type $func.A (func (param (ref $array.B)) (result (ref $array.A)))) + + ;; CHECK: (type $func.B (func_subtype (param (ref $array.A)) (result (ref $array.B)) $func.A)) + + ;; CHECK: (type $struct.A (struct (field i32))) + (type $struct.A (struct (field i32))) + ;; CHECK: (type $struct.B (struct_subtype (field i32) (field i64) $struct.A)) + (type $struct.B (struct_subtype (field i32) (field i64) $struct.A)) + + (type $array.A (array (ref $struct.A))) + (type $array.B (array_subtype (ref $struct.B) $array.A)) + + (type $func.A (func (param (ref $array.B)) (result (ref $array.A)))) + (type $func.B (func_subtype (param (ref $array.A)) (result (ref $array.B)) $func.A)) + + ;; CHECK: (func $func.A (type $func.A) (param $0 (ref $array.B)) (result (ref $array.A)) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $func.A (type $func.A) (param $0 (ref $array.B)) (result (ref $array.A)) + (unreachable) + ) + + ;; CHECK: (func $func.B (type $func.B) (param $0 (ref $array.A)) (result (ref $array.B)) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $func.B (type $func.B) (param $0 (ref $array.A)) (result (ref $array.B)) + (unreachable) + ) +) |