summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/SignaturePruning.cpp14
-rw-r--r--test/lit/passes/signature-pruning.wast39
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)
+ )
+)