Skip to content

Commit cb4046f

Browse files
Account for global effects in LinearExecutionWalker
1 parent 3ef8d19 commit cb4046f

2 files changed

Lines changed: 82 additions & 6 deletions

File tree

src/ir/linear-execution.h

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

83-
auto handleCall = [&](bool isReturn) {
83+
auto handleCall = [&](bool mayThrow, bool isReturn) {
8484
if (!self->connectAdjacentBlocks) {
85-
// Control is nonlinear if we return, or if EH is enabled or may be.
86-
if (isReturn || !self->getModule() ||
87-
self->getModule()->features.hasExceptionHandling()) {
85+
// Control is nonlinear if we return or throw.
86+
if (isReturn || !self->getModule() || mayThrow) {
8887
self->pushTask(SubType::doNoteNonLinear, currp);
8988
}
9089
}
@@ -153,11 +152,31 @@ struct LinearExecutionWalker : public PostWalker<SubType, VisitorType> {
153152
break;
154153
}
155154
case Expression::Id::CallId: {
156-
handleCall(curr->cast<Call>()->isReturn);
155+
auto* call = curr->cast<Call>();
156+
157+
bool mayThrow = !self->getModule() ||
158+
self->getModule()->features.hasExceptionHandling();
159+
if (mayThrow && self->getModule()) {
160+
auto* effects =
161+
self->getModule()->getFunction(call->target)->effects.get();
162+
163+
if (effects && !effects->throws_) {
164+
mayThrow = false;
165+
}
166+
}
167+
168+
handleCall(mayThrow, call->isReturn);
157169
return;
158170
}
159171
case Expression::Id::CallRefId: {
160-
handleCall(curr->cast<CallRef>()->isReturn);
172+
auto* callRef = curr->cast<CallRef>();
173+
174+
// TODO: Effect analysis for indirect calls isn't implemented yet.
175+
// Assume any indirect call my throw for now.
176+
bool mayThrow = !self->getModule() ||
177+
self->getModule()->features.hasExceptionHandling();
178+
179+
handleCall(mayThrow, callRef->isReturn);
161180
return;
162181
}
163182
case Expression::Id::TryId: {
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
2+
;; RUN: foreach %s %t wasm-opt --enable-exception-handling --generate-global-effects --simplify-locals -S -o - | filecheck %s
3+
4+
(module
5+
;; CHECK: (global $g (mut i32) (i32.const 0))
6+
7+
;; CHECK: (tag $t (type $0))
8+
(tag $t)
9+
10+
(global $g (mut i32) (i32.const 0))
11+
12+
;; CHECK: (func $nop
13+
;; CHECK-NEXT: )
14+
(func $nop
15+
)
16+
17+
;; CHECK: (func $throws
18+
;; CHECK-NEXT: (throw $t)
19+
;; CHECK-NEXT: )
20+
(func $throws
21+
(throw $t)
22+
)
23+
24+
;; CHECK: (func $read-g (result i32)
25+
;; CHECK-NEXT: (local $x i32)
26+
;; CHECK-NEXT: (nop)
27+
;; CHECK-NEXT: (call $nop)
28+
;; CHECK-NEXT: (global.get $g)
29+
;; CHECK-NEXT: )
30+
(func $read-g (result i32)
31+
(local $x i32)
32+
(local.set $x (global.get $g))
33+
34+
;; With --global-effects, we can tell that this doesn't throw, so it
35+
;; doesn't act as a barrier to optimize. The local is optimized away.
36+
(call $nop)
37+
(local.get $x)
38+
)
39+
40+
;; CHECK: (func $read-g-with-throw-in-between (result i32)
41+
;; CHECK-NEXT: (local $x i32)
42+
;; CHECK-NEXT: (local.set $x
43+
;; CHECK-NEXT: (global.get $g)
44+
;; CHECK-NEXT: )
45+
;; CHECK-NEXT: (call $throws)
46+
;; CHECK-NEXT: (local.get $x)
47+
;; CHECK-NEXT: )
48+
(func $read-g-with-throw-in-between (result i32)
49+
(local $x i32)
50+
(local.set $x (global.get $g))
51+
52+
;; A potential throw halts our optimizations.
53+
(call $throws)
54+
55+
(local.get $x)
56+
)
57+
)

0 commit comments

Comments
 (0)