diff options
Diffstat (limited to 'src/passes/GlobalEffects.cpp')
-rw-r--r-- | src/passes/GlobalEffects.cpp | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/src/passes/GlobalEffects.cpp b/src/passes/GlobalEffects.cpp new file mode 100644 index 000000000..1dd91e5d7 --- /dev/null +++ b/src/passes/GlobalEffects.cpp @@ -0,0 +1,101 @@ +/* + * 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. + */ + +// +// Handle the computation of global effects. The effects are stored on the +// PassOptions structure; see more details there. +// + +#include "ir/module-utils.h" +#include "pass.h" +#include "wasm.h" + +namespace wasm { + +struct GenerateGlobalEffects : public Pass { + void run(PassRunner* runner, Module* module) override { + // TODO: Full transitive closure of effects. For now, we just look at each + // function by itself. + + auto& funcEffectsMap = runner->options.funcEffectsMap; + + // First, clear any previous effects. + funcEffectsMap.reset(); + + // When we find useful effects, we'll save them. If we can't find anything, + // the final map we emit will not have an entry there at all. + using PossibleEffects = std::unique_ptr<EffectAnalyzer>; + + ModuleUtils::ParallelFunctionAnalysis<PossibleEffects> analysis( + *module, [&](Function* func, PossibleEffects& storedEffects) { + if (func->imported()) { + // Imports can do anything, so we need to assume the worst anyhow, + // which is the same as not specifying any effects for them in the + // map. + return; + } + + // Gather the effects. + auto effects = std::make_unique<EffectAnalyzer>( + runner->options, *module, func->body); + + // If the body has a call, give up - that means we can't infer a more + // specific set of effects than the pessimistic case of just assuming + // any call to here is an arbitrary call. (See the TODO above for + // improvements.) + if (effects->calls) { + return; + } + + // We can ignore branching out of the function body - this can only be + // a return, and that is only noticeable in the function, not outside. + effects->branchesOut = false; + + // Ignore local effects - when the function exits, those become + // unnoticeable anyhow. + effects->localsWritten.clear(); + effects->localsRead.clear(); + + // Save the useful effects we found. + storedEffects = std::move(effects); + }); + + // Generate the final data structure. + for (auto& [func, possibleEffects] : analysis.map) { + if (possibleEffects) { + // Only allocate a new funcEffectsMap if we actually have data for it + // (which might make later effect computation slightly faster, to + // quickly skip the funcEffectsMap code path). + if (!funcEffectsMap) { + funcEffectsMap = std::make_shared<FuncEffectsMap>(); + } + funcEffectsMap->emplace(func->name, *possibleEffects); + } + } + } +}; + +struct DiscardGlobalEffects : public Pass { + void run(PassRunner* runner, Module* module) override { + runner->options.funcEffectsMap.reset(); + } +}; + +Pass* createGenerateGlobalEffectsPass() { return new GenerateGlobalEffects(); } + +Pass* createDiscardGlobalEffectsPass() { return new DiscardGlobalEffects(); } + +} // namespace wasm |