Commit 73df92fc authored by gdeepti's avatar gdeepti Committed by Commit bot

Convert SIMD machine ops to runtime function calls

 - Add Simd128 type to Wasm AST types
 - Add a pass that converts SIMD machine ops to runtime calls
 - Sample opcodes Int32x4Splat, Int32x4ExtractLane and test
 - Separate out generic SIMD Machine ops as these cannot be
 handled by runtime functions just yet.

LOG=N
BUG=v8:4124

R=bradnelson@chromium.org, bbudge@chromium.org, titzer@chromium.org

Review-Url: https://codereview.chromium.org/1991143002
Cr-Commit-Position: refs/heads/master@{#37789}
parent ebf166df
...@@ -1029,6 +1029,8 @@ v8_source_set("v8_base") { ...@@ -1029,6 +1029,8 @@ v8_source_set("v8_base") {
"src/compiler/scheduler.h", "src/compiler/scheduler.h",
"src/compiler/select-lowering.cc", "src/compiler/select-lowering.cc",
"src/compiler/select-lowering.h", "src/compiler/select-lowering.h",
"src/compiler/simd-lowering.cc",
"src/compiler/simd-lowering.h",
"src/compiler/simplified-lowering.cc", "src/compiler/simplified-lowering.cc",
"src/compiler/simplified-lowering.h", "src/compiler/simplified-lowering.h",
"src/compiler/simplified-operator-reducer.cc", "src/compiler/simplified-operator-reducer.cc",
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/compiler/simd-lowering.h"
namespace v8 {
namespace internal {
namespace compiler {
static ConversionSignature* SigCreateInt32x4;
static ConversionSignature* SigCreateFloat32x4;
static ConversionSignature* SigCreateInt16x8;
static ConversionSignature* SigCreateInt8x16;
static ConversionSignature* SigExtractLaneInt;
static ConversionSignature* SigExtractLaneFloat;
static ConversionSignature* SigDefault;
SimdLowering::~SimdLowering() {}
void SimdLowering::InitializeSignatures() {
// Initialize signatures for runtime calls
const int kReturnCount = 1;
const int kBinop = 2;
const int kSimd32x4 = 4;
const int kSimd16x8 = 8;
const int kSimd8x16 = 16;
ConversionSignature::Builder CreateInt32x4Builder(zone_, kReturnCount,
kSimd32x4);
ConversionSignature::Builder CreateFloat32x4Builder(zone_, kReturnCount,
kSimd32x4);
ConversionSignature::Builder CreateInt16x8Builder(zone_, kReturnCount,
kSimd16x8);
ConversionSignature::Builder CreateInt8x16Builder(zone_, kReturnCount,
kSimd8x16);
ConversionSignature::Builder ExtractLaneIntBuilder(zone_, kReturnCount,
kBinop);
ConversionSignature::Builder ExtractLaneFloatBuilder(zone_, kReturnCount,
kBinop);
ConversionSignature::Builder DefaultBuilder(zone_, kReturnCount, kSimd8x16);
// Initialize Signatures for create functions
for (int i = 0; i < kSimd32x4; i++) {
CreateInt32x4Builder.AddParam(Conversion::kInt32);
CreateFloat32x4Builder.AddParam(Conversion::kFloat32);
}
CreateInt32x4Builder.AddReturn(Conversion::kOpaque);
SigCreateInt32x4 = CreateInt32x4Builder.Build();
CreateFloat32x4Builder.AddReturn(Conversion::kOpaque);
SigCreateFloat32x4 = CreateFloat32x4Builder.Build();
for (int i = 0; i < kSimd16x8; i++) {
CreateInt16x8Builder.AddParam(Conversion::kInt32);
}
CreateInt16x8Builder.AddReturn(Conversion::kOpaque);
SigCreateInt16x8 = CreateInt16x8Builder.Build();
for (int i = 0; i < kSimd8x16; i++) {
CreateInt8x16Builder.AddParam(Conversion::kInt32);
}
CreateInt8x16Builder.AddReturn(Conversion::kOpaque);
SigCreateInt8x16 = CreateInt8x16Builder.Build();
// Initialize signatures for ExtractLane functions
ExtractLaneIntBuilder.AddParam(Conversion::kOpaque);
ExtractLaneIntBuilder.AddParam(Conversion::kInt32);
ExtractLaneIntBuilder.AddReturn(Conversion::kInt32);
SigExtractLaneInt = ExtractLaneIntBuilder.Build();
ExtractLaneFloatBuilder.AddParam(Conversion::kOpaque);
ExtractLaneFloatBuilder.AddParam(Conversion::kFloat32);
ExtractLaneFloatBuilder.AddReturn(Conversion::kFloat32);
SigExtractLaneFloat = ExtractLaneFloatBuilder.Build();
// Initialize default signature.
for (int i = 0; i < kSimd8x16; i++) {
DefaultBuilder.AddParam(Conversion::kNone);
}
DefaultBuilder.AddReturn(Conversion::kNone);
SigDefault = DefaultBuilder.Build();
}
Reduction SimdLowering::Reduce(Node* node) {
// For now lower everything to runtime calls.
switch (node->opcode()) {
case IrOpcode::kCreateInt32x4: {
return Replace(builder_->ChangeToRuntimeCall(
node, Runtime::kCreateInt32x4, SigCreateInt32x4));
}
case IrOpcode::kCreateInt16x8: {
return Replace(builder_->ChangeToRuntimeCall(
node, Runtime::kCreateInt16x8, SigCreateInt16x8));
}
case IrOpcode::kCreateInt8x16: {
return Replace(builder_->ChangeToRuntimeCall(
node, Runtime::kCreateInt8x16, SigCreateInt8x16));
}
case IrOpcode::kCreateFloat32x4: {
return Replace(builder_->ChangeToRuntimeCall(
node, Runtime::kCreateFloat32x4, SigCreateFloat32x4));
}
case IrOpcode::kInt8x16ExtractLane:
case IrOpcode::kInt16x8ExtractLane:
case IrOpcode::kInt32x4ExtractLane: {
return Replace(builder_->ChangeToRuntimeCall(
node, Runtime::kInt32x4ExtractLane, SigExtractLaneInt));
}
case IrOpcode::kFloat32x4ExtractLane: {
return Replace(builder_->ChangeToRuntimeCall(
node, Runtime::kFloat32x4ExtractLane, SigExtractLaneFloat));
}
default: { break; }
}
// TODO(gdeepti): Implement and test.
// Assume the others are all just simd in and out.
switch (node->opcode()) {
#define F(Opcode) \
case IrOpcode::k##Opcode: { \
return Replace( \
builder_->ChangeToRuntimeCall(node, Runtime::k##Opcode, SigDefault)); \
}
MACHINE_SIMD_RETURN_SIMD_OP_LIST(F)
MACHINE_SIMD_RETURN_BOOL_OP_LIST(F)
#undef F
default: { return NoChange(); }
}
UNREACHABLE();
return NoChange();
}
} // namespace compiler
} // namespace internal
} // namespace v8
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_COMPILER_SIMD_LOWERING_H_
#define V8_COMPILER_SIMD_LOWERING_H_
#include "src/compiler/graph-reducer.h"
#include "src/compiler/wasm-compiler.h"
#include "src/runtime/runtime.h"
namespace v8 {
namespace internal {
namespace compiler {
typedef Signature<Conversion> ConversionSignature;
class SimdLowering final : public Reducer {
public:
SimdLowering(Zone* zone, WasmGraphBuilder* builder)
: builder_(builder), zone_(zone) {
InitializeSignatures();
}
virtual ~SimdLowering();
Reduction Reduce(Node* node) override;
private:
WasmGraphBuilder* builder_;
Zone* zone_;
void InitializeSignatures();
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_SIMD_LOWERING_H_
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "src/compiler/machine-operator.h" #include "src/compiler/machine-operator.h"
#include "src/compiler/node-matchers.h" #include "src/compiler/node-matchers.h"
#include "src/compiler/pipeline.h" #include "src/compiler/pipeline.h"
#include "src/compiler/simd-lowering.h"
#include "src/compiler/source-position.h" #include "src/compiler/source-position.h"
#include "src/compiler/zone-pool.h" #include "src/compiler/zone-pool.h"
...@@ -2346,6 +2347,12 @@ Node* WasmGraphBuilder::ToJS(Node* node, Node* context, wasm::LocalType type) { ...@@ -2346,6 +2347,12 @@ Node* WasmGraphBuilder::ToJS(Node* node, Node* context, wasm::LocalType type) {
} }
} }
Node* WasmGraphBuilder::BuildChangeTaggedToInt32(Node* value) {
value = BuildChangeTaggedToFloat64(value);
value = graph()->NewNode(jsgraph()->machine()->ChangeFloat64ToInt32(), value);
return value;
}
Node* WasmGraphBuilder::BuildJavaScriptToNumber(Node* node, Node* context, Node* WasmGraphBuilder::BuildJavaScriptToNumber(Node* node, Node* context,
Node* effect, Node* control) { Node* effect, Node* control) {
Callable callable = CodeFactory::ToNumber(jsgraph()->isolate()); Callable callable = CodeFactory::ToNumber(jsgraph()->isolate());
...@@ -2785,6 +2792,12 @@ Node* WasmGraphBuilder::MemSize(uint32_t offset) { ...@@ -2785,6 +2792,12 @@ Node* WasmGraphBuilder::MemSize(uint32_t offset) {
} }
} }
Node* WasmGraphBuilder::DefaultS128Value() {
Node* zero = jsgraph()->Int32Constant(0);
return graph()->NewNode(jsgraph()->machine()->CreateInt32x4(), zero, zero,
zero, zero);
}
Node* WasmGraphBuilder::FunctionTable() { Node* WasmGraphBuilder::FunctionTable() {
DCHECK(module_ && module_->instance && DCHECK(module_ && module_->instance &&
!module_->instance->function_table.is_null()); !module_->instance->function_table.is_null());
...@@ -2794,6 +2807,79 @@ Node* WasmGraphBuilder::FunctionTable() { ...@@ -2794,6 +2807,79 @@ Node* WasmGraphBuilder::FunctionTable() {
return function_table_; return function_table_;
} }
Node* WasmGraphBuilder::ChangeToRuntimeCall(Node* node,
Runtime::FunctionId function_id,
Signature<Conversion>* signature) {
SimplifiedOperatorBuilder simplified(jsgraph()->zone());
const Runtime::Function* function = Runtime::FunctionForId(function_id);
CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
jsgraph()->zone(), function_id, function->nargs, Operator::kNoProperties,
CallDescriptor::kNoFlags);
const int kInputSize = 16;
const int kDefaultFunctionParams = 6;
Node* inputs[kInputSize + kDefaultFunctionParams];
DCHECK_LE(function->nargs + kDefaultFunctionParams,
static_cast<int>(arraysize(inputs)));
// Either there are control + effect or not.
DCHECK(node->InputCount() == function->nargs ||
node->InputCount() == function->nargs + 2);
int index = 0;
inputs[index++] = jsgraph()->CEntryStubConstant(function->result_size);
for (int i = 0; i < function->nargs; ++i) {
Node* arg = node->InputAt(i);
switch (signature->GetParam(i)) {
case Conversion::kInt32:
arg = BuildChangeInt32ToTagged(arg);
break;
case Conversion::kFloat32:
arg = jsgraph()->graph()->NewNode(
jsgraph()->machine()->ChangeFloat32ToFloat64(), arg);
arg = BuildChangeFloat64ToTagged(arg);
break;
case Conversion::kFloat64:
arg = BuildChangeFloat64ToTagged(arg);
break;
default:
break;
}
inputs[index++] = arg;
}
inputs[index++] = jsgraph()->ExternalConstant(
ExternalReference(function_id, jsgraph()->isolate()));
inputs[index++] = jsgraph()->Int32Constant(function->nargs);
inputs[index++] = jsgraph()->Constant(module_->instance->context);
// Loads and stores have control and effect, others do not and use
// the start node instead.
if (node->InputCount() == function->nargs + 2) {
inputs[index++] = node->InputAt(function->nargs + 1); // effect
inputs[index++] = node->InputAt(function->nargs + 2); // control
} else {
inputs[index++] = jsgraph()->graph()->start(); // effect
inputs[index++] = jsgraph()->graph()->start(); // control
}
Node* ret = jsgraph()->graph()->NewNode(jsgraph()->common()->Call(desc),
index, inputs);
Conversion return_type = signature->GetReturn();
switch (return_type) {
case Conversion::kInt32:
ret = BuildChangeTaggedToInt32(ret);
break;
case Conversion::kFloat32:
NodeProperties::SetType(ret, Type::Number());
ret = BuildChangeTaggedToFloat64(ret);
ret = jsgraph()->graph()->NewNode(
jsgraph()->machine()->TruncateInt64ToInt32(), ret);
break;
case Conversion::kFloat64:
ret = BuildChangeTaggedToFloat64(ret);
break;
default:
break;
}
return ret;
}
Node* WasmGraphBuilder::LoadGlobal(uint32_t index) { Node* WasmGraphBuilder::LoadGlobal(uint32_t index) {
MachineType mem_type = module_->GetGlobalType(index); MachineType mem_type = module_->GetGlobalType(index);
Node* addr = jsgraph()->RelocatableIntPtrConstant( Node* addr = jsgraph()->RelocatableIntPtrConstant(
...@@ -3190,6 +3276,25 @@ void WasmGraphBuilder::SetSourcePosition(Node* node, ...@@ -3190,6 +3276,25 @@ void WasmGraphBuilder::SetSourcePosition(Node* node,
source_position_table_->SetSourcePosition(node, pos); source_position_table_->SetSourcePosition(node, pos);
} }
MachineOperatorBuilder* WasmGraphBuilder::simd() {
has_simd_ops_ = true;
return jsgraph()->machine();
}
Node* WasmGraphBuilder::SimdOp(wasm::WasmOpcode opcode,
const NodeVector& inputs) {
switch (opcode) {
case wasm::kExprI32x4ExtractLane:
return graph()->NewNode(simd()->Int32x4ExtractLane(), inputs[0],
inputs[1]);
case wasm::kExprI32x4Splat:
return graph()->NewNode(simd()->CreateInt32x4(), inputs[0], inputs[0],
inputs[0], inputs[0]);
default:
return graph()->NewNode(UnsupportedOpcode(opcode), nullptr);
}
}
static void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag, static void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag,
Isolate* isolate, Handle<Code> code, Isolate* isolate, Handle<Code> code,
const char* message, uint32_t index, const char* message, uint32_t index,
...@@ -3402,6 +3507,21 @@ SourcePositionTable* WasmCompilationUnit::BuildGraphForWasmFunction( ...@@ -3402,6 +3507,21 @@ SourcePositionTable* WasmCompilationUnit::BuildGraphForWasmFunction(
} }
int index = static_cast<int>(function_->func_index); int index = static_cast<int>(function_->func_index);
// Run lowering pass if SIMD ops are present in the function
if (builder.has_simd_ops()) {
SimdLowering simd(jsgraph_->zone(), &builder);
GraphReducer graph_reducer(jsgraph_->zone(), graph);
graph_reducer.AddReducer(&simd);
graph_reducer.ReduceGraph();
if (FLAG_trace_turbo_graph) { // Simple textual RPO.
OFStream os(stdout);
os << "-- Graph after simd lowering -- " << std::endl;
os << AsRPO(*graph);
}
}
if (index >= FLAG_trace_wasm_ast_start && index < FLAG_trace_wasm_ast_end) { if (index >= FLAG_trace_wasm_ast_start && index < FLAG_trace_wasm_ast_end) {
OFStream os(stdout); OFStream os(stdout);
PrintAst(isolate_->allocator(), body, os, nullptr); PrintAst(isolate_->allocator(), body, os, nullptr);
......
...@@ -22,6 +22,7 @@ class JSGraph; ...@@ -22,6 +22,7 @@ class JSGraph;
class Graph; class Graph;
class Operator; class Operator;
class SourcePositionTable; class SourcePositionTable;
class MachineOperatorBuilder;
} // namespace compiler } // namespace compiler
namespace wasm { namespace wasm {
...@@ -90,6 +91,8 @@ Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::ModuleEnv* module, ...@@ -90,6 +91,8 @@ Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::ModuleEnv* module,
// Abstracts details of building TurboFan graph nodes for WASM to separate // Abstracts details of building TurboFan graph nodes for WASM to separate
// the WASM decoder from the internal details of TurboFan. // the WASM decoder from the internal details of TurboFan.
class WasmTrapHelper; class WasmTrapHelper;
enum class Conversion { kNone, kOpaque, kInt32, kFloat32, kFloat64 };
typedef ZoneVector<Node*> NodeVector;
class WasmGraphBuilder { class WasmGraphBuilder {
public: public:
WasmGraphBuilder( WasmGraphBuilder(
...@@ -124,6 +127,7 @@ class WasmGraphBuilder { ...@@ -124,6 +127,7 @@ class WasmGraphBuilder {
Node* Float32Constant(float value); Node* Float32Constant(float value);
Node* Float64Constant(double value); Node* Float64Constant(double value);
Node* HeapConstant(Handle<HeapObject> value); Node* HeapConstant(Handle<HeapObject> value);
Node* DefaultS128Value();
Node* Binop(wasm::WasmOpcode opcode, Node* left, Node* right, Node* Binop(wasm::WasmOpcode opcode, Node* left, Node* right,
wasm::WasmCodePosition position = wasm::kNoCodePosition); wasm::WasmCodePosition position = wasm::kNoCodePosition);
Node* Unop(wasm::WasmOpcode opcode, Node* input, Node* Unop(wasm::WasmOpcode opcode, Node* input,
...@@ -161,6 +165,8 @@ class WasmGraphBuilder { ...@@ -161,6 +165,8 @@ class WasmGraphBuilder {
Node* FromJS(Node* node, Node* context, wasm::LocalType type); Node* FromJS(Node* node, Node* context, wasm::LocalType type);
Node* Invert(Node* node); Node* Invert(Node* node);
Node* FunctionTable(); Node* FunctionTable();
Node* ChangeToRuntimeCall(Node* node, Runtime::FunctionId function_id,
Signature<Conversion>* signature);
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
// Operations that concern the linear memory. // Operations that concern the linear memory.
...@@ -192,6 +198,10 @@ class WasmGraphBuilder { ...@@ -192,6 +198,10 @@ class WasmGraphBuilder {
void SetSourcePosition(Node* node, wasm::WasmCodePosition position); void SetSourcePosition(Node* node, wasm::WasmCodePosition position);
Node* SimdOp(wasm::WasmOpcode opcode, const NodeVector& inputs);
bool has_simd_ops() { return has_simd_ops_; }
private: private:
static const int kDefaultBufferSize = 16; static const int kDefaultBufferSize = 16;
friend class WasmTrapHelper; friend class WasmTrapHelper;
...@@ -213,6 +223,7 @@ class WasmGraphBuilder { ...@@ -213,6 +223,7 @@ class WasmGraphBuilder {
SetOncePointer<const Operator> allocate_heap_number_operator_; SetOncePointer<const Operator> allocate_heap_number_operator_;
compiler::SourcePositionTable* source_position_table_ = nullptr; compiler::SourcePositionTable* source_position_table_ = nullptr;
bool has_simd_ops_;
// Internal helper methods. // Internal helper methods.
JSGraph* jsgraph() { return jsgraph_; } JSGraph* jsgraph() { return jsgraph_; }
...@@ -316,6 +327,7 @@ class WasmGraphBuilder { ...@@ -316,6 +327,7 @@ class WasmGraphBuilder {
Node* BuildJavaScriptToNumber(Node* node, Node* context, Node* effect, Node* BuildJavaScriptToNumber(Node* node, Node* context, Node* effect,
Node* control); Node* control);
Node* BuildChangeInt32ToTagged(Node* value); Node* BuildChangeInt32ToTagged(Node* value);
Node* BuildChangeTaggedToInt32(Node* value);
Node* BuildChangeFloat64ToTagged(Node* value); Node* BuildChangeFloat64ToTagged(Node* value);
Node* BuildChangeTaggedToFloat64(Node* value); Node* BuildChangeTaggedToFloat64(Node* value);
...@@ -348,6 +360,9 @@ class WasmGraphBuilder { ...@@ -348,6 +360,9 @@ class WasmGraphBuilder {
if (buf != buffer) memcpy(buf, buffer, old_count * sizeof(Node*)); if (buf != buffer) memcpy(buf, buffer, old_count * sizeof(Node*));
return buf; return buf;
} }
// Simd helper functions
MachineOperatorBuilder* simd();
}; };
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
......
...@@ -513,6 +513,8 @@ DEFINE_INT(typed_array_max_size_in_heap, 64, ...@@ -513,6 +513,8 @@ DEFINE_INT(typed_array_max_size_in_heap, 64,
DEFINE_BOOL(wasm_jit_prototype, false, DEFINE_BOOL(wasm_jit_prototype, false,
"enable experimental wasm runtime dynamic code generation") "enable experimental wasm runtime dynamic code generation")
DEFINE_BOOL(wasm_simd_prototype, false,
"enable prototype simd opcodes for wasm")
// Profiler flags. // Profiler flags.
DEFINE_INT(frame_count, 1, "number of stack frames inspected by the profiler") DEFINE_INT(frame_count, 1, "number of stack frames inspected by the profiler")
......
...@@ -660,6 +660,8 @@ ...@@ -660,6 +660,8 @@
'compiler/scheduler.h', 'compiler/scheduler.h',
'compiler/select-lowering.cc', 'compiler/select-lowering.cc',
'compiler/select-lowering.h', 'compiler/select-lowering.h',
'compiler/simd-lowering.cc',
'compiler/simd-lowering.h',
'compiler/simplified-lowering.cc', 'compiler/simplified-lowering.cc',
'compiler/simplified-lowering.h', 'compiler/simplified-lowering.h',
'compiler/simplified-operator-reducer.cc', 'compiler/simplified-operator-reducer.cc',
......
...@@ -1019,6 +1019,15 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -1019,6 +1019,15 @@ class WasmFullDecoder : public WasmDecoder {
len = 1 + operand.length; len = 1 + operand.length;
break; break;
} }
case kSimdPrefix: {
if (FLAG_wasm_simd_prototype) {
len++;
byte simd_index = *(pc_ + 1);
opcode = static_cast<WasmOpcode>(opcode << 8 | simd_index);
DecodeSimdOpcode(opcode);
break;
}
}
case kExprJITSingleFunction: { case kExprJITSingleFunction: {
if (FLAG_wasm_jit_prototype) { if (FLAG_wasm_jit_prototype) {
JITSingleFunctionOperand operand(this, pc_); JITSingleFunctionOperand operand(this, pc_);
...@@ -1139,6 +1148,17 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -1139,6 +1148,17 @@ class WasmFullDecoder : public WasmDecoder {
return 1 + operand.length; return 1 + operand.length;
} }
void DecodeSimdOpcode(WasmOpcode opcode) {
FunctionSig* sig = WasmOpcodes::Signature(opcode);
compiler::NodeVector inputs(sig->parameter_count(), zone_);
for (size_t i = sig->parameter_count(); i > 0; i--) {
Value val = Pop(static_cast<int>(i - 1), sig->GetParam(i - 1));
inputs[i - 1] = val.node;
}
TFNode* node = BUILD(SimdOp, opcode, inputs);
Push(GetReturnType(sig), node);
}
void DoReturn() { void DoReturn() {
int count = static_cast<int>(sig_->return_count()); int count = static_cast<int>(sig_->return_count());
TFNode** buffer = nullptr; TFNode** buffer = nullptr;
......
...@@ -579,6 +579,13 @@ class LocalDeclEncoder { ...@@ -579,6 +579,13 @@ class LocalDeclEncoder {
#define WASM_I32_REINTERPRET_F32(x) x, kExprI32ReinterpretF32 #define WASM_I32_REINTERPRET_F32(x) x, kExprI32ReinterpretF32
#define WASM_I64_REINTERPRET_F64(x) x, kExprI64ReinterpretF64 #define WASM_I64_REINTERPRET_F64(x) x, kExprI64ReinterpretF64
//------------------------------------------------------------------------------
// Simd Operations.
//------------------------------------------------------------------------------
#define WASM_SIMD_I32x4_SPLAT(x) x, kSimdPrefix, kExprI32x4Splat & 0xff
#define WASM_SIMD_I32x4_EXTRACT_LANE(x, y) \
x, y, kSimdPrefix, kExprI32x4ExtractLane & 0xff
#define SIG_ENTRY_v_v kWasmFunctionTypeForm, 0, 0 #define SIG_ENTRY_v_v kWasmFunctionTypeForm, 0, 0
#define SIZEOF_SIG_ENTRY_v_v 3 #define SIZEOF_SIG_ENTRY_v_v 3
......
...@@ -68,15 +68,27 @@ FOREACH_SIGNATURE(DECLARE_SIG) ...@@ -68,15 +68,27 @@ FOREACH_SIGNATURE(DECLARE_SIG)
static const FunctionSig* kSimpleExprSigs[] = { static const FunctionSig* kSimpleExprSigs[] = {
nullptr, FOREACH_SIGNATURE(DECLARE_SIG_ENTRY)}; nullptr, FOREACH_SIGNATURE(DECLARE_SIG_ENTRY)};
#define DECLARE_SIMD_SIG_ENTRY(name, ...) &kSig_##name,
static const FunctionSig* kSimdExprSigs[] = {
nullptr, FOREACH_SIMD_SIGNATURE(DECLARE_SIMD_SIG_ENTRY)};
static byte kSimpleExprSigTable[256]; static byte kSimpleExprSigTable[256];
static byte kSimdExprSigTable[256];
// Initialize the signature table. // Initialize the signature table.
static void InitSigTable() { static void InitSigTables() {
#define SET_SIG_TABLE(name, opcode, sig) \ #define SET_SIG_TABLE(name, opcode, sig) \
kSimpleExprSigTable[opcode] = static_cast<int>(kSigEnum_##sig) + 1; kSimpleExprSigTable[opcode] = static_cast<int>(kSigEnum_##sig) + 1;
FOREACH_SIMPLE_OPCODE(SET_SIG_TABLE); FOREACH_SIMPLE_OPCODE(SET_SIG_TABLE);
FOREACH_SIMPLE_MEM_OPCODE(SET_SIG_TABLE); FOREACH_SIMPLE_MEM_OPCODE(SET_SIG_TABLE);
FOREACH_ASMJS_COMPAT_OPCODE(SET_SIG_TABLE); FOREACH_ASMJS_COMPAT_OPCODE(SET_SIG_TABLE);
#undef SET_SIG_TABLE
byte simd_index;
#define SET_SIG_TABLE(name, opcode, sig) \
simd_index = opcode & 0xff; \
kSimdExprSigTable[simd_index] = static_cast<int>(kSigEnum_##sig) + 1;
FOREACH_SIMD_OPCODE(SET_SIG_TABLE)
#undef SET_SIG_TABLE #undef SET_SIG_TABLE
} }
...@@ -84,18 +96,26 @@ class SigTable { ...@@ -84,18 +96,26 @@ class SigTable {
public: public:
SigTable() { SigTable() {
// TODO(ahaas): Move {InitSigTable} into the class. // TODO(ahaas): Move {InitSigTable} into the class.
InitSigTable(); InitSigTables();
} }
FunctionSig* Signature(WasmOpcode opcode) const { FunctionSig* Signature(WasmOpcode opcode) const {
return const_cast<FunctionSig*>( return const_cast<FunctionSig*>(
kSimpleExprSigs[kSimpleExprSigTable[static_cast<byte>(opcode)]]); kSimpleExprSigs[kSimpleExprSigTable[static_cast<byte>(opcode)]]);
} }
FunctionSig* SimdSignature(WasmOpcode opcode) const {
return const_cast<FunctionSig*>(
kSimdExprSigs[kSimdExprSigTable[static_cast<byte>(opcode & 0xff)]]);
}
}; };
static base::LazyInstance<SigTable>::type sig_table = LAZY_INSTANCE_INITIALIZER; static base::LazyInstance<SigTable>::type sig_table = LAZY_INSTANCE_INITIALIZER;
FunctionSig* WasmOpcodes::Signature(WasmOpcode opcode) { FunctionSig* WasmOpcodes::Signature(WasmOpcode opcode) {
return sig_table.Get().Signature(opcode); if (opcode >> 8 == kSimdPrefix) {
return sig_table.Get().SimdSignature(opcode);
} else {
return sig_table.Get().Signature(opcode);
}
} }
// TODO(titzer): pull WASM_64 up to a common header. // TODO(titzer): pull WASM_64 up to a common header.
......
...@@ -465,11 +465,16 @@ const WasmCodePosition kNoCodePosition = -1; ...@@ -465,11 +465,16 @@ const WasmCodePosition kNoCodePosition = -1;
V(s_sii, kAstS128, kAstS128, kAstI32, kAstI32) \ V(s_sii, kAstS128, kAstS128, kAstI32, kAstI32) \
V(s_si, kAstS128, kAstS128, kAstI32) V(s_si, kAstS128, kAstS128, kAstI32)
#define FOREACH_PREFIX(V) V(Simd, 0xe5)
enum WasmOpcode { enum WasmOpcode {
// Declare expression opcodes. // Declare expression opcodes.
#define DECLARE_NAMED_ENUM(name, opcode, sig) kExpr##name = opcode, #define DECLARE_NAMED_ENUM(name, opcode, sig) kExpr##name = opcode,
FOREACH_OPCODE(DECLARE_NAMED_ENUM) FOREACH_OPCODE(DECLARE_NAMED_ENUM)
#undef DECLARE_NAMED_ENUM #undef DECLARE_NAMED_ENUM
#define DECLARE_PREFIX(name, opcode) k##name##Prefix = opcode,
FOREACH_PREFIX(DECLARE_PREFIX)
#undef DECLARE_PREFIX
}; };
// The reason for a trap. // The reason for a trap.
......
...@@ -188,9 +188,10 @@ ...@@ -188,9 +188,10 @@
'wasm/test-run-wasm-interpreter.cc', 'wasm/test-run-wasm-interpreter.cc',
'wasm/test-run-wasm-js.cc', 'wasm/test-run-wasm-js.cc',
'wasm/test-run-wasm-module.cc', 'wasm/test-run-wasm-module.cc',
'wasm/test-run-wasm-relocation.cc',
'wasm/test-run-wasm-simd.cc',
'wasm/test-signatures.h', 'wasm/test-signatures.h',
'wasm/test-wasm-function-name-table.cc', 'wasm/test-wasm-function-name-table.cc',
'wasm/test-run-wasm-relocation.cc',
'wasm/test-wasm-stack.cc', 'wasm/test-wasm-stack.cc',
'wasm/test-wasm-trap-position.cc', 'wasm/test-wasm-trap-position.cc',
'wasm/wasm-run-utils.h', 'wasm/wasm-run-utils.h',
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdlib.h>
#include <string.h>
#include "src/wasm/encoder.h"
#include "src/wasm/wasm-js.h"
#include "src/wasm/wasm-macro-gen.h"
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-opcodes.h"
#include "test/cctest/cctest.h"
#include "test/cctest/wasm/test-signatures.h"
using namespace v8::base;
using namespace v8::internal;
using namespace v8::internal::compiler;
using namespace v8::internal::wasm;
namespace {
void TestModule(Zone* zone, WasmModuleBuilder* builder,
int32_t expected_result) {
FLAG_wasm_simd_prototype = true;
FLAG_wasm_num_compilation_tasks = 0;
ZoneBuffer buffer(zone);
builder->WriteTo(buffer);
Isolate* isolate = CcTest::InitIsolateOnce();
HandleScope scope(isolate);
WasmJs::InstallWasmFunctionMap(isolate, isolate->native_context());
int32_t result =
testing::CompileAndRunWasmModule(isolate, buffer.begin(), buffer.end());
CHECK_EQ(expected_result, result);
}
void ExportAsMain(WasmFunctionBuilder* f) {
static const char kMainName[] = "main";
f->SetExported();
f->SetName(kMainName, arraysize(kMainName) - 1);
}
} // namespace
TEST(Run_WasmMoule_simd) {
v8::base::AccountingAllocator allocator;
Zone zone(&allocator);
TestSignatures sigs;
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
uint16_t f_index = builder->AddFunction();
WasmFunctionBuilder* f = builder->FunctionAt(f_index);
f->SetSignature(sigs.i_i());
ExportAsMain(f);
byte code[] = {WASM_SIMD_I32x4_EXTRACT_LANE(
WASM_SIMD_I32x4_SPLAT(WASM_I8(123)), WASM_I8(2))};
f->EmitCode(code, sizeof(code));
TestModule(&zone, builder, 123);
}
...@@ -35,7 +35,8 @@ class TestSignatures { ...@@ -35,7 +35,8 @@ class TestSignatures {
sig_v_v(0, 0, kIntTypes4), sig_v_v(0, 0, kIntTypes4),
sig_v_i(0, 1, kIntTypes4), sig_v_i(0, 1, kIntTypes4),
sig_v_ii(0, 2, kIntTypes4), sig_v_ii(0, 2, kIntTypes4),
sig_v_iii(0, 3, kIntTypes4) { sig_v_iii(0, 3, kIntTypes4),
sig_s_i(1, 1, kSimd128IntTypes4) {
// I used C++ and you won't believe what happened next.... // I used C++ and you won't believe what happened next....
for (int i = 0; i < 4; i++) kIntTypes4[i] = kAstI32; for (int i = 0; i < 4; i++) kIntTypes4[i] = kAstI32;
for (int i = 0; i < 4; i++) kLongTypes4[i] = kAstI64; for (int i = 0; i < 4; i++) kLongTypes4[i] = kAstI64;
...@@ -44,9 +45,11 @@ class TestSignatures { ...@@ -44,9 +45,11 @@ class TestSignatures {
for (int i = 0; i < 4; i++) kIntLongTypes4[i] = kAstI64; for (int i = 0; i < 4; i++) kIntLongTypes4[i] = kAstI64;
for (int i = 0; i < 4; i++) kIntFloatTypes4[i] = kAstF32; for (int i = 0; i < 4; i++) kIntFloatTypes4[i] = kAstF32;
for (int i = 0; i < 4; i++) kIntDoubleTypes4[i] = kAstF64; for (int i = 0; i < 4; i++) kIntDoubleTypes4[i] = kAstF64;
for (int i = 0; i < 4; i++) kSimd128IntTypes4[i] = kAstS128;
kIntLongTypes4[0] = kAstI32; kIntLongTypes4[0] = kAstI32;
kIntFloatTypes4[0] = kAstI32; kIntFloatTypes4[0] = kAstI32;
kIntDoubleTypes4[0] = kAstI32; kIntDoubleTypes4[0] = kAstI32;
kSimd128IntTypes4[1] = kAstI32;
} }
FunctionSig* i_v() { return &sig_i_v; } FunctionSig* i_v() { return &sig_i_v; }
...@@ -71,6 +74,7 @@ class TestSignatures { ...@@ -71,6 +74,7 @@ class TestSignatures {
FunctionSig* v_i() { return &sig_v_i; } FunctionSig* v_i() { return &sig_v_i; }
FunctionSig* v_ii() { return &sig_v_ii; } FunctionSig* v_ii() { return &sig_v_ii; }
FunctionSig* v_iii() { return &sig_v_iii; } FunctionSig* v_iii() { return &sig_v_iii; }
FunctionSig* s_i() { return &sig_s_i; }
FunctionSig* many(Zone* zone, LocalType ret, LocalType param, int count) { FunctionSig* many(Zone* zone, LocalType ret, LocalType param, int count) {
FunctionSig::Builder builder(zone, ret == kAstStmt ? 0 : 1, count); FunctionSig::Builder builder(zone, ret == kAstStmt ? 0 : 1, count);
...@@ -89,6 +93,7 @@ class TestSignatures { ...@@ -89,6 +93,7 @@ class TestSignatures {
LocalType kIntLongTypes4[4]; LocalType kIntLongTypes4[4];
LocalType kIntFloatTypes4[4]; LocalType kIntFloatTypes4[4];
LocalType kIntDoubleTypes4[4]; LocalType kIntDoubleTypes4[4];
LocalType kSimd128IntTypes4[4];
FunctionSig sig_i_v; FunctionSig sig_i_v;
FunctionSig sig_i_i; FunctionSig sig_i_i;
...@@ -112,6 +117,7 @@ class TestSignatures { ...@@ -112,6 +117,7 @@ class TestSignatures {
FunctionSig sig_v_i; FunctionSig sig_v_i;
FunctionSig sig_v_ii; FunctionSig sig_v_ii;
FunctionSig sig_v_iii; FunctionSig sig_v_iii;
FunctionSig sig_s_i;
}; };
} // namespace wasm } // namespace wasm
} // namespace internal } // namespace internal
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --expose-wasm --wasm-simd-prototype --wasm-num-compilation-tasks=0
load('test/mjsunit/wasm/wasm-constants.js');
load('test/mjsunit/wasm/wasm-module-builder.js');
// TODO(gdeepti): Currently wasm simd ops are tested using runtime calls to
// JS runtime functions, as this needs heap allocation sequential compile is
// triggered here. This is only used for bootstrapping and needs to be removed
// when we have architectuaral/scalar implementations for wasm simd ops.
(function SimdSplatExtractTest() {
var module = new WasmModuleBuilder();
module.addFunction("splatextract", kSig_i_ii)
.addBody([kExprGetLocal, 0, kExprSimdPrefix, kExprI32x4Splat,
kExprI32Const, 1, kExprSimdPrefix, kExprI32x4ExtractLane])
.exportAs("main");
var instance = module.instantiate();
assertEquals(123, instance.exports.main(123, 2));
})();
...@@ -303,6 +303,9 @@ var kExprI32Ror = 0xb6; ...@@ -303,6 +303,9 @@ var kExprI32Ror = 0xb6;
var kExprI32Rol = 0xb7; var kExprI32Rol = 0xb7;
var kExprI64Ror = 0xb8; var kExprI64Ror = 0xb8;
var kExprI64Rol = 0xb9; var kExprI64Rol = 0xb9;
var kExprSimdPrefix = 0xe5;
var kExprI32x4Splat = 0x1b;
var kExprI32x4ExtractLane = 0x1c;
var kExprJITSingleFunction = 0xf0; var kExprJITSingleFunction = 0xf0;
......
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