| /* | |
| * Copyright 2024 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. | |
| */ | |
| // | |
| // DebugLocationPropagation aim to pass debug location from parents or | |
| // previous siblings to expression which has no debug location. This is | |
| // useful for compilers that use Binaryen API to generate WebAssembly modules. | |
| // | |
| #include "pass.h" | |
| #include "wasm-traversal.h" | |
| #include "wasm.h" | |
| #include <cassert> | |
| #include <unordered_map> | |
| namespace wasm { | |
| struct DebugLocationPropagation | |
| : WalkerPass<PostWalker<DebugLocationPropagation>> { | |
| // The top element of this stack is the previous sibling or parent of the | |
| // current expression in `doPrevisit`. To maintain this invariant, expressions | |
| // are only popped once we are done visiting their parents. | |
| ExpressionStack expressionStack; | |
| using Super = WalkerPass<PostWalker<DebugLocationPropagation>>; | |
| bool isFunctionParallel() override { return true; } | |
| bool modifiesBinaryenIR() override { return false; } | |
| bool requiresNonNullableLocalFixups() override { return false; } | |
| void runOnFunction(Module* module, Function* func) override { | |
| if (!func->debugLocations.empty()) { | |
| Super::runOnFunction(module, func); | |
| } | |
| } | |
| Expression* getPrevious() { | |
| if (expressionStack.empty()) { | |
| return nullptr; | |
| } | |
| assert(expressionStack.size() >= 1); | |
| return expressionStack[expressionStack.size() - 1]; | |
| } | |
| static void doPreVisit(DebugLocationPropagation* self, Expression** currp) { | |
| auto* curr = *currp; | |
| auto& locs = self->getFunction()->debugLocations; | |
| auto& expressionStack = self->expressionStack; | |
| if (locs.find(curr) == locs.end()) { | |
| // No debug location, see if we should inherit one. | |
| if (auto* previous = self->getPrevious()) { | |
| if (auto it = locs.find(previous); it != locs.end()) { | |
| locs[curr] = it->second; | |
| } | |
| } else if (self->getFunction()->prologLocation) { | |
| // Instructions may inherit their locations from the function | |
| // prolog. | |
| locs[curr] = *self->getFunction()->prologLocation; | |
| } | |
| } | |
| expressionStack.push_back(curr); | |
| } | |
| static void doPostVisit(DebugLocationPropagation* self, Expression** currp) { | |
| auto& exprStack = self->expressionStack; | |
| while (exprStack.back() != *currp) { | |
| // pop all the child expressions and keep current expression in stack. | |
| exprStack.pop_back(); | |
| } | |
| // the stack should never be empty | |
| assert(!exprStack.empty()); | |
| } | |
| static void scan(DebugLocationPropagation* self, Expression** currp) { | |
| self->pushTask(DebugLocationPropagation::doPostVisit, currp); | |
| PostWalker<DebugLocationPropagation>::scan(self, currp); | |
| self->pushTask(DebugLocationPropagation::doPreVisit, currp); | |
| } | |
| std::unique_ptr<Pass> create() override { | |
| return std::make_unique<DebugLocationPropagation>(); | |
| } | |
| }; | |
| Pass* createDebugLocationPropagationPass() { | |
| return new DebugLocationPropagation(); | |
| } | |
| } // namespace wasm |