Skip to content

Commit e54b1d3

Browse files
authored
wasm2js: optimize away unneeded load coercions (#2107)
1 parent 104d52a commit e54b1d3

97 files changed

Lines changed: 287 additions & 20 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

scripts/fuzz_opt.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
# parameters
2828

29-
NANS = True
29+
NANS = False
3030

3131
FEATURE_OPTS = [] # '--all-features' etc
3232

@@ -44,7 +44,7 @@
4444
'--experimental-wasm-return-call'
4545
]
4646

47-
INPUT_SIZE_LIMIT = 150 * 1024
47+
INPUT_SIZE_LIMIT = 50 * 1024
4848

4949
LOG_LIMIT = 125
5050

@@ -145,7 +145,10 @@ def run_bynterp(wasm):
145145

146146
def run_wasm2js(wasm):
147147
wrapper = run([in_bin('wasm-opt'), wasm, '--emit-js-wrapper=/dev/stdout'] + FEATURE_OPTS)
148-
main = run([in_bin('wasm2js'), wasm, '--emscripten'] + FEATURE_OPTS)
148+
cmd = [in_bin('wasm2js'), wasm, '--emscripten']
149+
if random.random() < 0.5:
150+
cmd += ['-O']
151+
main = run(cmd + FEATURE_OPTS)
149152
with open(os.path.join(options.binaryen_root, 'scripts', 'wasm2js.js')) as f:
150153
glue = f.read()
151154
with open('js.js', 'w') as f:
@@ -162,9 +165,9 @@ def run_wasm2js(wasm):
162165
def run_vms(prefix):
163166
wasm = prefix + 'wasm'
164167
results = []
165-
results.append(run_bynterp(wasm))
166-
results.append(fix_output(run_vm([os.path.expanduser('d8'), prefix + 'js'] + V8_OPTS + ['--', wasm])))
167-
# results.append(run_wasm2js(wasm))
168+
# results.append(run_bynterp(wasm))
169+
# results.append(fix_output(run_vm([os.path.expanduser('d8'), prefix + 'js'] + V8_OPTS + ['--', wasm])))
170+
results.append(run_wasm2js(wasm))
168171

169172
# append to add results from VMs
170173
# results += [fix_output(run_vm([os.path.expanduser('d8'), prefix + 'js'] + V8_OPTS + ['--', prefix + 'wasm']))]

src/tools/wasm2js.cpp

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -128,15 +128,13 @@ static void traversePost(Ref node, std::function<void(Ref)> visit) {
128128
traversePrePost(node, [](Ref node) {}, visit);
129129
}
130130

131-
#if 0
132131
static void replaceInPlace(Ref target, Ref value) {
133132
assert(target->isArray() && value->isArray());
134-
target->resize(value->size());
133+
target->setSize(value->size());
135134
for (size_t i = 0; i < value->size(); i++) {
136135
target[i] = value[i];
137136
}
138137
}
139-
#endif
140138

141139
static void optimizeJS(Ref ast) {
142140
// Helpers
@@ -272,18 +270,44 @@ static void optimizeJS(Ref ast) {
272270
node[3] = child[3];
273271
}
274272
}
275-
// A load into an & may allow using a simpler heap, e.g. HEAPU8[..] & 1
276-
// (a load of a boolean) may be HEAP8[..] & 1. The signed heaps are more
277-
// commonly used, so it compresses better, and also they seem to have
278-
// better performance (perhaps since HEAPU32 is at risk of not being a
279-
// smallint).
280-
if (node[1] == AND && isHeapAccess(node[2])) {
273+
if (isHeapAccess(node[2])) {
281274
auto heap = getHeapFromAccess(node[2]);
282-
if (isConstantBitwise(node, AND, 1)) {
283-
if (heap == HEAPU8) {
284-
setHeapOnAccess(node[2], HEAP8);
275+
IString replacementHeap;
276+
// We can avoid a cast of a load by using the load to do it instead.
277+
if (isOrZero(node)) {
278+
if (isIntegerHeap(heap)) {
279+
replacementHeap = heap;
280+
}
281+
} else if (isConstantBitwise(node, TRSHIFT, 0)) {
282+
// For signed or unsigned loads smaller than 32 bits, doing an | 0
283+
// was safe either way - they aren't in the range an | 0 can affect.
284+
// For >>> 0 however, a negative value would change, so we still
285+
// need the cast.
286+
if (heap == HEAP32 || heap == HEAPU32) {
287+
replacementHeap = HEAPU32;
285288
} else if (heap == HEAPU16) {
286-
setHeapOnAccess(node[2], HEAP16);
289+
replacementHeap = HEAPU16;
290+
} else if (heap == HEAPU8) {
291+
replacementHeap = HEAPU8;
292+
}
293+
}
294+
if (!replacementHeap.isNull()) {
295+
setHeapOnAccess(node[2], replacementHeap);
296+
replaceInPlace(node, node[2]);
297+
return;
298+
}
299+
// A load into an & may allow using a simpler heap, e.g. HEAPU8[..] & 1
300+
// (a load of a boolean) may be HEAP8[..] & 1. The signed heaps are more
301+
// commonly used, so it compresses better, and also they seem to have
302+
// better performance (perhaps since HEAPU32 is at risk of not being a
303+
// smallint).
304+
if (node[1] == AND) {
305+
if (isConstantBitwise(node, AND, 1)) {
306+
if (heap == HEAPU8) {
307+
setHeapOnAccess(node[2], HEAP8);
308+
} else if (heap == HEAPU16) {
309+
setHeapOnAccess(node[2], HEAP16);
310+
}
287311
}
288312
}
289313
}

src/wasm2js.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,7 @@ void Wasm2JSBuilder::addBasics(Ref ast) {
439439
addHeap(HEAP32, INT32ARRAY);
440440
addHeap(HEAPU8, UINT8ARRAY);
441441
addHeap(HEAPU16, UINT16ARRAY);
442+
addHeap(HEAPU32, UINT32ARRAY);
442443
addHeap(HEAPF32, FLOAT32ARRAY);
443444
addHeap(HEAPF64, FLOAT64ARRAY);
444445
// core asm.js imports
@@ -1708,10 +1709,12 @@ void Wasm2JSBuilder::addMemoryGrowthFuncs(Ref ast, Module* wasm) {
17081709
ValueBuilder::makeName(IString("newBuffer"))))));
17091710
};
17101711

1712+
setHeap(HEAP8, INT8ARRAY);
17111713
setHeap(HEAP16, INT16ARRAY);
17121714
setHeap(HEAP32, INT32ARRAY);
17131715
setHeap(HEAPU8, UINT8ARRAY);
17141716
setHeap(HEAPU16, UINT16ARRAY);
1717+
setHeap(HEAPU32, UINT32ARRAY);
17151718
setHeap(HEAPF32, FLOAT32ARRAY);
17161719
setHeap(HEAPF64, FLOAT64ARRAY);
17171720

test/binaryen.js/emit_asmjs.js.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ function asmFunc(global, env, buffer) {
66
var HEAP32 = new global.Int32Array(buffer);
77
var HEAPU8 = new global.Uint8Array(buffer);
88
var HEAPU16 = new global.Uint16Array(buffer);
9+
var HEAPU32 = new global.Uint32Array(buffer);
910
var HEAPF32 = new global.Float32Array(buffer);
1011
var HEAPF64 = new global.Float64Array(buffer);
1112
var Math_imul = global.Math.imul;

test/wasm2js.asserts.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ function asmFunc0(global, env, buffer) {
3737
var HEAP32 = new global.Int32Array(buffer);
3838
var HEAPU8 = new global.Uint8Array(buffer);
3939
var HEAPU16 = new global.Uint16Array(buffer);
40+
var HEAPU32 = new global.Uint32Array(buffer);
4041
var HEAPF32 = new global.Float32Array(buffer);
4142
var HEAPF64 = new global.Float64Array(buffer);
4243
var Math_imul = global.Math.imul;

test/wasm2js.traps.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ function asmFunc0(global, env, buffer) {
3737
var HEAP32 = new global.Int32Array(buffer);
3838
var HEAPU8 = new global.Uint8Array(buffer);
3939
var HEAPU16 = new global.Uint16Array(buffer);
40+
var HEAPU32 = new global.Uint32Array(buffer);
4041
var HEAPF32 = new global.Float32Array(buffer);
4142
var HEAPF64 = new global.Float64Array(buffer);
4243
var Math_imul = global.Math.imul;

test/wasm2js/address.2asm.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ function asmFunc(global, env, buffer) {
77
var HEAP32 = new global.Int32Array(buffer);
88
var HEAPU8 = new global.Uint8Array(buffer);
99
var HEAPU16 = new global.Uint16Array(buffer);
10+
var HEAPU32 = new global.Uint32Array(buffer);
1011
var HEAPF32 = new global.Float32Array(buffer);
1112
var HEAPF64 = new global.Float64Array(buffer);
1213
var Math_imul = global.Math.imul;
@@ -54,10 +55,12 @@ function asmFunc(global, env, buffer) {
5455
var newHEAP8 = new global.Int8Array(newBuffer);
5556
newHEAP8.set(HEAP8);
5657
HEAP8 = newHEAP8;
58+
HEAP8 = new global.Int8Array(newBuffer);
5759
HEAP16 = new global.Int16Array(newBuffer);
5860
HEAP32 = new global.Int32Array(newBuffer);
5961
HEAPU8 = new global.Uint8Array(newBuffer);
6062
HEAPU16 = new global.Uint16Array(newBuffer);
63+
HEAPU32 = new global.Uint32Array(newBuffer);
6164
HEAPF32 = new global.Float32Array(newBuffer);
6265
HEAPF64 = new global.Float64Array(newBuffer);
6366
buffer = newBuffer;

test/wasm2js/base64.2asm.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ function asmFunc(global, env, buffer) {
66
var HEAP32 = new global.Int32Array(buffer);
77
var HEAPU8 = new global.Uint8Array(buffer);
88
var HEAPU16 = new global.Uint16Array(buffer);
9+
var HEAPU32 = new global.Uint32Array(buffer);
910
var HEAPF32 = new global.Float32Array(buffer);
1011
var HEAPF64 = new global.Float64Array(buffer);
1112
var Math_imul = global.Math.imul;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ function asmFunc(global, env, buffer) {
66
var HEAP32 = new global.Int32Array(buffer);
77
var HEAPU8 = new global.Uint8Array(buffer);
88
var HEAPU16 = new global.Uint16Array(buffer);
9+
var HEAPU32 = new global.Uint32Array(buffer);
910
var HEAPF32 = new global.Float32Array(buffer);
1011
var HEAPF64 = new global.Float64Array(buffer);
1112
var Math_imul = global.Math.imul;

test/wasm2js/block.2asm.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ function asmFunc(global, env, buffer) {
66
var HEAP32 = new global.Int32Array(buffer);
77
var HEAPU8 = new global.Uint8Array(buffer);
88
var HEAPU16 = new global.Uint16Array(buffer);
9+
var HEAPU32 = new global.Uint32Array(buffer);
910
var HEAPF32 = new global.Float32Array(buffer);
1011
var HEAPF64 = new global.Float64Array(buffer);
1112
var Math_imul = global.Math.imul;

0 commit comments

Comments
 (0)