Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 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/effect-control-linearizer.h" | |
| 6 | |
| 7 #include "src/code-factory.h" | |
| 8 #include "src/compiler/access-builder.h" | |
| 9 #include "src/compiler/js-graph.h" | |
| 10 #include "src/compiler/linkage.h" | |
| 11 #include "src/compiler/node-properties.h" | |
| 12 #include "src/compiler/node.h" | |
| 13 #include "src/compiler/schedule.h" | |
| 14 | |
| 15 namespace v8 { | |
| 16 namespace internal { | |
| 17 namespace compiler { | |
| 18 | |
| 19 EffectControlLinearizer::EffectControlLinearizer(JSGraph* js_graph, | |
| 20 Schedule* schedule, | |
| 21 Zone* temp_zone) | |
| 22 : js_graph_(js_graph), schedule_(schedule), temp_zone_(temp_zone) {} | |
| 23 | |
| 24 Graph* EffectControlLinearizer::graph() const { return js_graph_->graph(); } | |
| 25 CommonOperatorBuilder* EffectControlLinearizer::common() const { | |
| 26 return js_graph_->common(); | |
| 27 } | |
| 28 SimplifiedOperatorBuilder* EffectControlLinearizer::simplified() const { | |
| 29 return js_graph_->simplified(); | |
| 30 } | |
| 31 MachineOperatorBuilder* EffectControlLinearizer::machine() const { | |
| 32 return js_graph_->machine(); | |
| 33 } | |
| 34 | |
| 35 namespace { | |
| 36 | |
| 37 struct BlockEffectData { | |
| 38 Node* current_effect = nullptr; // New effect. | |
| 39 }; | |
| 40 | |
| 41 // Effect phis that need to be updated after the first pass. | |
| 42 struct PendingEffectPhi { | |
| 43 Node* effect_phi; | |
| 44 BasicBlock* block; | |
| 45 | |
| 46 PendingEffectPhi(Node* effect_phi, BasicBlock* block) | |
| 47 : effect_phi(effect_phi), block(block) {} | |
| 48 }; | |
| 49 | |
| 50 void UpdateEffectPhi(Node* node, BasicBlock* block, | |
| 51 ZoneVector<BlockEffectData>* block_effects) { | |
| 52 // Update all inputs to an effect phi with the effects from the given | |
| 53 // block->effect map. | |
| 54 DCHECK_EQ(IrOpcode::kEffectPhi, node->opcode()); | |
| 55 DCHECK_EQ(node->op()->EffectInputCount(), block->PredecessorCount()); | |
| 56 for (int i = 0; i < node->op()->EffectInputCount(); i++) { | |
| 57 Node* input = node->InputAt(i); | |
| 58 BasicBlock* predecessor = block->PredecessorAt(static_cast<size_t>(i)); | |
| 59 Node* input_effect = | |
| 60 (*block_effects)[predecessor->rpo_number()].current_effect; | |
| 61 if (input != input_effect) { | |
| 62 node->ReplaceInput(i, input_effect); | |
| 63 } | |
| 64 } | |
| 65 } | |
| 66 | |
| 67 bool HasIncomingBackEdges(BasicBlock* block) { | |
| 68 for (BasicBlock* pred : block->predecessors()) { | |
| 69 if (pred->rpo_number() >= block->rpo_number()) { | |
| 70 return true; | |
| 71 } | |
| 72 } | |
| 73 return false; | |
| 74 } | |
| 75 | |
| 76 void RemoveRegionNode(Node* node) { | |
| 77 DCHECK(IrOpcode::kFinishRegion == node->opcode() || | |
| 78 IrOpcode::kBeginRegion == node->opcode()); | |
| 79 // Update the value/context uses to the value input of the finish node and | |
| 80 // the effect uses to the effect input. | |
| 81 for (Edge edge : node->use_edges()) { | |
| 82 DCHECK(!edge.from()->IsDead()); | |
| 83 if (NodeProperties::IsEffectEdge(edge)) { | |
| 84 edge.UpdateTo(NodeProperties::GetEffectInput(node)); | |
| 85 } else { | |
| 86 DCHECK(!NodeProperties::IsControlEdge(edge)); | |
| 87 DCHECK(!NodeProperties::IsFrameStateEdge(edge)); | |
| 88 edge.UpdateTo(node->InputAt(0)); | |
| 89 } | |
| 90 } | |
| 91 node->Kill(); | |
| 92 } | |
| 93 | |
| 94 } // namespace | |
| 95 | |
| 96 void EffectControlLinearizer::Run() { | |
| 97 ZoneVector<BlockEffectData> block_effects(temp_zone()); | |
| 98 ZoneVector<PendingEffectPhi> pending_effect_phis(temp_zone()); | |
| 99 block_effects.resize(schedule()->RpoBlockCount()); | |
| 100 NodeVector inputs_buffer(temp_zone()); | |
| 101 | |
| 102 for (BasicBlock* block : *(schedule()->rpo_order())) { | |
| 103 size_t instr = 0; | |
| 104 | |
| 105 // The control node should be the first. | |
|
Benedikt Meurer
2016/04/18 04:34:18
DCHECK this assumption.
Jarin
2016/04/18 07:53:33
Done.
| |
| 106 Node* control = block->NodeAt(instr); | |
| 107 instr++; | |
| 108 | |
| 109 // Iterate over the phis and update the effect phis. | |
| 110 Node* effect = nullptr; | |
| 111 Node* terminate = nullptr; | |
| 112 for (; instr < block->NodeCount(); instr++) { | |
| 113 Node* node = block->NodeAt(instr); | |
| 114 // Only go through the phis and effect phis. | |
| 115 if (node->opcode() == IrOpcode::kEffectPhi) { | |
| 116 // There should be at most one effect phi in a block. | |
| 117 DCHECK_NULL(effect); | |
| 118 // IfException blocks should not have effect phis. | |
| 119 DCHECK_NE(IrOpcode::kIfException, control->opcode()); | |
| 120 effect = node; | |
| 121 | |
| 122 // Make sure we update the inputs to the incoming blocks' effects. | |
| 123 if (HasIncomingBackEdges(block)) { | |
| 124 // In case of loops, we do not update the effect phi immediately | |
| 125 // because the back predecessor has not been handled yet. We just | |
| 126 // record the effect phi for later processing. | |
| 127 pending_effect_phis.push_back(PendingEffectPhi(node, block)); | |
| 128 } else { | |
| 129 UpdateEffectPhi(node, block, &block_effects); | |
| 130 } | |
| 131 } else if (node->opcode() == IrOpcode::kPhi) { | |
| 132 // Just skip phis. | |
| 133 } else if (node->opcode() == IrOpcode::kTerminate) { | |
| 134 DCHECK(terminate == nullptr); | |
| 135 terminate = node; | |
| 136 } else { | |
| 137 break; | |
| 138 } | |
| 139 } | |
| 140 | |
| 141 if (effect == nullptr) { | |
| 142 // There was no effect phi. | |
| 143 DCHECK(!HasIncomingBackEdges(block)); | |
| 144 if (block == schedule()->start()) { | |
| 145 // Start block => effect is start. | |
| 146 DCHECK_EQ(graph()->start(), control); | |
| 147 effect = graph()->start(); | |
| 148 } else if (control->opcode() == IrOpcode::kEnd) { | |
| 149 // End block is a just dummy, no effect needed. | |
|
Benedikt Meurer
2016/04/18 04:34:18
a just dummy -> just a dummy
Jarin
2016/04/18 07:53:33
Done.
| |
| 150 DCHECK_EQ(BasicBlock::kNone, block->control()); | |
| 151 DCHECK_EQ(1, block->size()); | |
|
Benedikt Meurer
2016/04/18 04:34:18
DCHECK_EQ(1u, block->size())
Jarin
2016/04/18 07:53:33
Done.
| |
| 152 effect = nullptr; | |
| 153 } else { | |
| 154 // If all the predecessors have the same effect, we can use it | |
| 155 // as our current effect. | |
| 156 int rpo_number = block->PredecessorAt(0)->rpo_number(); | |
| 157 effect = block_effects[rpo_number].current_effect; | |
| 158 for (size_t i = 1; i < block->PredecessorCount(); i++) { | |
| 159 int rpo_number = block->PredecessorAt(i)->rpo_number(); | |
| 160 if (block_effects[rpo_number].current_effect != effect) { | |
| 161 effect = nullptr; | |
| 162 break; | |
| 163 } | |
| 164 } | |
| 165 if (effect == nullptr) { | |
| 166 DCHECK_NE(IrOpcode::kIfException, control->opcode()); | |
| 167 // The input blocks do not have the same effect. We have | |
| 168 // to create an effect phi node. | |
| 169 inputs_buffer.clear(); | |
| 170 inputs_buffer.resize(block->PredecessorCount(), graph()->start()); | |
| 171 inputs_buffer.push_back(control); | |
| 172 effect = graph()->NewNode( | |
| 173 common()->EffectPhi(static_cast<int>(block->PredecessorCount())), | |
| 174 static_cast<int>(inputs_buffer.size()), &(inputs_buffer.front())); | |
| 175 // Let us update the effect phi node later. | |
| 176 pending_effect_phis.push_back(PendingEffectPhi(effect, block)); | |
| 177 } else if (control->opcode() == IrOpcode::kIfException) { | |
| 178 // The IfException is connected into the effect chain, so we need | |
| 179 // to process it here. | |
| 180 ProcessNode(control, &effect, &control); | |
| 181 } | |
| 182 } | |
| 183 } | |
| 184 | |
| 185 // Fixup the Terminate node. | |
| 186 if (terminate != nullptr) { | |
| 187 NodeProperties::ReplaceEffectInput(terminate, effect); | |
| 188 } | |
| 189 | |
| 190 // Process the ordinary instructions. | |
| 191 for (; instr < block->NodeCount(); instr++) { | |
| 192 Node* node = block->NodeAt(instr); | |
| 193 ProcessNode(node, &effect, &control); | |
| 194 } | |
| 195 | |
| 196 switch (block->control()) { | |
| 197 case BasicBlock::kGoto: | |
| 198 case BasicBlock::kNone: | |
| 199 break; | |
| 200 | |
| 201 case BasicBlock::kCall: | |
| 202 case BasicBlock::kTailCall: | |
| 203 case BasicBlock::kBranch: | |
| 204 case BasicBlock::kSwitch: | |
| 205 case BasicBlock::kReturn: | |
| 206 case BasicBlock::kDeoptimize: | |
| 207 case BasicBlock::kThrow: | |
| 208 ProcessNode(block->control_input(), &effect, &control); | |
| 209 break; | |
| 210 } | |
| 211 | |
| 212 // Store the effect for later use. | |
| 213 block_effects[block->rpo_number()].current_effect = effect; | |
| 214 } | |
| 215 | |
| 216 // Update the incoming edges of the effect phis that could not be processed | |
| 217 // during the first pass (because they could have incoming back edges). | |
| 218 for (const PendingEffectPhi& pending_effect_phi : pending_effect_phis) { | |
| 219 UpdateEffectPhi(pending_effect_phi.effect_phi, pending_effect_phi.block, | |
| 220 &block_effects); | |
| 221 } | |
| 222 } | |
| 223 | |
| 224 void EffectControlLinearizer::ProcessNode(Node* node, Node** effect, | |
| 225 Node** control) { | |
| 226 // If the node needs to be wired into the effect/control chain, do this | |
| 227 // here. | |
| 228 if (TryWireInStateEffect(node, effect, control)) { | |
| 229 return; | |
| 230 } | |
| 231 | |
| 232 // Remove the end markers of 'atomic' allocation region because the | |
| 233 // region should be wired-in now. | |
| 234 if (node->opcode() == IrOpcode::kFinishRegion || | |
| 235 node->opcode() == IrOpcode::kBeginRegion) { | |
| 236 // Update the value uses to the value input of the finish node and | |
| 237 // the effect uses to the effect input. | |
| 238 | |
| 239 // TODO(jarin) Enable this once we make sure everything with side effects | |
| 240 // is marked as effectful. | |
| 241 if (false) { | |
| 242 return RemoveRegionNode(node); | |
| 243 } | |
| 244 } | |
| 245 | |
| 246 // If the node takes an effect, replace with the current one. | |
| 247 if (node->op()->EffectInputCount() > 0) { | |
| 248 DCHECK_EQ(1, node->op()->EffectInputCount()); | |
| 249 Node* input_effect = NodeProperties::GetEffectInput(node); | |
| 250 | |
| 251 if (input_effect != *effect) { | |
| 252 NodeProperties::ReplaceEffectInput(node, *effect); | |
| 253 } | |
| 254 | |
| 255 // If the node produces an effect, update our current effect. (However, | |
| 256 // ignore new effect chains started with ValueEffect.) | |
| 257 if (node->op()->EffectOutputCount() > 0) { | |
| 258 DCHECK_EQ(1, node->op()->EffectOutputCount()); | |
| 259 *effect = node; | |
| 260 } | |
| 261 } else { | |
| 262 // New effect chain is only started with a Start or ValueEffect node. | |
| 263 DCHECK(node->op()->EffectOutputCount() == 0 || | |
| 264 node->opcode() == IrOpcode::kStart); | |
| 265 } | |
| 266 } | |
| 267 | |
| 268 bool EffectControlLinearizer::TryWireInStateEffect(Node* node, Node** effect, | |
| 269 Node** control) { | |
| 270 ValueEffectControl state(nullptr, nullptr, nullptr); | |
| 271 switch (node->opcode()) { | |
| 272 case IrOpcode::kChangeInt32ToTagged: | |
| 273 state = LowerChangeInt32ToTagged(node, *effect, *control); | |
| 274 break; | |
| 275 case IrOpcode::kChangeUint32ToTagged: | |
| 276 state = LowerChangeUint32ToTagged(node, *effect, *control); | |
| 277 break; | |
| 278 case IrOpcode::kChangeFloat64ToTagged: | |
| 279 state = LowerChangeFloat64ToTagged(node, *effect, *control); | |
| 280 break; | |
| 281 default: | |
| 282 return false; | |
| 283 } | |
| 284 NodeProperties::ReplaceUses(node, state.value); | |
| 285 *effect = state.effect; | |
| 286 *control = state.control; | |
| 287 return true; | |
| 288 } | |
| 289 | |
| 290 EffectControlLinearizer::ValueEffectControl | |
| 291 EffectControlLinearizer::LowerChangeFloat64ToTagged(Node* node, Node* effect, | |
| 292 Node* control) { | |
| 293 Node* value = node->InputAt(0); | |
| 294 | |
| 295 Type* const value_type = NodeProperties::GetType(value); | |
| 296 Node* const value32 = graph()->NewNode( | |
| 297 machine()->TruncateFloat64ToInt32(TruncationMode::kRoundToZero), value); | |
| 298 // TODO(bmeurer): This fast case must be disabled until we kill the asm.js | |
| 299 // support in the generic JavaScript pipeline, because LoadBuffer is lying | |
| 300 // about its result. | |
| 301 // if (value_type->Is(Type::Signed32())) { | |
| 302 // return ChangeInt32ToTagged(value32, control); | |
| 303 // } | |
| 304 Node* check_same = graph()->NewNode( | |
| 305 machine()->Float64Equal(), value, | |
| 306 graph()->NewNode(machine()->ChangeInt32ToFloat64(), value32)); | |
| 307 Node* branch_same = graph()->NewNode(common()->Branch(), check_same, control); | |
| 308 | |
| 309 Node* if_smi = graph()->NewNode(common()->IfTrue(), branch_same); | |
| 310 Node* vsmi; | |
| 311 Node* if_box = graph()->NewNode(common()->IfFalse(), branch_same); | |
| 312 | |
| 313 // We only need to check for -0 if the {value} can potentially contain -0. | |
| 314 if (value_type->Maybe(Type::MinusZero())) { | |
| 315 Node* check_zero = graph()->NewNode(machine()->Word32Equal(), value32, | |
| 316 jsgraph()->Int32Constant(0)); | |
| 317 Node* branch_zero = graph()->NewNode(common()->Branch(BranchHint::kFalse), | |
| 318 check_zero, if_smi); | |
| 319 | |
| 320 Node* if_zero = graph()->NewNode(common()->IfTrue(), branch_zero); | |
| 321 Node* if_notzero = graph()->NewNode(common()->IfFalse(), branch_zero); | |
| 322 | |
| 323 // In case of 0, we need to check the high bits for the IEEE -0 pattern. | |
| 324 Node* check_negative = graph()->NewNode( | |
| 325 machine()->Int32LessThan(), | |
| 326 graph()->NewNode(machine()->Float64ExtractHighWord32(), value), | |
| 327 jsgraph()->Int32Constant(0)); | |
| 328 Node* branch_negative = graph()->NewNode( | |
| 329 common()->Branch(BranchHint::kFalse), check_negative, if_zero); | |
| 330 | |
| 331 Node* if_negative = graph()->NewNode(common()->IfTrue(), branch_negative); | |
| 332 Node* if_notnegative = | |
| 333 graph()->NewNode(common()->IfFalse(), branch_negative); | |
| 334 | |
| 335 // We need to create a box for negative 0. | |
| 336 if_smi = graph()->NewNode(common()->Merge(2), if_notzero, if_notnegative); | |
| 337 if_box = graph()->NewNode(common()->Merge(2), if_box, if_negative); | |
| 338 } | |
| 339 | |
| 340 // On 64-bit machines we can just wrap the 32-bit integer in a smi, for 32-bit | |
| 341 // machines we need to deal with potential overflow and fallback to boxing. | |
| 342 if (machine()->Is64() || value_type->Is(Type::SignedSmall())) { | |
| 343 vsmi = ChangeInt32ToSmi(value32); | |
| 344 } else { | |
| 345 Node* smi_tag = | |
| 346 graph()->NewNode(machine()->Int32AddWithOverflow(), value32, value32); | |
| 347 | |
| 348 Node* check_ovf = graph()->NewNode(common()->Projection(1), smi_tag); | |
| 349 Node* branch_ovf = graph()->NewNode(common()->Branch(BranchHint::kFalse), | |
| 350 check_ovf, if_smi); | |
| 351 | |
| 352 Node* if_ovf = graph()->NewNode(common()->IfTrue(), branch_ovf); | |
| 353 if_box = graph()->NewNode(common()->Merge(2), if_ovf, if_box); | |
| 354 | |
| 355 if_smi = graph()->NewNode(common()->IfFalse(), branch_ovf); | |
| 356 vsmi = graph()->NewNode(common()->Projection(0), smi_tag); | |
| 357 } | |
| 358 | |
| 359 // Allocate the box for the {value}. | |
| 360 ValueEffectControl box = AllocateHeapNumberWithValue(value, effect, if_box); | |
| 361 | |
| 362 control = graph()->NewNode(common()->Merge(2), if_smi, box.control); | |
| 363 value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), | |
| 364 vsmi, box.value, control); | |
| 365 effect = | |
| 366 graph()->NewNode(common()->EffectPhi(2), effect, box.effect, control); | |
| 367 return ValueEffectControl(value, effect, control); | |
| 368 } | |
| 369 | |
| 370 EffectControlLinearizer::ValueEffectControl | |
| 371 EffectControlLinearizer::LowerChangeInt32ToTagged(Node* node, Node* effect, | |
| 372 Node* control) { | |
| 373 Node* value = node->InputAt(0); | |
| 374 | |
| 375 if (machine()->Is64() || | |
| 376 NodeProperties::GetType(value)->Is(Type::SignedSmall())) { | |
| 377 return ValueEffectControl(ChangeInt32ToSmi(value), effect, control); | |
| 378 } | |
| 379 | |
| 380 Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), value, value); | |
| 381 | |
| 382 Node* ovf = graph()->NewNode(common()->Projection(1), add); | |
| 383 Node* branch = | |
| 384 graph()->NewNode(common()->Branch(BranchHint::kFalse), ovf, control); | |
| 385 | |
| 386 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); | |
| 387 ValueEffectControl alloc = | |
| 388 AllocateHeapNumberWithValue(ChangeInt32ToFloat64(value), effect, if_true); | |
| 389 | |
| 390 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); | |
| 391 Node* vfalse = graph()->NewNode(common()->Projection(0), add); | |
| 392 | |
| 393 Node* merge = graph()->NewNode(common()->Merge(2), alloc.control, if_false); | |
| 394 Node* phi = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), | |
| 395 alloc.value, vfalse, merge); | |
| 396 Node* ephi = | |
| 397 graph()->NewNode(common()->EffectPhi(2), alloc.effect, effect, merge); | |
| 398 | |
| 399 return ValueEffectControl(phi, ephi, merge); | |
| 400 } | |
| 401 | |
| 402 EffectControlLinearizer::ValueEffectControl | |
| 403 EffectControlLinearizer::LowerChangeUint32ToTagged(Node* node, Node* effect, | |
| 404 Node* control) { | |
| 405 Node* value = node->InputAt(0); | |
| 406 | |
| 407 if (NodeProperties::GetType(value)->Is(Type::UnsignedSmall())) { | |
| 408 return ValueEffectControl(ChangeUint32ToSmi(value), effect, control); | |
| 409 } | |
| 410 | |
| 411 Node* check = graph()->NewNode(machine()->Uint32LessThanOrEqual(), value, | |
| 412 SmiMaxValueConstant()); | |
| 413 Node* branch = | |
| 414 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); | |
| 415 | |
| 416 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); | |
| 417 Node* vtrue = ChangeUint32ToSmi(value); | |
| 418 | |
| 419 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); | |
| 420 ValueEffectControl alloc = AllocateHeapNumberWithValue( | |
| 421 ChangeUint32ToFloat64(value), effect, if_false); | |
| 422 | |
| 423 Node* merge = graph()->NewNode(common()->Merge(2), if_true, alloc.control); | |
| 424 Node* phi = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), | |
| 425 vtrue, alloc.value, merge); | |
| 426 Node* ephi = | |
| 427 graph()->NewNode(common()->EffectPhi(2), effect, alloc.effect, merge); | |
| 428 | |
| 429 return ValueEffectControl(phi, ephi, merge); | |
| 430 } | |
| 431 | |
| 432 EffectControlLinearizer::ValueEffectControl | |
| 433 EffectControlLinearizer::AllocateHeapNumberWithValue(Node* value, Node* effect, | |
| 434 Node* control) { | |
| 435 // The AllocateHeapNumberStub does not use the context, so we can safely pass | |
| 436 // in Smi zero here. | |
| 437 Callable callable = CodeFactory::AllocateHeapNumber(jsgraph()->isolate()); | |
| 438 Node* target = jsgraph()->HeapConstant(callable.code()); | |
| 439 Node* context = jsgraph()->NoContextConstant(); | |
| 440 if (!allocate_heap_number_operator_.is_set()) { | |
| 441 CallDescriptor* descriptor = Linkage::GetStubCallDescriptor( | |
| 442 jsgraph()->isolate(), jsgraph()->zone(), callable.descriptor(), 0, | |
| 443 CallDescriptor::kNoFlags, Operator::kNoThrow); | |
| 444 allocate_heap_number_operator_.set(common()->Call(descriptor)); | |
| 445 } | |
| 446 Node* heap_number = graph()->NewNode(allocate_heap_number_operator_.get(), | |
| 447 target, context, effect, control); | |
| 448 Node* store = graph()->NewNode( | |
| 449 machine()->Store(StoreRepresentation(MachineRepresentation::kFloat64, | |
| 450 kNoWriteBarrier)), | |
| 451 heap_number, HeapNumberValueIndexConstant(), value, heap_number, control); | |
| 452 return ValueEffectControl(heap_number, store, control); | |
| 453 } | |
| 454 | |
| 455 Node* EffectControlLinearizer::ChangeInt32ToSmi(Node* value) { | |
| 456 if (machine()->Is64()) { | |
| 457 value = graph()->NewNode(machine()->ChangeInt32ToInt64(), value); | |
| 458 } | |
| 459 return graph()->NewNode(machine()->WordShl(), value, SmiShiftBitsConstant()); | |
| 460 } | |
| 461 | |
| 462 Node* EffectControlLinearizer::ChangeUint32ToSmi(Node* value) { | |
| 463 if (machine()->Is64()) { | |
| 464 value = graph()->NewNode(machine()->ChangeUint32ToUint64(), value); | |
| 465 } | |
| 466 return graph()->NewNode(machine()->WordShl(), value, SmiShiftBitsConstant()); | |
| 467 } | |
| 468 | |
| 469 Node* EffectControlLinearizer::ChangeInt32ToFloat64(Node* value) { | |
| 470 return graph()->NewNode(machine()->ChangeInt32ToFloat64(), value); | |
| 471 } | |
| 472 | |
| 473 Node* EffectControlLinearizer::ChangeUint32ToFloat64(Node* value) { | |
| 474 return graph()->NewNode(machine()->ChangeUint32ToFloat64(), value); | |
| 475 } | |
| 476 | |
| 477 Node* EffectControlLinearizer::HeapNumberValueIndexConstant() { | |
| 478 return jsgraph()->IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag); | |
| 479 } | |
| 480 | |
| 481 Node* EffectControlLinearizer::SmiMaxValueConstant() { | |
| 482 return jsgraph()->Int32Constant(Smi::kMaxValue); | |
| 483 } | |
| 484 | |
| 485 Node* EffectControlLinearizer::SmiShiftBitsConstant() { | |
| 486 return jsgraph()->IntPtrConstant(kSmiShiftSize + kSmiTagSize); | |
| 487 } | |
| 488 | |
| 489 } // namespace compiler | |
| 490 } // namespace internal | |
| 491 } // namespace v8 | |
| OLD | NEW |