Convert SIMD wasm ops to runtime function calls
- Add Simd128 type to Wasm AST types - Decode SIMD prefix, wasm opcodes correctly - Add a pass that converts SIMD machine ops to runtime calls - Sample opcodes Int32x4Splat, Int32x4ExtractLane and test LOG=N BUG=v8:4124 R=bradnelson@chromium.org, bbudge@chromium.org, titzer@chromium.org Committed: https://crrev.com/73df92fc2fdbbfadc17e8ab4e58ec56ae2b3d91a Review-Url: https://codereview.chromium.org/1991143002 Cr-Original-Commit-Position: refs/heads/master@{#37789} Cr-Commit-Position: refs/heads/master@{#37807}
This commit is contained in:
parent
4ab82dd67b
commit
18543ff1da
2
BUILD.gn
2
BUILD.gn
@ -1046,6 +1046,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",
|
||||
|
116
src/compiler/simd-lowering.cc
Normal file
116
src/compiler/simd-lowering.cc
Normal file
@ -0,0 +1,116 @@
|
||||
// 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 {
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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
|
46
src/compiler/simd-lowering.h
Normal file
46
src/compiler/simd-lowering.h
Normal file
@ -0,0 +1,46 @@
|
||||
// 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:
|
||||
void InitializeSignatures();
|
||||
|
||||
ConversionSignature* SigCreateInt32x4;
|
||||
ConversionSignature* SigCreateFloat32x4;
|
||||
ConversionSignature* SigCreateInt16x8;
|
||||
ConversionSignature* SigCreateInt8x16;
|
||||
ConversionSignature* SigExtractLaneInt;
|
||||
ConversionSignature* SigExtractLaneFloat;
|
||||
ConversionSignature* SigDefault;
|
||||
|
||||
WasmGraphBuilder* builder_;
|
||||
Zone* zone_;
|
||||
};
|
||||
|
||||
} // 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_ = false;
|
||||
|
||||
// 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
|
||||
|
@ -514,6 +514,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.
|
||||
|
@ -189,9 +189,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',
|
||||
|
60
test/cctest/wasm/test-run-wasm-simd.cc
Normal file
60
test/cctest/wasm/test-run-wasm-simd.cc
Normal file
@ -0,0 +1,60 @@
|
||||
// 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
|
||||
|
23
test/mjsunit/wasm/test-wasm-simd-ops.js
Normal file
23
test/mjsunit/wasm/test-wasm-simd-ops.js
Normal file
@ -0,0 +1,23 @@
|
||||
// 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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user