Commit 81ad6b52 authored by aseemgarg's avatar aseemgarg Committed by Commit bot

[wasm]implement simd lowering for f32x4->i32x4, i32x4 min/max and shift instructions

This fixes and relands https://codereview.chromium.org/2718323003.

R=bbudge@chromium.org,titzer@chromium.org,ahaas@chromium.org,machenbach@chromium.org,bradnelson@chromium.org
BUG=v8:6020

Review-Url: https://codereview.chromium.org/2724973003
Cr-Commit-Position: refs/heads/master@{#43561}
parent ebe9e8cb
......@@ -17,24 +17,19 @@ namespace internal {
namespace compiler {
SimdScalarLowering::SimdScalarLowering(
Graph* graph, MachineOperatorBuilder* machine,
CommonOperatorBuilder* common, Zone* zone,
Signature<MachineRepresentation>* signature)
: zone_(zone),
graph_(graph),
machine_(machine),
common_(common),
state_(graph, 3),
stack_(zone),
JSGraph* jsgraph, Signature<MachineRepresentation>* signature)
: jsgraph_(jsgraph),
state_(jsgraph->graph(), 3),
stack_(jsgraph_->zone()),
replacements_(nullptr),
signature_(signature),
placeholder_(
graph->NewNode(common->Parameter(-2, "placeholder"), graph->start())),
placeholder_(graph()->NewNode(common()->Parameter(-2, "placeholder"),
graph()->start())),
parameter_count_after_lowering_(-1) {
DCHECK_NOT_NULL(graph);
DCHECK_NOT_NULL(graph->end());
replacements_ = zone->NewArray<Replacement>(graph->NodeCount());
memset(replacements_, 0, sizeof(Replacement) * graph->NodeCount());
DCHECK_NOT_NULL(graph());
DCHECK_NOT_NULL(graph()->end());
replacements_ = zone()->NewArray<Replacement>(graph()->NodeCount());
memset(replacements_, 0, sizeof(Replacement) * graph()->NodeCount());
}
void SimdScalarLowering::LowerGraph() {
......@@ -80,9 +75,15 @@ void SimdScalarLowering::LowerGraph() {
V(Int32x4Add) \
V(Int32x4Sub) \
V(Int32x4Mul) \
V(Int32x4Min) \
V(Int32x4Max) \
V(Uint32x4Min) \
V(Uint32x4Max) \
V(Simd128And) \
V(Simd128Or) \
V(Simd128Xor)
V(Simd128Xor) \
V(Int32x4FromFloat32x4) \
V(Uint32x4FromFloat32x4)
#define FOREACH_FLOAT32X4_OPCODE(V) \
V(Float32x4Splat) \
......@@ -115,11 +116,20 @@ void SimdScalarLowering::SetLoweredType(Node* node, Node* output) {
}
#undef CASE_STMT
default: {
if (output->opcode() == IrOpcode::kFloat32x4FromInt32x4 ||
output->opcode() == IrOpcode::kFloat32x4FromUint32x4) {
replacements_[node->id()].type = SimdType::kInt32;
} else {
replacements_[node->id()].type = replacements_[output->id()].type;
switch (output->opcode()) {
case IrOpcode::kFloat32x4FromInt32x4:
case IrOpcode::kFloat32x4FromUint32x4: {
replacements_[node->id()].type = SimdType::kInt32;
break;
}
case IrOpcode::kInt32x4FromFloat32x4:
case IrOpcode::kUint32x4FromFloat32x4: {
replacements_[node->id()].type = SimdType::kFloat32;
break;
}
default: {
replacements_[node->id()].type = replacements_[output->id()].type;
}
}
}
}
......@@ -264,6 +274,104 @@ void SimdScalarLowering::LowerUnaryOp(Node* node, SimdType input_rep_type,
ReplaceNode(node, rep_node);
}
void SimdScalarLowering::LowerIntMinMax(Node* node, const Operator* op,
bool is_max) {
DCHECK(node->InputCount() == 2);
Node** rep_left = GetReplacementsWithType(node->InputAt(0), SimdType::kInt32);
Node** rep_right =
GetReplacementsWithType(node->InputAt(1), SimdType::kInt32);
Node* rep_node[kMaxLanes];
for (int i = 0; i < kMaxLanes; ++i) {
Diamond d(graph(), common(),
graph()->NewNode(op, rep_left[i], rep_right[i]));
if (is_max) {
rep_node[i] =
d.Phi(MachineRepresentation::kWord32, rep_right[i], rep_left[i]);
} else {
rep_node[i] =
d.Phi(MachineRepresentation::kWord32, rep_left[i], rep_right[i]);
}
}
ReplaceNode(node, rep_node);
}
Node* SimdScalarLowering::BuildF64Trunc(Node* input) {
if (machine()->Float64RoundTruncate().IsSupported()) {
return graph()->NewNode(machine()->Float64RoundTruncate().op(), input);
} else {
ExternalReference ref =
ExternalReference::wasm_f64_trunc(jsgraph_->isolate());
Node* stack_slot =
graph()->NewNode(machine()->StackSlot(MachineRepresentation::kFloat64));
const Operator* store_op = machine()->Store(
StoreRepresentation(MachineRepresentation::kFloat64, kNoWriteBarrier));
Node* effect =
graph()->NewNode(store_op, stack_slot, jsgraph_->Int32Constant(0),
input, graph()->start(), graph()->start());
Node* function = graph()->NewNode(common()->ExternalConstant(ref));
Node** args = zone()->NewArray<Node*>(4);
args[0] = function;
args[1] = stack_slot;
args[2] = effect;
args[3] = graph()->start();
Signature<MachineType>::Builder sig_builder(zone(), 0, 1);
sig_builder.AddParam(MachineType::Pointer());
CallDescriptor* desc =
Linkage::GetSimplifiedCDescriptor(zone(), sig_builder.Build());
Node* call = graph()->NewNode(common()->Call(desc), 4, args);
return graph()->NewNode(machine()->Load(LoadRepresentation::Float64()),
stack_slot, jsgraph_->Int32Constant(0), call,
graph()->start());
}
}
void SimdScalarLowering::LowerConvertFromFloat(Node* node, bool is_signed) {
DCHECK(node->InputCount() == 1);
Node** rep = GetReplacementsWithType(node->InputAt(0), SimdType::kFloat32);
Node* rep_node[kMaxLanes];
Node* double_zero = graph()->NewNode(common()->Float64Constant(0.0));
Node* min = graph()->NewNode(
common()->Float64Constant(static_cast<double>(is_signed ? kMinInt : 0)));
Node* max = graph()->NewNode(common()->Float64Constant(
static_cast<double>(is_signed ? kMaxInt : 0xffffffffu)));
for (int i = 0; i < kMaxLanes; ++i) {
Node* double_rep =
graph()->NewNode(machine()->ChangeFloat32ToFloat64(), rep[i]);
Diamond nan_d(graph(), common(), graph()->NewNode(machine()->Float64Equal(),
double_rep, double_rep));
Node* temp =
nan_d.Phi(MachineRepresentation::kFloat64, double_rep, double_zero);
Diamond min_d(graph(), common(),
graph()->NewNode(machine()->Float64LessThan(), temp, min));
temp = min_d.Phi(MachineRepresentation::kFloat64, min, temp);
Diamond max_d(graph(), common(),
graph()->NewNode(machine()->Float64LessThan(), max, temp));
temp = max_d.Phi(MachineRepresentation::kFloat64, max, temp);
Node* trunc = BuildF64Trunc(temp);
if (is_signed) {
rep_node[i] = graph()->NewNode(machine()->ChangeFloat64ToInt32(), trunc);
} else {
rep_node[i] =
graph()->NewNode(machine()->TruncateFloat64ToUint32(), trunc);
}
}
ReplaceNode(node, rep_node);
}
void SimdScalarLowering::LowerShiftOp(Node* node, const Operator* op) {
static int32_t shift_mask = 0x1f;
DCHECK_EQ(1, node->InputCount());
int32_t shift_amount = OpParameter<int32_t>(node);
Node* shift_node =
graph()->NewNode(common()->Int32Constant(shift_amount & shift_mask));
Node** rep = GetReplacementsWithType(node->InputAt(0), SimdType::kInt32);
Node* rep_node[kMaxLanes];
for (int i = 0; i < kMaxLanes; ++i) {
rep_node[i] = graph()->NewNode(op, rep[i], shift_node);
}
ReplaceNode(node, rep_node);
}
void SimdScalarLowering::LowerNode(Node* node) {
SimdType rep_type = ReplacementType(node);
switch (node->opcode()) {
......@@ -422,6 +530,22 @@ void SimdScalarLowering::LowerNode(Node* node) {
I32X4_BINOP_CASE(kSimd128Or, Word32Or)
I32X4_BINOP_CASE(kSimd128Xor, Word32Xor)
#undef I32X4_BINOP_CASE
case IrOpcode::kInt32x4Max: {
LowerIntMinMax(node, machine()->Int32LessThan(), true);
break;
}
case IrOpcode::kInt32x4Min: {
LowerIntMinMax(node, machine()->Int32LessThan(), false);
break;
}
case IrOpcode::kUint32x4Max: {
LowerIntMinMax(node, machine()->Uint32LessThan(), true);
break;
}
case IrOpcode::kUint32x4Min: {
LowerIntMinMax(node, machine()->Uint32LessThan(), false);
break;
}
case IrOpcode::kInt32x4Neg: {
DCHECK(node->InputCount() == 1);
Node** rep = GetReplacementsWithType(node->InputAt(0), rep_type);
......@@ -444,6 +568,26 @@ void SimdScalarLowering::LowerNode(Node* node) {
ReplaceNode(node, rep_node);
break;
}
case IrOpcode::kInt32x4FromFloat32x4: {
LowerConvertFromFloat(node, true);
break;
}
case IrOpcode::kUint32x4FromFloat32x4: {
LowerConvertFromFloat(node, false);
break;
}
case IrOpcode::kInt32x4ShiftLeftByScalar: {
LowerShiftOp(node, machine()->Word32Shl());
break;
}
case IrOpcode::kInt32x4ShiftRightByScalar: {
LowerShiftOp(node, machine()->Word32Sar());
break;
}
case IrOpcode::kUint32x4ShiftRightByScalar: {
LowerShiftOp(node, machine()->Word32Shr());
break;
}
#define F32X4_BINOP_CASE(name) \
case IrOpcode::kFloat32x4##name: { \
LowerBinaryOp(node, rep_type, machine()->Float32##name()); \
......
......@@ -7,6 +7,7 @@
#include "src/compiler/common-operator.h"
#include "src/compiler/graph.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/machine-operator.h"
#include "src/compiler/node-marker.h"
#include "src/zone/zone-containers.h"
......@@ -17,8 +18,7 @@ namespace compiler {
class SimdScalarLowering {
public:
SimdScalarLowering(Graph* graph, MachineOperatorBuilder* machine,
CommonOperatorBuilder* common, Zone* zone,
SimdScalarLowering(JSGraph* jsgraph,
Signature<MachineRepresentation>* signature);
void LowerGraph();
......@@ -38,10 +38,15 @@ class SimdScalarLowering {
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_; }
struct NodeState {
Node* node;
int input_index;
};
Zone* zone() const { return jsgraph_->zone(); }
Graph* graph() const { return jsgraph_->graph(); }
MachineOperatorBuilder* machine() const { return jsgraph_->machine(); }
CommonOperatorBuilder* common() const { return jsgraph_->common(); }
Signature<MachineRepresentation>* signature() const { return signature_; }
void LowerNode(Node* node);
......@@ -61,16 +66,12 @@ class SimdScalarLowering {
const Operator* store_op, SimdType rep_type);
void LowerBinaryOp(Node* node, SimdType input_rep_type, const Operator* op);
void LowerUnaryOp(Node* node, SimdType input_rep_type, const Operator* op);
void LowerIntMinMax(Node* node, const Operator* op, bool is_max);
void LowerConvertFromFloat(Node* node, bool is_signed);
void LowerShiftOp(Node* node, const Operator* op);
Node* BuildF64Trunc(Node* input);
struct NodeState {
Node* node;
int input_index;
};
Zone* zone_;
Graph* const graph_;
MachineOperatorBuilder* machine_;
CommonOperatorBuilder* common_;
JSGraph* const jsgraph_;
NodeMarker<State> state_;
ZoneDeque<NodeState> stack_;
Replacement* replacements_;
......
......@@ -3335,9 +3335,7 @@ void WasmGraphBuilder::Int64LoweringForTesting() {
}
void WasmGraphBuilder::SimdScalarLoweringForTesting() {
SimdScalarLowering(jsgraph()->graph(), jsgraph()->machine(),
jsgraph()->common(), jsgraph()->zone(), sig_)
.LowerGraph();
SimdScalarLowering(jsgraph(), sig_).LowerGraph();
}
void WasmGraphBuilder::SetSourcePosition(Node* node,
......@@ -4063,8 +4061,7 @@ SourcePositionTable* WasmCompilationUnit::BuildGraphForWasmFunction(
}
if (builder.has_simd() && !CpuFeatures::SupportsSimd128()) {
SimdScalarLowering(graph, machine, common, jsgraph_->zone(), function_->sig)
.LowerGraph();
SimdScalarLowering(jsgraph_, function_->sig).LowerGraph();
}
int index = static_cast<int>(function_->func_index);
......
......@@ -761,7 +761,9 @@ WASM_EXEC_COMPILED_TEST(I8x16ReplaceLane) {
CHECK_EQ(1, r.Call(1, 2));
}
#endif // V8_TARGET_ARCH_ARM
#if V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET
// Determines if conversion from float to int will be valid.
bool CanRoundToZeroAndConvert(double val, bool unsigned_integer) {
const double max_uint = static_cast<double>(0xffffffffu);
......@@ -826,9 +828,7 @@ WASM_EXEC_COMPILED_TEST(I32x4FromFloat32x4) {
CHECK_EQ(1, r.Call(*i, signed_value, unsigned_value));
}
}
#endif // V8_TARGET_ARCH_ARM
#if V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET
void RunI32x4UnOpTest(WasmOpcode simd_op, Int32UnOp expected_op) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t, int32_t, int32_t> r(kExecuteCompiled);
......@@ -878,9 +878,7 @@ WASM_EXEC_COMPILED_TEST(S128And) { RunI32x4BinOpTest(kExprS128And, And); }
WASM_EXEC_COMPILED_TEST(S128Or) { RunI32x4BinOpTest(kExprS128Or, Or); }
WASM_EXEC_COMPILED_TEST(S128Xor) { RunI32x4BinOpTest(kExprS128Xor, Xor); }
#endif // V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET
#if V8_TARGET_ARCH_ARM
WASM_EXEC_COMPILED_TEST(I32x4Min) {
RunI32x4BinOpTest(kExprI32x4MinS, Minimum);
}
......@@ -896,9 +894,9 @@ WASM_EXEC_COMPILED_TEST(Ui32x4Min) {
WASM_EXEC_COMPILED_TEST(Ui32x4Max) {
RunI32x4BinOpTest(kExprI32x4MaxU, UnsignedMaximum);
}
#endif // V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET
#if V8_TARGET_ARCH_ARM
void RunI32x4CompareOpTest(WasmOpcode simd_op, Int32BinOp expected_op) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t, int32_t, int32_t, int32_t> r(kExecuteCompiled);
......@@ -959,7 +957,9 @@ WASM_EXEC_COMPILED_TEST(Ui32x4Less) {
WASM_EXEC_COMPILED_TEST(Ui32x4LessEqual) {
RunI32x4CompareOpTest(kExprI32x4LeU, UnsignedLessEqual);
}
#endif // V8_TARGET_ARCH_ARM
#if V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET
void RunI32x4ShiftOpTest(WasmOpcode simd_op, Int32ShiftOp expected_op,
int shift) {
FLAG_wasm_simd_prototype = true;
......@@ -986,6 +986,9 @@ WASM_EXEC_COMPILED_TEST(I32x4ShrS) {
WASM_EXEC_COMPILED_TEST(I32x4ShrU) {
RunI32x4ShiftOpTest(kExprI32x4ShrU, LogicalShiftRight, 1);
}
#endif // V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET
#if V8_TARGET_ARCH_ARM
void RunI16x8UnOpTest(WasmOpcode simd_op, Int16UnOp expected_op) {
FLAG_wasm_simd_prototype = true;
......
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