summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2022-04-25 08:23:55 -0700
committerGitHub <noreply@github.com>2022-04-25 08:23:55 -0700
commit94d77efa788b46ec3d245fd0e180163877fe2a88 (patch)
tree35eb706d8fe958df0c963fd2337a1463602182c0 /src
parentbe25a9cfb881153ab631e52e36a37e1eed872ff5 (diff)
downloadbinaryen-94d77efa788b46ec3d245fd0e180163877fe2a88.tar.gz
binaryen-94d77efa788b46ec3d245fd0e180163877fe2a88.tar.bz2
binaryen-94d77efa788b46ec3d245fd0e180163877fe2a88.zip
OptimizeInstructions: Refinalize after a cast removal (#4611)
Casts can replace a type with a subtype, which normally has no downsides, but in a corner case of struct types it can lead to us needing to refinalize higher up too, see details in the comment. We have avoided any Refinalize calls in OptimizeInstructions, but the case handled here requires it sadly. I considered moving it to another pass, but this is a peephole optimization so there isn't really a better place.
Diffstat (limited to 'src')
-rw-r--r--src/passes/OptimizeInstructions.cpp26
1 files changed, 26 insertions, 0 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index bde60e093..4b499213f 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -208,6 +208,9 @@ struct OptimizeInstructions
bool fastMath;
+ // In rare cases we make a change to a type, and will do a refinalize.
+ bool refinalize = false;
+
void doWalkFunction(Function* func) {
fastMath = getPassOptions().fastMath;
@@ -221,6 +224,10 @@ struct OptimizeInstructions
// Main walk.
super::doWalkFunction(func);
+ if (refinalize) {
+ ReFinalize().walkFunctionInModule(func, getModule());
+ }
+
// Final optimizations.
{
FinalOptimizer optimizer(getPassOptions());
@@ -1622,6 +1629,25 @@ struct OptimizeInstructions
passOptions));
} else {
replaceCurrent(curr->ref);
+
+ // We must refinalize here, as we may be returning a more specific
+ // type, which can alter the parent. For example:
+ //
+ // (struct.get $parent 0
+ // (ref.cast_static $parent
+ // (local.get $child)
+ // )
+ // )
+ //
+ // Try to cast a $child to its parent, $parent. That always works,
+ // so the cast can be removed.
+ // Then once the cast is removed, the outer struct.get
+ // will have a reference with a different type, making it a
+ // (struct.get $child ..) instead of $parent.
+ // But if $parent and $child have different types on field 0 (the
+ // child may have a more refined one) then the struct.get must be
+ // refinalized so the IR node has the expected type.
+ refinalize = true;
}
return;
}