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") {
"src/compiler/scheduler.h",
"src/compiler/select-lowering.cc",
"src/compiler/select-lowering.h",
"src/compiler/simd-lowering.cc",
"src/compiler/simd-lowering.h",
"src/compiler/simplified-lowering.cc",
"src/compiler/simplified-lowering.h",
"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 @@
#include "src/compiler/machine-operator.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/pipeline.h"
#include "src/compiler/simd-lowering.h"
#include "src/compiler/source-position.h"
#include "src/compiler/zone-pool.h"
......@@ -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* effect, Node* control) {
Callable callable = CodeFactory::ToNumber(jsgraph()->isolate());
......@@ -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() {
DCHECK(module_ && module_->instance &&
!module_->instance->function_table.is_null());
......@@ -2794,6 +2807,79 @@ Node* WasmGraphBuilder::FunctionTable() {
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) {
MachineType mem_type = module_->GetGlobalType(index);
Node* addr = jsgraph()->RelocatableIntPtrConstant(
......@@ -3190,6 +3276,25 @@ void WasmGraphBuilder::SetSourcePosition(Node* node,
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,
Isolate* isolate, Handle<Code> code,
const char* message, uint32_t index,
......@@ -3402,6 +3507,21 @@ SourcePositionTable* WasmCompilationUnit::BuildGraphForWasmFunction(
}
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) {
OFStream os(stdout);
PrintAst(isolate_->allocator(), body, os, nullptr);
......
......@@ -22,6 +22,7 @@ class JSGraph;
class Graph;
class Operator;
class SourcePositionTable;
class MachineOperatorBuilder;
} // namespace compiler
namespace wasm {
......@@ -90,6 +91,8 @@ Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::ModuleEnv* module,
// Abstracts details of building TurboFan graph nodes for WASM to separate
// the WASM decoder from the internal details of TurboFan.
class WasmTrapHelper;
enum class Conversion { kNone, kOpaque, kInt32, kFloat32, kFloat64 };
typedef ZoneVector<Node*> NodeVector;
class WasmGraphBuilder {
public:
WasmGraphBuilder(
......@@ -124,6 +127,7 @@ class WasmGraphBuilder {
Node* Float32Constant(float value);
Node* Float64Constant(double value);
Node* HeapConstant(Handle<HeapObject> value);
Node* DefaultS128Value();
Node* Binop(wasm::WasmOpcode opcode, Node* left, Node* right,
wasm::WasmCodePosition position = wasm::kNoCodePosition);
Node* Unop(wasm::WasmOpcode opcode, Node* input,
......@@ -161,6 +165,8 @@ class WasmGraphBuilder {
Node* FromJS(Node* node, Node* context, wasm::LocalType type);
Node* Invert(Node* node);
Node* FunctionTable();
Node* ChangeToRuntimeCall(Node* node, Runtime::FunctionId function_id,
Signature<Conversion>* signature);
//-----------------------------------------------------------------------
// Operations that concern the linear memory.
......@@ -192,6 +198,10 @@ class WasmGraphBuilder {
void SetSourcePosition(Node* node, wasm::WasmCodePosition position);
Node* SimdOp(wasm::WasmOpcode opcode, const NodeVector& inputs);
bool has_simd_ops() { return has_simd_ops_; }
private:
static const int kDefaultBufferSize = 16;
friend class WasmTrapHelper;
......@@ -213,6 +223,7 @@ class WasmGraphBuilder {
SetOncePointer<const Operator> allocate_heap_number_operator_;
compiler::SourcePositionTable* source_position_table_ = nullptr;
bool has_simd_ops_;
// Internal helper methods.
JSGraph* jsgraph() { return jsgraph_; }
......@@ -316,6 +327,7 @@ class WasmGraphBuilder {
Node* BuildJavaScriptToNumber(Node* node, Node* context, Node* effect,
Node* control);
Node* BuildChangeInt32ToTagged(Node* value);
Node* BuildChangeTaggedToInt32(Node* value);
Node* BuildChangeFloat64ToTagged(Node* value);
Node* BuildChangeTaggedToFloat64(Node* value);
......@@ -348,6 +360,9 @@ class WasmGraphBuilder {
if (buf != buffer) memcpy(buf, buffer, old_count * sizeof(Node*));
return buf;
}
// Simd helper functions
MachineOperatorBuilder* simd();
};
} // namespace compiler
} // namespace internal
......
......@@ -513,6 +513,8 @@ DEFINE_INT(typed_array_max_size_in_heap, 64,
DEFINE_BOOL(wasm_jit_prototype, false,
"enable experimental wasm runtime dynamic code generation")
DEFINE_BOOL(wasm_simd_prototype, false,
"enable prototype simd opcodes for wasm")
// Profiler flags.
DEFINE_INT(frame_count, 1, "number of stack frames inspected by the profiler")
......
......@@ -660,6 +660,8 @@
'compiler/scheduler.h',
'compiler/select-lowering.cc',
'compiler/select-lowering.h',
'compiler/simd-lowering.cc',
'compiler/simd-lowering.h',
'compiler/simplified-lowering.cc',
'compiler/simplified-lowering.h',
'compiler/simplified-operator-reducer.cc',
......
......@@ -1019,6 +1019,15 @@ class WasmFullDecoder : public WasmDecoder {
len = 1 + operand.length;
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: {
if (FLAG_wasm_jit_prototype) {
JITSingleFunctionOperand operand(this, pc_);
......@@ -1139,6 +1148,17 @@ class WasmFullDecoder : public WasmDecoder {
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() {
int count = static_cast<int>(sig_->return_count());
TFNode** buffer = nullptr;
......
......@@ -579,6 +579,13 @@ class LocalDeclEncoder {
#define WASM_I32_REINTERPRET_F32(x) x, kExprI32ReinterpretF32
#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 SIZEOF_SIG_ENTRY_v_v 3
......
......@@ -68,15 +68,27 @@ FOREACH_SIGNATURE(DECLARE_SIG)
static const FunctionSig* kSimpleExprSigs[] = {
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 kSimdExprSigTable[256];
// Initialize the signature table.
static void InitSigTable() {
static void InitSigTables() {
#define SET_SIG_TABLE(name, opcode, sig) \
kSimpleExprSigTable[opcode] = static_cast<int>(kSigEnum_##sig) + 1;
FOREACH_SIMPLE_OPCODE(SET_SIG_TABLE);
FOREACH_SIMPLE_MEM_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
}
......@@ -84,18 +96,26 @@ class SigTable {
public:
SigTable() {
// TODO(ahaas): Move {InitSigTable} into the class.
InitSigTable();
InitSigTables();
}
FunctionSig* Signature(WasmOpcode opcode) const {
return const_cast<FunctionSig*>(
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;
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.
......
......@@ -465,11 +465,16 @@ const WasmCodePosition kNoCodePosition = -1;
V(s_sii, kAstS128, kAstS128, kAstI32, kAstI32) \
V(s_si, kAstS128, kAstS128, kAstI32)
#define FOREACH_PREFIX(V) V(Simd, 0xe5)
enum WasmOpcode {
// Declare expression opcodes.
#define DECLARE_NAMED_ENUM(name, opcode, sig) kExpr##name = opcode,
FOREACH_OPCODE(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.
......
......@@ -188,9 +188,10 @@
'wasm/test-run-wasm-interpreter.cc',
'wasm/test-run-wasm-js.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-wasm-function-name-table.cc',
'wasm/test-run-wasm-relocation.cc',
'wasm/test-wasm-stack.cc',
'wasm/test-wasm-trap-position.cc',
'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 {
sig_v_v(0, 0, kIntTypes4),
sig_v_i(0, 1, 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....
for (int i = 0; i < 4; i++) kIntTypes4[i] = kAstI32;
for (int i = 0; i < 4; i++) kLongTypes4[i] = kAstI64;
......@@ -44,9 +45,11 @@ class TestSignatures {
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++) kIntDoubleTypes4[i] = kAstF64;
for (int i = 0; i < 4; i++) kSimd128IntTypes4[i] = kAstS128;
kIntLongTypes4[0] = kAstI32;
kIntFloatTypes4[0] = kAstI32;
kIntDoubleTypes4[0] = kAstI32;
kSimd128IntTypes4[1] = kAstI32;
}
FunctionSig* i_v() { return &sig_i_v; }
......@@ -71,6 +74,7 @@ class TestSignatures {
FunctionSig* v_i() { return &sig_v_i; }
FunctionSig* v_ii() { return &sig_v_ii; }
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::Builder builder(zone, ret == kAstStmt ? 0 : 1, count);
......@@ -89,6 +93,7 @@ class TestSignatures {
LocalType kIntLongTypes4[4];
LocalType kIntFloatTypes4[4];
LocalType kIntDoubleTypes4[4];
LocalType kSimd128IntTypes4[4];
FunctionSig sig_i_v;
FunctionSig sig_i_i;
......@@ -112,6 +117,7 @@ class TestSignatures {
FunctionSig sig_v_i;
FunctionSig sig_v_ii;
FunctionSig sig_v_iii;
FunctionSig sig_s_i;
};
} // namespace wasm
} // 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;
var kExprI32Rol = 0xb7;
var kExprI64Ror = 0xb8;
var kExprI64Rol = 0xb9;
var kExprSimdPrefix = 0xe5;
var kExprI32x4Splat = 0x1b;
var kExprI32x4ExtractLane = 0x1c;
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