/* * 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 #include namespace wasm { struct DebugLocationPropagation : WalkerPass> { // 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>; 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::scan(self, currp); self->pushTask(DebugLocationPropagation::doPreVisit, currp); } std::unique_ptr create() override { return std::make_unique(); } }; Pass* createDebugLocationPropagationPass() { return new DebugLocationPropagation(); } } // namespace wasm