diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/passes/OptimizeInstructions.cpp | 26 |
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; } |