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