summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2023-11-14 19:09:49 -0800
committerGitHub <noreply@github.com>2023-11-14 19:09:49 -0800
commit20fe882b47c4b2570c70b2f9d82189c5b2144d03 (patch)
tree51eb6b6b63ccfecf21d732dc682cee646272947f /src
parent001be441be8ec04df0b03035aefc411923485780 (diff)
downloadbinaryen-20fe882b47c4b2570c70b2f9d82189c5b2144d03.tar.gz
binaryen-20fe882b47c4b2570c70b2f9d82189c5b2144d03.tar.bz2
binaryen-20fe882b47c4b2570c70b2f9d82189c5b2144d03.zip
SignatureRefining: Notice LUB requirements of intrinsic calls (#6122)
call.without.effects implies a call to the function reference in the last parameter, so the values sent in the other parameters must be taken into account when computing LUBs for refining arguments, otherwise we might refine so much that the intrinsic call no longer validates.
Diffstat (limited to 'src')
-rw-r--r--src/passes/SignatureRefining.cpp26
1 files changed, 26 insertions, 0 deletions
diff --git a/src/passes/SignatureRefining.cpp b/src/passes/SignatureRefining.cpp
index 24d120dda..ae124dc79 100644
--- a/src/passes/SignatureRefining.cpp
+++ b/src/passes/SignatureRefining.cpp
@@ -73,6 +73,15 @@ struct SignatureRefining : public Pass {
std::vector<Call*> calls;
std::vector<CallRef*> callRefs;
+ // Additional calls to take into account. We store intrinsic calls here,
+ // as they must appear twice: call.without.effects is both a normal call
+ // and also takes a final parameter that is a function reference that is
+ // called, and so two signatures are relevant for it. For the latter, we
+ // add the call as an "extra call" (which is an unusual call, as it has an
+ // extra parameter at the end, the function reference, compared to what we
+ // expect for the signature being called).
+ std::vector<Call*> extraCalls;
+
// A possibly improved LUB for the results.
LUBFinder resultsLUB;
@@ -107,6 +116,17 @@ struct SignatureRefining : public Pass {
// called.
for (auto* call : info.calls) {
allInfo[module->getFunction(call->target)->type].calls.push_back(call);
+
+ // For call.without.effects, we also add the effective function being
+ // called as well. The final operand is the function reference being
+ // called, which defines that type.
+ if (Intrinsics(*module).isCallWithoutEffects(call)) {
+ auto targetType = call->operands.back()->type;
+ if (!targetType.isRef()) {
+ continue;
+ }
+ allInfo[targetType.getHeapType()].extraCalls.push_back(call);
+ }
}
// For indirect calls, add each call_ref to the type the call_ref uses.
@@ -187,6 +207,12 @@ struct SignatureRefining : public Pass {
for (auto* callRef : info.callRefs) {
updateLUBs(callRef->operands);
}
+ for (auto* call : info.extraCalls) {
+ // Note that these intrinsic calls have an extra function reference
+ // param at the end, but updateLUBs looks at |numParams| only, so it
+ // considers just the relevant parameters.
+ updateLUBs(call->operands);
+ }
// Find the final LUBs, and see if we found an improvement.
std::vector<Type> newParamsTypes;