diff options
-rw-r--r-- | src/wasm-stack.h | 5 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 43 | ||||
-rw-r--r-- | test/exception-handling.wast.fromBinary | 11 | ||||
-rw-r--r-- | test/exception-handling.wast.fromBinary.noDebugInfo | 11 | ||||
-rw-r--r-- | test/lit/multivalue.wast | 86 |
5 files changed, 53 insertions, 103 deletions
diff --git a/src/wasm-stack.h b/src/wasm-stack.h index 03ec4eef5..1f66212ad 100644 --- a/src/wasm-stack.h +++ b/src/wasm-stack.h @@ -148,6 +148,11 @@ private: InsertOrderedMap<Type, Index> scratchLocals; void countScratchLocals(); void setScratchLocals(); + + // local.get, local.tee, and glboal.get expressions that will be followed by + // tuple.extracts. We can optimize these by getting only the local for the + // extracted index. + std::unordered_map<Expression*, Index> extractedGets; }; // Takes binaryen IR and converts it to something else (binary or stack IR) diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 1ddf69d41..c3d53f126 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -87,6 +87,13 @@ void BinaryInstWriter::visitCallIndirect(CallIndirect* curr) { } void BinaryInstWriter::visitLocalGet(LocalGet* curr) { + if (auto it = extractedGets.find(curr); it != extractedGets.end()) { + // We have a tuple of locals to get, but we will only end up using one of + // them, so we can just emit that one. + o << int8_t(BinaryConsts::LocalGet) + << U32LEB(mappedLocals[std::make_pair(curr->index, it->second)]); + return; + } size_t numValues = func->getLocalType(curr->index).size(); for (Index i = 0; i < numValues; ++i) { o << int8_t(BinaryConsts::LocalGet) @@ -96,14 +103,28 @@ void BinaryInstWriter::visitLocalGet(LocalGet* curr) { void BinaryInstWriter::visitLocalSet(LocalSet* curr) { size_t numValues = func->getLocalType(curr->index).size(); + // If this is a tuple, set all the elements with nonzero index. for (Index i = numValues - 1; i >= 1; --i) { o << int8_t(BinaryConsts::LocalSet) << U32LEB(mappedLocals[std::make_pair(curr->index, i)]); } if (!curr->isTee()) { + // This is not a tee, so just finish setting the values. o << int8_t(BinaryConsts::LocalSet) << U32LEB(mappedLocals[std::make_pair(curr->index, 0)]); + } else if (auto it = extractedGets.find(curr); it != extractedGets.end()) { + // We only need to get the single extracted value. + if (it->second == 0) { + o << int8_t(BinaryConsts::LocalTee) + << U32LEB(mappedLocals[std::make_pair(curr->index, 0)]); + } else { + o << int8_t(BinaryConsts::LocalSet) + << U32LEB(mappedLocals[std::make_pair(curr->index, 0)]); + o << int8_t(BinaryConsts::LocalGet) + << U32LEB(mappedLocals[std::make_pair(curr->index, it->second)]); + } } else { + // We need to get all the values. o << int8_t(BinaryConsts::LocalTee) << U32LEB(mappedLocals[std::make_pair(curr->index, 0)]); for (Index i = 1; i < numValues; ++i) { @@ -114,8 +135,14 @@ void BinaryInstWriter::visitLocalSet(LocalSet* curr) { } void BinaryInstWriter::visitGlobalGet(GlobalGet* curr) { - // Emit a global.get for each element if this is a tuple global Index index = parent.getGlobalIndex(curr->name); + if (auto it = extractedGets.find(curr); it != extractedGets.end()) { + // We have a tuple of globals to get, but we will only end up using one of + // them, so we can just emit that one. + o << int8_t(BinaryConsts::GlobalGet) << U32LEB(index + it->second); + return; + } + // Emit a global.get for each element if this is a tuple global size_t numValues = curr->type.size(); for (Index i = 0; i < numValues; ++i) { o << int8_t(BinaryConsts::GlobalGet) << U32LEB(index + i); @@ -1970,6 +1997,10 @@ void BinaryInstWriter::visitTupleMake(TupleMake* curr) { } void BinaryInstWriter::visitTupleExtract(TupleExtract* curr) { + if (extractedGets.count(curr->tuple)) { + // We already have just the extracted value on the stack. + return; + } size_t numVals = curr->tuple->type.size(); // Drop all values after the one we want for (size_t i = curr->index + 1; i < numVals; ++i) { @@ -2506,6 +2537,7 @@ void BinaryInstWriter::mapLocalsAndEmitHeader() { } } setScratchLocals(); + o << U32LEB(numLocalsByType.size()); for (auto& localType : localTypes) { o << U32LEB(numLocalsByType.at(localType)); @@ -2532,6 +2564,15 @@ void BinaryInstWriter::countScratchLocals() { for (auto& [type, _] : scratchLocals) { noteLocalType(type); } + // While we have all the tuple.extracts, also find extracts of local.gets, + // local.tees, and global.gets that we can optimize. + for (auto* extract : extracts.list) { + auto* tuple = extract->tuple; + if (tuple->is<LocalGet>() || tuple->is<LocalSet>() || + tuple->is<GlobalGet>()) { + extractedGets.insert({tuple, extract->index}); + } + } } void BinaryInstWriter::setScratchLocals() { diff --git a/test/exception-handling.wast.fromBinary b/test/exception-handling.wast.fromBinary index d5cc2c179..44bd2e5c3 100644 --- a/test/exception-handling.wast.fromBinary +++ b/test/exception-handling.wast.fromBinary @@ -20,7 +20,6 @@ (local $1 i64) (local $2 (i32 i64)) (local $3 i32) - (local $4 i32) (try $label$3 (do (throw $e-i32 @@ -60,15 +59,7 @@ ) ) (drop - (block (result i32) - (local.set $4 - (local.get $x) - ) - (drop - (local.get $1) - ) - (local.get $4) - ) + (local.get $x) ) ) ) diff --git a/test/exception-handling.wast.fromBinary.noDebugInfo b/test/exception-handling.wast.fromBinary.noDebugInfo index 5c527119e..27202e8a6 100644 --- a/test/exception-handling.wast.fromBinary.noDebugInfo +++ b/test/exception-handling.wast.fromBinary.noDebugInfo @@ -20,7 +20,6 @@ (local $1 i64) (local $2 (i32 i64)) (local $3 i32) - (local $4 i32) (try $label$3 (do (throw $tag$0 @@ -60,15 +59,7 @@ ) ) (drop - (block (result i32) - (local.set $4 - (local.get $0) - ) - (drop - (local.get $1) - ) - (local.get $4) - ) + (local.get $0) ) ) ) diff --git a/test/lit/multivalue.wast b/test/lit/multivalue.wast index f75182ca4..0d52f5382 100644 --- a/test/lit/multivalue.wast +++ b/test/lit/multivalue.wast @@ -155,13 +155,6 @@ ;; CHECK-NEXT: (local $5 (i32 i64 f32)) ;; CHECK-NEXT: (local $6 i64) ;; CHECK-NEXT: (local $7 i32) - ;; CHECK-NEXT: (local $8 i64) - ;; CHECK-NEXT: (local $9 i32) - ;; CHECK-NEXT: (local $10 i64) - ;; CHECK-NEXT: (local $11 i32) - ;; CHECK-NEXT: (local $12 i64) - ;; CHECK-NEXT: (local $13 i32) - ;; CHECK-NEXT: (local $14 f32) ;; CHECK-NEXT: (local.set $5 ;; CHECK-NEXT: (call $triple) ;; CHECK-NEXT: ) @@ -190,69 +183,10 @@ ;; CHECK-NEXT: (local.get $7) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i32) - ;; CHECK-NEXT: (local.set $9 - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i64) - ;; CHECK-NEXT: (local.set $8 - ;; CHECK-NEXT: (local.get $1) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $4 - ;; CHECK-NEXT: (local.get $3) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $8) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $9) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (tuple.make - ;; CHECK-NEXT: (block (result f32) - ;; CHECK-NEXT: (local.set $14 - ;; CHECK-NEXT: (local.get $4) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i32) - ;; CHECK-NEXT: (local.set $11 - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $2 - ;; CHECK-NEXT: (block (result i64) - ;; CHECK-NEXT: (local.set $10 - ;; CHECK-NEXT: (local.get $1) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $3) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $10) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $11) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $14) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $2) - ;; CHECK-NEXT: (block (result i32) - ;; CHECK-NEXT: (local.set $13 - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i64) - ;; CHECK-NEXT: (local.set $12 - ;; CHECK-NEXT: (local.get $1) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $3) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $12) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $13) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $3) + ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $reverse (result f32 i64 i32) @@ -296,7 +230,6 @@ ;; CHECK: (func $global (type $0) (result i32 i64) ;; CHECK-NEXT: (local $0 i64) ;; CHECK-NEXT: (local $1 i32) - ;; CHECK-NEXT: (local $2 i32) ;; CHECK-NEXT: (global.set $g1 ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (local.set $1 @@ -309,18 +242,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i32) - ;; CHECK-NEXT: (local.set $2 - ;; CHECK-NEXT: (global.get $g1) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (global.get $g2) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $2) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (global.get $g2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (tuple.make ;; CHECK-NEXT: (global.get $global$2) |