Просмотр исходного кода

Implement the first few SIMD opcodes for fast interpreter (v128.const, v128.any_true) (#3818)

Tested on the following code:
```
(module
  (import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
  (memory (export "memory") 1)

  ;; WASI entry point
  (func $main (export "_start")
    v128.const i8x16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    v128.any_true
    if
      unreachable
    end
    
    v128.const i8x16 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15     
    v128.any_true
    i32.const 0
    i32.eq
    if
      unreachable
    end

    i32.const 0
    call $proc_exit
  )
)
```
Marcin Kolny 1 год назад
Родитель
Сommit
326aea298c

+ 25 - 0
core/iwasm/common/wasm_runtime_common.h

@@ -37,6 +37,10 @@ extern "C" {
     do {                                   \
         *(int64 *)(addr) = (int64)(value); \
     } while (0)
+#define PUT_V128_TO_ADDR(addr, value) \
+    do {                              \
+        *(V128 *)(addr) = (value);    \
+    } while (0)
 #define PUT_F64_TO_ADDR(addr, value)           \
     do {                                       \
         *(float64 *)(addr) = (float64)(value); \
@@ -49,6 +53,7 @@ extern "C" {
 #define GET_I64_FROM_ADDR(addr) (*(int64 *)(addr))
 #define GET_F64_FROM_ADDR(addr) (*(float64 *)(addr))
 #define GET_REF_FROM_ADDR(addr) (*(void **)(addr))
+#define GET_V128_FROM_ADDR(addr) (*(V128 *)(addr))
 
 /* For STORE opcodes */
 #define STORE_I64 PUT_I64_TO_ADDR
@@ -83,6 +88,15 @@ STORE_U8(void *addr, uint8_t value)
 
 #else /* WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 */
 
+#define PUT_V128_TO_ADDR(addr, value)        \
+    do {                                     \
+        uint32 *addr_u32 = (uint32 *)(addr); \
+        addr_u32[0] = (value).i32x4[0];      \
+        addr_u32[1] = (value).i32x4[1];      \
+        addr_u32[2] = (value).i32x4[2];      \
+        addr_u32[3] = (value).i32x4[3];      \
+    } while (0)
+
 #define PUT_I64_TO_ADDR(addr, value)         \
     do {                                     \
         uint32 *addr_u32 = (uint32 *)(addr); \
@@ -124,6 +138,17 @@ STORE_U8(void *addr, uint8_t value)
     } while (0)
 #endif
 
+static inline V128
+GET_V128_FROM_ADDR(uint32 *addr)
+{
+    V128 ret;
+    ret.i32x4[0] = addr[0];
+    ret.i32x4[1] = addr[1];
+    ret.i32x4[2] = addr[2];
+    ret.i32x4[3] = addr[3];
+    return ret;
+}
+
 static inline int64
 GET_I64_FROM_ADDR(uint32 *addr)
 {

+ 32 - 0
core/iwasm/interpreter/wasm_interp_fast.c

@@ -433,6 +433,8 @@ wasm_interp_get_frame_ref(WASMInterpFrame *frame)
     (type) GET_I64_FROM_ADDR(frame_lp + *(int16 *)(frame_ip + off))
 #define GET_OPERAND_F64(type, off) \
     (type) GET_F64_FROM_ADDR(frame_lp + *(int16 *)(frame_ip + off))
+#define GET_OPERAND_V128(off) \
+    GET_V128_FROM_ADDR(frame_lp + *(int16 *)(frame_ip + off))
 #define GET_OPERAND_REF(type, off) \
     (type) GET_REF_FROM_ADDR(frame_lp + *(int16 *)(frame_ip + off))
 
@@ -5642,7 +5644,37 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 #endif
                 goto call_func_from_entry;
             }
+#if WASM_ENABLE_SIMD != 0
+            HANDLE_OP(WASM_OP_SIMD_PREFIX)
+            {
+                GET_OPCODE();
+
+                switch (opcode) {
+                    case SIMD_v128_const:
+                    {
+                        uint8 *orig_ip = frame_ip;
+
+                        frame_ip += sizeof(V128);
+                        addr_ret = GET_OFFSET();
 
+                        PUT_V128_TO_ADDR(frame_lp + addr_ret, *(V128 *)orig_ip);
+                        break;
+                    }
+                    case SIMD_v128_any_true:
+                    {
+                        V128 value = GET_OPERAND_V128(0);
+                        frame_ip += 2;
+                        addr_ret = GET_OFFSET();
+                        frame_lp[addr_ret] =
+                            value.i64x2[0] != 0 || value.i64x2[1] != 0;
+                        break;
+                    }
+                    default:
+                        wasm_set_exception(module, "unsupported SIMD opcode");
+                }
+                HANDLE_OP_END();
+            }
+#endif
             HANDLE_OP(WASM_OP_CALL)
             {
 #if WASM_ENABLE_THREAD_MGR != 0

+ 48 - 15
core/iwasm/interpreter/wasm_loader.c

@@ -307,7 +307,8 @@ is_byte_a_type(uint8 type)
 }
 
 #if WASM_ENABLE_SIMD != 0
-#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
+#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) \
+    || (WASM_ENABLE_FAST_INTERP != 0)
 static V128
 read_i8x16(uint8 *p_buf, char *error_buf, uint32 error_buf_size)
 {
@@ -320,7 +321,8 @@ read_i8x16(uint8 *p_buf, char *error_buf, uint32 error_buf_size)
 
     return result;
 }
-#endif /* end of (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) */
+#endif /* end of (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) || \
+          (WASM_ENABLE_FAST_INTERP != 0) */
 #endif /* end of WASM_ENABLE_SIMD */
 
 static void *
@@ -707,7 +709,8 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end,
                     goto fail;
                 break;
 #if WASM_ENABLE_SIMD != 0
-#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
+#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) \
+    || (WASM_ENABLE_FAST_INTERP != 0)
             /* v128.const */
             case INIT_EXPR_TYPE_V128_CONST:
             {
@@ -736,7 +739,8 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end,
 #endif
                 break;
             }
-#endif /* end of (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) */
+#endif /* end of (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) || \
+          (WASM_ENABLE_FAST_INTERP != 0) */
 #endif /* end of WASM_ENABLE_SIMD */
 
 #if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0
@@ -4105,7 +4109,8 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
                         return false;
                     }
 #if WASM_ENABLE_SIMD != 0
-#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
+#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) \
+    || (WASM_ENABLE_FAST_INTERP != 0)
                     /* TODO: check func type, if it has v128 param or result,
                              report error */
 #endif
@@ -7566,7 +7571,8 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache,
             }
 
 #if WASM_ENABLE_SIMD != 0
-#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
+#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) \
+    || (WASM_ENABLE_FAST_INTERP != 0)
             case WASM_OP_SIMD_PREFIX:
             {
                 uint32 opcode1;
@@ -7659,7 +7665,8 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache,
                 }
                 break;
             }
-#endif /* end of (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) */
+#endif /* end of (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) || \
+          (WASM_ENABLE_FAST_INTERP != 0) */
 #endif /* end of WASM_ENABLE_SIMD */
 
 #if WASM_ENABLE_SHARED_MEMORY != 0
@@ -9903,7 +9910,8 @@ check_memory_access_align(uint8 opcode, uint32 align, char *error_buf,
 }
 
 #if WASM_ENABLE_SIMD != 0
-#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
+#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) \
+    || (WASM_ENABLE_FAST_INTERP != 0)
 static bool
 check_simd_memory_access_align(uint8 opcode, uint32 align, char *error_buf,
                                uint32 error_buf_size)
@@ -12120,10 +12128,20 @@ re_scan:
 #endif
                     }
 #if WASM_ENABLE_SIMD != 0
-#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
+#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) \
+    || (WASM_ENABLE_FAST_INTERP != 0)
                     else if (*(loader_ctx->frame_ref - 1) == VALUE_TYPE_V128) {
                         loader_ctx->frame_ref -= 4;
                         loader_ctx->stack_cell_num -= 4;
+#if WASM_ENABLE_FAST_INTERP != 0
+                        skip_label();
+                        loader_ctx->frame_offset -= 4;
+                        if ((*(loader_ctx->frame_offset)
+                             > loader_ctx->start_dynamic_offset)
+                            && (*(loader_ctx->frame_offset)
+                                < loader_ctx->max_dynamic_offset))
+                            loader_ctx->dynamic_offset -= 4;
+#endif
                     }
 #endif
 #endif
@@ -12210,10 +12228,12 @@ re_scan:
 #endif /* end of WASM_ENABLE_FAST_INTERP */
                             break;
 #if WASM_ENABLE_SIMD != 0
-#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
+#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) \
+    || (WASM_ENABLE_FAST_INTERP != 0)
                         case VALUE_TYPE_V128:
                             break;
-#endif /* (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) */
+#endif /* (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) || \
+          (WASM_ENABLE_FAST_INTERP != 0) */
 #endif /* WASM_ENABLE_SIMD != 0 */
                         default:
                         {
@@ -12308,8 +12328,9 @@ re_scan:
                     uint8 opcode_tmp = WASM_OP_SELECT;
 
                     if (type == VALUE_TYPE_V128) {
-#if (WASM_ENABLE_SIMD == 0) \
-    || ((WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0))
+#if (WASM_ENABLE_SIMD == 0)                                        \
+    || ((WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) \
+        && (WASM_ENABLE_FAST_INTERP == 0))
                         set_error_buf(error_buf, error_buf_size,
                                       "SIMD v128 type isn't supported");
                         goto fail;
@@ -14870,7 +14891,8 @@ re_scan:
             }
 
 #if WASM_ENABLE_SIMD != 0
-#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
+#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) \
+    || (WASM_ENABLE_FAST_INTERP != 0)
             case WASM_OP_SIMD_PREFIX:
             {
                 uint32 opcode1;
@@ -14882,6 +14904,10 @@ re_scan:
 
                 read_leb_uint32(p, p_end, opcode1);
 
+#if WASM_ENABLE_FAST_INTERP != 0
+                emit_byte(loader_ctx, opcode1);
+#endif
+
                 /* follow the order of enum WASMSimdEXTOpcode in wasm_opcode.h
                  */
                 switch (opcode1) {
@@ -14938,7 +14964,13 @@ re_scan:
                     /* basic operation */
                     case SIMD_v128_const:
                     {
+                        uint64 high, low;
                         CHECK_BUF1(p, p_end, 16);
+#if WASM_ENABLE_FAST_INTERP != 0
+                        wasm_runtime_read_v128(p, &high, &low);
+                        emit_uint64(loader_ctx, high);
+                        emit_uint64(loader_ctx, low);
+#endif
                         p += 16;
                         PUSH_V128();
                         break;
@@ -15524,7 +15556,8 @@ re_scan:
                 }
                 break;
             }
-#endif /* end of (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) */
+#endif /* end of (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) || \
+          (WASM_ENABLE_FAST_INTERP != 0) */
 #endif /* end of WASM_ENABLE_SIMD */
 
 #if WASM_ENABLE_SHARED_MEMORY != 0

+ 2 - 1
core/iwasm/interpreter/wasm_opcode.h

@@ -782,7 +782,8 @@ typedef enum WASMAtomicEXTOpcode {
 
 #define SET_GOTO_TABLE_ELEM(opcode) [opcode] = HANDLE_OPCODE(opcode)
 
-#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_SIMD != 0
+#if (WASM_ENABLE_JIT != 0 || WASM_ENABLE_FAST_INTERP != 0) \
+    && WASM_ENABLE_SIMD != 0
 #define SET_GOTO_TABLE_SIMD_PREFIX_ELEM() \
     SET_GOTO_TABLE_ELEM(WASM_OP_SIMD_PREFIX),
 #else