| /* |
| * 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_ir_drop_h |
| #define wasm_ir_drop_h |
| |
| #include "ir/branch-utils.h" |
| #include "ir/effects.h" |
| #include "ir/iteration.h" |
| #include "wasm-builder.h" |
| #include "wasm.h" |
| |
| namespace wasm { |
| |
| // Given an expression, returns a new expression that drops the given |
| // expression's children that cannot be removed outright due to their side |
| // effects. Note that this only operates on children that execute |
| // unconditionally. That is the case in almost all expressions, except for those |
| // with conditional execution, like if, which unconditionally executes the |
| // condition but then conditionally executes one of the two arms. |
| Expression* getDroppedChildrenAndAppend(Expression* curr, |
| Module& wasm, |
| const PassOptions& options, |
| Expression* last) { |
| // We check for shallow effects here, since we may be able to remove |curr| |
| // itself but keep its children around - we don't want effects in the children |
| // to stop us from improving the code. Note that there are cases where the |
| // combined curr+children has fewer effects than curr itself, such as if curr |
| // is a block and the child branches to it, but in such cases we cannot remove |
| // curr anyhow (those cases are ruled out below), so looking at non-shallow |
| // effects would never help us (and would be slower to run). |
| ShallowEffectAnalyzer effects(options, wasm, curr); |
| // Ignore a trap, as the unreachable replacement would trap too. |
| if (last->is<Unreachable>()) { |
| effects.trap = false; |
| } |
| |
| // We cannot remove |
| // 1. Expressions with unremovable side effects |
| // 2. if: 'if's contains conditional expressions |
| // 3. try: Removing a try could leave a pop without a proper parent |
| // 4. pop: Pops are struturally necessary in catch bodies |
| // 5. Branch targets: We will need the target for the branches to it to |
| // validate. |
| Builder builder(wasm); |
| if (effects.hasUnremovableSideEffects() || curr->is<If>() || |
| curr->is<Try>() || curr->is<Pop>() || |
| BranchUtils::getDefinedName(curr).is()) { |
| return builder.makeSequence(builder.makeDrop(curr), last); |
| } |
| |
| std::vector<Expression*> contents; |
| for (auto* child : ChildIterator(curr)) { |
| if (!EffectAnalyzer(options, wasm, child).hasUnremovableSideEffects()) { |
| continue; |
| } |
| if (child->type.isConcrete()) { |
| contents.push_back(builder.makeDrop(child)); |
| } else { |
| // The child is unreachable, or none (none is possible as a child of a |
| // block or loop, etc.); in both cases we do not need a drop. |
| contents.push_back(child); |
| } |
| } |
| if (contents.empty()) { |
| return last; |
| } |
| contents.push_back(last); |
| return builder.makeBlock(contents); |
| } |
| |
| } // namespace wasm |
| |
| #endif // wasm_ir_drop_h |