| /* |
| * Copyright 2019 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_ir_local_utils_h |
| #define wasm_ir_local_utils_h |
| |
| #include <ir/effects.h> |
| #include <ir/manipulation.h> |
| #include <ir/utils.h> |
| |
| namespace wasm { |
| |
| struct LocalGetCounter : public PostWalker<LocalGetCounter> { |
| std::vector<Index> num; |
| |
| LocalGetCounter() = default; |
| LocalGetCounter(Function* func) { analyze(func, func->body); } |
| LocalGetCounter(Function* func, Expression* ast) { analyze(func, ast); } |
| |
| void analyze(Function* func) { analyze(func, func->body); } |
| void analyze(Function* func, Expression* ast) { |
| num.clear(); |
| num.resize(func->getNumLocals()); |
| walk(ast); |
| } |
| |
| void visitLocalGet(LocalGet* curr) { num[curr->index]++; } |
| }; |
| |
| // Removes trivially unneeded sets: sets for whom there is no possible get, and |
| // sets of the same value immediately. |
| struct UnneededSetRemover : public PostWalker<UnneededSetRemover> { |
| PassOptions& passOptions; |
| |
| LocalGetCounter* localGetCounter = nullptr; |
| Module& module; |
| |
| UnneededSetRemover(Function* func, PassOptions& passOptions, Module& module) |
| : passOptions(passOptions), module(module) { |
| LocalGetCounter counter(func); |
| UnneededSetRemover inner(counter, func, passOptions, module); |
| removed = inner.removed; |
| } |
| |
| UnneededSetRemover(LocalGetCounter& localGetCounter, |
| Function* func, |
| PassOptions& passOptions, |
| Module& module) |
| : passOptions(passOptions), localGetCounter(&localGetCounter), |
| module(module) { |
| walk(func->body); |
| |
| if (refinalize) { |
| ReFinalize().walkFunctionInModule(func, &module); |
| } |
| } |
| |
| bool removed = false; |
| bool refinalize = false; |
| |
| void visitLocalSet(LocalSet* curr) { |
| // If no possible uses, remove. |
| if (localGetCounter->num[curr->index] == 0) { |
| remove(curr); |
| } |
| // If setting the same value as we already have, remove. |
| auto* value = curr->value; |
| while (true) { |
| if (auto* set = value->dynCast<LocalSet>()) { |
| if (set->index == curr->index) { |
| remove(curr); |
| } else { |
| // Handle tee chains. |
| value = set->value; |
| continue; |
| } |
| } else if (auto* get = value->dynCast<LocalGet>()) { |
| if (get->index == curr->index) { |
| remove(curr); |
| } |
| } |
| break; |
| } |
| } |
| |
| void remove(LocalSet* set) { |
| auto* value = set->value; |
| if (set->isTee()) { |
| replaceCurrent(value); |
| if (value->type != set->type) { |
| // The value is more refined, so we'll need to refinalize. |
| refinalize = true; |
| } |
| } else if (EffectAnalyzer(passOptions, module, set->value) |
| .hasSideEffects()) { |
| Drop* drop = ExpressionManipulator::convert<LocalSet, Drop>(set); |
| drop->value = value; |
| drop->finalize(); |
| } else { |
| ExpressionManipulator::nop(set); |
| } |
| removed = true; |
| } |
| }; |
| |
| } // namespace wasm |
| |
| #endif // wasm_ir_local_utils_h |