Skip to content

Commit ff7c909

Browse files
authored
[GC] Precompute: Handle non-constant effects in recomputed GC values (#8014)
We had the logic to recompute the effects, which handled tracked globals/locals/etc. However, we also need to check the effect of the result being non-constant, which can happen if we propagate values and find an input is not constant. Fixes #8013
1 parent 7e782f6 commit ff7c909

File tree

2 files changed

+96
-1
lines changed

2 files changed

+96
-1
lines changed

src/passes/Precompute.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,13 @@ class PrecomputingExpressionRunner
210210
if (hasEffects) {
211211
// Visit, so we recompute the effects. (This is rare, see comment
212212
// above.)
213-
visitFunc();
213+
auto flow = visitFunc();
214+
// Also check the result of the effects - if it is non-constant, we
215+
// cannot use it. (This can happen during propagation, when we see that
216+
// other inputs exist to something we depend on.)
217+
if (flow.breaking()) {
218+
return flow;
219+
}
214220
}
215221
// Refer to the same canonical GCData that we already created.
216222
return Literal(data, curr->type.getHeapType());
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
2+
3+
;; RUN: wasm-opt %s --remove-unused-names --precompute-propagate --fuzz-exec -all -S -o - \
4+
;; RUN: | filecheck %s
5+
6+
(module
7+
;; CHECK: (type $struct (sub (struct (field i32))))
8+
(type $struct (sub (struct (field i32))))
9+
10+
;; CHECK: (func $loop-different (type $1)
11+
;; CHECK-NEXT: (local $struct (ref null $struct))
12+
;; CHECK-NEXT: (local $int i32)
13+
;; CHECK-NEXT: (local.set $int
14+
;; CHECK-NEXT: (i32.const 0)
15+
;; CHECK-NEXT: )
16+
;; CHECK-NEXT: (loop $loop
17+
;; CHECK-NEXT: (local.set $struct
18+
;; CHECK-NEXT: (struct.new $struct
19+
;; CHECK-NEXT: (local.get $int)
20+
;; CHECK-NEXT: )
21+
;; CHECK-NEXT: )
22+
;; CHECK-NEXT: (local.set $int
23+
;; CHECK-NEXT: (i32.const 1)
24+
;; CHECK-NEXT: )
25+
;; CHECK-NEXT: (br_if $loop
26+
;; CHECK-NEXT: (i32.eqz
27+
;; CHECK-NEXT: (block $block1 (result i32)
28+
;; CHECK-NEXT: (block $block
29+
;; CHECK-NEXT: (drop
30+
;; CHECK-NEXT: (br_on_null $block
31+
;; CHECK-NEXT: (local.get $struct)
32+
;; CHECK-NEXT: )
33+
;; CHECK-NEXT: )
34+
;; CHECK-NEXT: (br $block1
35+
;; CHECK-NEXT: (struct.get $struct 0
36+
;; CHECK-NEXT: (local.get $struct)
37+
;; CHECK-NEXT: )
38+
;; CHECK-NEXT: )
39+
;; CHECK-NEXT: )
40+
;; CHECK-NEXT: (i32.const 0)
41+
;; CHECK-NEXT: )
42+
;; CHECK-NEXT: )
43+
;; CHECK-NEXT: )
44+
;; CHECK-NEXT: )
45+
;; CHECK-NEXT: )
46+
(func $loop-different
47+
(local $struct (ref null $struct))
48+
(local $int i32)
49+
;; This int is set before the loop, and read at the loop top. The value there
50+
;; is *not* 0, because we set a new value in the loop, which takes effect in
51+
;; later iterations.
52+
(local.set $int
53+
(i32.const 0)
54+
)
55+
(loop $loop
56+
(local.set $struct
57+
(struct.new $struct
58+
(local.get $int)
59+
)
60+
)
61+
(local.set $int
62+
(i32.const 1)
63+
)
64+
65+
;; The rest of the code is needed to prevent the testcase from getting
66+
;; optimized trivially away. This br should not be optimized away or
67+
;; simplfied - it executes in the first loop iteration but not the second.
68+
(br_if $loop
69+
(i32.eqz
70+
(block $block1 (result i32)
71+
(block $block
72+
(drop
73+
(br_on_null $block
74+
(local.get $struct)
75+
)
76+
)
77+
(br $block1
78+
(struct.get $struct 0
79+
(local.get $struct)
80+
)
81+
)
82+
)
83+
(i32.const 0)
84+
)
85+
)
86+
)
87+
)
88+
)
89+
)

0 commit comments

Comments
 (0)