summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2023-02-02 12:08:42 -0800
committerGitHub <noreply@github.com>2023-02-02 12:08:42 -0800
commit91f54df07766a5884203aa1fcfd6b0d61a3eb142 (patch)
tree82e85642ed86b0033dbf5b472710fb8f934baf7c /src
parentd1b75970e5425a5e8b08ca87801d1343df43fde7 (diff)
downloadbinaryen-91f54df07766a5884203aa1fcfd6b0d61a3eb142.tar.gz
binaryen-91f54df07766a5884203aa1fcfd6b0d61a3eb142.tar.bz2
binaryen-91f54df07766a5884203aa1fcfd6b0d61a3eb142.zip
[Wasm GC] Fix RemoveUnusedModuleEffects struct field reads with call.without.effects (#5477)
If we see (struct.new $A (call $call.without.effects ;; intrinsic (ref.func $getter) ) ) then we can ignore side effects in that call, as the intrinsic tells us to. However, that function is still called (it will be called normally, after intrinsics are lowered away), and we should not remove it. That is, such an intrinsic call can be removed, but it cannot be left as it is and also ignored as if it does not exist.
Diffstat (limited to 'src')
-rw-r--r--src/passes/RemoveUnusedModuleElements.cpp36
1 files changed, 31 insertions, 5 deletions
diff --git a/src/passes/RemoveUnusedModuleElements.cpp b/src/passes/RemoveUnusedModuleElements.cpp
index 2ae03391b..358add76b 100644
--- a/src/passes/RemoveUnusedModuleElements.cpp
+++ b/src/passes/RemoveUnusedModuleElements.cpp
@@ -38,6 +38,7 @@
#include <memory>
#include "ir/element-utils.h"
+#include "ir/find_all.h"
#include "ir/intrinsics.h"
#include "ir/module-utils.h"
#include "ir/subtypes.h"
@@ -492,11 +493,36 @@ struct Analyzer {
for (Index i = 0; i < new_->operands.size(); i++) {
auto* operand = new_->operands[i];
auto structField = StructField{type, i};
- if (readStructFields.count(structField) ||
- EffectAnalyzer(options, *module, operand).hasSideEffects()) {
- // This data can be read, so just walk it. Or, this has side effects,
- // which is tricky to reason about - the side effects must happen even
- // if we never read the struct field - so give up and consider it used.
+
+ // If this struct field has already been read, then we should use the
+ // contents there now.
+ auto useOperandNow = readStructFields.count(structField);
+
+ // Side effects are tricky to reason about - the side effects must happen
+ // even if we never read the struct field - so give up and consider it
+ // used.
+ if (!useOperandNow) {
+ useOperandNow =
+ EffectAnalyzer(options, *module, operand).hasSideEffects();
+ }
+
+ // We must handle the call.without.effects intrinsic here in a special
+ // manner. That intrinsic is reported as having no side effects in
+ // EffectAnalyzer, but even though for optimization purposes we can ignore
+ // effects, the called code *is* actually reached, and it might have side
+ // effects. In other words, the point of the intrinsic is to temporarily
+ // ignore those effects during one phase of optimization. Or, put another
+ // way, the intrinsic lets us ignore the effects of computing some value,
+ // but we do still need to compute that value if it is received and used
+ // (if it is not received and used, other passes will remove it).
+ if (!useOperandNow) {
+ // To detect this, look for any call. A non-intrinsic call would have
+ // already been detected when we looked for side effects, so this will
+ // only notice intrinsic calls.
+ useOperandNow = !FindAll<Call>(operand).list.empty();
+ }
+
+ if (useOperandNow) {
use(operand);
} else {
// This data does not need to be read now, but might be read later. Note