Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/passes/Print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2786,8 +2786,9 @@ void PrintSExpression::printMetadata(Expression* curr) {
if (auto iter = currFunction->expressionLocations.find(curr);
iter != currFunction->expressionLocations.end()) {
Colors::grey(o);
o << ";; code offset: 0x" << std::hex << iter->second.start << std::dec
<< '\n';
const auto& span = iter->second;
o << ";; code offset: 0x" << std::hex << span.start << " - 0x"
<< span.end << std::dec << '\n';
restoreNormalColor(o);
doIndent(o, indent);
}
Expand Down
27 changes: 24 additions & 3 deletions src/wasm/wasm-ir-builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1078,24 +1078,45 @@ Result<> IRBuilder::visitEnd() {
auto& label = isTry ? scope.branchLabel : scope.label;
auto blockType = scope.getResultType();

// When we wrap an expression then push the wrapper, we would end up with the
// binary start location attached to the original expression and the end
// location attached to the wrapper. Move the binary start location to the
// wrapper to avoid splitting the span information.
Comment thread
kripken marked this conversation as resolved.
auto moveBinaryPosToWrapper = [&](Expression* original, Expression* wrapper) {
if (!func) {
return;
}
if (auto it = func->expressionLocations.find(original);
it != func->expressionLocations.end()) {
auto span = it->second;
assert(span.end == 0);
func->expressionLocations.erase(it);
[[maybe_unused]] auto [_, inserted] =
func->expressionLocations.insert({wrapper, span});
assert(inserted);
}
};

// If the scope expression cannot be directly labeled, we may need to wrap it
// in a block.
auto maybeWrapForLabel = [&](Expression* curr) -> Expression* {
if (!label) {
return curr;
}
curr = fixExtraOutput(scope, label, curr);
auto* fixed = fixExtraOutput(scope, label, curr);
// We can re-use unnamed blocks instead of wrapping them.
if (auto* block = curr->dynCast<Block>(); block && !block->name) {
if (auto* block = fixed->dynCast<Block>(); block && !block->name) {
block->name = label;
block->type = blockType;
moveBinaryPosToWrapper(curr, block);
return block;
}
auto* block = builder.makeBlock();
block->name = label;
block->list.push_back(curr);
block->list.push_back(fixed);
block->finalize(blockType,
scope.labelUsed ? Block::HasBreak : Block::NoBreak);
moveBinaryPosToWrapper(curr, block);
return block;
};

Expand Down
73 changes: 73 additions & 0 deletions test/lit/debug/control-flow-wrappers.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.

;; Regression test for a bug in IRBuilder would assign end offsets incorrectly
;; when control flow structures required wrapping.

;; RUN: env BINARYEN_PRINT_FULL=1 wasm-opt %s.wasm -all --debuginfo --print -o /dev/null | filecheck %s

;; Test module generated with `wasm-tools parse` on the following wat:
;; (module
;; ;; Add a dummy DWARF section so the parser will collect code offsets.
;; (@custom ".debug_info" "")
;; (tag $e)
;; (func
;; ;; The end offset would never be set because it would be assigned to the
;; ;; wrapper block instead.
;; try
;; br 0
;; catch $e
;; end
;; ;; Same here. Two instructions having the same end offset (0) would cause an
;; ;; assertion failure.
;; try
;; br 0
;; catch $e
;; end
;; )
;; )

;; CHECK: (type $0 (func))

;; CHECK: (tag $e (type $0))

;; CHECK: (func $0 (type $0) (; (ref (exact $func.0)) ;)
;; CHECK-NEXT: ;;@
;; CHECK-NEXT: (block (; none ;)
;; CHECK-NEXT: ;;@
;; CHECK-NEXT: ;; code offset: 0x3 - 0xa
;; CHECK-NEXT: (block $label (; none ;)
;; CHECK-NEXT: ;;@
;; CHECK-NEXT: (try
;; CHECK-NEXT: (do
;; CHECK-NEXT: ;;@
;; CHECK-NEXT: ;; code offset: 0x5 - 0x7
;; CHECK-NEXT: (br $label) (; unreachable ;)
;; CHECK-NEXT: )
;; CHECK-NEXT: ;; code offset: 0x7
;; CHECK-NEXT: (catch $e
;; CHECK-NEXT: ;;@
;; CHECK-NEXT: (block (; none ;)
;; CHECK-NEXT: ) ;; end block (; none ;)
;; CHECK-NEXT: )
;; CHECK-NEXT: ) ;; end try (; none ;)
;; CHECK-NEXT: ) ;; end block label
;; CHECK-NEXT: ;;@
;; CHECK-NEXT: ;; code offset: 0xa - 0x11
;; CHECK-NEXT: (block $label1 (; none ;)
;; CHECK-NEXT: ;;@
;; CHECK-NEXT: (try
;; CHECK-NEXT: (do
;; CHECK-NEXT: ;;@
;; CHECK-NEXT: ;; code offset: 0xc - 0xe
;; CHECK-NEXT: (br $label1) (; unreachable ;)
;; CHECK-NEXT: )
;; CHECK-NEXT: ;; code offset: 0xe
;; CHECK-NEXT: (catch $e
;; CHECK-NEXT: ;;@
;; CHECK-NEXT: (block (; none ;)
;; CHECK-NEXT: ) ;; end block (; none ;)
;; CHECK-NEXT: )
;; CHECK-NEXT: ) ;; end try (; none ;)
;; CHECK-NEXT: ) ;; end block label1 (; none ;)
;; CHECK-NEXT: ) ;; end block (; none ;)
;; CHECK-NEXT: )
Binary file added test/lit/debug/control-flow-wrappers.test.wasm
Binary file not shown.
Loading
Loading