summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/tools/wasm-reduce.cpp21
-rw-r--r--test/reduce/gc.wast28
-rw-r--r--test/reduce/gc.wast.txt16
3 files changed, 64 insertions, 1 deletions
diff --git a/src/tools/wasm-reduce.cpp b/src/tools/wasm-reduce.cpp
index 3b9229462..6613c8899 100644
--- a/src/tools/wasm-reduce.cpp
+++ b/src/tools/wasm-reduce.cpp
@@ -304,7 +304,7 @@ struct Reducer
"--simplify-globals",
"--simplify-locals --vacuum",
"--strip",
- "--remove-unused-types",
+ "--remove-unused-types --closed-world",
"--vacuum"};
auto oldSize = file_size(working);
bool more = true;
@@ -627,6 +627,25 @@ struct Reducer
// children (which would recreate the current state).
return;
}
+ } else if (auto* structNew = curr->dynCast<StructNew>()) {
+ // If all the fields are defaultable, try to replace this with a
+ // struct.new_with_default.
+ if (!structNew->isWithDefault() && structNew->type != Type::unreachable) {
+ auto& fields = structNew->type.getHeapType().getStruct().fields;
+ if (std::all_of(fields.begin(), fields.end(), [&](auto& field) {
+ return field.type.isDefaultable();
+ })) {
+ ExpressionList operands(getModule()->allocator);
+ operands.swap(structNew->operands);
+ assert(structNew->isWithDefault());
+ if (tryToReplaceCurrent(structNew)) {
+ return;
+ } else {
+ structNew->operands.swap(operands);
+ assert(!structNew->isWithDefault());
+ }
+ }
+ }
}
// Finally, try to replace with a child.
for (auto* child : ChildIterator(curr)) {
diff --git a/test/reduce/gc.wast b/test/reduce/gc.wast
new file mode 100644
index 000000000..98d1cd075
--- /dev/null
+++ b/test/reduce/gc.wast
@@ -0,0 +1,28 @@
+(module
+ (rec
+ (type $A (struct (field (mut i32)) (field funcref)))
+ ;; This type can be optimized away.
+ (type $unused (struct))
+ )
+
+ (global $A (ref null $A) (struct.new $A
+ ;; These particular values are not used, and can be removed, leaving the
+ ;; struct.new as struct.new_default.
+ (i32.const 0)
+ (ref.func $use-global)
+ ))
+
+ (func $use-global (export "use-global") (result i32)
+ ;; This function stores 42 in the global struct, then reads and returns
+ ;; that. We don't manage to optimize away anything in this function, which
+ ;; only serves to keep alive the type and the global for the above testing.
+ (struct.set $A 0
+ (global.get $A)
+ (i32.const 42)
+ )
+ (struct.get $A 0
+ (global.get $A)
+ )
+ )
+)
+
diff --git a/test/reduce/gc.wast.txt b/test/reduce/gc.wast.txt
new file mode 100644
index 000000000..3af5287ce
--- /dev/null
+++ b/test/reduce/gc.wast.txt
@@ -0,0 +1,16 @@
+(module
+ (type $0 (struct (field (mut i32)) (field funcref)))
+ (type $1 (func (result i32)))
+ (global $global$0 (ref null $0) (struct.new_default $0))
+ (export "use-global" (func $0))
+ (func $0 (result i32)
+ (struct.set $0 0
+ (global.get $global$0)
+ (i32.const 42)
+ )
+ (struct.get $0 0
+ (global.get $global$0)
+ )
+ )
+)
+