1
1
2
+ #include " ir/properties.h"
2
3
#include " pass.h"
3
4
#include " wasm-traversal.h"
4
5
#include " wasm.h"
6
+ #include < stack>
5
7
#include < vector>
6
8
7
9
namespace wasm {
8
10
9
11
namespace {
10
12
11
13
struct Finder : TryDepthWalker<Finder> {
14
+ explicit Finder (const PassOptions& passOptions)
15
+ : TryDepthWalker<Finder>(), passOptions(passOptions) {}
16
+ const PassOptions& passOptions;
12
17
std::vector<Call*> tailCalls;
13
18
std::vector<CallIndirect*> tailCallIndirects;
14
- void visitFunction (Function* curr) { checkTailCall (curr->body ); }
15
- void visitReturn (Return* curr) { checkTailCall (curr->value ); }
16
-
17
- private:
18
- void checkTailCall (Expression* expr) {
19
- if (expr == nullptr ) {
19
+ void visitFunction (Function* curr) {
20
+ if (passOptions.shrinkLevel > 0 && passOptions.optimizeLevel == 0 ) {
21
+ // When we more force on the binary size, add return_call will increase
22
+ // the code size.
20
23
return ;
21
24
}
25
+ checkTailCall (curr->body );
26
+ }
27
+ void visitReturn (Return* curr) {
22
28
if (tryDepth > 0 ) {
23
- // We are in a try block, so we cannot optimize tail calls.
24
- return ;
25
- }
26
- if (auto * call = expr->dynCast <Call>()) {
27
- if (!call->isReturn && call->type == getFunction ()->getResults ()) {
28
- tailCalls.push_back (call);
29
- }
30
- return ;
31
- }
32
- if (auto * call = expr->dynCast <CallIndirect>()) {
33
- if (!call->isReturn && call->type == getFunction ()->getResults ()) {
34
- tailCallIndirects.push_back (call);
35
- }
36
- return ;
37
- }
38
- if (auto * block = expr->dynCast <Block>()) {
39
- return checkTailCall (block->list );
40
- }
41
- if (auto * ifElse = expr->dynCast <If>()) {
42
- checkTailCall (ifElse->ifTrue );
43
- checkTailCall (ifElse->ifFalse );
29
+ // (return (call ...)) is not equal to (return_call ...) in try block
44
30
return ;
45
31
}
32
+ checkTailCall (curr->value );
46
33
}
47
- void checkTailCall (ExpressionList const & exprs) {
48
- if (exprs.empty ()) {
49
- return ;
34
+
35
+ private:
36
+ void checkTailCall (Expression* const curr) {
37
+ std::stack<Expression*> workList{};
38
+ workList.push (curr);
39
+ while (!workList.empty ()) {
40
+ Expression* const target = workList.top ();
41
+ workList.pop ();
42
+ if (auto * call = target->dynCast <Call>()) {
43
+ if (!call->isReturn && call->type == getFunction ()->getResults ()) {
44
+ tailCalls.push_back (call);
45
+ }
46
+ } else if (auto * call = target->dynCast <CallIndirect>()) {
47
+ if (!call->isReturn && call->type == getFunction ()->getResults ()) {
48
+ tailCallIndirects.push_back (call);
49
+ }
50
+ } else if (auto * ifElse = target->dynCast <If>()) {
51
+ workList.push (ifElse->ifTrue );
52
+ workList.push (ifElse->ifFalse );
53
+ } else {
54
+ Expression* const next = Properties::getImmediateFallthrough (
55
+ target, passOptions, *getModule ());
56
+ if (next != target) {
57
+ workList.push (next);
58
+ }
59
+ }
50
60
}
51
- checkTailCall (exprs.back ());
52
- return ;
53
61
}
54
62
};
55
63
@@ -64,7 +72,7 @@ struct TailCallOptimizer : public Pass {
64
72
if (!module ->features .hasTailCall ()) {
65
73
return ;
66
74
}
67
- Finder finder{};
75
+ Finder finder{getPassOptions () };
68
76
finder.walkFunctionInModule (function, module );
69
77
for (Call* call : finder.tailCalls ) {
70
78
if (!call->isReturn ) {
0 commit comments