summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/wasm/wasm-stack.cpp38
-rw-r--r--test/lit/binary/dwarf-multivalue.test106
-rwxr-xr-xtest/lit/binary/dwarf-multivalue.test.wasmbin0 -> 6099 bytes
3 files changed, 135 insertions, 9 deletions
diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp
index dda47ffa6..1ed60abed 100644
--- a/src/wasm/wasm-stack.cpp
+++ b/src/wasm/wasm-stack.cpp
@@ -2568,25 +2568,45 @@ void BinaryInstWriter::mapLocalsAndEmitHeader() {
for (Index i = 0; i < func->getNumParams(); i++) {
mappedLocals[std::make_pair(i, 0)] = i;
}
+
// Normally we map all locals of the same type into a range of adjacent
// addresses, which is more compact. However, if we need to keep DWARF valid,
// do not do any reordering at all - instead, do a trivial mapping that
// keeps everything unmoved.
+ //
+ // Unless we have run DWARF-invalidating passes, all locals added during the
+ // process that are not in DWARF info (tuple locals, tuple scratch locals,
+ // locals to resolve stacky format, ..) have been all tacked on to the
+ // existing locals and happen at the end, so as long as we print the local
+ // types in order, we don't invalidate original local DWARF info here.
if (DWARF) {
- FindAll<TupleExtract> extracts(func->body);
- if (!extracts.list.empty()) {
- Fatal() << "DWARF + multivalue is not yet complete";
+ Index mappedIndex = func->getVarIndexBase();
+ for (Index i = func->getVarIndexBase(); i < func->getNumLocals(); i++) {
+ size_t size = func->getLocalType(i).size();
+ for (Index j = 0; j < size; j++) {
+ mappedLocals[std::make_pair(i, j)] = mappedIndex + j;
+ }
+ mappedIndex += size;
}
- Index varStart = func->getVarIndexBase();
- Index varEnd = varStart + func->getNumVars();
- o << U32LEB(func->getNumVars());
- for (Index i = varStart; i < varEnd; i++) {
- mappedLocals[std::make_pair(i, 0)] = i;
+ countScratchLocals();
+
+ size_t numBinaryLocals =
+ mappedIndex - func->getVarIndexBase() + scratchLocals.size();
+ o << U32LEB(numBinaryLocals);
+ for (Index i = func->getVarIndexBase(); i < func->getNumLocals(); i++) {
+ for (const auto& type : func->getLocalType(i)) {
+ o << U32LEB(1);
+ parent.writeType(type);
+ }
+ }
+ for (auto& [type, _] : scratchLocals) {
o << U32LEB(1);
- parent.writeType(func->getLocalType(i));
+ parent.writeType(type);
+ scratchLocals[type] = mappedIndex++;
}
return;
}
+
for (auto type : func->vars) {
for (const auto& t : type) {
noteLocalType(t);
diff --git a/test/lit/binary/dwarf-multivalue.test b/test/lit/binary/dwarf-multivalue.test
new file mode 100644
index 000000000..435aebe25
--- /dev/null
+++ b/test/lit/binary/dwarf-multivalue.test
@@ -0,0 +1,106 @@
+;; Test that we handle multivalue + DWARF correctly. When we need to preserve
+;; DWARF info, we don't do any local reordering and all newly added locals
+;; during parsing/writing are added at the end of the local list.
+
+;; Generated from this c file with the following command:
+;; $ emcc -g -Xclang -target-abi -Xclang experimental-mv dwarf-multivalue.c -o dwarf-multivalue.wasm
+;;
+;; struct MyStruct {
+;; int a;
+;; float b;
+;; };
+;;
+;; struct MyStruct foo() {
+;; struct MyStruct ret = {.a = 3, .b = 3.5};
+;; return ret;
+;; }
+;;
+;; void test() {
+;; struct MyStruct s = foo();
+;; }
+;;
+;; int main() {
+;; test();
+;; return 0;
+;; }
+
+;; The original wasm file's $test function's locals are as follows:
+;; (func $test
+;; (local $0 i32)
+;; (local $1 i32)
+;; (local $2 i32)
+;; (local $3 i32)
+;; (local $4 f32)
+;; (local $5 i32)
+;; (local $6 i32)
+;; (local $7 i32)
+;; (local $8 f32)
+;; (local $9 i32)
+;; (local $10 f32)
+
+;; If we parse this wasm file into Binaryen IR, two locals are added in the
+;; process. Here $11 is added for tuple parsing and $12 is added for stacky IR
+;; resolving during binary reading process.
+;; RUN: wasm-dis %s.wasm -o - | filecheck %s --check-prefix=ORIG
+;; ORIG: (func $test
+;; ORIG-NEXT: (local $0 i32)
+;; ORIG-NEXT: (local $1 i32)
+;; ORIG-NEXT: (local $2 i32)
+;; ORIG-NEXT: (local $3 i32)
+;; ORIG-NEXT: (local $4 f32)
+;; ORIG-NEXT: (local $5 i32)
+;; ORIG-NEXT: (local $6 i32)
+;; ORIG-NEXT: (local $7 i32)
+;; ORIG-NEXT: (local $8 f32)
+;; ORIG-NEXT: (local $9 i32)
+;; ORIG-NEXT: (local $10 f32)
+;; ORIG-NEXT: (local $11 (tuple i32 f32))
+;; ORIG-NEXT: (local $12 i32)
+
+;; If we write this IR into binary, even if this cannot be displayed in the wast
+;; format, the local order of $test will look like this, because we don't
+;; reorder locals:
+;; (func $test
+;; (local $0 i32)
+;; (local $1 i32)
+;; (local $2 i32)
+;; (local $3 i32)
+;; (local $4 f32)
+;; (local $5 i32)
+;; (local $6 i32)
+;; (local $7 i32)
+;; (local $8 f32)
+;; (local $9 i32)
+;; (local $10 f32)
+;; (local $11 i32) ;; Previous (local $11 (tuple i32 f32))'s first element
+;; (local $12 f32) ;; Previous (local $11 (tuple i32 f32))'s second element
+;; (local $13 i32) ;; Previous (local $12 i32)
+;; (local $14 f32) ;; scratch local for f32
+
+;; We parse this binary again into Binaryen IR, roundtripping the original
+;; binary. Here until (local $14) is the same with the previous list, and $15 is
+;; is added for tuple parsing and $16 is added for stacky IR resolving during
+;; binary reading process.
+;; RUN: wasm-opt -all -g --roundtrip %s.wasm -S -o - | filecheck %s --check-prefix=ROUNDTRIP
+;; ROUNDTRIP: (func $test
+;; ROUNDTRIP-NEXT: (local $0 i32)
+;; ROUNDTRIP-NEXT: (local $1 i32)
+;; ROUNDTRIP-NEXT: (local $2 i32)
+;; ROUNDTRIP-NEXT: (local $3 i32)
+;; ROUNDTRIP-NEXT: (local $4 f32)
+;; ROUNDTRIP-NEXT: (local $5 i32)
+;; ROUNDTRIP-NEXT: (local $6 i32)
+;; ROUNDTRIP-NEXT: (local $7 i32)
+;; ROUNDTRIP-NEXT: (local $8 f32)
+;; ROUNDTRIP-NEXT: (local $9 i32)
+;; ROUNDTRIP-NEXT: (local $10 f32)
+;; ROUNDTRIP-NEXT: (local $11 i32)
+;; ROUNDTRIP-NEXT: (local $12 f32)
+;; ROUNDTRIP-NEXT: (local $13 i32)
+;; ROUNDTRIP-NEXT: (local $14 f32)
+;; ROUNDTRIP-NEXT: (local $15 (tuple i32 f32))
+;; ROUNDTRIP-NEXT: (local $16 i32)
+
+;; We can see that we don't reorder the locals during the process and the
+;; original list of locals, local $0~$10, is untouched, to NOT invalidate DWARF
+;; info.
diff --git a/test/lit/binary/dwarf-multivalue.test.wasm b/test/lit/binary/dwarf-multivalue.test.wasm
new file mode 100755
index 000000000..14d7dc60e
--- /dev/null
+++ b/test/lit/binary/dwarf-multivalue.test.wasm
Binary files differ