| /* | |
| * Copyright 2022 WebAssembly Community Group participants | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #ifndef wasm_pass_param_utils_h | |
| #define wasm_pass_param_utils_h | |
| #include "pass.h" | |
| #include "support/sorted_vector.h" | |
| #include "wasm.h" | |
| // Helper code for passes that manipulate function parameters, specifically | |
| // checking if they are used and removing them if so. This is closely tied to | |
| // the internals of those passes, and so is not in /ir/ (it would be inside the | |
| // pass .cpp file, but there is more than one). | |
| namespace wasm::ParamUtils { | |
| // Find which parameters are actually used in the function, that is, that the | |
| // values arriving in the parameter are read. This ignores values set in the | |
| // function, like this: | |
| // | |
| // function foo(x) { | |
| // x = 10; | |
| // bar(x); // read of a param index, but not the param value passed in. | |
| // } | |
| // | |
| // This is an actual use: | |
| // | |
| // function foo(x) { | |
| // bar(x); // read of a param value | |
| // } | |
| std::unordered_set<Index> getUsedParams(Function* func, Module* module); | |
| // The outcome of an attempt to remove a parameter(s). | |
| enum RemovalOutcome { | |
| // We removed successfully. | |
| Success = 0, | |
| // We failed, but only because of fixable nested effects. The caller can move | |
| // those effects out (e.g. using ChildLocalizer, or the helper localizeCallsTo | |
| // below) and repeat. | |
| Failure = 1, | |
| }; | |
| // Try to remove a parameter from a set of functions and replace it with a local | |
| // instead. This may not succeed if the parameter type cannot be used in a | |
| // local, or if we hit another limitation, in which case this returns false and | |
| // does nothing. If we succeed then the parameter is removed both from the | |
| // functions and from the calls to it, which are passed in (the caller must | |
| // ensure to pass in all relevant calls and call_refs). | |
| // | |
| // This does not check if removing the parameter would change the semantics | |
| // (say, if the parameter's value is used), which the caller is assumed to do. | |
| // | |
| // This assumes that the set of functions all have the same signature. The main | |
| // use cases are either to send a single function, or to send a set of functions | |
| // that all have the same heap type (and so if they all do not use some | |
| // parameter, it can be removed from them all). | |
| // | |
| // This does *not* update the types in call_refs. It is assumed that the caller | |
| // will be updating types, which is simpler as there may be other locations that | |
| // need adjusting and it is easier to do it all in one place. Also, the caller | |
| // can update all the types at once throughout the program after making | |
| // multiple calls to removeParameter(). | |
| RemovalOutcome removeParameter(const std::vector<Function*>& funcs, | |
| Index index, | |
| const std::vector<Call*>& calls, | |
| const std::vector<CallRef*>& callRefs, | |
| Module* module, | |
| PassRunner* runner); | |
| // The same as removeParameter, but gets a sorted list of indexes. It tries to | |
| // remove them all, and returns which we removed, as well as an indication as | |
| // to whether we might remove more if effects were not in the way (specifically, | |
| // we return Success if we removed any index, Failure if we removed none, and | |
| // FailureDueToEffects if at least one index could have been removed but for | |
| // effects). | |
| std::pair<SortedVector<Index>, RemovalOutcome> | |
| removeParameters(const std::vector<Function*>& funcs, | |
| SortedVector<Index> indexes, | |
| const std::vector<Call*>& calls, | |
| const std::vector<CallRef*>& callRefs, | |
| Module* module, | |
| PassRunner* runner); | |
| // Given a set of functions and the calls and call_refs that reach them, find | |
| // which parameters are passed the same constant value in all the calls. For | |
| // each such parameter, apply it inside the function, that is, do a local.set of | |
| // that value in the function. The parameter's incoming value is then ignored, | |
| // which allows other optimizations to remove it. | |
| // | |
| // Returns the indexes that were optimized. | |
| SortedVector<Index> applyConstantValues(const std::vector<Function*>& funcs, | |
| const std::vector<Call*>& calls, | |
| const std::vector<CallRef*>& callRefs, | |
| Module* module); | |
| // Helper that localizes all calls to a set of targets, in an entire module. | |
| // This basically calls ChildLocalizer in each function, on the relevant calls. | |
| // This is useful when we get FailureDueToEffects, see above. | |
| // | |
| // The set of targets can be function names (the individual functions we want to | |
| // handle calls towards) or heap types (which will then include all functions | |
| // with those types). | |
| // | |
| // The onChange() callback is called when we modify a function. | |
| void localizeCallsTo(const std::unordered_set<Name>& callTargets, | |
| Module& wasm, | |
| PassRunner* runner, | |
| std::function<void(Function*)> onChange); | |
| void localizeCallsTo(const std::unordered_set<HeapType>& callTargets, | |
| Module& wasm, | |
| PassRunner* runner); | |
| } // namespace wasm::ParamUtils | |
| #endif // wasm_pass_param_utils_h |