diff options
Diffstat (limited to 'src/wasm2js.h')
-rw-r--r-- | src/wasm2js.h | 68 |
1 files changed, 63 insertions, 5 deletions
diff --git a/src/wasm2js.h b/src/wasm2js.h index 5adcdb740..3accfad75 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -1437,8 +1437,11 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, Ref store = ValueBuilder::makeCall(ABI::wasm2js::SCRATCH_STORE_F32, visit(curr->value, EXPRESSION_RESULT)); + // 32-bit scratch memory uses index 2, so that it does not + // conflict with indexes 0, 1 which are used for 64-bit, see + // comment where |scratchBuffer| is defined. Ref load = ValueBuilder::makeCall(ABI::wasm2js::SCRATCH_LOAD_I32, - ValueBuilder::makeInt(0)); + ValueBuilder::makeInt(2)); return ValueBuilder::makeSeq(store, load); } // generate (~~expr), what Emscripten does @@ -1528,9 +1531,12 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, ABI::wasm2js::ensureHelpers(module, ABI::wasm2js::SCRATCH_LOAD_F32); + // 32-bit scratch memory uses index 2, so that it does not + // conflict with indexes 0, 1 which are used for 64-bit, see + // comment where |scratchBuffer| is defined. Ref store = ValueBuilder::makeCall(ABI::wasm2js::SCRATCH_STORE_I32, - ValueBuilder::makeNum(0), + ValueBuilder::makeNum(2), visit(curr->value, EXPRESSION_RESULT)); Ref load = ValueBuilder::makeCall(ABI::wasm2js::SCRATCH_LOAD_F32); return ValueBuilder::makeSeq(store, load); @@ -2462,8 +2468,60 @@ void Wasm2JSGlue::emitSpecialSupport() { return; } + // Scratch memory uses 3 indexes, each referring to 4 bytes. Indexes 0, 1 are + // used for 64-bit operations, while 2 is for 32-bit. These operations need + // separate indexes because we need to handle the case where the optimizer + // reorders a 32-bit reinterpret in between a 64-bit's split-out parts. + // That situation can occur because the 64-bit reinterpret was split up into + // pieces early, in the 64-bit lowering pass, while the 32-bit reinterprets + // are lowered only at the very end, and until then the optimizer sees wasm + // reinterprets which have no side effects (but they will have the side effect + // of altering scratch memory). That is, conceptual code like this: + // + // a = reinterpret_64(b) + // x = reinterpret_32(y) + // + // turns into + // + // scratch_write(b) + // a_low = scratch_read(0) + // a_high = scratch_read(1) + // x = reinterpret_32(y) + // + // (Note how the single wasm instruction for a 64-bit reinterpret turns into + // multiple operations. We have to do such splitting, because in JS we will + // have to have separate operations to receive each 32-bit chunk anyhow. A + // *32*-bit reinterpret *could* be a single function, but given we have the + // separate functions anyhow for the 64-bit case, it's more compact to reuse + // those.) + // At this point, the scratch_* functions look like they have side effects to + // the optimizer (which is true, as they modify scratch memory), but the + // reinterpret_32 is still a normal wasm instruction without side effects, so + // the optimizer might do this: + // + // scratch_write(b) + // a_low = scratch_read(0) + // x = reinterpret_32(y) ;; this moved one line up + // a_high = scratch_read(1) + // + // When we do lower the reinterpret_32 into JS, we get: + // + // scratch_write(b) + // a_low = scratch_read(0) + // scratch_write(y) + // x = scratch_read() + // a_high = scratch_read(1) + // + // The second write occurs before the first's values have been read, so they + // interfere. + // + // There isn't a problem with reordering 32-bit reinterprets with each other + // as each is lowered into a pair of write+read in JS (after the wasm + // optimizer runs), so they are guaranteed to be adjacent (and a JS optimizer + // that runs later will handle that ok since they are calls, which can always + // have side effects). out << R"( - var scratchBuffer = new ArrayBuffer(8); + var scratchBuffer = new ArrayBuffer(16); var i32ScratchView = new Int32Array(scratchBuffer); var f32ScratchView = new Float32Array(scratchBuffer); var f64ScratchView = new Float64Array(scratchBuffer); @@ -2494,13 +2552,13 @@ void Wasm2JSGlue::emitSpecialSupport() { } else if (import->base == ABI::wasm2js::SCRATCH_STORE_F32) { out << R"( function wasm2js_scratch_store_f32(value) { - f32ScratchView[0] = value; + f32ScratchView[2] = value; } )"; } else if (import->base == ABI::wasm2js::SCRATCH_LOAD_F32) { out << R"( function wasm2js_scratch_load_f32() { - return f32ScratchView[0]; + return f32ScratchView[2]; } )"; } else if (import->base == ABI::wasm2js::SCRATCH_STORE_F64) { |