Skip to content

Commit beef3e9

Browse files
authored
Re-land #2235 with fixes (#2245)
#2242 had exposed the bug that the `Trapper` pass was defining `walkFunction` when it should have been defining `doWalkFunction`.
1 parent aed3d6c commit beef3e9

File tree

5 files changed

+108
-13
lines changed

5 files changed

+108
-13
lines changed

src/ir/manipulation.h

+5
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ template<typename InputType> inline Nop* nop(InputType* target) {
3838
return convert<InputType, Nop>(target);
3939
}
4040

41+
template<typename InputType>
42+
inline Unreachable* unreachable(InputType* target) {
43+
return convert<InputType, Unreachable>(target);
44+
}
45+
4146
// Convert a node that allocates
4247
template<typename InputType, typename OutputType>
4348
inline OutputType* convert(InputType* input, MixedArena& allocator) {

src/passes/MemoryPacking.cpp

+42-4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
* limitations under the License.
1515
*/
1616

17+
#include "ir/manipulation.h"
18+
#include "ir/utils.h"
1719
#include "pass.h"
1820
#include "wasm-binary.h"
1921
#include "wasm-builder.h"
@@ -32,11 +34,13 @@ struct MemoryPacking : public Pass {
3234
return;
3335
}
3436

35-
// Conservatively refuse to change segments if any are passive to avoid
36-
// invalidating segment indices or segment contents referenced from
37-
// memory.init instructions.
38-
// TODO: optimize in the presence of memory.init instructions
3937
if (module->features.hasBulkMemory()) {
38+
// Remove any references to active segments that might be invalidated.
39+
optimizeTrappingBulkMemoryOps(runner, module);
40+
// Conservatively refuse to change segments if any are passive to avoid
41+
// invalidating segment indices or segment contents referenced from
42+
// memory.init and data.drop instructions.
43+
// TODO: optimize in the presence of memory.init and data.drop
4044
for (auto segment : module->memory.segments) {
4145
if (segment.isPassive) {
4246
return;
@@ -120,6 +124,40 @@ struct MemoryPacking : public Pass {
120124
}
121125
module->memory.segments.swap(packed);
122126
}
127+
128+
void optimizeTrappingBulkMemoryOps(PassRunner* runner, Module* module) {
129+
struct Trapper : WalkerPass<PostWalker<Trapper>> {
130+
bool isFunctionParallel() override { return true; }
131+
bool changed;
132+
133+
Pass* create() override { return new Trapper; }
134+
135+
void visitMemoryInit(MemoryInit* curr) {
136+
if (!getModule()->memory.segments[curr->segment].isPassive) {
137+
Builder builder(*getModule());
138+
replaceCurrent(builder.blockify(builder.makeDrop(curr->dest),
139+
builder.makeDrop(curr->offset),
140+
builder.makeDrop(curr->size),
141+
builder.makeUnreachable()));
142+
changed = true;
143+
}
144+
}
145+
void visitDataDrop(DataDrop* curr) {
146+
if (!getModule()->memory.segments[curr->segment].isPassive) {
147+
ExpressionManipulator::unreachable(curr);
148+
changed = true;
149+
}
150+
}
151+
void doWalkFunction(Function* func) {
152+
changed = false;
153+
super::doWalkFunction(func);
154+
if (changed) {
155+
ReFinalize().walkFunctionInModule(func, getModule());
156+
}
157+
}
158+
} trapper;
159+
trapper.run(runner, module);
160+
}
123161
};
124162

125163
Pass* createMemoryPackingPass() { return new MemoryPacking(); }

src/wasm/wasm-validator.cpp

+14-8
Original file line numberDiff line numberDiff line change
@@ -970,8 +970,6 @@ void FunctionValidator::visitSIMDShift(SIMDShift* curr) {
970970
}
971971

972972
void FunctionValidator::visitMemoryInit(MemoryInit* curr) {
973-
shouldBeTrue(
974-
getModule()->memory.exists, curr, "Memory operations require a memory");
975973
shouldBeTrue(getModule()->features.hasBulkMemory(),
976974
curr,
977975
"Bulk memory operation (bulk memory is disabled)");
@@ -983,27 +981,33 @@ void FunctionValidator::visitMemoryInit(MemoryInit* curr) {
983981
curr->offset->type, i32, curr, "memory.init offset must be an i32");
984982
shouldBeEqualOrFirstIsUnreachable(
985983
curr->size->type, i32, curr, "memory.init size must be an i32");
984+
if (!shouldBeTrue(getModule()->memory.exists,
985+
curr,
986+
"Memory operations require a memory")) {
987+
return;
988+
}
986989
shouldBeTrue(curr->segment < getModule()->memory.segments.size(),
987990
curr,
988991
"memory.init segment index out of bounds");
989992
}
990993

991994
void FunctionValidator::visitDataDrop(DataDrop* curr) {
992-
shouldBeTrue(
993-
getModule()->memory.exists, curr, "Memory operations require a memory");
994995
shouldBeTrue(getModule()->features.hasBulkMemory(),
995996
curr,
996997
"Bulk memory operation (bulk memory is disabled)");
997998
shouldBeEqualOrFirstIsUnreachable(
998999
curr->type, none, curr, "data.drop must have type none");
1000+
if (!shouldBeTrue(getModule()->memory.exists,
1001+
curr,
1002+
"Memory operations require a memory")) {
1003+
return;
1004+
}
9991005
shouldBeTrue(curr->segment < getModule()->memory.segments.size(),
10001006
curr,
10011007
"data.drop segment index out of bounds");
10021008
}
10031009

10041010
void FunctionValidator::visitMemoryCopy(MemoryCopy* curr) {
1005-
shouldBeTrue(
1006-
getModule()->memory.exists, curr, "Memory operations require a memory");
10071011
shouldBeTrue(getModule()->features.hasBulkMemory(),
10081012
curr,
10091013
"Bulk memory operation (bulk memory is disabled)");
@@ -1015,11 +1019,11 @@ void FunctionValidator::visitMemoryCopy(MemoryCopy* curr) {
10151019
curr->source->type, i32, curr, "memory.copy source must be an i32");
10161020
shouldBeEqualOrFirstIsUnreachable(
10171021
curr->size->type, i32, curr, "memory.copy size must be an i32");
1022+
shouldBeTrue(
1023+
getModule()->memory.exists, curr, "Memory operations require a memory");
10181024
}
10191025

10201026
void FunctionValidator::visitMemoryFill(MemoryFill* curr) {
1021-
shouldBeTrue(
1022-
getModule()->memory.exists, curr, "Memory operations require a memory");
10231027
shouldBeTrue(getModule()->features.hasBulkMemory(),
10241028
curr,
10251029
"Bulk memory operation (bulk memory is disabled)");
@@ -1031,6 +1035,8 @@ void FunctionValidator::visitMemoryFill(MemoryFill* curr) {
10311035
curr->value->type, i32, curr, "memory.fill value must be an i32");
10321036
shouldBeEqualOrFirstIsUnreachable(
10331037
curr->size->type, i32, curr, "memory.fill size must be an i32");
1038+
shouldBeTrue(
1039+
getModule()->memory.exists, curr, "Memory operations require a memory");
10341040
}
10351041

10361042
void FunctionValidator::validateMemBytes(uint8_t bytes,

test/passes/memory-packing.txt renamed to test/passes/memory-packing_all-features.txt

+27
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,30 @@
1818
(import "env" "memory" (memory $0 2048 2048))
1919
(import "env" "memoryBase" (global $memoryBase i32))
2020
)
21+
(module
22+
(type $FUNCSIG$v (func))
23+
(memory $0 1 1)
24+
(func $foo (; 0 ;) (type $FUNCSIG$v)
25+
(block
26+
(drop
27+
(i32.const 0)
28+
)
29+
(drop
30+
(i32.const 0)
31+
)
32+
(drop
33+
(i32.const 0)
34+
)
35+
(unreachable)
36+
)
37+
(unreachable)
38+
)
39+
(func $bar (; 1 ;) (type $FUNCSIG$v)
40+
(drop
41+
(loop $loop-in (result i32)
42+
(unreachable)
43+
(i32.const 42)
44+
)
45+
)
46+
)
47+
)

test/passes/memory-packing.wast renamed to test/passes/memory-packing_all-features.wast

+20-1
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,23 @@
1717
(import "env" "memoryBase" (global $memoryBase i32))
1818
(data (i32.const 4066) "") ;; empty
1919
)
20-
20+
(module
21+
(memory $0 1 1)
22+
(data (i32.const 0) "")
23+
(func $foo
24+
(memory.init 0
25+
(i32.const 0)
26+
(i32.const 0)
27+
(i32.const 0)
28+
)
29+
(data.drop 0)
30+
)
31+
(func $bar
32+
(drop
33+
(loop (result i32)
34+
(data.drop 0)
35+
(i32.const 42)
36+
)
37+
)
38+
)
39+
)

0 commit comments

Comments
 (0)