diff options
author | Alon Zakai <azakai@google.com> | 2023-11-14 19:09:49 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-14 19:09:49 -0800 |
commit | 20fe882b47c4b2570c70b2f9d82189c5b2144d03 (patch) | |
tree | 51eb6b6b63ccfecf21d732dc682cee646272947f /src | |
parent | 001be441be8ec04df0b03035aefc411923485780 (diff) | |
download | binaryen-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.cpp | 26 |
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; |