summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/wasm-stack.h5
-rw-r--r--src/wasm/wasm-stack.cpp43
-rw-r--r--test/exception-handling.wast.fromBinary11
-rw-r--r--test/exception-handling.wast.fromBinary.noDebugInfo11
-rw-r--r--test/lit/multivalue.wast86
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)