diff options
author | Alon Zakai <azakai@google.com> | 2019-06-07 11:05:30 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-06-07 11:05:30 -0700 |
commit | cac94c5aece24855c2d8cdc73e75f7f5abb29cd2 (patch) | |
tree | dae61541d5d48a4714037bc3a4c138e8666496e6 /src | |
parent | 5f252c3a6c2129a3f86e00401806b74bc2f266df (diff) | |
download | binaryen-cac94c5aece24855c2d8cdc73e75f7f5abb29cd2.tar.gz binaryen-cac94c5aece24855c2d8cdc73e75f7f5abb29cd2.tar.bz2 binaryen-cac94c5aece24855c2d8cdc73e75f7f5abb29cd2.zip |
Copy debug info when inlining (#2168)
Diffstat (limited to 'src')
-rw-r--r-- | src/ir/debug.h | 59 | ||||
-rw-r--r-- | src/passes/Inlining.cpp | 17 |
2 files changed, 70 insertions, 6 deletions
diff --git a/src/ir/debug.h b/src/ir/debug.h new file mode 100644 index 000000000..d4ecf2b70 --- /dev/null +++ b/src/ir/debug.h @@ -0,0 +1,59 @@ +/* + * 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_debug_h +#define wasm_ir_debug_h + +#include <wasm-traversal.h> + +namespace wasm { + +namespace debug { + +// Given an expression and a copy of it in another function, copy the debug +// info into the second function. +inline void copyDebugInfo(Expression* origin, + Expression* copy, + Function* originFunc, + Function* copyFunc) { + struct Lister : public PostWalker<Lister, UnifiedExpressionVisitor<Lister>> { + std::vector<Expression*> list; + void visitExpression(Expression* curr) { list.push_back(curr); } + }; + + Lister originList; + originList.walk(origin); + Lister copyList; + copyList.walk(copy); + + auto& originDebug = originFunc->debugLocations; + auto& copyDebug = copyFunc->debugLocations; + + assert(originList.list.size() == copyList.list.size()); + for (Index i = 0; i < originList.list.size(); i++) { + auto iter = originDebug.find(originList.list[i]); + if (iter != originDebug.end()) { + auto location = iter->second; + copyDebug[copyList.list[i]] = location; + } + } +}; + +} // namespace debug + +} // namespace wasm + +#endif // wasm_ir_debug_h diff --git a/src/passes/Inlining.cpp b/src/passes/Inlining.cpp index 5ed68a783..2aa800d62 100644 --- a/src/passes/Inlining.cpp +++ b/src/passes/Inlining.cpp @@ -32,6 +32,7 @@ #include <atomic> +#include "ir/debug.h" #include "ir/literal-utils.h" #include "ir/module-utils.h" #include "ir/utils.h" @@ -175,7 +176,7 @@ doInlining(Module* module, Function* into, InliningAction& action) { auto* block = Builder(*module).makeBlock(); block->name = Name(std::string("__inlined_func$") + from->name.str); *action.callSite = block; - // set up a locals mapping + // Prepare to update the inlined code's locals and other things. struct Updater : public PostWalker<Updater> { std::map<Index, Index> localMapping; Name returnName; @@ -193,33 +194,37 @@ doInlining(Module* module, Function* into, InliningAction& action) { } updater; updater.returnName = block->name; updater.builder = &builder; + // Set up a locals mapping for (Index i = 0; i < from->getNumLocals(); i++) { updater.localMapping[i] = builder.addVar(into, from->getLocalType(i)); } - // assign the operands into the params + // Assign the operands into the params for (Index i = 0; i < from->params.size(); i++) { block->list.push_back( builder.makeLocalSet(updater.localMapping[i], call->operands[i])); } - // zero out the vars (as we may be in a loop, and may depend on their + // Zero out the vars (as we may be in a loop, and may depend on their // zero-init value for (Index i = 0; i < from->vars.size(); i++) { block->list.push_back( builder.makeLocalSet(updater.localMapping[from->getVarIndexBase() + i], LiteralUtils::makeZero(from->vars[i], *module))); } - // generate and update the inlined contents + // Generate and update the inlined contents auto* contents = ExpressionManipulator::copy(from->body, *module); + if (!from->debugLocations.empty()) { + debug::copyDebugInfo(from->body, contents, from, into); + } updater.walk(contents); block->list.push_back(contents); block->type = call->type; - // if the function returned a value, we just set the block containing the + // If the function returned a value, we just set the block containing the // inlined code to have that type. or, if the function was void and // contained void, that is fine too. a bad case is a void function in which // we have unreachable code, so we would be replacing a void call with an // unreachable; we need to handle if (contents->type == unreachable && block->type == none) { - // make the block reachable by adding a break to it + // Make the block reachable by adding a break to it block->list.push_back(builder.makeBreak(block->name)); } return block; |