Skip to content
Merged
Changes from 1 commit
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
f6bd1b0
work
kripken Jun 5, 2024
dd673f8
note
kripken Jun 6, 2024
3232bae
note
kripken Jun 6, 2024
4517e55
Merge remote-tracking branch 'origin/main' into mono.moar
kripken Jun 11, 2024
d47f4c2
Merge remote-tracking branch 'origin/main' into mono.moar
kripken Jun 27, 2024
c876ff5
comments
kripken Jun 27, 2024
f804c95
comments
kripken Jun 27, 2024
6817d67
comments
kripken Jun 27, 2024
7c975c3
work
kripken Jun 27, 2024
38488b9
work
kripken Jun 27, 2024
0877c0a
work
kripken Jun 27, 2024
bc47504
work
kripken Jul 1, 2024
a8fbc5e
format
kripken Jul 1, 2024
a11b9d3
Merge remote-tracking branch 'origin/main' into mono.moar
kripken Jul 1, 2024
38ab29a
work
kripken Jul 1, 2024
3339ef7
work
kripken Jul 1, 2024
d978b55
work
kripken Jul 1, 2024
52ad9f0
work
kripken Jul 1, 2024
e428820
work
kripken Jul 1, 2024
996a95d
bad
kripken Jul 1, 2024
2aa99fa
work
kripken Jul 1, 2024
235c5fd
work
kripken Jul 1, 2024
9bb4af5
work
kripken Jul 1, 2024
7ca4545
work
kripken Jul 1, 2024
4d04aea
work
kripken Jul 1, 2024
e26d753
work
kripken Jul 1, 2024
e48ebb8
work
kripken Jul 1, 2024
a669e47
work
kripken Jul 1, 2024
1d598ef
work
kripken Jul 1, 2024
aaacb45
work
kripken Jul 1, 2024
21a879f
work
kripken Jul 1, 2024
71f3d43
test
kripken Jul 2, 2024
1b7b27b
test
kripken Jul 2, 2024
b52f1ff
test
kripken Jul 2, 2024
91c6143
test
kripken Jul 2, 2024
27bbb77
test
kripken Jul 2, 2024
bdf8250
work
kripken Jul 2, 2024
9c7a6d6
test
kripken Jul 2, 2024
3b50f1b
almost
kripken Jul 2, 2024
8ef96f7
work
kripken Jul 2, 2024
5afbd14
work
kripken Jul 2, 2024
4867379
moar
kripken Jul 2, 2024
3a72b38
work
kripken Jul 2, 2024
e9505a0
work
kripken Jul 2, 2024
c3dca8b
work
kripken Jul 2, 2024
90e7ebb
work
kripken Jul 2, 2024
baca207
work
kripken Jul 2, 2024
c2a1dbd
work
kripken Jul 2, 2024
aca108c
work
kripken Jul 2, 2024
9c2d3fa
work
kripken Jul 2, 2024
b4933b2
work
kripken Jul 3, 2024
62fb4eb
work
kripken Jul 3, 2024
4742228
work
kripken Jul 3, 2024
8bb827f
work
kripken Jul 3, 2024
6bedb13
fix
kripken Jul 3, 2024
d24bb59
format
kripken Jul 3, 2024
cb50b7c
Merge remote-tracking branch 'origin/main' into mono.moar
kripken Jul 3, 2024
2091277
work
kripken Jul 3, 2024
8ddbc3e
work
kripken Jul 3, 2024
d781015
work
kripken Jul 3, 2024
2aa8509
work
kripken Jul 3, 2024
b4f6a41
work
kripken Jul 3, 2024
b3fce26
work
kripken Jul 3, 2024
a3b8153
fix
kripken Jul 3, 2024
57da116
fix test
kripken Jul 3, 2024
533e849
format
kripken Jul 3, 2024
decabfb
Merge remote-tracking branch 'myself/mono.moar' into mono.moar
kripken Jul 10, 2024
0a8e2ab
feedback: move cheaper check earlier
kripken Jul 10, 2024
649e8ad
feedback: TODO for global.get etc.
kripken Jul 10, 2024
b6cfd63
feedback: rename debug method
kripken Jul 10, 2024
e8df956
format
kripken Jul 10, 2024
d32d44a
feedback: improve TODO
kripken Jul 10, 2024
89b6bd4
feedback: remove second copy of function body
kripken Jul 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
work
  • Loading branch information
kripken committed Jul 1, 2024
commit 2aa99fa8a9c45339f49ddb9490b5dacc65983cd1
101 changes: 50 additions & 51 deletions src/passes/Monomorphize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,51 @@ struct CallContext {

bool operator!=(const CallContext& other) const { return !(*this == other); }

// Build the context from a given call. This builds up the generalized
// parameters as explained in the comments above, and generates the new
// operands for the call to have (through the out param).
void buildFromCall(Call* call, std::vector<Expression*>& newOperands, Module& wasm) {
Builder builder(wasm);

for (auto* operand : call->operands) {
// Process the operand, generating the generalized one. This is a copy
// operation, as so long as we find things that we can "reverse-inline"
// into the called function as part of the call context then we continue
// to do so. When we cannot move code in that manner then we emit a
// local.get, as that is a new parameter.
operands.push_back(ExpressionManipulator::flexibleCopy(
operand, wasm, [&](Expression* child) -> Expression* {
if (canBeMovedIntoContext(child)) {
// This can be moved, great: let the copy happen.
return nullptr;
}

// This cannot be moved, so we stop here: this is a value that is sent
// into the monomorphized function. It is a new operand in the call,
// and in the context operands it is a local.get, that reads that
// value.
auto paramIndex = newOperands.size();
newOperands.push_back(child);
// TODO: If one operand is a tee and another a get, we could actually
// reuse the local, effectively showing the monomorphized
// function that the values are the same.
return builder.makeLocalGet(paramIndex, child->type);
}));
}

// TODO: handle drop
dropped = false;
}

// Checks whether an expression can be moved into the context. Things that can
// be, become part of the context, and so they become part of the refined
// functions that we create with the context.
bool canBeMovedIntoContext(Expression* curr) {
// Constant numbers, funcs, strings, etc. can all be copied, so it is ok to
// add them to the context.
return Properties::isSingleConstantExpression(curr);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this is not true for constant global.get, but that might be good to include as well.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, yeah, this could capture anything "copyable" really. I added a TODO.

}

// Check if a context is trivial relative to a call, that is, the context
// contains no information that can allow optimization at all. Such contexts
// can be dismissed early.
Expand Down Expand Up @@ -281,45 +326,11 @@ struct Monomorphize : public Pass {

// TODO: igmore calls with unreachable operands for simplicty

Builder builder(wasm);

// Compute the call context. This builds up the generalized parameters as
// explained in the comments on CallContext, and sets up the operands for
// the new call (which may have less, more, or different parameters than the
// original).
// TODO: make this a helper func on CallContext, returning newOperands
// Compute the call context.
CallContext context;
std::vector<Expression*> newOperands;
// auto params = func->getParams();
for (auto* operand : call->operands) {
// Process the operand, generating the generalized one. This is a copy
// operation, as so long as we find things that we can "reverse-inline"
// into the called function as part of the call context then we continue
// to do so. When we cannot move code in that manner then we emit a
// local.get, as that is a new parameter.
context.operands.push_back(ExpressionManipulator::flexibleCopy(
operand, wasm, [&](Expression* child) -> Expression* {
if (canBeMovedIntoContext(child)) {
// This can be moved, great: let the copy happen.
return nullptr;
}

// This cannot be moved, so we stop here: this is a value that is sent
// into the monomorphized function. It is a new operand in the call,
// and in the context operands it is a local.get, that reads that
// value.
auto paramIndex = newOperands.size();
newOperands.push_back(child);
// TODO: If one operand is a tee and another a get, we could actually
// reuse the local, effectively showing the monomorphized
// function that the values are the same.
return builder.makeLocalGet(paramIndex, child->type);
}));
}

// TODO: handle drop
context.dropped = false;

context.buildFromCall(call, newOperands, wasm);

// See if we've already computed this call context.
auto iter = funcContextMap.find({target, context});
if (iter != funcContextMap.end()) {
Expand All @@ -334,11 +345,8 @@ struct Monomorphize : public Pass {
return;
}

// This is the first time we see this situation. Let's see if it is worth
// monomorphizing.

// Check if it the context is trivial and has no opportunities for
// optimization.
// This is the first time we see this situation. Firs, check if it the
// context is trivial and has no opportunities for optimization.
if (context.isTrivial(call)) {
// Memoize the failure, and stop.
funcContextMap[{target, context}] = target;
Expand Down Expand Up @@ -511,15 +519,6 @@ struct Monomorphize : public Pass {
runner.runOnFunction(func);
}

// Checks whether an expression can be moved into the context. Things that can
// be, become part of the context, and so they become part of the refined
// functions that we create with the context.
bool canBeMovedIntoContext(Expression* curr) {
// Constant numbers, funcs, strings, etc. can all be copied, so it is ok to
// add them to the context.
return Properties::isSingleConstantExpression(curr);
}

// Maps [func name, call info] to the name of a new function which is
// specialized to that call info.
//
Expand Down