summaryrefslogtreecommitdiff
path: root/src/passes/GlobalEffects.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/passes/GlobalEffects.cpp')
-rw-r--r--src/passes/GlobalEffects.cpp101
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