summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/OptimizeInstructions.cpp33
-rw-r--r--test/lit/passes/optimize-instructions-gc-heap.wast30
2 files changed, 43 insertions, 20 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index 5613aca11..3486fe82a 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -1931,12 +1931,6 @@ struct OptimizeInstructions
return false;
}
- if (new_->isWithDefault()) {
- // Ignore a new_default for now. If the fields are defaultable then we
- // could add them, in principle, but that might increase code size.
- return false;
- }
-
auto index = set->index;
auto& operands = new_->operands;
@@ -1953,20 +1947,35 @@ struct OptimizeInstructions
}
// We must move the set's value past indexes greater than it (Y and Z in
- // the example in the comment on this function).
+ // the example in the comment on this function). If this is not with_default
+ // then we must check for effects.
// TODO When this function is called repeatedly in a sequence this can
// become quadratic - perhaps we should memoize (though, struct sizes
// tend to not be ridiculously large).
- for (Index i = index + 1; i < operands.size(); i++) {
- auto operandEffects = effects(operands[i]);
- if (operandEffects.invalidates(setValueEffects)) {
- // TODO: we could use locals to reorder everything
- return false;
+ if (!new_->isWithDefault()) {
+ for (Index i = index + 1; i < operands.size(); i++) {
+ auto operandEffects = effects(operands[i]);
+ if (operandEffects.invalidates(setValueEffects)) {
+ // TODO: we could use locals to reorder everything
+ return false;
+ }
}
}
+ // We can optimize here!
Builder builder(*getModule());
+ // If this was with_default then we add default values now. That does
+ // increase code size in some cases (if there are many values, and few sets
+ // that get removed), but in general this optimization is worth it.
+ if (new_->isWithDefault()) {
+ auto& fields = new_->type.getHeapType().getStruct().fields;
+ for (auto& field : fields) {
+ auto zero = Literal::makeZero(field.type);
+ operands.push_back(builder.makeConstantExpression(zero));
+ }
+ }
+
// See if we need to keep the old value.
if (effects(operands[index]).hasUnremovableSideEffects()) {
operands[index] =
diff --git a/test/lit/passes/optimize-instructions-gc-heap.wast b/test/lit/passes/optimize-instructions-gc-heap.wast
index 137105468..6db63fae3 100644
--- a/test/lit/passes/optimize-instructions-gc-heap.wast
+++ b/test/lit/passes/optimize-instructions-gc-heap.wast
@@ -9,10 +9,11 @@
;; CHECK: (type $struct (struct (field (mut i32))))
(type $struct (struct (field (mut i32))))
+ ;; CHECK: (type $struct3 (struct (field (mut i32)) (field (mut i32)) (field (mut i32))))
+
;; CHECK: (type $struct2 (struct (field (mut i32)) (field (mut i32))))
(type $struct2 (struct (field (mut i32)) (field (mut i32))))
- ;; CHECK: (type $struct3 (struct (field (mut i32)) (field (mut i32)) (field (mut i32))))
(type $struct3 (struct (field (mut i32)) (field (mut i32)) (field (mut i32))))
;; CHECK: (func $tee (type $1)
@@ -575,22 +576,35 @@
;; CHECK: (func $default (type $1)
;; CHECK-NEXT: (local $ref (ref null $struct))
- ;; CHECK-NEXT: (struct.set $struct 0
- ;; CHECK-NEXT: (local.tee $ref
- ;; CHECK-NEXT: (struct.new_default $struct)
+ ;; CHECK-NEXT: (local $ref3 (ref null $struct3))
+ ;; CHECK-NEXT: (local.set $ref
+ ;; CHECK-NEXT: (struct.new $struct
+ ;; CHECK-NEXT: (i32.const 10)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $ref3
+ ;; CHECK-NEXT: (struct.new $struct3
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.const 33)
+ ;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $default
(local $ref (ref null $struct))
+ (local $ref3 (ref null $struct3))
+ ;; We optimize new_default as well, adding default values as needed.
(struct.set $struct 0
(local.tee $ref
- ;; Ignore a new_default for now. If the fields are defaultable then we
- ;; could add them, in principle, but that might increase code size.
(struct.new_default $struct)
)
- (i32.const 20)
+ (i32.const 10)
+ )
+ (struct.set $struct3 1
+ (local.tee $ref3
+ (struct.new_default $struct3)
+ )
+ (i32.const 33)
)
)