Skip to content

Commit c0eeea8

Browse files
LinearExecutionWalker indirect call effects
1 parent 1d75c25 commit c0eeea8

3 files changed

Lines changed: 43 additions & 37 deletions

File tree

src/ir/linear-execution.h

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,12 @@ struct LinearExecutionWalker : public PostWalker<SubType, VisitorType> {
8080
static void scan(SubType* self, Expression** currp) {
8181
Expression* curr = *currp;
8282

83-
auto handleCall = [&](bool mayThrow, bool isReturn) {
83+
auto handleCall = [&](bool isReturn, const EffectAnalyzer* effects) {
84+
bool refutesThrowEffect = effects && !effects->throws();
85+
bool mayThrow = !self->getModule() ||
86+
self->getModule()->features.hasExceptionHandling();
87+
mayThrow = mayThrow && !refutesThrowEffect;
88+
8489
if (!self->connectAdjacentBlocks) {
8590
// Control is nonlinear if we return or throw. Traps don't need to be
8691
// taken into account since they don't break control flow in a way
@@ -156,40 +161,39 @@ struct LinearExecutionWalker : public PostWalker<SubType, VisitorType> {
156161
case Expression::Id::CallId: {
157162
auto* call = curr->cast<Call>();
158163

159-
bool mayThrow = !self->getModule() ||
160-
self->getModule()->features.hasExceptionHandling();
161-
if (mayThrow && self->getModule()) {
162-
auto* effects =
163-
self->getModule()->getFunction(call->target)->effects.get();
164-
165-
if (effects && !effects->throws_) {
166-
mayThrow = false;
167-
}
168-
}
169-
170-
handleCall(mayThrow, call->isReturn);
164+
const EffectAnalyzer* effects =
165+
self->getModule()
166+
? self->getModule()->getFunction(call->target)->effects.get()
167+
: nullptr;
168+
handleCall(call->isReturn, effects);
171169
break;
172170
}
173171
case Expression::Id::CallRefId: {
174172
auto* callRef = curr->cast<CallRef>();
175173

176-
// TODO: Effect analysis for indirect calls isn't implemented yet.
177-
// Assume any indirect call may throw for now.
178-
bool mayThrow = !self->getModule() ||
179-
self->getModule()->features.hasExceptionHandling();
180-
181-
handleCall(mayThrow, callRef->isReturn);
174+
const EffectAnalyzer* effects = nullptr;
175+
if (self->getModule()) {
176+
if (const auto& effects_ptr =
177+
find_or_null(self->getModule()->indirectCallEffects,
178+
callRef->target->type.getHeapType())) {
179+
effects = effects_ptr->get();
180+
}
181+
}
182+
handleCall(callRef->isReturn, effects);
182183
break;
183184
}
184185
case Expression::Id::CallIndirectId: {
185186
auto* callIndirect = curr->cast<CallIndirect>();
186187

187-
// TODO: Effect analysis for indirect calls isn't implemented yet.
188-
// Assume any indirect call may throw for now.
189-
bool mayThrow = !self->getModule() ||
190-
self->getModule()->features.hasExceptionHandling();
191-
192-
handleCall(mayThrow, callIndirect->isReturn);
188+
const EffectAnalyzer* effects = nullptr;
189+
if (self->getModule()) {
190+
if (const auto& effects_ptr =
191+
find_or_null(self->getModule()->indirectCallEffects,
192+
callIndirect->heapType)) {
193+
effects = effects_ptr->get();
194+
}
195+
}
196+
handleCall(callIndirect->isReturn, effects);
193197
break;
194198
}
195199
case Expression::Id::TryId: {

src/support/utilities.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,14 @@ template<typename... Ts> struct overloaded : Ts... {
107107

108108
template<typename... Ts> overloaded(Ts...) -> overloaded<Ts...>;
109109

110+
// Lookup a value from `map` and return a pointer to the underlying value
111+
// or nullptr if not present. Returns a const pointer if `map` is const and
112+
// non-const otherwise
113+
auto* find_or_null(auto& map, const auto& key) {
114+
auto it = map.find(key);
115+
return it != map.end() ? &it->second : nullptr;
116+
}
117+
110118
} // namespace wasm
111119

112120
#endif // wasm_support_utilities_h

test/lit/passes/simplify-locals-global-effects-eh.wast

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -92,24 +92,20 @@
9292

9393
;; CHECK: (func $read-g (type $3) (param $ref (ref null $const-type)) (result i32)
9494
;; CHECK-NEXT: (local $x i32)
95-
;; CHECK-NEXT: (local.set $x
96-
;; CHECK-NEXT: (global.get $g)
97-
;; CHECK-NEXT: )
95+
;; CHECK-NEXT: (nop)
9896
;; CHECK-NEXT: (drop
9997
;; CHECK-NEXT: (call_ref $const-type
10098
;; CHECK-NEXT: (local.get $ref)
10199
;; CHECK-NEXT: )
102100
;; CHECK-NEXT: )
103-
;; CHECK-NEXT: (local.get $x)
101+
;; CHECK-NEXT: (global.get $g)
104102
;; CHECK-NEXT: )
105103
(func $read-g (param $ref (ref null $const-type)) (result i32)
106104
(local $x i32)
107105
(local.set $x (global.get $g))
108106

109-
;; With more precise effect analysis for indirect calls, we can determine
110-
;; that the only possible target for this ref is $const in a closed world,
111-
;; which wouldn't block our optimizations.
112-
;; TODO: Add effects analysis for indirect calls.
107+
;; With --closed-world enabled, we can tell that this can only possibly call
108+
;; $const, which doesn't block our optimizations.
113109
(drop (call_ref $const-type (local.get $ref)))
114110

115111
(local.get $x)
@@ -140,15 +136,13 @@
140136

141137
;; CHECK: (func $read-g-with-call-indirect-in-between (type $5) (result i32)
142138
;; CHECK-NEXT: (local $x i32)
143-
;; CHECK-NEXT: (local.set $x
144-
;; CHECK-NEXT: (global.get $g)
145-
;; CHECK-NEXT: )
139+
;; CHECK-NEXT: (nop)
146140
;; CHECK-NEXT: (drop
147141
;; CHECK-NEXT: (call_indirect $t (type $const-type)
148142
;; CHECK-NEXT: (i32.const 0)
149143
;; CHECK-NEXT: )
150144
;; CHECK-NEXT: )
151-
;; CHECK-NEXT: (local.get $x)
145+
;; CHECK-NEXT: (global.get $g)
152146
;; CHECK-NEXT: )
153147
(func $read-g-with-call-indirect-in-between (result i32)
154148
(local $x i32)

0 commit comments

Comments
 (0)