Skip to content

Commit 193792f

Browse files
Fix type merging for unknown effects (#8833)
Fixes #8831. See the incorrect optimization described in that issue.
1 parent c2a1cc8 commit 193792f

2 files changed

Lines changed: 85 additions & 20 deletions

File tree

src/ir/type-updating.cpp

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -331,22 +331,28 @@ void GlobalTypeRewriter::mapTypes(const TypeMap& oldToNewTypes) {
331331
// effects.
332332
std::unordered_map<HeapType, std::shared_ptr<const EffectAnalyzer>>
333333
newTypeEffects;
334-
for (auto& [oldType, oldEffects] : wasm.indirectCallEffects) {
335-
if (!oldEffects) {
334+
335+
for (const auto& [oldType, newType] : oldToNewTypes) {
336+
std::shared_ptr<const EffectAnalyzer>* oldEffects =
337+
find_or_null(wasm.indirectCallEffects, oldType);
338+
std::shared_ptr<const EffectAnalyzer>* targetEffects =
339+
find_or_null(wasm.indirectCallEffects, newType);
340+
341+
if (!targetEffects) {
342+
// Nothing to update, we already know nothing and assume all effects.
336343
continue;
337344
}
338345

339-
auto newType = updater.getNew(oldType);
340-
std::shared_ptr<const EffectAnalyzer>& targetEffects =
341-
newTypeEffects[newType];
342-
if (!targetEffects) {
343-
targetEffects = oldEffects;
344-
} else {
345-
auto merged = std::make_shared<EffectAnalyzer>(*targetEffects);
346-
merged->mergeIn(*oldEffects);
347-
targetEffects = merged;
346+
if (!oldEffects) {
347+
targetEffects->reset();
348+
continue;
348349
}
350+
351+
auto merged = std::make_shared<EffectAnalyzer>(**targetEffects);
352+
merged->mergeIn(**oldEffects);
353+
*targetEffects = std::move(merged);
349354
}
355+
350356
wasm.indirectCallEffects = std::move(newTypeEffects);
351357
}
352358

test/lit/passes/global-effects-indirect-merge.wast

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
2-
;; RUN: wasm-opt %s --all-features --closed-world --generate-global-effects --vacuum --type-merging --remove-unused-types -S -o - | filecheck %s --check-prefix VACUUM_FIRST
3-
;; RUN: wasm-opt %s --all-features --closed-world --generate-global-effects --type-merging --remove-unused-types --vacuum -S -o - | filecheck %s --check-prefix MERGE_FIRST
2+
;; RUN: foreach %s %t wasm-opt --all-features --closed-world --generate-global-effects --vacuum --type-merging --remove-unused-types -S -o - | filecheck %s --check-prefix VACUUM_FIRST
3+
;; RUN: foreach %s %t wasm-opt --all-features --closed-world --generate-global-effects --type-merging --remove-unused-types --vacuum -S -o - | filecheck %s --check-prefix MERGE_FIRST
44

55
;; Test that indirect call effects are preserved when types are rewritten
66
;; globally. When we rewrite $effectful and $not-effectful into the same type,
@@ -37,13 +37,7 @@
3737
(i32.const 0)
3838
)
3939

40-
;; VACUUM_FIRST: (func $f (type $1)
41-
;; VACUUM_FIRST-NEXT: (nop)
42-
;; VACUUM_FIRST-NEXT: )
43-
;; MERGE_FIRST: (func $f (type $1)
44-
;; MERGE_FIRST-NEXT: (nop)
45-
;; MERGE_FIRST-NEXT: )
46-
(func $f
40+
(func
4741
;; Reference the functions in a ref.func so that it's possible that they're
4842
;; the target of indirect calls.
4943
(drop (ref.func $unreachable))
@@ -82,3 +76,68 @@
8276
)
8377
)
8478
)
79+
80+
(module
81+
(rec
82+
;; VACUUM_FIRST: (type $nop-type (func))
83+
;; MERGE_FIRST: (type $nop-type (func))
84+
(type $nop-type (func))
85+
86+
(type $effectful-type (func))
87+
)
88+
89+
;; VACUUM_FIRST: (type $import-type (func))
90+
;; MERGE_FIRST: (type $import-type (func))
91+
(type $import-type (func))
92+
93+
;; VACUUM_FIRST: (import "" "" (func $import (type $import-type)))
94+
;; MERGE_FIRST: (import "" "" (func $import (type $import-type)))
95+
(import "" "" (func $import (type $import-type)))
96+
97+
;; VACUUM_FIRST: (func $nop (type $nop-type)
98+
;; VACUUM_FIRST-NEXT: (nop)
99+
;; VACUUM_FIRST-NEXT: )
100+
;; MERGE_FIRST: (func $nop (type $nop-type)
101+
;; MERGE_FIRST-NEXT: (nop)
102+
;; MERGE_FIRST-NEXT: )
103+
(func $nop (type $nop-type)
104+
(nop)
105+
)
106+
107+
;; VACUUM_FIRST: (func $effectful (type $nop-type)
108+
;; VACUUM_FIRST-NEXT: (call $import)
109+
;; VACUUM_FIRST-NEXT: )
110+
;; MERGE_FIRST: (func $effectful (type $nop-type)
111+
;; MERGE_FIRST-NEXT: (call $import)
112+
;; MERGE_FIRST-NEXT: )
113+
(func $effectful (type $effectful-type)
114+
;; We need an extra indirection here for the test.
115+
;; If we give $import the type $effectful-type directly, the type will be
116+
;; public and --type-merging won't optimize it.
117+
(call $import)
118+
)
119+
120+
(func
121+
(drop (ref.func $nop))
122+
(drop (ref.func $effectful))
123+
)
124+
125+
;; VACUUM_FIRST: (func $calls-effectful-type (type $0) (param $ref (ref $nop-type))
126+
;; VACUUM_FIRST-NEXT: (call_ref $nop-type
127+
;; VACUUM_FIRST-NEXT: (local.get $ref)
128+
;; VACUUM_FIRST-NEXT: )
129+
;; VACUUM_FIRST-NEXT: )
130+
;; MERGE_FIRST: (func $calls-effectful-type (type $0) (param $ref (ref $nop-type))
131+
;; MERGE_FIRST-NEXT: (call_ref $nop-type
132+
;; MERGE_FIRST-NEXT: (local.get $ref)
133+
;; MERGE_FIRST-NEXT: )
134+
;; MERGE_FIRST-NEXT: )
135+
(func $calls-effectful-type (param $ref (ref $effectful-type))
136+
;; See #8831. Test that effects are preserved after type merging even for
137+
;; 'unknown' effects that are represented with a missing entry in the
138+
;; `indirectCallEffects` map.
139+
(call_ref $effectful-type
140+
(local.get $ref)
141+
)
142+
)
143+
)

0 commit comments

Comments
 (0)