| Index: src/compiler/simd-scalar-lowering.cc
|
| diff --git a/src/compiler/simd-scalar-lowering.cc b/src/compiler/simd-scalar-lowering.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..6ca0311e85572ed4dcdfdb95f1f0558f8887921f
|
| --- /dev/null
|
| +++ b/src/compiler/simd-scalar-lowering.cc
|
| @@ -0,0 +1,409 @@
|
| +// 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-scalar-lowering.h"
|
| +#include "src/compiler/diamond.h"
|
| +#include "src/compiler/linkage.h"
|
| +#include "src/compiler/node-matchers.h"
|
| +#include "src/compiler/node-properties.h"
|
| +
|
| +#include "src/compiler/node.h"
|
| +#include "src/wasm/wasm-module.h"
|
| +
|
| +namespace v8 {
|
| +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),
|
| + replacements_(nullptr),
|
| + signature_(signature),
|
| + 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());
|
| +}
|
| +
|
| +void SimdScalarLowering::LowerGraph() {
|
| + stack_.push_back({graph()->end(), 0});
|
| + state_.Set(graph()->end(), State::kOnStack);
|
| + replacements_[graph()->end()->id()].type = SimdType::kInt32;
|
| +
|
| + while (!stack_.empty()) {
|
| + NodeState& top = stack_.back();
|
| + if (top.input_index == top.node->InputCount()) {
|
| + // All inputs of top have already been lowered, now lower top.
|
| + stack_.pop_back();
|
| + state_.Set(top.node, State::kVisited);
|
| + LowerNode(top.node);
|
| + } else {
|
| + // Push the next input onto the stack.
|
| + Node* input = top.node->InputAt(top.input_index++);
|
| + if (state_.Get(input) == State::kUnvisited) {
|
| + SetLoweredType(input, top.node);
|
| + if (input->opcode() == IrOpcode::kPhi) {
|
| + // To break cycles with phi nodes we push phis on a separate stack so
|
| + // that they are processed after all other nodes.
|
| + PreparePhiReplacement(input);
|
| + stack_.push_front({input, 0});
|
| + } else {
|
| + stack_.push_back({input, 0});
|
| + }
|
| + state_.Set(input, State::kOnStack);
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +#define FOREACH_INT32X4_OPCODE(V) \
|
| + V(Int32x4Add) \
|
| + V(Int32x4ExtractLane) \
|
| + V(CreateInt32x4)
|
| +
|
| +#define FOREACH_FLOAT32X4_OPCODE(V) \
|
| + V(Float32x4Add) \
|
| + V(Float32x4ExtractLane) \
|
| + V(CreateFloat32x4)
|
| +
|
| +void SimdScalarLowering::SetLoweredType(Node* node, Node* output) {
|
| + switch (node->opcode()) {
|
| +#define CASE_STMT(name) case IrOpcode::k##name:
|
| + FOREACH_INT32X4_OPCODE(CASE_STMT)
|
| + case IrOpcode::kReturn:
|
| + case IrOpcode::kParameter:
|
| + case IrOpcode::kCall: {
|
| + replacements_[node->id()].type = SimdType::kInt32;
|
| + break;
|
| + }
|
| + FOREACH_FLOAT32X4_OPCODE(CASE_STMT) {
|
| + replacements_[node->id()].type = SimdType::kFloat32;
|
| + break;
|
| + }
|
| +#undef CASE_STMT
|
| + default:
|
| + replacements_[node->id()].type = replacements_[output->id()].type;
|
| + }
|
| +}
|
| +
|
| +static int GetParameterIndexAfterLowering(
|
| + Signature<MachineRepresentation>* signature, int old_index) {
|
| + // In function calls, the simd128 types are passed as 4 Int32 types. The
|
| + // parameters are typecast to the types as needed for various operations.
|
| + int result = old_index;
|
| + for (int i = 0; i < old_index; i++) {
|
| + if (signature->GetParam(i) == MachineRepresentation::kSimd128) {
|
| + result += 3;
|
| + }
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +int SimdScalarLowering::GetParameterCountAfterLowering() {
|
| + if (parameter_count_after_lowering_ == -1) {
|
| + // GetParameterIndexAfterLowering(parameter_count) returns the parameter
|
| + // count after lowering.
|
| + parameter_count_after_lowering_ = GetParameterIndexAfterLowering(
|
| + signature(), static_cast<int>(signature()->parameter_count()));
|
| + }
|
| + return parameter_count_after_lowering_;
|
| +}
|
| +
|
| +static int GetReturnCountAfterLowering(
|
| + Signature<MachineRepresentation>* signature) {
|
| + int result = static_cast<int>(signature->return_count());
|
| + for (int i = 0; i < static_cast<int>(signature->return_count()); i++) {
|
| + if (signature->GetReturn(i) == MachineRepresentation::kSimd128) {
|
| + result += 3;
|
| + }
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +void SimdScalarLowering::LowerNode(Node* node) {
|
| + SimdType rep_type = ReplacementType(node);
|
| + switch (node->opcode()) {
|
| + case IrOpcode::kStart: {
|
| + int parameter_count = GetParameterCountAfterLowering();
|
| + // Only exchange the node if the parameter count actually changed.
|
| + if (parameter_count != signature()->parameter_count()) {
|
| + int delta =
|
| + parameter_count - static_cast<int>(signature()->parameter_count());
|
| + int new_output_count = node->op()->ValueOutputCount() + delta;
|
| + NodeProperties::ChangeOp(node, common()->Start(new_output_count));
|
| + }
|
| + break;
|
| + }
|
| + case IrOpcode::kParameter: {
|
| + DCHECK(node->InputCount() == 1);
|
| + // Only exchange the node if the parameter count actually changed. We do
|
| + // not even have to do the default lowering because the the start node,
|
| + // the only input of a parameter node, only changes if the parameter count
|
| + // changes.
|
| + if (GetParameterCountAfterLowering() != signature()->parameter_count()) {
|
| + int old_index = ParameterIndexOf(node->op());
|
| + int new_index = GetParameterIndexAfterLowering(signature(), old_index);
|
| + if (old_index == new_index) {
|
| + NodeProperties::ChangeOp(node, common()->Parameter(new_index));
|
| +
|
| + Node* new_node[kMaxLanes];
|
| + for (int i = 0; i < kMaxLanes; i++) {
|
| + new_node[i] = nullptr;
|
| + }
|
| + new_node[0] = node;
|
| + if (signature()->GetParam(old_index) ==
|
| + MachineRepresentation::kSimd128) {
|
| + for (int i = 1; i < kMaxLanes; i++) {
|
| + new_node[i] = graph()->NewNode(common()->Parameter(new_index + i),
|
| + graph()->start());
|
| + }
|
| + }
|
| + ReplaceNode(node, new_node);
|
| + }
|
| + }
|
| + break;
|
| + }
|
| + case IrOpcode::kReturn: {
|
| + DefaultLowering(node);
|
| + int new_return_count = GetReturnCountAfterLowering(signature());
|
| + if (signature()->return_count() != new_return_count) {
|
| + NodeProperties::ChangeOp(node, common()->Return(new_return_count));
|
| + }
|
| + break;
|
| + }
|
| + case IrOpcode::kCall: {
|
| + // TODO(turbofan): Make WASM code const-correct wrt. CallDescriptor.
|
| + CallDescriptor* descriptor =
|
| + const_cast<CallDescriptor*>(CallDescriptorOf(node->op()));
|
| + if (DefaultLowering(node) ||
|
| + (descriptor->ReturnCount() == 1 &&
|
| + descriptor->GetReturnType(0) == MachineType::Simd128())) {
|
| + // We have to adjust the call descriptor.
|
| + const Operator* op =
|
| + common()->Call(wasm::ModuleEnv::GetI32WasmCallDescriptorForSimd(
|
| + zone(), descriptor));
|
| + NodeProperties::ChangeOp(node, op);
|
| + }
|
| + if (descriptor->ReturnCount() == 1 &&
|
| + descriptor->GetReturnType(0) == MachineType::Simd128()) {
|
| + // We access the additional return values through projections.
|
| + Node* rep_node[kMaxLanes];
|
| + for (int i = 0; i < kMaxLanes; i++) {
|
| + rep_node[i] =
|
| + graph()->NewNode(common()->Projection(i), node, graph()->start());
|
| + }
|
| + ReplaceNode(node, rep_node);
|
| + }
|
| + break;
|
| + }
|
| + case IrOpcode::kPhi: {
|
| + MachineRepresentation rep = PhiRepresentationOf(node->op());
|
| + if (rep == MachineRepresentation::kSimd128) {
|
| + // The replacement nodes have already been created, we only have to
|
| + // replace placeholder nodes.
|
| + Node** rep_node = GetReplacements(node);
|
| + for (int i = 0; i < node->op()->ValueInputCount(); i++) {
|
| + Node** rep_input =
|
| + GetReplacementsWithType(node->InputAt(i), rep_type);
|
| + for (int j = 0; j < kMaxLanes; j++) {
|
| + rep_node[j]->ReplaceInput(i, rep_input[j]);
|
| + }
|
| + }
|
| + } else {
|
| + DefaultLowering(node);
|
| + }
|
| + break;
|
| + }
|
| +
|
| + case IrOpcode::kInt32x4Add: {
|
| + DCHECK(node->InputCount() == 2);
|
| + Node** rep_left = GetReplacementsWithType(node->InputAt(0), rep_type);
|
| + Node** rep_right = GetReplacementsWithType(node->InputAt(1), rep_type);
|
| + Node* rep_node[kMaxLanes];
|
| + for (int i = 0; i < kMaxLanes; i++) {
|
| + rep_node[i] =
|
| + graph()->NewNode(machine()->Int32Add(), rep_left[i], rep_right[i]);
|
| + }
|
| + ReplaceNode(node, rep_node);
|
| + break;
|
| + }
|
| +
|
| + case IrOpcode::kCreateInt32x4: {
|
| + Node* rep_node[kMaxLanes];
|
| + for (int i = 0; i < kMaxLanes; i++) {
|
| + DCHECK(!HasReplacement(1, node->InputAt(i)));
|
| + rep_node[i] = node->InputAt(i);
|
| + }
|
| + ReplaceNode(node, rep_node);
|
| + break;
|
| + }
|
| +
|
| + case IrOpcode::kInt32x4ExtractLane: {
|
| + Node* laneNode = node->InputAt(1);
|
| + DCHECK_EQ(laneNode->opcode(), IrOpcode::kInt32Constant);
|
| + int32_t lane = OpParameter<int32_t>(laneNode);
|
| + Node* rep_node[kMaxLanes] = {
|
| + GetReplacementsWithType(node->InputAt(0), rep_type)[lane], nullptr,
|
| + nullptr, nullptr};
|
| + ReplaceNode(node, rep_node);
|
| + break;
|
| + }
|
| +
|
| + case IrOpcode::kFloat32x4Add: {
|
| + DCHECK(node->InputCount() == 2);
|
| + Node** rep_left = GetReplacementsWithType(node->InputAt(0), rep_type);
|
| + Node** rep_right = GetReplacementsWithType(node->InputAt(1), rep_type);
|
| + Node* rep_node[kMaxLanes];
|
| + for (int i = 0; i < kMaxLanes; i++) {
|
| + rep_node[i] = graph()->NewNode(machine()->Float32Add(), rep_left[i],
|
| + rep_right[i]);
|
| + }
|
| + ReplaceNode(node, rep_node);
|
| + break;
|
| + }
|
| +
|
| + case IrOpcode::kCreateFloat32x4: {
|
| + Node* rep_node[kMaxLanes];
|
| + for (int i = 0; i < kMaxLanes; i++) {
|
| + DCHECK(!HasReplacement(1, node->InputAt(i)));
|
| + rep_node[i] = node->InputAt(i);
|
| + }
|
| + ReplaceNode(node, rep_node);
|
| + break;
|
| + }
|
| +
|
| + case IrOpcode::kFloat32x4ExtractLane: {
|
| + Node* laneNode = node->InputAt(1);
|
| + DCHECK_EQ(laneNode->opcode(), IrOpcode::kInt32Constant);
|
| + int32_t lane = OpParameter<int32_t>(laneNode);
|
| + Node* rep_node[kMaxLanes] = {
|
| + GetReplacementsWithType(node->InputAt(0), rep_type)[lane], nullptr,
|
| + nullptr, nullptr};
|
| + ReplaceNode(node, rep_node);
|
| + break;
|
| + }
|
| +
|
| + default: { DefaultLowering(node); }
|
| + }
|
| +}
|
| +
|
| +bool SimdScalarLowering::DefaultLowering(Node* node) {
|
| + bool something_changed = false;
|
| + for (int i = NodeProperties::PastValueIndex(node) - 1; i >= 0; i--) {
|
| + Node* input = node->InputAt(i);
|
| + if (HasReplacement(0, input)) {
|
| + something_changed = true;
|
| + node->ReplaceInput(i, GetReplacements(input)[0]);
|
| + }
|
| + if (HasReplacement(1, input)) {
|
| + something_changed = true;
|
| + for (int j = 1; j < kMaxLanes; j++) {
|
| + node->InsertInput(zone(), i + j, GetReplacements(input)[j]);
|
| + }
|
| + }
|
| + }
|
| + return something_changed;
|
| +}
|
| +
|
| +void SimdScalarLowering::ReplaceNode(Node* old, Node** new_node) {
|
| + // if new_low == nullptr, then also new_high == nullptr.
|
| + DCHECK(new_node[0] != nullptr ||
|
| + (new_node[1] == nullptr && new_node[2] == nullptr &&
|
| + new_node[3] == nullptr));
|
| + for (int i = 0; i < kMaxLanes; i++) {
|
| + replacements_[old->id()].node[i] = new_node[i];
|
| + }
|
| +}
|
| +
|
| +bool SimdScalarLowering::HasReplacement(size_t index, Node* node) {
|
| + return replacements_[node->id()].node[index] != nullptr;
|
| +}
|
| +
|
| +SimdScalarLowering::SimdType SimdScalarLowering::ReplacementType(Node* node) {
|
| + return replacements_[node->id()].type;
|
| +}
|
| +
|
| +Node** SimdScalarLowering::GetReplacements(Node* node) {
|
| + Node** result = replacements_[node->id()].node;
|
| + DCHECK(result);
|
| + return result;
|
| +}
|
| +
|
| +Node** SimdScalarLowering::GetReplacementsWithType(Node* node, SimdType type) {
|
| + Node** replacements = GetReplacements(node);
|
| + if (ReplacementType(node) == type) {
|
| + return GetReplacements(node);
|
| + }
|
| + Node** result = zone()->NewArray<Node*>(kMaxLanes);
|
| + if (ReplacementType(node) == SimdType::kInt32 && type == SimdType::kFloat32) {
|
| + for (int i = 0; i < kMaxLanes; i++) {
|
| + if (replacements[i] != nullptr) {
|
| + result[i] = graph()->NewNode(machine()->BitcastInt32ToFloat32(),
|
| + replacements[i]);
|
| + } else {
|
| + result[i] = nullptr;
|
| + }
|
| + }
|
| + } else {
|
| + for (int i = 0; i < kMaxLanes; i++) {
|
| + if (replacements[i] != nullptr) {
|
| + result[i] = graph()->NewNode(machine()->BitcastFloat32ToInt32(),
|
| + replacements[i]);
|
| + } else {
|
| + result[i] = nullptr;
|
| + }
|
| + }
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +void SimdScalarLowering::PreparePhiReplacement(Node* phi) {
|
| + MachineRepresentation rep = PhiRepresentationOf(phi->op());
|
| + if (rep == MachineRepresentation::kSimd128) {
|
| + // We have to create the replacements for a phi node before we actually
|
| + // lower the phi to break potential cycles in the graph. The replacements of
|
| + // input nodes do not exist yet, so we use a placeholder node to pass the
|
| + // graph verifier.
|
| + int value_count = phi->op()->ValueInputCount();
|
| + SimdType type = ReplacementType(phi);
|
| + Node** inputs_rep[kMaxLanes];
|
| + for (int i = 0; i < kMaxLanes; i++) {
|
| + inputs_rep[i] = zone()->NewArray<Node*>(value_count + 1);
|
| + inputs_rep[i][value_count] = NodeProperties::GetControlInput(phi, 0);
|
| + }
|
| + for (int i = 0; i < value_count; i++) {
|
| + for (int j = 0; j < kMaxLanes; j++) {
|
| + inputs_rep[j][i] = placeholder_;
|
| + }
|
| + }
|
| + Node* rep_nodes[kMaxLanes];
|
| + for (int i = 0; i < kMaxLanes; i++) {
|
| + if (type == SimdType::kInt32) {
|
| + rep_nodes[i] = graph()->NewNode(
|
| + common()->Phi(MachineRepresentation::kWord32, value_count),
|
| + value_count + 1, inputs_rep[i], false);
|
| + } else if (type == SimdType::kFloat32) {
|
| + rep_nodes[i] = graph()->NewNode(
|
| + common()->Phi(MachineRepresentation::kFloat32, value_count),
|
| + value_count + 1, inputs_rep[i], false);
|
| + } else {
|
| + UNREACHABLE();
|
| + }
|
| + }
|
| + ReplaceNode(phi, rep_nodes);
|
| + }
|
| +}
|
| +} // namespace compiler
|
| +} // namespace internal
|
| +} // namespace v8
|
|
|