diff options
-rw-r--r-- | src/wasm/wasm-stack.cpp | 38 | ||||
-rw-r--r-- | test/lit/binary/dwarf-multivalue.test | 106 | ||||
-rwxr-xr-x | test/lit/binary/dwarf-multivalue.test.wasm | bin | 0 -> 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 Binary files differnew file mode 100755 index 000000000..14d7dc60e --- /dev/null +++ b/test/lit/binary/dwarf-multivalue.test.wasm |