Attach indirect call effects directly to expression
diff --git a/src/ir/effects.h b/src/ir/effects.h index 56cea0a..20ef0a3 100644 --- a/src/ir/effects.h +++ b/src/ir/effects.h
@@ -758,7 +758,7 @@ parent.implicitTrap = true; const EffectAnalyzer* callTargetEffects = nullptr; - if (auto it = parent.module.indirectCallEffects.find(curr->heapType); + if (auto it = parent.module.indirectCallEffects.find(curr); it != parent.module.indirectCallEffects.end()) { callTargetEffects = it->second.get(); } @@ -770,8 +770,7 @@ } const EffectAnalyzer* callTargetEffects = nullptr; - if (auto it = parent.module.indirectCallEffects.find( - curr->target->type.getHeapType()); + if (auto it = parent.module.indirectCallEffects.find(curr); it != parent.module.indirectCallEffects.end()) { callTargetEffects = it->second.get(); }
diff --git a/src/ir/linear-execution.h b/src/ir/linear-execution.h index 9e69405..ea5bbd8 100644 --- a/src/ir/linear-execution.h +++ b/src/ir/linear-execution.h
@@ -185,8 +185,8 @@ return true; } - auto* effects = find_or_null(self->getModule()->indirectCallEffects, - callRef->target->type.getHeapType()); + auto* effects = + find_or_null(self->getModule()->indirectCallEffects, callRef); if (!effects) { return false; } @@ -202,7 +202,7 @@ bool refutesThrowEffect = false; if (self->getModule()) { if (auto* effects = find_or_null( - self->getModule()->indirectCallEffects, callIndirect->heapType); + self->getModule()->indirectCallEffects, callIndirect); effects) { refutesThrowEffect = !(*effects)->throws_; }
diff --git a/src/ir/type-updating.cpp b/src/ir/type-updating.cpp index ee7cf7d..0ca698a 100644 --- a/src/ir/type-updating.cpp +++ b/src/ir/type-updating.cpp
@@ -325,35 +325,6 @@ for (auto& tag : wasm.tags) { tag->type = updater.getNew(tag->type); } - - // Update indirect call effects per type. - // When A is rewritten to B, B inherits the effects of A and A loses its - // effects. - std::unordered_map<HeapType, std::shared_ptr<const EffectAnalyzer>> - newTypeEffects; - - for (const auto& [oldType, newType] : oldToNewTypes) { - std::shared_ptr<const EffectAnalyzer>* oldEffects = - find_or_null(wasm.indirectCallEffects, oldType); - std::shared_ptr<const EffectAnalyzer>* targetEffects = - find_or_null(wasm.indirectCallEffects, newType); - - if (!targetEffects) { - // Nothing to update, we already know nothing and assume all effects. - continue; - } - - if (!oldEffects) { - targetEffects->reset(); - continue; - } - - auto merged = std::make_shared<EffectAnalyzer>(**targetEffects); - merged->mergeIn(**oldEffects); - *targetEffects = std::move(merged); - } - - wasm.indirectCallEffects = std::move(newTypeEffects); } void GlobalTypeRewriter::mapTypeNamesAndIndices(const TypeMap& oldToNewTypes) {
diff --git a/src/passes/GlobalEffects.cpp b/src/passes/GlobalEffects.cpp index efcc45e..798a381 100644 --- a/src/passes/GlobalEffects.cpp +++ b/src/passes/GlobalEffects.cpp
@@ -41,8 +41,8 @@ // Directly-called functions from this function. std::unordered_set<Name> calledFunctions; - // Types that are targets of indirect calls. - std::unordered_set<HeapType> indirectCalledTypes; + // Expressions that are indirect calls. + std::vector<const Expression*> indirectCalls; }; // Only funcs that are referenced may be the target of an indirect call. A @@ -162,19 +162,12 @@ funcInfo.calledFunctions.insert(call->target); } else if (effects.calls && options.worldMode == WorldMode::Closed) { - HeapType type; - if (auto* callRef = curr->dynCast<CallRef>()) { - // call_ref on unreachable does not have a call effect, - // so this must be a HeapType. - type = callRef->target->type.getHeapType(); - } else if (auto* callIndirect = curr->dynCast<CallIndirect>()) { - type = callIndirect->heapType; + if (curr->is<CallRef>() || curr->is<CallIndirect>()) { + funcInfo.indirectCalls.push_back(curr); } else { funcInfo.effects = std::nullopt; return; } - - funcInfo.indirectCalledTypes.insert(type); } else if (effects.calls) { assert(options.worldMode == WorldMode::Open); funcInfo.effects = std::nullopt; @@ -245,7 +238,13 @@ // Function -> Type allFunctionTypes.insert(caller->type.getHeapType()); - for (HeapType calleeType : callerInfo.indirectCalledTypes) { + for (const Expression* expr : callerInfo.indirectCalls) { + HeapType calleeType; + if (auto* callRef = expr->dynCast<CallRef>()) { + calleeType = callRef->target->type.getHeapType(); + } else { + calleeType = expr->cast<CallIndirect>()->heapType; + } callees.insert(calleeType); // Add the key to ensure the lookup doesn't fail for indirect calls to @@ -447,6 +446,8 @@ struct GenerateGlobalEffects : public Pass { void run(Module* module) override { + module->indirectCallEffects.clear(); + std::map<Function*, FuncInfo> funcInfos = analyzeFuncs(*module, getPassOptions()); @@ -455,11 +456,25 @@ auto callGraph = buildCallGraph( *module, funcInfos, referencedFuncs, getPassOptions().worldMode); - propagateEffects(*module, - getPassOptions(), - funcInfos, - module->indirectCallEffects, - callGraph); + std::unordered_map<HeapType, std::shared_ptr<const EffectAnalyzer>> + typeEffects; + + propagateEffects( + *module, getPassOptions(), funcInfos, typeEffects, callGraph); + + for (const auto& [func, info] : funcInfos) { + for (const Expression* expr : info.indirectCalls) { + HeapType type; + if (auto* callRef = expr->dynCast<CallRef>()) { + type = callRef->target->type.getHeapType(); + } else { + type = expr->cast<CallIndirect>()->heapType; + } + if (auto it = typeEffects.find(type); it != typeEffects.end()) { + module->indirectCallEffects[expr] = it->second; + } + } + } } };
diff --git a/src/wasm.h b/src/wasm.h index f5cade5..b3bceb3 100644 --- a/src/wasm.h +++ b/src/wasm.h
@@ -2744,7 +2744,7 @@ // exists to a function, the data can be out of date (no effort is made to // clean up the data if e.g. all indirect calls to a function are removed). // TODO: Account for exactness here. - std::unordered_map<HeapType, std::shared_ptr<const EffectAnalyzer>> + std::unordered_map<const Expression*, std::shared_ptr<const EffectAnalyzer>> indirectCallEffects; MixedArena allocator;
diff --git a/test/lit/passes/global-effects-indirect-merge.wast b/test/lit/passes/global-effects-indirect-merge.wast index b4823e8..f8af349 100644 --- a/test/lit/passes/global-effects-indirect-merge.wast +++ b/test/lit/passes/global-effects-indirect-merge.wast
@@ -54,11 +54,6 @@ ;; MERGE_FIRST: (func $test (type $0) (param $effectful-ref (ref $effectful)) (param $not-effectful-ref (ref $effectful)) ;; MERGE_FIRST-NEXT: (drop ;; MERGE_FIRST-NEXT: (call_ref $effectful - ;; MERGE_FIRST-NEXT: (local.get $not-effectful-ref) - ;; MERGE_FIRST-NEXT: ) - ;; MERGE_FIRST-NEXT: ) - ;; MERGE_FIRST-NEXT: (drop - ;; MERGE_FIRST-NEXT: (call_ref $effectful ;; MERGE_FIRST-NEXT: (local.get $effectful-ref) ;; MERGE_FIRST-NEXT: ) ;; MERGE_FIRST-NEXT: )