Skip to content

Commit 51ba837

Browse files
authored
Allow GSI to work with supertype globals (#7594)
GSI previously only optimized globals whose types were the same as their initializer's types to ensure the glboal types were equality comparable. However, this is an overly conservative restriction because the global can have any type up to eqref without causing problems. Update the restriction to be more precise. This will help the GSI tests continue working once `struct.new` is typed as exact.
1 parent 4201149 commit 51ba837

File tree

2 files changed

+88
-6
lines changed

2 files changed

+88
-6
lines changed

src/passes/GlobalStructInference.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,12 +137,9 @@ struct GlobalStructInference : public Pass {
137137

138138
auto type = global->init->type.getHeapType();
139139

140-
// The global's declared type must match the init's type. If not, say if
141-
// we had a global declared as type |any| but that contains (ref $A), then
142-
// that is not something we can optimize, as ref.eq on a global.get of
143-
// that global will not validate. (This should not be a problem after
144-
// GlobalSubtyping runs, which will specialize the type of the global.)
145-
if (global->type != global->init->type) {
140+
// The global's declared type must be equality comparable.
141+
if (auto eq = wasm::HeapTypes::eq.getBasic(type.getShared());
142+
!Type::isSubType(global->type, Type(eq, Nullable))) {
146143
unoptimizable.insert(type);
147144
continue;
148145
}

test/lit/passes/gsi.wast

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2156,3 +2156,88 @@
21562156
)
21572157
)
21582158
)
2159+
2160+
;; The basic case, but now the globals have type eqref. This should still work.
2161+
(module
2162+
;; CHECK: (type $struct (struct (field i32)))
2163+
(type $struct (struct i32))
2164+
2165+
;; CHECK: (type $1 (func (param (ref null $struct))))
2166+
2167+
;; CHECK: (global $global1 eqref (struct.new $struct
2168+
;; CHECK-NEXT: (i32.const 42)
2169+
;; CHECK-NEXT: ))
2170+
(global $global1 eqref (struct.new $struct
2171+
(i32.const 42)
2172+
))
2173+
2174+
;; CHECK: (global $global2 eqref (struct.new $struct
2175+
;; CHECK-NEXT: (i32.const 1337)
2176+
;; CHECK-NEXT: ))
2177+
(global $global2 eqref (struct.new $struct
2178+
(i32.const 1337)
2179+
))
2180+
2181+
;; CHECK: (func $test (type $1) (param $struct (ref null $struct))
2182+
;; CHECK-NEXT: (drop
2183+
;; CHECK-NEXT: (select
2184+
;; CHECK-NEXT: (i32.const 42)
2185+
;; CHECK-NEXT: (i32.const 1337)
2186+
;; CHECK-NEXT: (ref.eq
2187+
;; CHECK-NEXT: (ref.as_non_null
2188+
;; CHECK-NEXT: (local.get $struct)
2189+
;; CHECK-NEXT: )
2190+
;; CHECK-NEXT: (global.get $global1)
2191+
;; CHECK-NEXT: )
2192+
;; CHECK-NEXT: )
2193+
;; CHECK-NEXT: )
2194+
;; CHECK-NEXT: )
2195+
(func $test (param $struct (ref null $struct))
2196+
;; We can infer that this get can reference either $global1 or $global2,
2197+
;; and nothing else (aside from a null), and can emit a select between
2198+
;; those values.
2199+
(drop
2200+
(struct.get $struct 0
2201+
(local.get $struct)
2202+
)
2203+
)
2204+
)
2205+
)
2206+
2207+
;; Same, but now the globals have type anyref, so they are not comparable and we
2208+
;; cannot optimize.
2209+
(module
2210+
;; CHECK: (type $struct (struct (field i32)))
2211+
(type $struct (struct i32))
2212+
2213+
;; CHECK: (type $1 (func (param (ref null $struct))))
2214+
2215+
;; CHECK: (global $global1 anyref (struct.new $struct
2216+
;; CHECK-NEXT: (i32.const 42)
2217+
;; CHECK-NEXT: ))
2218+
(global $global1 anyref (struct.new $struct
2219+
(i32.const 42)
2220+
))
2221+
2222+
;; CHECK: (global $global2 anyref (struct.new $struct
2223+
;; CHECK-NEXT: (i32.const 1337)
2224+
;; CHECK-NEXT: ))
2225+
(global $global2 anyref (struct.new $struct
2226+
(i32.const 1337)
2227+
))
2228+
2229+
;; CHECK: (func $test (type $1) (param $struct (ref null $struct))
2230+
;; CHECK-NEXT: (drop
2231+
;; CHECK-NEXT: (struct.get $struct 0
2232+
;; CHECK-NEXT: (local.get $struct)
2233+
;; CHECK-NEXT: )
2234+
;; CHECK-NEXT: )
2235+
;; CHECK-NEXT: )
2236+
(func $test (param $struct (ref null $struct))
2237+
(drop
2238+
(struct.get $struct 0
2239+
(local.get $struct)
2240+
)
2241+
)
2242+
)
2243+
)

0 commit comments

Comments
 (0)