blob: ff31abe518f07cdf60fa58d8acac90e2cbf0a907 [file] [log] [blame]
Ben Murdoch097c5b22016-05-18 11:27:45 +01001// Copyright 2014 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/compiler/int64-lowering.h"
6#include "src/compiler/common-operator.h"
7#include "src/compiler/graph.h"
8#include "src/compiler/linkage.h"
9#include "src/compiler/machine-operator.h"
10#include "src/compiler/node-properties.h"
11
12#include "src/compiler/node.h"
13#include "src/wasm/wasm-module.h"
14#include "src/zone.h"
15
16namespace v8 {
17namespace internal {
18namespace compiler {
19
20Int64Lowering::Int64Lowering(Graph* graph, MachineOperatorBuilder* machine,
21 CommonOperatorBuilder* common, Zone* zone,
22 Signature<MachineRepresentation>* signature)
23 : zone_(zone),
24 graph_(graph),
25 machine_(machine),
26 common_(common),
27 state_(graph, 4),
28 stack_(zone),
29 replacements_(zone->NewArray<Replacement>(graph->NodeCount())),
30 signature_(signature) {
31 memset(replacements_, 0, sizeof(Replacement) * graph->NodeCount());
32}
33
34void Int64Lowering::LowerGraph() {
35 if (4 != kPointerSize) {
36 return;
37 }
38 stack_.push(graph()->end());
39 state_.Set(graph()->end(), State::kOnStack);
40
41 while (!stack_.empty()) {
42 Node* top = stack_.top();
43 if (state_.Get(top) == State::kInputsPushed) {
44 stack_.pop();
45 state_.Set(top, State::kVisited);
46 // All inputs of top have already been reduced, now reduce top.
47 LowerNode(top);
48 } else {
49 // Push all children onto the stack.
50 for (Node* input : top->inputs()) {
51 if (state_.Get(input) == State::kUnvisited) {
52 stack_.push(input);
53 state_.Set(input, State::kOnStack);
54 }
55 }
56 state_.Set(top, State::kInputsPushed);
57 }
58 }
59}
60
61static int GetParameterIndexAfterLowering(
62 Signature<MachineRepresentation>* signature, int old_index) {
63 int result = old_index;
64 for (int i = 0; i < old_index; i++) {
65 if (signature->GetParam(i) == MachineRepresentation::kWord64) {
66 result++;
67 }
68 }
69 return result;
70}
71
72static int GetParameterCountAfterLowering(
73 Signature<MachineRepresentation>* signature) {
74 return GetParameterIndexAfterLowering(
75 signature, static_cast<int>(signature->parameter_count()));
76}
77
78static int GetReturnCountAfterLowering(
79 Signature<MachineRepresentation>* signature) {
80 int result = static_cast<int>(signature->return_count());
81 for (int i = 0; i < static_cast<int>(signature->return_count()); i++) {
82 if (signature->GetReturn(i) == MachineRepresentation::kWord64) {
83 result++;
84 }
85 }
86 return result;
87}
88
89void Int64Lowering::LowerNode(Node* node) {
90 switch (node->opcode()) {
91 case IrOpcode::kInt64Constant: {
92 int64_t value = OpParameter<int64_t>(node);
93 Node* low_node = graph()->NewNode(
94 common()->Int32Constant(static_cast<int32_t>(value & 0xFFFFFFFF)));
95 Node* high_node = graph()->NewNode(
96 common()->Int32Constant(static_cast<int32_t>(value >> 32)));
97 ReplaceNode(node, low_node, high_node);
98 break;
99 }
100 case IrOpcode::kLoad: {
101 LoadRepresentation load_rep = LoadRepresentationOf(node->op());
102
103 if (load_rep.representation() == MachineRepresentation::kWord64) {
104 Node* base = node->InputAt(0);
105 Node* index = node->InputAt(1);
106 Node* index_high =
107 graph()->NewNode(machine()->Int32Add(), index,
108 graph()->NewNode(common()->Int32Constant(4)));
109
110 const Operator* load_op = machine()->Load(MachineType::Int32());
111 Node* high_node;
112 if (node->InputCount() > 2) {
113 Node* effect_high = node->InputAt(2);
114 Node* control_high = node->InputAt(3);
115 high_node = graph()->NewNode(load_op, base, index_high, effect_high,
116 control_high);
117 // change the effect change from old_node --> old_effect to
118 // old_node --> high_node --> old_effect.
119 node->ReplaceInput(2, high_node);
120 } else {
121 high_node = graph()->NewNode(load_op, base, index_high);
122 }
123 NodeProperties::ChangeOp(node, load_op);
124 ReplaceNode(node, node, high_node);
125 }
126 break;
127 }
128 case IrOpcode::kStore: {
129 StoreRepresentation store_rep = StoreRepresentationOf(node->op());
130 if (store_rep.representation() == MachineRepresentation::kWord64) {
131 // We change the original store node to store the low word, and create
132 // a new store node to store the high word. The effect and control edges
133 // are copied from the original store to the new store node, the effect
134 // edge of the original store is redirected to the new store.
135 WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
136
137 Node* base = node->InputAt(0);
138 Node* index = node->InputAt(1);
139 Node* index_high =
140 graph()->NewNode(machine()->Int32Add(), index,
141 graph()->NewNode(common()->Int32Constant(4)));
142
143 Node* value = node->InputAt(2);
144 DCHECK(HasReplacementLow(value));
145 DCHECK(HasReplacementHigh(value));
146
147 const Operator* store_op = machine()->Store(StoreRepresentation(
148 MachineRepresentation::kWord32, write_barrier_kind));
149
150 Node* high_node;
151 if (node->InputCount() > 3) {
152 Node* effect_high = node->InputAt(3);
153 Node* control_high = node->InputAt(4);
154 high_node = graph()->NewNode(store_op, base, index_high,
155 GetReplacementHigh(value), effect_high,
156 control_high);
157 node->ReplaceInput(3, high_node);
158
159 } else {
160 high_node = graph()->NewNode(store_op, base, index_high,
161 GetReplacementHigh(value));
162 }
163
164 node->ReplaceInput(2, GetReplacementLow(value));
165 NodeProperties::ChangeOp(node, store_op);
166 ReplaceNode(node, node, high_node);
167 }
168 break;
169 }
170 case IrOpcode::kWord64And: {
171 DCHECK(node->InputCount() == 2);
172 Node* left = node->InputAt(0);
173 Node* right = node->InputAt(1);
174
175 Node* low_node =
176 graph()->NewNode(machine()->Word32And(), GetReplacementLow(left),
177 GetReplacementLow(right));
178 Node* high_node =
179 graph()->NewNode(machine()->Word32And(), GetReplacementHigh(left),
180 GetReplacementHigh(right));
181 ReplaceNode(node, low_node, high_node);
182 break;
183 }
184 case IrOpcode::kTruncateInt64ToInt32: {
185 DCHECK(node->InputCount() == 1);
186 Node* input = node->InputAt(0);
187 ReplaceNode(node, GetReplacementLow(input), nullptr);
188 node->NullAllInputs();
189 break;
190 }
191 case IrOpcode::kStart: {
192 int parameter_count = GetParameterCountAfterLowering(signature());
193 // Only exchange the node if the parameter count actually changed.
194 if (parameter_count != signature()->parameter_count()) {
195 int delta =
196 parameter_count - static_cast<int>(signature()->parameter_count());
197 int new_output_count = node->op()->ValueOutputCount() + delta;
198 NodeProperties::ChangeOp(node, common()->Start(new_output_count));
199 }
200 break;
201 }
202 case IrOpcode::kParameter: {
203 DCHECK(node->InputCount() == 1);
204 // Only exchange the node if the parameter count actually changed. We do
205 // not even have to do the default lowering because the the start node,
206 // the only input of a parameter node, only changes if the parameter count
207 // changes.
208 if (GetParameterCountAfterLowering(signature()) !=
209 signature()->parameter_count()) {
210 int old_index = ParameterIndexOf(node->op());
211 int new_index = GetParameterIndexAfterLowering(signature(), old_index);
212 NodeProperties::ChangeOp(node, common()->Parameter(new_index));
213
214 Node* high_node = nullptr;
215 if (signature()->GetParam(old_index) ==
216 MachineRepresentation::kWord64) {
217 high_node = graph()->NewNode(common()->Parameter(new_index + 1),
218 graph()->start());
219 }
220 ReplaceNode(node, node, high_node);
221 }
222 break;
223 }
224 case IrOpcode::kReturn: {
225 DefaultLowering(node);
226 int new_return_count = GetReturnCountAfterLowering(signature());
227 if (signature()->return_count() != new_return_count) {
228 NodeProperties::ChangeOp(node, common()->Return(new_return_count));
229 }
230 break;
231 }
232 case IrOpcode::kCall: {
233 CallDescriptor* descriptor = OpParameter<CallDescriptor*>(node);
234 if (DefaultLowering(node) ||
235 (descriptor->ReturnCount() == 1 &&
236 descriptor->GetReturnType(0) == MachineType::Int64())) {
237 // We have to adjust the call descriptor.
238 const Operator* op = common()->Call(
239 wasm::ModuleEnv::GetI32WasmCallDescriptor(zone(), descriptor));
240 NodeProperties::ChangeOp(node, op);
241 }
242 if (descriptor->ReturnCount() == 1 &&
243 descriptor->GetReturnType(0) == MachineType::Int64()) {
244 // We access the additional return values through projections.
245 Node* low_node = graph()->NewNode(common()->Projection(0), node);
246 Node* high_node = graph()->NewNode(common()->Projection(1), node);
247 ReplaceNode(node, low_node, high_node);
248 }
249 break;
250 }
251 default: { DefaultLowering(node); }
252 }
253}
254
255bool Int64Lowering::DefaultLowering(Node* node) {
256 bool something_changed = false;
257 for (int i = NodeProperties::PastValueIndex(node) - 1; i >= 0; i--) {
258 Node* input = node->InputAt(i);
259 if (HasReplacementLow(input)) {
260 something_changed = true;
261 node->ReplaceInput(i, GetReplacementLow(input));
262 }
263 if (HasReplacementHigh(input)) {
264 something_changed = true;
265 node->InsertInput(zone(), i + 1, GetReplacementHigh(input));
266 }
267 }
268 return something_changed;
269}
270
271void Int64Lowering::ReplaceNode(Node* old, Node* new_low, Node* new_high) {
272 // if new_low == nullptr, then also new_high == nullptr.
273 DCHECK(new_low != nullptr || new_high == nullptr);
274 replacements_[old->id()].low = new_low;
275 replacements_[old->id()].high = new_high;
276}
277
278bool Int64Lowering::HasReplacementLow(Node* node) {
279 return replacements_[node->id()].low != nullptr;
280}
281
282Node* Int64Lowering::GetReplacementLow(Node* node) {
283 Node* result = replacements_[node->id()].low;
284 DCHECK(result);
285 return result;
286}
287
288bool Int64Lowering::HasReplacementHigh(Node* node) {
289 return replacements_[node->id()].high != nullptr;
290}
291
292Node* Int64Lowering::GetReplacementHigh(Node* node) {
293 Node* result = replacements_[node->id()].high;
294 DCHECK(result);
295 return result;
296}
297} // namespace compiler
298} // namespace internal
299} // namespace v8