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