Commit cf9ee0ec authored by aseemgarg's avatar aseemgarg Committed by Commit bot

[wasm] simd scalar lowering F32x4Add and I32x4Add

BUG=v8:4124
TEST:test-run-wasm-simd-lowering
R=titzer@chromium.org,bradnelson@chromium.org,gdeepti@chromium.org

Review-Url: https://chromiumcodereview.appspot.com/2294743003
Cr-Commit-Position: refs/heads/master@{#40448}
parent 71e390fa
......@@ -1170,6 +1170,8 @@ v8_source_set("v8_base") {
"src/compiler/scheduler.h",
"src/compiler/select-lowering.cc",
"src/compiler/select-lowering.h",
"src/compiler/simd-scalar-lowering.cc",
"src/compiler/simd-scalar-lowering.h",
"src/compiler/simplified-lowering.cc",
"src/compiler/simplified-lowering.h",
"src/compiler/simplified-operator-reducer.cc",
......
This diff is collapsed.
// 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_SCALAR_LOWERING_H_
#define V8_COMPILER_SIMD_SCALAR_LOWERING_H_
#include "src/compiler/common-operator.h"
#include "src/compiler/graph.h"
#include "src/compiler/machine-operator.h"
#include "src/compiler/node-marker.h"
#include "src/zone/zone-containers.h"
namespace v8 {
namespace internal {
namespace compiler {
class SimdScalarLowering {
public:
SimdScalarLowering(Graph* graph, MachineOperatorBuilder* machine,
CommonOperatorBuilder* common, Zone* zone,
Signature<MachineRepresentation>* signature);
void LowerGraph();
int GetParameterCountAfterLowering();
private:
enum class State : uint8_t { kUnvisited, kOnStack, kVisited };
enum class SimdType : uint8_t { kInt32, kFloat32 };
static const size_t kMaxLanes = 4;
struct Replacement {
Node* node[kMaxLanes];
SimdType type; // represents what input type is expected
};
Zone* zone() const { return zone_; }
Graph* graph() const { return graph_; }
MachineOperatorBuilder* machine() const { return machine_; }
CommonOperatorBuilder* common() const { return common_; }
Signature<MachineRepresentation>* signature() const { return signature_; }
void LowerNode(Node* node);
bool DefaultLowering(Node* node);
void ReplaceNode(Node* old, Node** new_nodes);
bool HasReplacement(size_t index, Node* node);
Node** GetReplacements(Node* node);
Node** GetReplacementsWithType(Node* node, SimdType type);
SimdType ReplacementType(Node* node);
void PreparePhiReplacement(Node* phi);
void SetLoweredType(Node* node, Node* output);
struct NodeState {
Node* node;
int input_index;
};
Zone* zone_;
Graph* const graph_;
MachineOperatorBuilder* machine_;
CommonOperatorBuilder* common_;
NodeMarker<State> state_;
ZoneDeque<NodeState> stack_;
Replacement* replacements_;
Signature<MachineRepresentation>* signature_;
Node* placeholder_;
int parameter_count_after_lowering_;
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_SIMD_SCALAR_LOWERING_H_
......@@ -24,6 +24,7 @@
#include "src/compiler/machine-operator.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/pipeline.h"
#include "src/compiler/simd-scalar-lowering.h"
#include "src/compiler/source-position.h"
#include "src/compiler/zone-stats.h"
......@@ -3046,6 +3047,13 @@ void WasmGraphBuilder::Int64LoweringForTesting() {
}
}
void WasmGraphBuilder::SimdScalarLoweringForTesting() {
SimdScalarLowering(jsgraph()->graph(), jsgraph()->machine(),
jsgraph()->common(), jsgraph()->zone(),
function_signature_)
.LowerGraph();
}
void WasmGraphBuilder::SetSourcePosition(Node* node,
wasm::WasmCodePosition position) {
DCHECK_NE(position, wasm::kNoCodePosition);
......@@ -3068,6 +3076,18 @@ Node* WasmGraphBuilder::SimdOp(wasm::WasmOpcode opcode,
case wasm::kExprI32x4Splat:
return graph()->NewNode(jsgraph()->machine()->CreateInt32x4(), inputs[0],
inputs[0], inputs[0], inputs[0]);
case wasm::kExprI32x4Add:
return graph()->NewNode(jsgraph()->machine()->Int32x4Add(), inputs[0],
inputs[1]);
case wasm::kExprF32x4ExtractLane:
return graph()->NewNode(jsgraph()->machine()->Float32x4ExtractLane(),
inputs[0], inputs[1]);
case wasm::kExprF32x4Splat:
return graph()->NewNode(jsgraph()->machine()->CreateFloat32x4(),
inputs[0], inputs[0], inputs[0], inputs[0]);
case wasm::kExprF32x4Add:
return graph()->NewNode(jsgraph()->machine()->Float32x4Add(), inputs[0],
inputs[1]);
default:
return graph()->NewNode(UnsupportedOpcode(opcode), nullptr);
}
......@@ -3079,6 +3099,9 @@ Node* WasmGraphBuilder::SimdExtractLane(wasm::WasmOpcode opcode, uint8_t lane,
case wasm::kExprI32x4ExtractLane:
return graph()->NewNode(jsgraph()->machine()->Int32x4ExtractLane(), input,
Int32Constant(lane));
case wasm::kExprF32x4ExtractLane:
return graph()->NewNode(jsgraph()->machine()->Float32x4ExtractLane(),
input, Int32Constant(lane));
default:
return graph()->NewNode(UnsupportedOpcode(opcode), nullptr);
}
......@@ -3294,6 +3317,9 @@ SourcePositionTable* WasmCompilationUnit::BuildGraphForWasmFunction(
r.LowerGraph();
}
SimdScalarLowering(graph, machine, common, jsgraph_->zone(), function_->sig)
.LowerGraph();
int index = static_cast<int>(function_->func_index);
if (index >= FLAG_trace_wasm_ast_start && index < FLAG_trace_wasm_ast_end) {
......
......@@ -200,6 +200,8 @@ class WasmGraphBuilder {
void Int64LoweringForTesting();
void SimdScalarLoweringForTesting();
void SetSourcePosition(Node* node, wasm::WasmCodePosition position);
Node* CreateS128Value(int32_t value);
......
......@@ -307,26 +307,23 @@ CallDescriptor* ModuleEnv::GetWasmCallDescriptor(Zone* zone,
"wasm-call");
}
CallDescriptor* ModuleEnv::GetI32WasmCallDescriptor(
Zone* zone, CallDescriptor* descriptor) {
CallDescriptor* ReplaceTypeInCallDescriptorWith(
Zone* zone, CallDescriptor* descriptor, size_t num_replacements,
MachineType input_type, MachineRepresentation output_type) {
size_t parameter_count = descriptor->ParameterCount();
size_t return_count = descriptor->ReturnCount();
for (size_t i = 0; i < descriptor->ParameterCount(); i++) {
if (descriptor->GetParameterType(i) == MachineType::Int64()) {
// For each int64 input we get two int32 inputs.
parameter_count++;
if (descriptor->GetParameterType(i) == input_type) {
parameter_count += num_replacements - 1;
}
}
for (size_t i = 0; i < descriptor->ReturnCount(); i++) {
if (descriptor->GetReturnType(i) == MachineType::Int64()) {
// For each int64 return we get two int32 returns.
return_count++;
if (descriptor->GetReturnType(i) == input_type) {
return_count += num_replacements - 1;
}
}
if (parameter_count == descriptor->ParameterCount() &&
return_count == descriptor->ReturnCount()) {
// If there is no int64 parameter or return value, we can just return the
// original descriptor.
return descriptor;
}
......@@ -335,10 +332,10 @@ CallDescriptor* ModuleEnv::GetI32WasmCallDescriptor(
Allocator rets = return_registers.Get();
for (size_t i = 0; i < descriptor->ReturnCount(); i++) {
if (descriptor->GetReturnType(i) == MachineType::Int64()) {
// For each int64 return we get two int32 returns.
locations.AddReturn(rets.Next(MachineRepresentation::kWord32));
locations.AddReturn(rets.Next(MachineRepresentation::kWord32));
if (descriptor->GetReturnType(i) == input_type) {
for (size_t j = 0; j < num_replacements; j++) {
locations.AddReturn(rets.Next(output_type));
}
} else {
locations.AddReturn(
rets.Next(descriptor->GetReturnType(i).representation()));
......@@ -348,10 +345,10 @@ CallDescriptor* ModuleEnv::GetI32WasmCallDescriptor(
Allocator params = parameter_registers.Get();
for (size_t i = 0; i < descriptor->ParameterCount(); i++) {
if (descriptor->GetParameterType(i) == MachineType::Int64()) {
// For each int64 input we get two int32 inputs.
locations.AddParam(params.Next(MachineRepresentation::kWord32));
locations.AddParam(params.Next(MachineRepresentation::kWord32));
if (descriptor->GetParameterType(i) == input_type) {
for (size_t j = 0; j < num_replacements; j++) {
locations.AddParam(params.Next(output_type));
}
} else {
locations.AddParam(
params.Next(descriptor->GetParameterType(i).representation()));
......@@ -369,8 +366,20 @@ CallDescriptor* ModuleEnv::GetI32WasmCallDescriptor(
descriptor->CalleeSavedFPRegisters(), // callee-saved fp regs
descriptor->flags(), // flags
descriptor->debug_name());
}
return descriptor;
CallDescriptor* ModuleEnv::GetI32WasmCallDescriptor(
Zone* zone, CallDescriptor* descriptor) {
return ReplaceTypeInCallDescriptorWith(zone, descriptor, 2,
MachineType::Int64(),
MachineRepresentation::kWord32);
}
CallDescriptor* ModuleEnv::GetI32WasmCallDescriptorForSimd(
Zone* zone, CallDescriptor* descriptor) {
return ReplaceTypeInCallDescriptorWith(zone, descriptor, 4,
MachineType::Simd128(),
MachineRepresentation::kWord32);
}
} // namespace wasm
......
......@@ -701,6 +701,8 @@
'compiler/scheduler.h',
'compiler/select-lowering.cc',
'compiler/select-lowering.h',
'compiler/simd-scalar-lowering.cc',
'compiler/simd-scalar-lowering.h',
'compiler/simplified-lowering.cc',
'compiler/simplified-lowering.h',
'compiler/simplified-operator-reducer.cc',
......
......@@ -150,6 +150,16 @@ struct Control {
(build() ? CheckForException(builder_->func(__VA_ARGS__)) : nullptr)
#define BUILD0(func) (build() ? CheckForException(builder_->func()) : nullptr)
struct LaneOperand {
uint8_t lane;
unsigned length;
inline LaneOperand(Decoder* decoder, const byte* pc) {
lane = decoder->checked_read_u8(pc, 2, "lane");
length = 1;
}
};
// Generic Wasm bytecode decoder with utilities for decoding operands,
// lengths, etc.
class WasmDecoder : public Decoder {
......@@ -240,8 +250,17 @@ class WasmDecoder : public Decoder {
return true;
}
inline bool Validate(const byte* pc, LaneOperand& operand) {
if (operand.lane < 0 || operand.lane > 3) {
error(pc_, pc_ + 2, "invalid extract lane value");
return false;
} else {
return true;
}
}
unsigned OpcodeLength(const byte* pc) {
switch (static_cast<WasmOpcode>(*pc)) {
switch (static_cast<byte>(*pc)) {
#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE)
FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
......@@ -304,6 +323,27 @@ class WasmDecoder : public Decoder {
return 5;
case kExprF64Const:
return 9;
case kSimdPrefix: {
byte simd_index = *(pc + 1);
WasmOpcode opcode =
static_cast<WasmOpcode>(kSimdPrefix << 8 | simd_index);
switch (opcode) {
#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
FOREACH_SIMD_0_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
#undef DECLARE_OPCODE_CASE
{
return 2;
}
#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
FOREACH_SIMD_1_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
#undef DECLARE_OPCODE_CASE
{
return 3;
}
default:
UNREACHABLE();
}
}
default:
return 1;
}
......@@ -1249,18 +1289,25 @@ class WasmFullDecoder : public WasmDecoder {
return 1 + operand.length;
}
unsigned ExtractLane(WasmOpcode opcode, LocalType type) {
LaneOperand operand(this, pc_);
if (Validate(pc_, operand)) {
TFNode* input = Pop(0, LocalType::kSimd128).node;
TFNode* node = BUILD(SimdExtractLane, opcode, operand.lane, input);
Push(type, node);
}
return operand.length;
}
unsigned DecodeSimdOpcode(WasmOpcode opcode) {
unsigned len = 0;
switch (opcode) {
case kExprI32x4ExtractLane: {
uint8_t lane = this->checked_read_u8(pc_, 2, "lane number");
if (lane < 0 || lane > 3) {
error(pc_, pc_ + 2, "invalid extract lane value");
}
TFNode* input = Pop(0, LocalType::kSimd128).node;
TFNode* node = BUILD(SimdExtractLane, opcode, lane, input);
Push(LocalType::kWord32, node);
len++;
len = ExtractLane(opcode, LocalType::kWord32);
break;
}
case kExprF32x4ExtractLane: {
len = ExtractLane(opcode, LocalType::kFloat32);
break;
}
default: {
......
......@@ -614,6 +614,11 @@ class LocalDeclEncoder {
#define WASM_SIMD_I32x4_SPLAT(x) x, kSimdPrefix, kExprI32x4Splat & 0xff
#define WASM_SIMD_I32x4_EXTRACT_LANE(lane, x) \
x, kSimdPrefix, kExprI32x4ExtractLane & 0xff, static_cast<byte>(lane)
#define WASM_SIMD_I32x4_ADD(x, y) x, y, kSimdPrefix, kExprI32x4Add & 0xff
#define WASM_SIMD_F32x4_SPLAT(x) x, kSimdPrefix, kExprF32x4Splat & 0xff
#define WASM_SIMD_F32x4_EXTRACT_LANE(lane, x) \
x, kSimdPrefix, kExprF32x4ExtractLane & 0xff, static_cast<byte>(lane)
#define WASM_SIMD_F32x4_ADD(x, y) x, y, kSimdPrefix, kExprF32x4Add & 0xff
#define SIG_ENTRY_v_v kWasmFunctionTypeForm, 0, 0
#define SIZEOF_SIG_ENTRY_v_v 3
......
......@@ -333,6 +333,8 @@ struct V8_EXPORT_PRIVATE ModuleEnv {
FunctionSig* sig);
static compiler::CallDescriptor* GetI32WasmCallDescriptor(
Zone* zone, compiler::CallDescriptor* descriptor);
static compiler::CallDescriptor* GetI32WasmCallDescriptorForSimd(
Zone* zone, compiler::CallDescriptor* descriptor);
};
// A helper for printing out the names of functions.
......
......@@ -277,6 +277,7 @@ v8_executable("cctest") {
"test-log-stack-tracer.cc",
"test-macro-assembler-x64.cc",
"test-run-wasm-relocation-x64.cc",
"wasm/test-run-wasm-simd-lowering.cc",
"wasm/test-run-wasm-simd.cc",
]
} else if (v8_current_cpu == "x87") {
......
......@@ -235,7 +235,8 @@
'test-macro-assembler-x64.cc',
'test-log-stack-tracer.cc',
'test-run-wasm-relocation-x64.cc',
'wasm/test-run-wasm-simd.cc'
'wasm/test-run-wasm-simd.cc',
'wasm/test-run-wasm-simd-lowering.cc',
],
'cctest_sources_arm': [ ### gcmole(arch:arm) ###
'test-assembler-arm.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/wasm/wasm-macro-gen.h"
#include "src/wasm/wasm-module.h"
#include "test/cctest/cctest.h"
#include "test/cctest/compiler/value-helper.h"
#include "test/cctest/wasm/wasm-run-utils.h"
#include "test/common/wasm/test-signatures.h"
using namespace v8::base;
using namespace v8::internal;
using namespace v8::internal::compiler;
using namespace v8::internal::wasm;
WASM_EXEC_TEST(Simd_I32x4_Splat) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32());
BUILD(r,
WASM_SIMD_I32x4_EXTRACT_LANE(0, WASM_SIMD_I32x4_SPLAT(WASM_I32V(5))));
FOR_INT32_INPUTS(i) { CHECK_EQ(5, r.Call()); }
}
WASM_EXEC_TEST(Simd_I32x4_Add) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32());
BUILD(r, WASM_SIMD_I32x4_EXTRACT_LANE(
0, WASM_SIMD_I32x4_ADD(WASM_SIMD_I32x4_SPLAT(WASM_I32V(5)),
WASM_SIMD_I32x4_SPLAT(WASM_I32V(6)))));
FOR_INT32_INPUTS(i) { CHECK_EQ(11, r.Call()); }
}
WASM_EXEC_TEST(Simd_F32x4_Splat) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32());
BUILD(r,
WASM_IF_ELSE(WASM_F32_EQ(WASM_SIMD_F32x4_EXTRACT_LANE(
0, WASM_SIMD_F32x4_SPLAT(WASM_F32(9.5))),
WASM_F32(9.5)),
WASM_RETURN1(WASM_I32V(1)), WASM_RETURN1(WASM_I32V(0))));
FOR_INT32_INPUTS(i) { CHECK_EQ(1, r.Call()); }
}
WASM_EXEC_TEST(Simd_I32x4_Extract_With_F32x4) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32());
BUILD(r,
WASM_IF_ELSE(WASM_I32_EQ(WASM_SIMD_I32x4_EXTRACT_LANE(
0, WASM_SIMD_F32x4_SPLAT(WASM_F32(30.5))),
WASM_I32_REINTERPRET_F32(WASM_F32(30.5))),
WASM_RETURN1(WASM_I32V(1)), WASM_RETURN1(WASM_I32V(0))));
FOR_INT32_INPUTS(i) { CHECK_EQ(1, r.Call()); }
}
WASM_EXEC_TEST(Simd_F32x4_Extract_With_I32x4) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32());
BUILD(r,
WASM_IF_ELSE(WASM_F32_EQ(WASM_SIMD_F32x4_EXTRACT_LANE(
0, WASM_SIMD_I32x4_SPLAT(WASM_I32V(15))),
WASM_F32_REINTERPRET_I32(WASM_I32V(15))),
WASM_RETURN1(WASM_I32V(1)), WASM_RETURN1(WASM_I32V(0))));
FOR_INT32_INPUTS(i) { CHECK_EQ(1, r.Call()); }
}
WASM_EXEC_TEST(Simd_F32x4_Add_With_I32x4) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32());
BUILD(r,
WASM_IF_ELSE(
WASM_F32_EQ(WASM_SIMD_F32x4_EXTRACT_LANE(
0, WASM_SIMD_F32x4_ADD(
WASM_SIMD_I32x4_SPLAT(WASM_I32V(32)),
WASM_SIMD_I32x4_SPLAT(WASM_I32V(19)))),
WASM_F32_ADD(WASM_F32_REINTERPRET_I32(WASM_I32V(32)),
WASM_F32_REINTERPRET_I32(WASM_I32V(19)))),
WASM_RETURN1(WASM_I32V(1)), WASM_RETURN1(WASM_I32V(0))));
FOR_INT32_INPUTS(i) { CHECK_EQ(1, r.Call()); }
}
WASM_EXEC_TEST(Simd_I32x4_Add_With_F32x4) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t> r(kExecuteCompiled, MachineType::Int32());
BUILD(r,
WASM_IF_ELSE(
WASM_I32_EQ(WASM_SIMD_I32x4_EXTRACT_LANE(
0, WASM_SIMD_I32x4_ADD(
WASM_SIMD_F32x4_SPLAT(WASM_F32(21.25)),
WASM_SIMD_F32x4_SPLAT(WASM_F32(31.5)))),
WASM_I32_ADD(WASM_I32_REINTERPRET_F32(WASM_F32(21.25)),
WASM_I32_REINTERPRET_F32(WASM_F32(31.5)))),
WASM_RETURN1(WASM_I32V(1)), WASM_RETURN1(WASM_I32V(0))));
FOR_INT32_INPUTS(i) { CHECK_EQ(1, r.Call()); }
}
......@@ -300,6 +300,7 @@ inline void TestBuildingGraph(Zone* zone, JSGraph* jsgraph, ModuleEnv* module,
FATAL(str.str().c_str());
}
builder.Int64LoweringForTesting();
builder.SimdScalarLoweringForTesting();
}
template <typename ReturnType>
......
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