diff options
-rw-r--r-- | src/parser/wat-parser.cpp | 55 | ||||
-rw-r--r-- | test/lit/wat-kitchen-sink.wast | 26 |
2 files changed, 81 insertions, 0 deletions
diff --git a/src/parser/wat-parser.cpp b/src/parser/wat-parser.cpp index 8675f4e36..5503a8295 100644 --- a/src/parser/wat-parser.cpp +++ b/src/parser/wat-parser.cpp @@ -19,6 +19,7 @@ #include "ir/names.h" #include "lexer.h" #include "parsers.h" +#include "pass.h" #include "wasm-type.h" #include "wasm.h" @@ -90,6 +91,58 @@ Result<> parseDefs(Ctx& ctx, return Ok{}; } +void propagateDebugLocations(Module& wasm) { + // Copy debug locations from parents or previous siblings to expressions that + // do not already have their own debug locations. + struct Propagator : WalkerPass<ExpressionStackWalker<Propagator>> { + using Super = WalkerPass<ExpressionStackWalker<Propagator>>; + 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); + } + } + + // Unannotated instructions inherit either their previous sibling's location + // or their parent's location. Look up whichever is current for a given + // parent. + std::unordered_map<Expression*, Function::DebugLocation> parentDefaults; + + static void doPreVisit(Propagator* self, Expression** currp) { + Super::doPreVisit(self, currp); + auto* curr = *currp; + auto& locs = self->getFunction()->debugLocations; + auto& parentDefaults = self->parentDefaults; + if (auto it = locs.find(curr); it != locs.end()) { + // Children will inherit this location. + parentDefaults[curr] = it->second; + if (auto* parent = self->getParent()) { + // Subsequent siblings will inherit this location. + parentDefaults[parent] = it->second; + } + } else { + // No annotation, see if we should inherit one. + if (auto* parent = self->getParent()) { + if (auto defaultIt = parentDefaults.find(parent); + defaultIt != parentDefaults.end()) { + // We have a default to inherit. Our children will inherit it, too. + locs[curr] = parentDefaults[curr] = defaultIt->second; + } + } + } + } + + std::unique_ptr<Pass> create() override { + return std::make_unique<Propagator>(); + } + }; + PassRunner runner(&wasm); + runner.add(std::make_unique<Propagator>()); + runner.run(); +} + // ================ // Parser Functions // ================ @@ -212,6 +265,8 @@ Result<> parseModule(Module& wasm, std::string_view input) { } } + propagateDebugLocations(wasm); + return Ok{}; } diff --git a/test/lit/wat-kitchen-sink.wast b/test/lit/wat-kitchen-sink.wast index 55bd87f2e..33f570702 100644 --- a/test/lit/wat-kitchen-sink.wast +++ b/test/lit/wat-kitchen-sink.wast @@ -5192,6 +5192,32 @@ end ) + ;; CHECK: (func $source-map-propagation (type $void) + ;; CHECK-NEXT: ;;@ src.cpp:20:1 + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.add + ;; CHECK-NEXT: ;;@ src.cpp:10:1 + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ;;@ src.cpp:10:1 + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ;;@ src.cpp:20:1 + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $source-map-propagation + ;;@ src.cpp:10:1 + i32.const 0 + i32.const 1 + i32.add + ;;@ src.cpp:20:1 + drop + i32.const 2 + drop + ) + ;; CHECK: (func $use-types (type $104) (param $0 (ref $s0)) (param $1 (ref $s1)) (param $2 (ref $s2)) (param $3 (ref $s3)) (param $4 (ref $s4)) (param $5 (ref $s5)) (param $6 (ref $s6)) (param $7 (ref $s7)) (param $8 (ref $s8)) (param $9 (ref $a0)) (param $10 (ref $a1)) (param $11 (ref $a2)) (param $12 (ref $a3)) (param $13 (ref $subvoid)) (param $14 (ref $submany)) (param $15 (ref $all-types)) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) |