From 3bc9d6163eaef129ab42463a1c8a58c9de858422 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Wed, 1 Apr 2026 21:38:19 -0700 Subject: [PATCH 1/2] Group locals by written type in binary writer We have logic to group locals by type in the binary writer to take advantage of the run-length encoding of locals. But that logic previously grouped locals by their IR types, rather than the types that would actually be written to the binary. These can differ in when the IR uses more precise types than are allowed to be written given the enabled feature set. For example, the IR might use exact types but have to write inexact types because custom descriptors are not enabled. In such cases, it is possible that different groups of locals would be written with the same type, which is suboptimal. Fix the problem by grouping locals by their written types given the enabled features. Fixes #7934. --- src/wasm-stack.h | 1 + src/wasm/wasm-stack.cpp | 21 ++++++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/wasm-stack.h b/src/wasm-stack.h index 2c9fdd616fa..05898623187 100644 --- a/src/wasm-stack.h +++ b/src/wasm-stack.h @@ -150,6 +150,7 @@ class BinaryInstWriter : public OverriddenVisitor { std::unordered_map numLocalsByType; void noteLocalType(Type type, Index count = 1); + Index getNumLocalsForType(Type type); // Keeps track of the binary index of the scratch locals used to lower // tuple.extract. If there are multiple scratch locals of the same type, they diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 496d15ca878..add6f9b1421 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -3245,7 +3245,7 @@ void BinaryInstWriter::mapLocalsAndEmitHeader() { Index baseIndex = func->getVarIndexBase(); for (auto& type : localTypes) { nextFreeIndex[type] = baseIndex; - baseIndex += numLocalsByType[type]; + baseIndex += getNumLocalsForType(type); } // Map the IR index pairs to indices. @@ -3261,14 +3261,20 @@ void BinaryInstWriter::mapLocalsAndEmitHeader() { scratchLocals[type] = nextFreeIndex[type]; } - o << U32LEB(numLocalsByType.size()); + o << U32LEB(localTypes.size()); for (auto& localType : localTypes) { - o << U32LEB(numLocalsByType.at(localType)); + o << U32LEB(getNumLocalsForType(localType)); parent.writeType(localType); } } void BinaryInstWriter::noteLocalType(Type type, Index count) { + // Group types by the type they will eventually be written out as. For + // example, we do not need to differentiate exact and inexact versions of the + // same reference type if custom descriptors is not enabled and the type will + // be written as inexact either way. + auto feats = parent.getModule()->features; + type = type.asWrittenGivenFeatures(feats); auto& num = numLocalsByType[type]; if (num == 0) { localTypes.push_back(type); @@ -3276,6 +3282,15 @@ void BinaryInstWriter::noteLocalType(Type type, Index count) { num += count; } +Index BinaryInstWriter::getNumLocalsForType(Type type) { + auto feats = parent.getModule()->features; + type = type.asWrittenGivenFeatures(feats); + if (auto it = numLocalsByType.find(type); it != numLocalsByType.end()) { + return it->second; + } + return 0; +} + InsertOrderedMap BinaryInstWriter::countScratchLocals() { struct ScratchLocalFinder : PostWalker { BinaryInstWriter& parent; From 8353a3dde20b8e4fb355b09439edfd7290495a10 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Thu, 2 Apr 2026 09:23:57 -0700 Subject: [PATCH 2/2] Apply suggestion from @tlively --- src/wasm/wasm-stack.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index add6f9b1421..ea932dc175c 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -3269,7 +3269,7 @@ void BinaryInstWriter::mapLocalsAndEmitHeader() { } void BinaryInstWriter::noteLocalType(Type type, Index count) { - // Group types by the type they will eventually be written out as. For + // Group locals by the type they will eventually be written out as. For // example, we do not need to differentiate exact and inexact versions of the // same reference type if custom descriptors is not enabled and the type will // be written as inexact either way.