Index: src/compiler/int64-lowering.cc |
diff --git a/src/compiler/int64-lowering.cc b/src/compiler/int64-lowering.cc |
index c2952319be24a4345a4095bb6a2e221f6b7a9edf..c9c87b65d6de55807e5fa6a13afbe5bc232a3287 100644 |
--- a/src/compiler/int64-lowering.cc |
+++ b/src/compiler/int64-lowering.cc |
@@ -5,8 +5,12 @@ |
#include "src/compiler/int64-lowering.h" |
#include "src/compiler/common-operator.h" |
#include "src/compiler/graph.h" |
+#include "src/compiler/linkage.h" |
#include "src/compiler/machine-operator.h" |
+#include "src/compiler/node-properties.h" |
+ |
#include "src/compiler/node.h" |
+#include "src/wasm/wasm-module.h" |
#include "src/zone.h" |
namespace v8 { |
@@ -14,17 +18,23 @@ namespace internal { |
namespace compiler { |
Int64Lowering::Int64Lowering(Graph* graph, MachineOperatorBuilder* machine, |
- CommonOperatorBuilder* common, Zone* zone) |
- : graph_(graph), |
+ CommonOperatorBuilder* common, Zone* zone, |
+ Signature<MachineRepresentation>* signature) |
+ : zone_(zone), |
+ graph_(graph), |
machine_(machine), |
common_(common), |
state_(graph, 4), |
stack_(zone), |
- replacements_(zone->NewArray<Replacement>(graph->NodeCount())) { |
+ replacements_(zone->NewArray<Replacement>(graph->NodeCount())), |
+ signature_(signature) { |
memset(replacements_, 0, sizeof(Replacement) * graph->NodeCount()); |
} |
-void Int64Lowering::ReduceGraph() { |
+void Int64Lowering::LowerGraph() { |
+ if (4 != kPointerSize) { |
+ return; |
+ } |
stack_.push(graph()->end()); |
state_.Set(graph()->end(), State::kOnStack); |
@@ -34,7 +44,7 @@ void Int64Lowering::ReduceGraph() { |
stack_.pop(); |
state_.Set(top, State::kVisited); |
// All inputs of top have already been reduced, now reduce top. |
- ReduceNode(top); |
+ LowerNode(top); |
} else { |
// Push all children onto the stack. |
for (Node* input : top->inputs()) { |
@@ -48,7 +58,35 @@ void Int64Lowering::ReduceGraph() { |
} |
} |
-void Int64Lowering::ReduceNode(Node* node) { |
+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::kWord64) { |
+ result++; |
+ } |
+ } |
+ return result; |
+} |
+ |
+static int GetParameterCountAfterLowering( |
+ Signature<MachineRepresentation>* signature) { |
+ 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::kWord64) { |
+ result++; |
+ } |
+ } |
+ return result; |
+} |
+ |
+void Int64Lowering::LowerNode(Node* node) { |
switch (node->opcode()) { |
case IrOpcode::kInt64Constant: { |
int64_t value = OpParameter<int64_t>(node); |
@@ -56,48 +94,207 @@ void Int64Lowering::ReduceNode(Node* node) { |
common()->Int32Constant(static_cast<int32_t>(value & 0xFFFFFFFF))); |
Node* high_node = graph()->NewNode( |
common()->Int32Constant(static_cast<int32_t>(value >> 32))); |
- replacements_[node->id()].low = low_node; |
- replacements_[node->id()].high = high_node; |
+ ReplaceNode(node, low_node, high_node); |
+ break; |
+ } |
+ case IrOpcode::kLoad: { |
+ LoadRepresentation load_rep = LoadRepresentationOf(node->op()); |
+ |
+ if (load_rep.representation() == MachineRepresentation::kWord64) { |
+ Node* base = node->InputAt(0); |
+ Node* index = node->InputAt(1); |
+ Node* index_high = |
+ graph()->NewNode(machine()->Int32Add(), index, |
+ graph()->NewNode(common()->Int32Constant(4))); |
+ |
+ const Operator* load_op = machine()->Load(MachineType::Int32()); |
+ Node* high_node; |
+ if (node->InputCount() > 2) { |
+ Node* effect_high = node->InputAt(2); |
+ Node* control_high = node->InputAt(3); |
+ high_node = graph()->NewNode(load_op, base, index_high, effect_high, |
+ control_high); |
+ // change the effect change from old_node --> old_effect to |
+ // old_node --> high_node --> old_effect. |
+ node->ReplaceInput(2, high_node); |
+ } else { |
+ high_node = graph()->NewNode(load_op, base, index_high); |
+ } |
+ NodeProperties::ChangeOp(node, load_op); |
+ ReplaceNode(node, node, high_node); |
+ } |
+ break; |
+ } |
+ case IrOpcode::kStore: { |
+ StoreRepresentation store_rep = StoreRepresentationOf(node->op()); |
+ if (store_rep.representation() == MachineRepresentation::kWord64) { |
+ // We change the original store node to store the low word, and create |
+ // a new store node to store the high word. The effect and control edges |
+ // are copied from the original store to the new store node, the effect |
+ // edge of the original store is redirected to the new store. |
+ WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind(); |
+ |
+ Node* base = node->InputAt(0); |
+ Node* index = node->InputAt(1); |
+ Node* index_high = |
+ graph()->NewNode(machine()->Int32Add(), index, |
+ graph()->NewNode(common()->Int32Constant(4))); |
+ |
+ Node* value = node->InputAt(2); |
+ DCHECK(HasReplacementLow(value)); |
+ DCHECK(HasReplacementHigh(value)); |
+ |
+ const Operator* store_op = machine()->Store(StoreRepresentation( |
+ MachineRepresentation::kWord32, write_barrier_kind)); |
+ |
+ Node* high_node; |
+ if (node->InputCount() > 3) { |
+ Node* effect_high = node->InputAt(3); |
+ Node* control_high = node->InputAt(4); |
+ high_node = graph()->NewNode(store_op, base, index_high, |
+ GetReplacementHigh(value), effect_high, |
+ control_high); |
+ node->ReplaceInput(3, high_node); |
+ |
+ } else { |
+ high_node = graph()->NewNode(store_op, base, index_high, |
+ GetReplacementHigh(value)); |
+ } |
+ |
+ node->ReplaceInput(2, GetReplacementLow(value)); |
+ NodeProperties::ChangeOp(node, store_op); |
+ ReplaceNode(node, node, high_node); |
+ } |
break; |
} |
case IrOpcode::kWord64And: { |
+ DCHECK(node->InputCount() == 2); |
Node* left = node->InputAt(0); |
- DCHECK(replacements_[left->id()].low); |
- Node* left_low = replacements_[left->id()].low; |
- Node* left_high = replacements_[left->id()].high; |
- |
Node* right = node->InputAt(1); |
- DCHECK(replacements_[right->id()].low); |
- Node* right_low = replacements_[right->id()].low; |
- Node* right_high = replacements_[right->id()].high; |
- |
- replacements_[node->id()].low = |
- graph()->NewNode(machine()->Word32And(), left_low, right_low); |
- replacements_[node->id()].high = |
- graph()->NewNode(machine()->Word32And(), left_high, right_high); |
+ |
+ Node* low_node = |
+ graph()->NewNode(machine()->Word32And(), GetReplacementLow(left), |
+ GetReplacementLow(right)); |
+ Node* high_node = |
+ graph()->NewNode(machine()->Word32And(), GetReplacementHigh(left), |
+ GetReplacementHigh(right)); |
+ ReplaceNode(node, low_node, high_node); |
break; |
} |
case IrOpcode::kTruncateInt64ToInt32: { |
+ DCHECK(node->InputCount() == 1); |
Node* input = node->InputAt(0); |
- DCHECK(replacements_[input->id()].low); |
- replacements_[node->id()].low = replacements_[input->id()].low; |
+ ReplaceNode(node, GetReplacementLow(input), nullptr); |
+ node->NullAllInputs(); |
break; |
} |
- default: { |
- // Also the inputs of nodes can change which do not expect int64 inputs. |
- for (int i = 0; i < node->InputCount(); i++) { |
- Node* input = node->InputAt(i); |
- // The input has changed altough it was not an int64 input. This can |
- // happen e.g. if the input node is IrOpcode::kTruncateInt64ToInt32. We |
- // use the low word replacement as the new input. |
- if (replacements_[input->id()].low) { |
- node->ReplaceInput(i, replacements_[input->id()].low); |
+ 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); |
+ Node* low_node = |
+ graph()->NewNode(common()->Parameter(new_index), graph()->start()); |
+ |
+ Node* high_node = nullptr; |
+ if (signature()->GetParam(old_index) == |
+ MachineRepresentation::kWord64) { |
+ high_node = graph()->NewNode(common()->Parameter(new_index + 1), |
+ graph()->start()); |
} |
+ ReplaceNode(node, low_node, high_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: { |
+ CallDescriptor* descriptor = OpParameter<CallDescriptor*>(node); |
+ if (DefaultLowering(node) || |
+ (descriptor->ReturnCount() == 1 && |
+ descriptor->GetReturnType(0) == MachineType::Int64())) { |
+ // We have to adjust the call descriptor. |
+ const Operator* op = common()->Call( |
+ wasm::ModuleEnv::GetI32WasmCallDescriptor(zone(), descriptor)); |
+ NodeProperties::ChangeOp(node, op); |
+ } |
+ if (descriptor->ReturnCount() == 1 && |
+ descriptor->GetReturnType(0) == MachineType::Int64()) { |
+ // We access the additional return values through projections. |
+ Node* low_node = graph()->NewNode(common()->Projection(0), node); |
+ Node* high_node = graph()->NewNode(common()->Projection(1), node); |
+ ReplaceNode(node, low_node, high_node); |
+ } |
+ break; |
} |
+ default: { DefaultLowering(node); } |
} |
} |
+bool Int64Lowering::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, GetReplacementLow(input)); |
+ } |
+ if (HasReplacementHigh(input)) { |
+ something_changed = true; |
+ node->InsertInput(zone(), i + 1, GetReplacementHigh(input)); |
+ } |
+ } |
+ return something_changed; |
+} |
+ |
+void Int64Lowering::ReplaceNode(Node* old, Node* new_low, Node* new_high) { |
+ // if new_low == nullptr, then also new_high == nullptr. |
+ DCHECK(new_low != nullptr || new_high == nullptr); |
+ replacements_[old->id()].low = new_low; |
+ replacements_[old->id()].high = new_high; |
+} |
+ |
+bool Int64Lowering::HasReplacementLow(Node* node) { |
+ return replacements_[node->id()].low != nullptr; |
+} |
+ |
+Node* Int64Lowering::GetReplacementLow(Node* node) { |
+ Node* result = replacements_[node->id()].low; |
+ DCHECK(result); |
+ return result; |
+} |
+ |
+bool Int64Lowering::HasReplacementHigh(Node* node) { |
+ return replacements_[node->id()].high != nullptr; |
+} |
+ |
+Node* Int64Lowering::GetReplacementHigh(Node* node) { |
+ Node* result = replacements_[node->id()].high; |
+ DCHECK(result); |
+ return result; |
+} |
} // namespace compiler |
} // namespace internal |
} // namespace v8 |