Commit eff26541 authored by Aseem Garg's avatar Aseem Garg Committed by Commit Bot

[wasm] Add simd splat to wasm interpreter

R=gdeepti@chromium.org,bbudge@chromium.org,clemensh@chromium.org,titzer@chromium.org
BUG=v8:6020

Change-Id: I25676d4f8a7ea7b1e02a54abe009faec0eb2c6db
Reviewed-on: https://chromium-review.googlesource.com/1018840
Commit-Queue: Aseem Garg <aseemgarg@chromium.org>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53266}
parent 518dbb9c
......@@ -1143,6 +1143,8 @@ class WasmDecoder : public Decoder {
case kExprI32AtomicStore16U:
case kExprS128StoreMem:
return {2, 0};
FOREACH_SIMD_1_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
return {1, 1};
default: {
sig = WasmOpcodes::Signature(opcode);
if (sig) {
......
......@@ -40,7 +40,7 @@ namespace wasm {
#define FOREACH_INTERNAL_OPCODE(V) V(Breakpoint, 0xFF)
#define WASM_CTYPES(V) \
V(I32, int32_t) V(I64, int64_t) V(F32, float) V(F64, double)
V(I32, int32_t) V(I64, int64_t) V(F32, float) V(F64, double) V(S128, Simd128)
#define FOREACH_SIMPLE_BINOP(V) \
V(I32Add, uint32_t, +) \
......@@ -1286,9 +1286,9 @@ class ThreadImpl {
for (auto p : code->locals.type_list) {
WasmValue val;
switch (p) {
#define CASE_TYPE(wasm, ctype) \
case kWasm##wasm: \
val = WasmValue(static_cast<ctype>(0)); \
#define CASE_TYPE(wasm, ctype) \
case kWasm##wasm: \
val = WasmValue(ctype{}); \
break;
WASM_CTYPES(CASE_TYPE)
#undef CASE_TYPE
......@@ -1622,6 +1622,42 @@ class ThreadImpl {
}
}
bool ExecuteSimdOp(WasmOpcode opcode, Decoder* decoder, InterpreterCode* code,
pc_t pc, int& len) {
switch (opcode) {
#define SPLAT_CASE(format, sType, valType, num) \
case kExpr##format##Splat: { \
WasmValue val = Pop(); \
valType v = val.to<valType>(); \
sType s; \
for (int i = 0; i < num; i++) s.val[i] = v; \
Push(WasmValue(Simd128(s))); \
return true; \
}
SPLAT_CASE(I32x4, int4, int32_t, 4)
SPLAT_CASE(F32x4, float4, float, 4)
SPLAT_CASE(I16x8, int8, int32_t, 8)
SPLAT_CASE(I8x16, int16, int32_t, 16)
#undef SPLAT_CASE
#define EXTRACT_LANE_CASE(format, name) \
case kExpr##format##ExtractLane: { \
SimdLaneImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc)); \
++len; \
WasmValue val = Pop(); \
Simd128 s = val.to_s128(); \
Push(WasmValue(s.to_##name().val[imm.lane])); \
return true; \
}
EXTRACT_LANE_CASE(I32x4, i32x4)
EXTRACT_LANE_CASE(F32x4, f32x4)
EXTRACT_LANE_CASE(I16x8, i16x8)
EXTRACT_LANE_CASE(I8x16, i8x16)
#undef EXTRACT_LANE_CASE
default:
return false;
}
}
// Check if our control stack (frames_) exceeds the limit. Trigger stack
// overflow if it does, and unwinding the current frame.
// Returns true if execution can continue, false if the current activation was
......@@ -2083,6 +2119,11 @@ class ThreadImpl {
if (!ExecuteAtomicOp(opcode, &decoder, code, pc, len)) return;
break;
}
case kSimdPrefix: {
++len;
if (!ExecuteSimdOp(opcode, &decoder, code, pc, len)) return;
break;
}
#define EXECUTE_SIMPLE_BINOP(name, ctype, op) \
case kExpr##name: { \
......
......@@ -6,6 +6,7 @@
#define V8_WASM_WASM_VALUE_H_
#include "src/boxed-float.h"
#include "src/utils.h"
#include "src/wasm/wasm-opcodes.h"
#include "src/zone/zone-containers.h"
......@@ -13,39 +14,76 @@ namespace v8 {
namespace internal {
namespace wasm {
#define FOREACH_SIMD_TYPE(V) \
V(float, float4, f32x4, 4) \
V(int32_t, int4, i32x4, 4) \
V(uint32_t, uint4, ui32x4, 4) \
V(int16_t, int8, i16x8, 8) \
V(uint16_t, uint8, ui16x8, 8) \
V(int8_t, int16, i8x16, 16) \
V(uint8_t, uint16, ui8x16, 16)
#define DEFINE_SIMD_TYPE(cType, sType, name, kSize) \
struct sType { \
cType val[kSize]; \
};
FOREACH_SIMD_TYPE(DEFINE_SIMD_TYPE)
#undef DEFINE_SIMD_TYPE
class Simd128 {
public:
Simd128() : val_() {
for (size_t i = 0; i < 16; i++) {
val_[i] = 0;
}
}
#define DEFINE_SIMD_TYPE_SPECIFIC_METHODS(cType, sType, name, size) \
explicit Simd128(sType val) { \
WriteUnalignedValue<sType>(reinterpret_cast<Address>(val_), val); \
} \
sType to_##name() { \
return ReadUnalignedValue<sType>(reinterpret_cast<Address>(val_)); \
}
FOREACH_SIMD_TYPE(DEFINE_SIMD_TYPE_SPECIFIC_METHODS)
#undef DEFINE_SIMD_TYPE_SPECIFIC_METHODS
private:
uint8_t val_[16];
};
// Macro for defining WasmValue methods for different types.
// Elements:
// - name (for to_<name>() method)
// - wasm type
// - c type
// - how to get bit pattern from value {v} of type {c type}
// - how to get value of type {c type} from bit pattern {p}
#define FOREACH_WASMVAL_TYPE(V) \
V(i32, kWasmI32, int32_t, static_cast<uint32_t>(v), static_cast<int32_t>(p)) \
V(u32, kWasmI32, uint32_t, v, static_cast<uint32_t>(p)) \
V(i64, kWasmI64, int64_t, static_cast<uint64_t>(v), static_cast<int64_t>(p)) \
V(u64, kWasmI64, uint64_t, v, p) \
V(f32, kWasmF32, float, bit_cast<uint32_t>(v), \
bit_cast<float>(static_cast<uint32_t>(p))) \
V(f32_boxed, kWasmF32, Float32, v.get_bits(), \
Float32::FromBits(static_cast<uint32_t>(p))) \
V(f64, kWasmF64, double, bit_cast<uint64_t>(v), bit_cast<double>(p)) \
V(f64_boxed, kWasmF64, Float64, v.get_bits(), Float64::FromBits(p))
#define FOREACH_WASMVAL_TYPE(V) \
V(i32, kWasmI32, int32_t) \
V(u32, kWasmI32, uint32_t) \
V(i64, kWasmI64, int64_t) \
V(u64, kWasmI64, uint64_t) \
V(f32, kWasmF32, float) \
V(f32_boxed, kWasmF32, Float32) \
V(f64, kWasmF64, double) \
V(f64_boxed, kWasmF64, Float64) \
V(s128, kWasmS128, Simd128)
// A wasm value with type information.
class WasmValue {
public:
WasmValue() : type_(kWasmStmt) {}
#define DEFINE_TYPE_SPECIFIC_METHODS(name, localtype, ctype, v_to_p, p_to_v) \
explicit WasmValue(ctype v) : type_(localtype), bit_pattern_(v_to_p) {} \
ctype to_##name() const { \
DCHECK_EQ(localtype, type_); \
return to_##name##_unchecked(); \
} \
ctype to_##name##_unchecked() const { \
auto p = bit_pattern_; \
return p_to_v; \
WasmValue() : type_(kWasmStmt), bit_pattern_{} {}
#define DEFINE_TYPE_SPECIFIC_METHODS(name, localtype, ctype) \
explicit WasmValue(ctype v) : type_(localtype), bit_pattern_{} { \
static_assert(sizeof(ctype) <= sizeof(bit_pattern_), \
"size too big for WasmValue"); \
WriteUnalignedValue<ctype>(reinterpret_cast<Address>(bit_pattern_), v); \
} \
ctype to_##name() const { \
DCHECK_EQ(localtype, type_); \
return to_##name##_unchecked(); \
} \
ctype to_##name##_unchecked() const { \
return ReadUnalignedValue<ctype>(reinterpret_cast<Address>(bit_pattern_)); \
}
FOREACH_WASMVAL_TYPE(DEFINE_TYPE_SPECIFIC_METHODS)
#undef DEFINE_TYPE_SPECIFIC_METHODS
......@@ -54,7 +92,8 @@ class WasmValue {
// Checks equality of type and bit pattern (also for float and double values).
bool operator==(const WasmValue& other) const {
return type_ == other.type_ && bit_pattern_ == other.bit_pattern_;
return type_ == other.type_ &&
!memcmp(bit_pattern_, other.bit_pattern_, 16);
}
template <typename T>
......@@ -65,7 +104,7 @@ class WasmValue {
private:
ValueType type_;
uint64_t bit_pattern_;
uint8_t bit_pattern_[16];
};
#define DECLARE_CAST(name, localtype, ctype, ...) \
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment