Ver Fonte

[Wasm SIMD] Typed array index

Ensure that loads and stores use the index directly, without skewing it
based on alignment. Add test entries. Rename m182 -> v128 in affected
test files.

Fixes #6259
Petr Penzin há 6 anos atrás
pai
commit
e861714826

+ 6 - 24
lib/Backend/IRBuilderAsmJs.cpp

@@ -6748,13 +6748,11 @@ IRBuilderAsmJs::BuildAsmSimdTypedArr(Js::OpCodeAsmJs newOpcode, uint32 offset, u
     IRType type = TySimd128F4;
     Js::RegSlot valueRegSlot = GetRegSlotFromSimd128Reg(value);
 
-    IR::RegOpnd * maskedOpnd = nullptr;
-    IR::Instr * maskInstr = nullptr;
+    IR::RegOpnd * addrOpnd = nullptr;
 
     Js::OpCode op = GetSimdOpcode(newOpcode);
     ValueType arrayType;
     bool isLd = false, isConst = false;
-    uint32 mask = 0;
 
     switch (newOpcode)
     {
@@ -6936,7 +6934,6 @@ IRBuilderAsmJs::BuildAsmSimdTypedArr(Js::OpCodeAsmJs newOpcode, uint32 offset, u
     {
 #define ARRAYBUFFER_VIEW(name, align, RegType, MemType, irSuffix) \
     case Js::ArrayBufferView::TYPE_##name: \
-        mask = ARRAYBUFFER_VIEW_MASK(align); \
         arrayType = ValueType::GetObject(ObjectType::##irSuffix##Array); \
         break;
 #include "Language/AsmJsArrayBufferViews.h"
@@ -6949,18 +6946,7 @@ IRBuilderAsmJs::BuildAsmSimdTypedArr(Js::OpCodeAsmJs newOpcode, uint32 offset, u
     {
 
         Js::RegSlot indexRegSlot = GetRegSlotFromIntReg(slotIndex);
-
-        if (mask)
-        {
-            // AND_I4 index, mask
-            maskedOpnd = IR::RegOpnd::New(TyUint32, m_func);
-            maskInstr = IR::Instr::New(Js::OpCode::And_I4, maskedOpnd, BuildSrcOpnd(indexRegSlot, TyInt32), IR::IntConstOpnd::New(mask, TyUint32, m_func), m_func);
-
-        }
-        else
-        {
-            maskedOpnd = BuildSrcOpnd(indexRegSlot, TyInt32);
-        }
+        addrOpnd = BuildSrcOpnd(indexRegSlot, TyInt32);
     }
 
     IR::Instr * instr = nullptr;
@@ -6976,11 +6962,11 @@ IRBuilderAsmJs::BuildAsmSimdTypedArr(Js::OpCodeAsmJs newOpcode, uint32 offset, u
         regOpnd->SetValueType(ValueType::Simd);
         if (!isConst)
         {
-            Assert(maskedOpnd);
+            Assert(addrOpnd);
             // Js::OpCodeAsmJs::Simd128_LdArr_I4:
             // Js::OpCodeAsmJs::Simd128_LdArr_F4:
             // Js::OpCodeAsmJs::Simd128_LdArr_D2:
-            indirOpnd = IR::IndirOpnd::New(baseOpnd, maskedOpnd, type, m_func);
+            indirOpnd = IR::IndirOpnd::New(baseOpnd, addrOpnd, type, m_func);
         }
         else
         {
@@ -6997,11 +6983,11 @@ IRBuilderAsmJs::BuildAsmSimdTypedArr(Js::OpCodeAsmJs newOpcode, uint32 offset, u
         regOpnd->SetValueType(ValueType::Simd);
         if (!isConst)
         {
-            Assert(maskedOpnd);
+            Assert(addrOpnd);
             // Js::OpCodeAsmJs::Simd128_StArr_I4:
             // Js::OpCodeAsmJs::Simd128_StArr_F4:
             // Js::OpCodeAsmJs::Simd128_StArr_D2:
-            indirOpnd = IR::IndirOpnd::New(baseOpnd, maskedOpnd, type, m_func);
+            indirOpnd = IR::IndirOpnd::New(baseOpnd, addrOpnd, type, m_func);
         }
         else
         {
@@ -7016,10 +7002,6 @@ IRBuilderAsmJs::BuildAsmSimdTypedArr(Js::OpCodeAsmJs newOpcode, uint32 offset, u
     Assert(dataWidth >= 4 && dataWidth <= 16);
     instr->dataWidth = dataWidth;
     indirOpnd->SetOffset(simdOffset);
-    if (maskInstr)
-    {
-        AddInstr(maskInstr, offset);
-    }
     AddInstr(instr, offset);
 
 }

+ 15 - 7
test/wasm.simd/loadTests.js

@@ -17,6 +17,7 @@ function testLoadOpsForType(funcname, module, laneValues, expectedResults, start
     const instance = new WebAssembly.Instance(module, { "dummy" : { "memory" : memObj } }).exports;
 
     let intArray = new Int32Array (memObj.buffer);
+    let int8Array = new Int8Array (memObj.buffer);
 
     let forEachTestPosition =  (action)  => {
 
@@ -60,12 +61,19 @@ function testLoadOpsForType(funcname, module, laneValues, expectedResults, start
         }
     }
     
-    check(0, "instance.m128_load4", MEM_SIZE_IN_BYTES - 32);
-    check(0, "instance.m128_load4", MEM_SIZE_IN_BYTES - 16);
-    check("Access index is out of range", "instance.m128_load4", MEM_SIZE_IN_BYTES - 8);
-    check("Access index is out of range", "instance.m128_load4", MEM_SIZE_IN_BYTES - 4);
-    check("Access index is out of range", "instance.m128_load4_offset", 0xFFFFFFFC);
-    check("Access index is out of range", "instance.m128_load4_offset", -1);
+    check(0, "instance.v128_load4", MEM_SIZE_IN_BYTES - 32);
+    check(0, "instance.v128_load4", MEM_SIZE_IN_BYTES - 16);
+    check("Access index is out of range", "instance.v128_load4", MEM_SIZE_IN_BYTES - 8);
+    check("Access index is out of range", "instance.v128_load4", MEM_SIZE_IN_BYTES - 4);
+    check("Access index is out of range", "instance.v128_load4_offset", 0xFFFFFFFC);
+    check("Access index is out of range", "instance.v128_load4_offset", -1);
+    // Verify read at "odd" index
+    int8Array[0] = 1;
+    int8Array[1] = 0;
+    int8Array[2] = 0;
+    int8Array[3] = 0;
+    int8Array[4] = 0;
+    check(0, "instance.v128_load4", 1);
 
 }
 
@@ -76,7 +84,7 @@ const laneValues = [0xAAAAAAAA, 0xFFFFFFFF, 0X80000000, 0x90A762A6];
 const expectedResults = [16, 32, 1, 14]; //i32.popcnt
 const startPositions = [0, 5, 11, 17];
 
-testLoadOpsForType("m128_load_test", module, laneValues, expectedResults, startPositions);
+testLoadOpsForType("v128_load_test", module, laneValues, expectedResults, startPositions);
 
 if (passed) {
     print("Passed");

BIN
test/wasm.simd/loads.wasm


+ 3 - 3
test/wasm.simd/loads.wast

@@ -6,15 +6,15 @@
 (module
     (import "dummy" "memory" (memory 1))
 
-    (func (export "m128_load4") (param $x i32) (result i32)
+    (func (export "v128_load4") (param $x i32) (result i32)
         (i32x4.extract_lane 0 (v128.load offset=0 (get_local $x)))
     )
 
-    (func (export "m128_load4_offset") (param $x i32) (result i32)
+    (func (export "v128_load4_offset") (param $x i32) (result i32)
         (i32x4.extract_lane 0 (v128.load offset=16 (get_local $x)))
     )
 
-    (func (export "m128_load_test") (param $x i32) (local v128)
+    (func (export "v128_load_test") (param $x i32) (local v128)
         (set_local 1 (v128.load offset=0 (get_local $x)))
         (i32.store offset=0 (get_local $x) (i32.popcnt (i32x4.extract_lane 0 (get_local 1))))
         (set_local 1 (v128.load offset=0 (get_local $x)))

+ 35 - 9
test/wasm.simd/storeTests.js

@@ -35,6 +35,7 @@ const module = new WebAssembly.Module(readbuffer('stores.wasm'));
 let memObj = new WebAssembly.Memory({initial:INITIAL_SIZE});
 const instance = new WebAssembly.Instance(module, { "dummy" : { "memory" : memObj } }).exports;
 let intArray = new Int32Array (memObj.buffer);
+let byteArray = new Uint8Array (memObj.buffer);
 
 let testStore = function (funcname, ...expected) {
     
@@ -51,18 +52,43 @@ let testStore = function (funcname, ...expected) {
 }
 
 
-testStore("m128_store4", 777, 888, 999, 1111);
-testStore("m128_store4", -1, 0, 0, -1);
-testStore("m128_store4", -1, -1, -1, -1);
+testStore("v128_store4", 777, 888, 999, 1111);
+testStore("v128_store4", -1, 0, 0, -1);
+testStore("v128_store4", -1, -1, -1, -1);
 
+for (let i = 0; i < 18; i++) {
+    byteArray[i] = 0;
+}
+
+// Check that v128 store does not overrun value boundaries
+instance.v128_store_i32x4(1, 0x01020304);
+
+assertEquals(0, byteArray[0]);
+assertEquals(4, byteArray[1]);
+assertEquals(3, byteArray[2]);
+assertEquals(2, byteArray[3]);
+assertEquals(1, byteArray[4]);
+assertEquals(4, byteArray[5]);
+assertEquals(3, byteArray[6]);
+assertEquals(2, byteArray[7]);
+assertEquals(1, byteArray[8]);
+assertEquals(4, byteArray[9]);
+assertEquals(3, byteArray[10]);
+assertEquals(2, byteArray[11]);
+assertEquals(1, byteArray[12]);
+assertEquals(4, byteArray[13]);
+assertEquals(3, byteArray[14]);
+assertEquals(2, byteArray[15]);
+assertEquals(1, byteArray[16]);
+assertEquals(0, byteArray[17]);
 
 const MEM_SIZE_IN_BYTES = 1024 * 64;
-check("RangeError", "instance.m128_store4", MEM_SIZE_IN_BYTES - 12, 777, 888, 999, 1111);
-check("RangeError", "instance.m128_store4", MEM_SIZE_IN_BYTES - 8, 777, 888, 999, 1111);
-check("RangeError", "instance.m128_store4", MEM_SIZE_IN_BYTES - 4, 777, 888, 999, 1111);
-check("RangeError", "instance.m128_store4_offset", -1, 777, 888, 999, 1111);
-check("RangeError", "instance.m128_store4_offset", 0xFFFFFFFC, 777, 888, 999, 1111);
-check(undefined, "instance.m128_store4", MEM_SIZE_IN_BYTES - 16, 777, 888, 999, 1111);
+check("RangeError", "instance.v128_store4", MEM_SIZE_IN_BYTES - 12, 777, 888, 999, 1111);
+check("RangeError", "instance.v128_store4", MEM_SIZE_IN_BYTES - 8, 777, 888, 999, 1111);
+check("RangeError", "instance.v128_store4", MEM_SIZE_IN_BYTES - 4, 777, 888, 999, 1111);
+check("RangeError", "instance.v128_store4_offset", -1, 777, 888, 999, 1111);
+check("RangeError", "instance.v128_store4_offset", 0xFFFFFFFC, 777, 888, 999, 1111);
+check(undefined, "instance.v128_store4", MEM_SIZE_IN_BYTES - 16, 777, 888, 999, 1111);
 
 if (passed) {
     print("Passed");

BIN
test/wasm.simd/stores.wasm


+ 8 - 2
test/wasm.simd/stores.wast

@@ -6,13 +6,19 @@
 (module
     (import "dummy" "memory" (memory 1))
 
-    (func (export "m128_store4") (param i32 i32 i32 i32 i32) (local v128)
+    (func (export "v128_store4") (param i32 i32 i32 i32 i32) (local v128)
         (set_local 5 (v128.load offset=0 (i32.const 16)))
         (v128.store offset=0 (get_local 0) (get_local 5))
     )
 
-    (func (export "m128_store4_offset") (param i32 i32 i32 i32 i32) (local v128)
+    (func (export "v128_store4_offset") (param i32 i32 i32 i32 i32) (local v128)
         (set_local 5 (v128.load offset=0 (i32.const 16)))
         (v128.store offset=16 (get_local 0) (get_local 5))
     )
+    (func
+        (export "v128_store_i32x4")
+        (param $index i32)
+        (param $value i32)
+        (v128.store align=4 (get_local $index) (i32x4.splat (get_local $value)))
+    )
 )