Chromium Code Reviews| 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..d9e5216a14054989eb9fe10dc1fd8b7b48791f59 |
| --- /dev/null |
| +++ b/src/compiler/simd-scalar-lowering.cc |
| @@ -0,0 +1,403 @@ |
| +// 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())) { |
| + 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) { |
| + SetType(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) |
| + |
|
bradnelson
2016/08/31 22:42:08
SetLoweredType ?
aseemgarg
2016/10/10 17:35:16
Done.
|
| +void SimdScalarLowering::SetType(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) { |
|
bradnelson
2016/08/31 22:42:08
Indent is weird, did this make it through git cl p
aseemgarg
2016/10/10 17:35:17
Did git cl format. And the changes seem to have ma
|
| + 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) { |
| + int result = old_index; |
| + for (int i = 0; i < old_index; i++) { |
| + if (signature->GetParam(i) == MachineRepresentation::kSimd128) { |
| + result += 3; |
|
bradnelson
2016/08/31 22:42:08
Comment explaining this is single items going to 4
aseemgarg
2016/10/10 17:35:16
Done.
|
| + } |
| + } |
| + return result; |
| +} |
| + |
| +int SimdScalarLowering::GetParameterCountAfterLowering( |
| + Signature<MachineRepresentation>* signature) { |
| + // GetParameterIndexAfterLowering(parameter_count) returns the parameter count |
| + // after lowering. |
| + return GetParameterIndexAfterLowering( |
| + signature, static_cast<int>(signature->parameter_count())); |
| +} |
| + |
| +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(signature()); |
| + // 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()) != |
| + signature()->parameter_count()) { |
| + int old_index = ParameterIndexOf(node->op()); |
| + int new_index = GetParameterIndexAfterLowering(signature(), old_index); |
| + NodeProperties::ChangeOp(node, common()->Parameter(new_index)); |
| + |
| + Node* new_node[4]; |
|
bradnelson
2016/08/31 22:42:08
constant
titzer
2016/09/05 12:59:35
Yes, please use kMaxLanes or similar.
aseemgarg
2016/10/10 17:35:16
Done.
|
| + for (int i = 0; i < 4; i++) { |
| + new_node[i] = nullptr; |
| + } |
| + new_node[0] = node; |
| + if (signature()->GetParam(old_index) == |
| + MachineRepresentation::kSimd128) { |
| + for (int i = 1; i < 4; 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[4]; |
| + for (int i = 0; i < 4; 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 < 4; j++) { |
| + rep_node[j]->ReplaceInput(i, rep_input[j]); |
| + } |
| + } |
| + } else { |
| + DefaultLowering(node); |
| + } |
| + break; |
| + } |
| + |
| + case IrOpcode::kInt32x4Add: { |
|
bradnelson
2016/08/31 22:42:08
Macros might be in order once you have more of the
aseemgarg
2016/10/10 17:35:16
that's the plan. Macros or functions.
|
| + 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[4]; |
| + for (int i = 0; i < 4; 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[4]; |
| + for (int i = 0; i < 4; i++) { |
| + DCHECK(!HasReplacementHigh(node->InputAt(i))); |
| + rep_node[i] = node->InputAt(i); |
| + } |
| + ReplaceNode(node, rep_node); |
| + break; |
| + } |
| + |
| + case IrOpcode::kInt32x4ExtractLane: { |
| + Node* rep_node[4] = { |
| + GetReplacementsWithType(node->InputAt(0), rep_type)[0], 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[4]; |
| + for (int i = 0; i < 4; 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[4]; |
| + for (int i = 0; i < 4; i++) { |
| + DCHECK(!HasReplacementHigh(node->InputAt(i))); |
| + rep_node[i] = node->InputAt(i); |
| + } |
| + ReplaceNode(node, rep_node); |
| + break; |
| + } |
| + |
| + case IrOpcode::kFloat32x4ExtractLane: { |
| + Node* rep_node[4] = { |
| + GetReplacementsWithType(node->InputAt(0), rep_type)[0], 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 (HasReplacementLow(input)) { |
| + something_changed = true; |
| + node->ReplaceInput(i, GetReplacements(input)[0]); |
| + } |
| + if (HasReplacementHigh(input)) { |
|
bradnelson
2016/08/31 22:42:08
This naming from the 64-bit stuff is goofy.
HasRep
aseemgarg
2016/10/10 17:35:16
Done.
|
| + something_changed = true; |
| + for (int j = 1; j < 4; 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 < 4; i++) { |
| + replacements_[old->id()].node[i] = new_node[i]; |
| + } |
| +} |
| + |
| +bool SimdScalarLowering::HasReplacementLow(Node* node) { |
| + return replacements_[node->id()].node[0] != nullptr; |
| +} |
| + |
| +bool SimdScalarLowering::HasReplacementHigh(Node* node) { |
| + return replacements_[node->id()].node[1] != 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*>(4); |
| + for (int i = 0; i < 4; i++) { |
|
titzer
2016/09/05 12:59:34
No need to initialize these to null if you are goi
aseemgarg
2016/10/10 17:35:16
Actually we do need to mark some null in case ther
|
| + result[i] = nullptr; |
| + } |
| + if (ReplacementType(node) == SimdType::kInt32 && type == SimdType::kFloat32) { |
|
titzer
2016/09/05 12:59:34
If you get rid of the kUndefined type, this will b
aseemgarg
2016/10/10 17:35:17
Done.
|
| + for (int i = 0; i < 4; i++) { |
| + if (replacements[i] != nullptr) { |
| + result[i] = graph()->NewNode(machine()->BitcastInt32ToFloat32(), |
| + replacements[i]); |
| + } |
| + } |
| + } else if (ReplacementType(node) == SimdType::kFloat32 && |
| + type == SimdType::kInt32) { |
| + for (int i = 0; i < 4; i++) { |
| + if (replacements[i] != nullptr) { |
| + result[i] = graph()->NewNode(machine()->BitcastFloat32ToInt32(), |
| + replacements[i]); |
| + } |
| + } |
| + } else { |
| + UNREACHABLE(); |
| + } |
| + 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[4]; |
| + for (int i = 0; i < 4; 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 < 4; j++) { |
| + inputs_rep[j][i] = placeholder_; |
| + } |
| + } |
| + Node* rep_nodes[4]; |
| + for (int i = 0; i < 4; 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 |