Skip to content

Commit 5611a52

Browse files
authored
[wasm-reduce] Reduce struct.new arguments away when possible (#7118)
If all the fields of a struct.new are defaultable, see if replacing it with a struct.new_default preserves the behavior, and reduce that way if so. Also add a missing --closed-world to the --remove-unused-types invocation. Without that, it was erroring and not working, which I noticed when testing this. The test also checks that.
1 parent 6ddacde commit 5611a52

3 files changed

Lines changed: 64 additions & 1 deletion

File tree

src/tools/wasm-reduce.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ struct Reducer
304304
"--simplify-globals",
305305
"--simplify-locals --vacuum",
306306
"--strip",
307-
"--remove-unused-types",
307+
"--remove-unused-types --closed-world",
308308
"--vacuum"};
309309
auto oldSize = file_size(working);
310310
bool more = true;
@@ -627,6 +627,25 @@ struct Reducer
627627
// children (which would recreate the current state).
628628
return;
629629
}
630+
} else if (auto* structNew = curr->dynCast<StructNew>()) {
631+
// If all the fields are defaultable, try to replace this with a
632+
// struct.new_with_default.
633+
if (!structNew->isWithDefault() && structNew->type != Type::unreachable) {
634+
auto& fields = structNew->type.getHeapType().getStruct().fields;
635+
if (std::all_of(fields.begin(), fields.end(), [&](auto& field) {
636+
return field.type.isDefaultable();
637+
})) {
638+
ExpressionList operands(getModule()->allocator);
639+
operands.swap(structNew->operands);
640+
assert(structNew->isWithDefault());
641+
if (tryToReplaceCurrent(structNew)) {
642+
return;
643+
} else {
644+
structNew->operands.swap(operands);
645+
assert(!structNew->isWithDefault());
646+
}
647+
}
648+
}
630649
}
631650
// Finally, try to replace with a child.
632651
for (auto* child : ChildIterator(curr)) {

test/reduce/gc.wast

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
(module
2+
(rec
3+
(type $A (struct (field (mut i32)) (field funcref)))
4+
;; This type can be optimized away.
5+
(type $unused (struct))
6+
)
7+
8+
(global $A (ref null $A) (struct.new $A
9+
;; These particular values are not used, and can be removed, leaving the
10+
;; struct.new as struct.new_default.
11+
(i32.const 0)
12+
(ref.func $use-global)
13+
))
14+
15+
(func $use-global (export "use-global") (result i32)
16+
;; This function stores 42 in the global struct, then reads and returns
17+
;; that. We don't manage to optimize away anything in this function, which
18+
;; only serves to keep alive the type and the global for the above testing.
19+
(struct.set $A 0
20+
(global.get $A)
21+
(i32.const 42)
22+
)
23+
(struct.get $A 0
24+
(global.get $A)
25+
)
26+
)
27+
)
28+

test/reduce/gc.wast.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
(module
2+
(type $0 (struct (field (mut i32)) (field funcref)))
3+
(type $1 (func (result i32)))
4+
(global $global$0 (ref null $0) (struct.new_default $0))
5+
(export "use-global" (func $0))
6+
(func $0 (result i32)
7+
(struct.set $0 0
8+
(global.get $global$0)
9+
(i32.const 42)
10+
)
11+
(struct.get $0 0
12+
(global.get $global$0)
13+
)
14+
)
15+
)
16+

0 commit comments

Comments
 (0)