summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/passes/OptimizeInstructions.cpp23
1 files changed, 21 insertions, 2 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index fff18b925..64d59ca1d 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -2248,8 +2248,27 @@ struct OptimizeInstructions
}
if (curr->op == ExternConvertAny || curr->op == AnyConvertExtern) {
- // We can't optimize these. Even removing a non-null cast is not valid as
- // they allow nulls to filter through, unlike other RefAs*.
+ // These pass nulls through, and we can reorder them with null traps:
+ //
+ // (any.convert_extern/extern.convert_any (ref.as_non_null.. ))
+ // =>
+ // (ref.as_non_null (any.convert_extern/extern.convert_any ..))
+ //
+ // By moving the RefAsNonNull outside, it may reach a position where it
+ // can be optimized (e.g. if the parent traps anyhow). And,
+ // ExternConvertAny/AnyConvertExtern cannot be folded with anything, so
+ // there is no harm to moving them inside.
+ if (auto* refAsChild = curr->value->dynCast<RefAs>()) {
+ if (refAsChild->op == RefAsNonNull) {
+ // Reorder and fix up the types.
+ curr->value = refAsChild->value;
+ curr->finalize();
+ refAsChild->value = curr;
+ refAsChild->finalize();
+ replaceCurrent(refAsChild);
+ }
+ }
+ // TODO: optimize away ExternConvertAny of AnyConvertExtern, etc.
return;
}