diff options
Diffstat (limited to 'js/src/jit-test/tests/wasm/float-unaligned.js')
-rw-r--r-- | js/src/jit-test/tests/wasm/float-unaligned.js | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/wasm/float-unaligned.js b/js/src/jit-test/tests/wasm/float-unaligned.js new file mode 100644 index 0000000000..a22ffe5fee --- /dev/null +++ b/js/src/jit-test/tests/wasm/float-unaligned.js @@ -0,0 +1,118 @@ +// Various tests for unaligned float accesses. These are specifically meant to +// test the SIGBUS handling on 32-bit ARM by exercising odd addresses and odd +// offsets. + +// For a triple of (numBallast, ty, offset), create the text for a pair of +// functions "get_ty_offset" and "set_ty_offset" where each has numBallast live +// dummy values across the operation of interest to force the use of different +// register numbers. (This is primarily for the FP registers as ARM code +// generation currently always uses the same scratch register for the base +// address of the access.) +// +// These must be augmented with a memory. Memory addresses 0-255 are reserved +// for internal use by these functions. The memory must start as zero. + +function makeLoadStore(numBallast, ty, offset) { + // The general idea of the ballast is that we occupy some FP registers and + // some int registers with non-dead values before we perform an operation, + // and then we consume the occupied registers after. + // + // In the case of load, the loaded result is stored back in memory before we + // consume the ballast, thus the ion regalloc will not simply always load + // the result into d0, but usually into some temp other than d0. Thus the + // amount of ballast affects the register. (Ditto baseline though the + // reasoning is simpler.) + // + // In the case of store, we keep the parameter value live until the end so + // that the tmp that we compute for the store is moved into a different + // register. The tmp has the same value as the parameter value but a + // non-JIT compiler can't know that. + + let loadtxt = + `(func (export "get_${ty}_${offset}") (param $p i32) (result ${ty}) + ${ballast(() => ` + (i32.const 8) + (i32.store (i32.const 8) (i32.add (i32.load (i32.const 8)) (i32.const 1))) + (${ty}.load (i32.const 8))`)} + + (${ty}.store (i32.const 0) (${ty}.load offset=${offset} (local.get $p))) + + ${ballast(() => ` + ${ty}.store`)} + + (${ty}.load (i32.const 0)))`; + + // This will assume the value at mem[16] is zero. + let storetxt = + `(func (export "set_${ty}_${offset}") (param $p i32) (param $v ${ty}) + (local $tmp ${ty}) + ${ballast(() => ` + (i32.const 8) + (i32.store (i32.const 8) (i32.add (i32.load (i32.const 8)) (i32.const 1))) + (${ty}.load (i32.const 8))`)} + + (local.set $tmp (${ty}.add (local.get $v) (${ty}.load (i32.const 16)))) + (${ty}.store offset=${offset} (local.get $p) (local.get $tmp)) + + ${ballast(() => ` + ${ty}.store`)} + (${ty}.store (i32.const 8) (local.get $v)))`; + + return `${loadtxt} + ${storetxt}`; + + function ballast(thunk) { + let s = ""; + for ( let i=0 ; i < numBallast; i++ ) + s += thunk(); + return s; + } +} + +// The complexity here comes from trying to force the source/target FP registers +// in the FP access instruction to vary. For Baseline this is not hard; for Ion +// trickier. + +function makeInstance(numBallast, offset) { + let txt = + `(module + (memory (export "memory") 1 1) + ${makeLoadStore(numBallast, 'f64', offset)} + ${makeLoadStore(numBallast, 'f32', offset)})`; + return new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(txt))); +} + +// `offset` corresponds to the "offset" directive in the instruction +for ( let offset=0 ; offset < 8; offset++ ) { + + // `numBallast` represents the amount of ballast registers we're trying to use, + // see comments above. + for ( let numBallast=0; numBallast < 16; numBallast++ ) { + let ins = makeInstance(numBallast, offset); + let mem = ins.exports.memory; + let buf = new DataView(mem.buffer); + + // `i` represents the offset in the pointer from a proper boundary + for ( let i=0; i < 9; i++ ) { + let offs = 256+i; + let val = Math.PI+i; + + buf.setFloat64(offs + offset, val, true); + assertEq(ins.exports["get_f64_" + offset](offs), val); + + ins.exports["set_f64_" + offset](offs + 32, val); + assertEq(buf.getFloat64(offs + 32 + offset, true), val); + } + + for ( let i=0; i < 9; i++ ) { + let offs = 512+i; + let val = Math.fround(Math.PI+i); + + buf.setFloat32(offs + offset, val, true); + assertEq(ins.exports["get_f32_" + offset](offs), val); + + ins.exports["set_f32_" + offset](offs + 32, val); + assertEq(buf.getFloat32(offs + 32 + offset, true), val); + } + } +} |