Skip to content

Commit f86375a

Browse files
authored
wasm2js: more coercion optimization (#2109)
1 parent cff4b75 commit f86375a

5 files changed

Lines changed: 209 additions & 19 deletions

File tree

src/tools/wasm2js.cpp

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,20 @@ static void replaceInPlaceIfPossible(Ref target, Ref value) {
145145
static void optimizeJS(Ref ast) {
146146
// Helpers
147147

148-
auto isOrZero = [](Ref node) {
148+
auto isBinary = [](Ref node, IString op) {
149149
return node->isArray() && !node->empty() && node[0] == BINARY &&
150-
node[1] == OR && node[3]->isNumber() && node[3]->getNumber() == 0;
150+
node[1] == op;
151+
};
152+
153+
auto isConstantBinary = [&](Ref node, IString op, int num) {
154+
return isBinary(node, op) && node[3]->isNumber() &&
155+
node[3]->getNumber() == num;
156+
};
157+
158+
auto isOrZero = [&](Ref node) { return isConstantBinary(node, OR, 0); };
159+
160+
auto isTrshiftZero = [&](Ref node) {
161+
return isConstantBinary(node, TRSHIFT, 0);
151162
};
152163

153164
auto isPlus = [](Ref node) {
@@ -174,11 +185,6 @@ static void optimizeJS(Ref ast) {
174185
node[1] == op;
175186
};
176187

177-
auto isConstantBitwise = [](Ref node, IString op, int num) {
178-
return node->isArray() && !node->empty() && node[0] == BINARY &&
179-
node[1] == op && node[3]->isNumber() && node[3]->getNumber() == num;
180-
};
181-
182188
auto isWhile = [](Ref node) {
183189
return node->isArray() && !node->empty() && node[0] == WHILE;
184190
};
@@ -243,11 +249,14 @@ static void optimizeJS(Ref ast) {
243249
};
244250

245251
auto optimizeBoolean = [&](Ref node) {
246-
// x ^ 1 => !x
247-
if (isConstantBitwise(node, XOR, 1)) {
252+
if (isConstantBinary(node, XOR, 1)) {
253+
// x ^ 1 => !x
248254
node[0]->setString(UNARY_PREFIX);
249255
node[1]->setString(L_NOT);
250256
node[3]->setNull();
257+
} else if (isOrZero(node) || isTrshiftZero(node)) {
258+
// Just being different from 0 is enough, casts don't matter.
259+
return node[2];
251260
}
252261
return node;
253262
};
@@ -257,7 +266,7 @@ static void optimizeJS(Ref ast) {
257266
// Pre-simplification
258267
traversePost(ast, [&](Ref node) {
259268
// x >> 0 => x | 0
260-
if (isConstantBitwise(node, RSHIFT, 0)) {
269+
if (isConstantBinary(node, RSHIFT, 0)) {
261270
node[1]->setString(OR);
262271
}
263272
});
@@ -270,10 +279,7 @@ static void optimizeJS(Ref ast) {
270279
// x | 0 | 0 => x | 0
271280
if (isOrZero(node)) {
272281
if (isBitwise(node[2])) {
273-
auto child = node[2];
274-
node[1] = child[1];
275-
node[2] = child[2];
276-
node[3] = child[3];
282+
replaceInPlace(node, node[2]);
277283
}
278284
}
279285
if (isHeapAccess(node[2])) {
@@ -284,7 +290,7 @@ static void optimizeJS(Ref ast) {
284290
if (isIntegerHeap(heap)) {
285291
replacementHeap = heap;
286292
}
287-
} else if (isConstantBitwise(node, TRSHIFT, 0)) {
293+
} else if (isTrshiftZero(node)) {
288294
// For signed or unsigned loads smaller than 32 bits, doing an | 0
289295
// was safe either way - they aren't in the range an | 0 can affect.
290296
// For >>> 0 however, a negative value would change, so we still
@@ -308,7 +314,7 @@ static void optimizeJS(Ref ast) {
308314
// better performance (perhaps since HEAPU32 is at risk of not being a
309315
// smallint).
310316
if (node[1] == AND) {
311-
if (isConstantBitwise(node, AND, 1)) {
317+
if (isConstantBinary(node, AND, 1)) {
312318
if (heap == HEAPU8) {
313319
setHeapOnAccess(node[2], HEAP8);
314320
} else if (heap == HEAPU16) {
@@ -348,6 +354,21 @@ static void optimizeJS(Ref ast) {
348354
} else if (isUnary(node, L_NOT)) {
349355
node[2] = optimizeBoolean(node[2]);
350356
}
357+
// Add/subtract can merge coercions up.
358+
else if (isBinary(node, PLUS) || isBinary(node, MINUS)) {
359+
auto left = node[2];
360+
auto right = node[3];
361+
if (isOrZero(left) && isOrZero(right)) {
362+
auto op = node[1]->getIString();
363+
// Add a coercion on top.
364+
node[1]->setString(OR);
365+
node[2] = left;
366+
node[3] = ValueBuilder::makeNum(0);
367+
// Add/subtract the inner uncoerced values.
368+
left[1]->setString(op);
369+
left[3] = right[2];
370+
}
371+
}
351372
// Assignment into a heap coerces.
352373
else if (node->isAssign()) {
353374
auto assign = node->asAssign();
@@ -357,12 +378,12 @@ static void optimizeJS(Ref ast) {
357378
if (isIntegerHeap(heap)) {
358379
if (heap == HEAP8 || heap == HEAPU8) {
359380
while (isOrZero(assign->value()) ||
360-
isConstantBitwise(assign->value(), AND, 255)) {
381+
isConstantBinary(assign->value(), AND, 255)) {
361382
assign->value() = assign->value()[2];
362383
}
363384
} else if (heap == HEAP16 || heap == HEAPU16) {
364385
while (isOrZero(assign->value()) ||
365-
isConstantBitwise(assign->value(), AND, 65535)) {
386+
isConstantBinary(assign->value(), AND, 65535)) {
366387
assign->value() = assign->value()[2];
367388
}
368389
} else {

test/wasm2js/br_table_temp.2asm.js.opt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12662,7 +12662,7 @@ function asmFunc(global, env, buffer) {
1266212662

1266312663
function $63($0) {
1266412664
$0 = $0 | 0;
12665-
if ($0 - 1 | 0) {
12665+
if ($0 - 1) {
1266612666
$0 = 9
1266712667
} else {
1266812668
$0 = 8

test/wasm2js/emscripten.2asm.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,48 @@ function asmFunc(global, env, buffer) {
9090
if ((HEAPU8[144 >> 0] | 0) >>> 0 < 3 >>> 0) {
9191
bar()
9292
}
93+
if ((bools(314159 | 0) | 0) >>> 7 | 0) {
94+
bar()
95+
}
96+
if ((bools(314159 | 0) | 0) >> 8 | 0) {
97+
bar()
98+
}
99+
if (~~Math_fround(getf32()) >>> 0) {
100+
bar()
101+
}
102+
if (~~Math_fround(getf32())) {
103+
bar()
104+
}
105+
if (~~+getf64() >>> 0) {
106+
bar()
107+
}
108+
if (~~+getf64()) {
109+
bar()
110+
}
111+
if (((geti32() | 0) + (geti32() | 0) | 0) + (geti32() | 0) | 0) {
112+
bar()
113+
}
114+
if ((geti32() | 0) + ((geti32() | 0) + (geti32() | 0) | 0) | 0) {
115+
bar()
116+
}
117+
if (((geti32() | 0) + (geti32() | 0) | 0) + ((geti32() | 0) + (geti32() | 0) | 0) | 0) {
118+
bar()
119+
}
120+
if ((((geti32() | 0) + (geti32() | 0) | 0) + ((geti32() | 0) + (geti32() | 0) | 0) | 0) + (((geti32() | 0) + (geti32() | 0) | 0) + ((geti32() | 0) + (geti32() | 0) | 0) | 0) | 0) {
121+
bar()
122+
}
123+
}
124+
125+
function geti32() {
126+
return geti32() | 0 | 0;
127+
}
128+
129+
function getf32() {
130+
return Math_fround(Math_fround(getf32()));
131+
}
132+
133+
function getf64() {
134+
return +(+getf64());
93135
}
94136

95137
function __growWasmMemory($0) {

test/wasm2js/emscripten.2asm.js.opt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,48 @@ function asmFunc(global, env, buffer) {
8383
if (HEAPU8[144] < 3) {
8484
bar()
8585
}
86+
if (bools(314159) >>> 7) {
87+
bar()
88+
}
89+
if (bools(314159) >> 8) {
90+
bar()
91+
}
92+
if (~~getf32()) {
93+
bar()
94+
}
95+
if (~~getf32()) {
96+
bar()
97+
}
98+
if (~~getf64()) {
99+
bar()
100+
}
101+
if (~~getf64()) {
102+
bar()
103+
}
104+
if ((geti32() + geti32() | 0) + geti32()) {
105+
bar()
106+
}
107+
if (geti32() + (geti32() + geti32() | 0)) {
108+
bar()
109+
}
110+
if (geti32() + geti32() + (geti32() + geti32())) {
111+
bar()
112+
}
113+
if (geti32() + geti32() + (geti32() + geti32()) + (geti32() + geti32() + (geti32() + geti32()))) {
114+
bar()
115+
}
116+
}
117+
118+
function geti32() {
119+
return geti32();
120+
}
121+
122+
function getf32() {
123+
return getf32();
124+
}
125+
126+
function getf64() {
127+
return getf64();
86128
}
87129

88130
function __growWasmMemory($0) {

test/wasm2js/emscripten.wast

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,91 @@
110110
(if (i32.lt_u (i32.load8_u (i32.const 144)) (i32.const 3))
111111
(call $bar)
112112
)
113+
(if (i32.shr_u (call $bools (i32.const 314159)) (i32.const 7))
114+
(call $bar)
115+
)
116+
(if (i32.shr_s (call $bools (i32.const 314159)) (i32.const 8))
117+
(call $bar)
118+
)
119+
(if (i32.trunc_f32_u (call $getf32))
120+
(call $bar)
121+
)
122+
(if (i32.trunc_f32_s (call $getf32))
123+
(call $bar)
124+
)
125+
(if (i32.trunc_f64_u (call $getf64))
126+
(call $bar)
127+
)
128+
(if (i32.trunc_f64_s (call $getf64))
129+
(call $bar)
130+
)
131+
(if
132+
(i32.add
133+
(i32.add
134+
(call $geti32)
135+
(call $geti32)
136+
)
137+
(call $geti32)
138+
)
139+
(call $bar)
140+
)
141+
(if
142+
(i32.add
143+
(call $geti32)
144+
(i32.add
145+
(call $geti32)
146+
(call $geti32)
147+
)
148+
)
149+
(call $bar)
150+
)
151+
(if
152+
(i32.add
153+
(i32.add
154+
(call $geti32)
155+
(call $geti32)
156+
)
157+
(i32.add
158+
(call $geti32)
159+
(call $geti32)
160+
)
161+
)
162+
(call $bar)
163+
)
164+
(if
165+
(i32.add
166+
(i32.add
167+
(i32.add
168+
(call $geti32)
169+
(call $geti32)
170+
)
171+
(i32.add
172+
(call $geti32)
173+
(call $geti32)
174+
)
175+
)
176+
(i32.add
177+
(i32.add
178+
(call $geti32)
179+
(call $geti32)
180+
)
181+
(i32.add
182+
(call $geti32)
183+
(call $geti32)
184+
)
185+
)
186+
)
187+
(call $bar)
188+
)
189+
)
190+
(func $geti32 (result i32)
191+
(call $geti32)
192+
)
193+
(func $getf32 (result f32)
194+
(call $getf32)
195+
)
196+
(func $getf64 (result f64)
197+
(call $getf64)
113198
)
114199
(func $__growWasmMemory (param $0 i32) (result i32)
115200
(grow_memory

0 commit comments

Comments
 (0)