| 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/instruction-selector-impl.h" | 5 #include "src/compiler/instruction-selector-impl.h" |
| 6 #include "src/compiler/node-matchers.h" | 6 #include "src/compiler/node-matchers.h" |
| 7 #include "src/compiler/node-properties-inl.h" | 7 #include "src/compiler/node-properties-inl.h" |
| 8 | 8 |
| 9 namespace v8 { | 9 namespace v8 { |
| 10 namespace internal { | 10 namespace internal { |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 152 Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL, | 152 Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL, |
| 153 g.UseRegister(base), g.UseImmediate(index), val); | 153 g.UseRegister(base), g.UseImmediate(index), val); |
| 154 } else { // store [%base + %index], %|#value | 154 } else { // store [%base + %index], %|#value |
| 155 Emit(opcode | AddressingModeField::encode(kMode_MR1I), NULL, | 155 Emit(opcode | AddressingModeField::encode(kMode_MR1I), NULL, |
| 156 g.UseRegister(base), g.UseRegister(index), val); | 156 g.UseRegister(base), g.UseRegister(index), val); |
| 157 } | 157 } |
| 158 // TODO(turbofan): addressing modes [r+r*{2,4,8}+K] | 158 // TODO(turbofan): addressing modes [r+r*{2,4,8}+K] |
| 159 } | 159 } |
| 160 | 160 |
| 161 | 161 |
| 162 // Shared routine for multiple binary operations. | |
| 163 static void VisitBinop(InstructionSelector* selector, Node* node, | 162 static void VisitBinop(InstructionSelector* selector, Node* node, |
| 164 InstructionCode opcode, FlagsContinuation* cont) { | 163 InstructionCode opcode, FlagsContinuation* cont) { |
| 165 IA32OperandGenerator g(selector); | 164 IA32OperandGenerator g(selector); |
| 166 Int32BinopMatcher m(node); | 165 Int32BinopMatcher m(node); |
| 167 InstructionOperand* inputs[4]; | 166 InstructionOperand* inputs[4]; |
| 168 size_t input_count = 0; | 167 size_t input_count = 0; |
| 169 InstructionOperand* outputs[2]; | 168 InstructionOperand* outputs[2]; |
| 170 size_t output_count = 0; | 169 size_t output_count = 0; |
| 171 | 170 |
| 172 // TODO(turbofan): match complex addressing modes. | 171 // TODO(turbofan): match complex addressing modes. |
| (...skipping 22 matching lines...) Expand all Loading... |
| 195 DCHECK_NE(0, output_count); | 194 DCHECK_NE(0, output_count); |
| 196 DCHECK_GE(ARRAY_SIZE(inputs), input_count); | 195 DCHECK_GE(ARRAY_SIZE(inputs), input_count); |
| 197 DCHECK_GE(ARRAY_SIZE(outputs), output_count); | 196 DCHECK_GE(ARRAY_SIZE(outputs), output_count); |
| 198 | 197 |
| 199 Instruction* instr = selector->Emit(cont->Encode(opcode), output_count, | 198 Instruction* instr = selector->Emit(cont->Encode(opcode), output_count, |
| 200 outputs, input_count, inputs); | 199 outputs, input_count, inputs); |
| 201 if (cont->IsBranch()) instr->MarkAsControl(); | 200 if (cont->IsBranch()) instr->MarkAsControl(); |
| 202 } | 201 } |
| 203 | 202 |
| 204 | 203 |
| 205 // Shared routine for multiple binary operations. | |
| 206 static void VisitBinop(InstructionSelector* selector, Node* node, | 204 static void VisitBinop(InstructionSelector* selector, Node* node, |
| 207 InstructionCode opcode) { | 205 InstructionCode opcode) { |
| 208 FlagsContinuation cont; | 206 FlagsContinuation cont; |
| 209 VisitBinop(selector, node, opcode, &cont); | 207 VisitBinop(selector, node, opcode, &cont); |
| 210 } | 208 } |
| 211 | 209 |
| 212 | 210 |
| 211 static void VisitBinop(InstructionSelector* selector, Node* node, |
| 212 InstructionCode opcode, |
| 213 FlagsCondition overflow_condition) { |
| 214 if (Node* overflow = node->FindProjection(1)) { |
| 215 FlagsContinuation cont(overflow_condition, overflow); |
| 216 return VisitBinop(selector, node, opcode, &cont); |
| 217 } |
| 218 FlagsContinuation cont; |
| 219 return VisitBinop(selector, node, opcode, &cont); |
| 220 } |
| 221 |
| 222 |
| 213 void InstructionSelector::VisitWord32And(Node* node) { | 223 void InstructionSelector::VisitWord32And(Node* node) { |
| 214 VisitBinop(this, node, kIA32And); | 224 VisitBinop(this, node, kIA32And); |
| 215 } | 225 } |
| 216 | 226 |
| 217 | 227 |
| 218 void InstructionSelector::VisitWord32Or(Node* node) { | 228 void InstructionSelector::VisitWord32Or(Node* node) { |
| 219 VisitBinop(this, node, kIA32Or); | 229 VisitBinop(this, node, kIA32Or); |
| 220 } | 230 } |
| 221 | 231 |
| 222 | 232 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 269 void InstructionSelector::VisitWord32Sar(Node* node) { | 279 void InstructionSelector::VisitWord32Sar(Node* node) { |
| 270 VisitShift(this, node, kIA32Sar); | 280 VisitShift(this, node, kIA32Sar); |
| 271 } | 281 } |
| 272 | 282 |
| 273 | 283 |
| 274 void InstructionSelector::VisitInt32Add(Node* node) { | 284 void InstructionSelector::VisitInt32Add(Node* node) { |
| 275 VisitBinop(this, node, kIA32Add); | 285 VisitBinop(this, node, kIA32Add); |
| 276 } | 286 } |
| 277 | 287 |
| 278 | 288 |
| 289 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) { |
| 290 VisitBinop(this, node, kIA32Add, kOverflow); |
| 291 } |
| 292 |
| 293 |
| 294 void InstructionSelector::VisitUint32AddWithOverflow(Node* node) { |
| 295 VisitBinop(this, node, kIA32Add, kUnsignedLessThan); |
| 296 } |
| 297 |
| 298 |
| 279 void InstructionSelector::VisitInt32Sub(Node* node) { | 299 void InstructionSelector::VisitInt32Sub(Node* node) { |
| 280 IA32OperandGenerator g(this); | 300 IA32OperandGenerator g(this); |
| 281 Int32BinopMatcher m(node); | 301 Int32BinopMatcher m(node); |
| 282 if (m.left().Is(0)) { | 302 if (m.left().Is(0)) { |
| 283 Emit(kIA32Neg, g.DefineSameAsFirst(node), g.Use(m.right().node())); | 303 Emit(kIA32Neg, g.DefineSameAsFirst(node), g.Use(m.right().node())); |
| 284 } else { | 304 } else { |
| 285 VisitBinop(this, node, kIA32Sub); | 305 VisitBinop(this, node, kIA32Sub); |
| 286 } | 306 } |
| 287 } | 307 } |
| 288 | 308 |
| 289 | 309 |
| 310 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { |
| 311 VisitBinop(this, node, kIA32Sub, kOverflow); |
| 312 } |
| 313 |
| 314 |
| 315 void InstructionSelector::VisitUint32SubWithOverflow(Node* node) { |
| 316 VisitBinop(this, node, kIA32Sub, kUnsignedLessThan); |
| 317 } |
| 318 |
| 319 |
| 290 void InstructionSelector::VisitInt32Mul(Node* node) { | 320 void InstructionSelector::VisitInt32Mul(Node* node) { |
| 291 IA32OperandGenerator g(this); | 321 IA32OperandGenerator g(this); |
| 292 Node* left = node->InputAt(0); | 322 Node* left = node->InputAt(0); |
| 293 Node* right = node->InputAt(1); | 323 Node* right = node->InputAt(1); |
| 294 if (g.CanBeImmediate(right)) { | 324 if (g.CanBeImmediate(right)) { |
| 295 Emit(kIA32Imul, g.DefineAsRegister(node), g.Use(left), | 325 Emit(kIA32Imul, g.DefineAsRegister(node), g.Use(left), |
| 296 g.UseImmediate(right)); | 326 g.UseImmediate(right)); |
| 297 } else if (g.CanBeImmediate(left)) { | 327 } else if (g.CanBeImmediate(left)) { |
| 298 Emit(kIA32Imul, g.DefineAsRegister(node), g.Use(right), | 328 Emit(kIA32Imul, g.DefineAsRegister(node), g.Use(right), |
| 299 g.UseImmediate(left)); | 329 g.UseImmediate(left)); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 410 | 440 |
| 411 void InstructionSelector::VisitFloat64Mod(Node* node) { | 441 void InstructionSelector::VisitFloat64Mod(Node* node) { |
| 412 IA32OperandGenerator g(this); | 442 IA32OperandGenerator g(this); |
| 413 InstructionOperand* temps[] = {g.TempRegister(eax)}; | 443 InstructionOperand* temps[] = {g.TempRegister(eax)}; |
| 414 Emit(kSSEFloat64Mod, g.DefineSameAsFirst(node), | 444 Emit(kSSEFloat64Mod, g.DefineSameAsFirst(node), |
| 415 g.UseDoubleRegister(node->InputAt(0)), | 445 g.UseDoubleRegister(node->InputAt(0)), |
| 416 g.UseDoubleRegister(node->InputAt(1)), 1, temps); | 446 g.UseDoubleRegister(node->InputAt(1)), 1, temps); |
| 417 } | 447 } |
| 418 | 448 |
| 419 | 449 |
| 420 void InstructionSelector::VisitInt32AddWithOverflow(Node* node, | |
| 421 FlagsContinuation* cont) { | |
| 422 VisitBinop(this, node, kIA32Add, cont); | |
| 423 } | |
| 424 | |
| 425 | |
| 426 void InstructionSelector::VisitInt32SubWithOverflow(Node* node, | |
| 427 FlagsContinuation* cont) { | |
| 428 VisitBinop(this, node, kIA32Sub, cont); | |
| 429 } | |
| 430 | |
| 431 | |
| 432 // Shared routine for multiple compare operations. | 450 // Shared routine for multiple compare operations. |
| 433 static inline void VisitCompare(InstructionSelector* selector, | 451 static inline void VisitCompare(InstructionSelector* selector, |
| 434 InstructionCode opcode, | 452 InstructionCode opcode, |
| 435 InstructionOperand* left, | 453 InstructionOperand* left, |
| 436 InstructionOperand* right, | 454 InstructionOperand* right, |
| 437 FlagsContinuation* cont) { | 455 FlagsContinuation* cont) { |
| 438 IA32OperandGenerator g(selector); | 456 IA32OperandGenerator g(selector); |
| 439 if (cont->IsBranch()) { | 457 if (cont->IsBranch()) { |
| 440 selector->Emit(cont->Encode(opcode), NULL, left, right, | 458 selector->Emit(cont->Encode(opcode), NULL, left, right, |
| 441 g.Label(cont->true_block()), | 459 g.Label(cont->true_block()), |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 493 void InstructionSelector::VisitFloat64Compare(Node* node, | 511 void InstructionSelector::VisitFloat64Compare(Node* node, |
| 494 FlagsContinuation* cont) { | 512 FlagsContinuation* cont) { |
| 495 IA32OperandGenerator g(this); | 513 IA32OperandGenerator g(this); |
| 496 Node* left = node->InputAt(0); | 514 Node* left = node->InputAt(0); |
| 497 Node* right = node->InputAt(1); | 515 Node* right = node->InputAt(1); |
| 498 VisitCompare(this, kSSEFloat64Cmp, g.UseDoubleRegister(left), g.Use(right), | 516 VisitCompare(this, kSSEFloat64Cmp, g.UseDoubleRegister(left), g.Use(right), |
| 499 cont); | 517 cont); |
| 500 } | 518 } |
| 501 | 519 |
| 502 | 520 |
| 521 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, |
| 522 BasicBlock* fbranch) { |
| 523 OperandGenerator g(this); |
| 524 Node* user = branch; |
| 525 Node* value = branch->InputAt(0); |
| 526 |
| 527 FlagsContinuation cont(kNotEqual, tbranch, fbranch); |
| 528 |
| 529 // If we can fall through to the true block, invert the branch. |
| 530 if (IsNextInAssemblyOrder(tbranch)) { |
| 531 cont.Negate(); |
| 532 cont.SwapBlocks(); |
| 533 } |
| 534 |
| 535 // Try to combine with comparisons against 0 by simply inverting the branch. |
| 536 while (CanCover(user, value)) { |
| 537 if (value->opcode() == IrOpcode::kWord32Equal) { |
| 538 Int32BinopMatcher m(value); |
| 539 if (m.right().Is(0)) { |
| 540 user = value; |
| 541 value = m.left().node(); |
| 542 cont.Negate(); |
| 543 } else { |
| 544 break; |
| 545 } |
| 546 } else { |
| 547 break; |
| 548 } |
| 549 } |
| 550 |
| 551 // Try to combine the branch with a comparison. |
| 552 if (CanCover(user, value)) { |
| 553 switch (value->opcode()) { |
| 554 case IrOpcode::kWord32Equal: |
| 555 cont.OverwriteAndNegateIfEqual(kEqual); |
| 556 return VisitWord32Compare(value, &cont); |
| 557 case IrOpcode::kInt32LessThan: |
| 558 cont.OverwriteAndNegateIfEqual(kSignedLessThan); |
| 559 return VisitWord32Compare(value, &cont); |
| 560 case IrOpcode::kInt32LessThanOrEqual: |
| 561 cont.OverwriteAndNegateIfEqual(kSignedLessThanOrEqual); |
| 562 return VisitWord32Compare(value, &cont); |
| 563 case IrOpcode::kUint32LessThan: |
| 564 cont.OverwriteAndNegateIfEqual(kUnsignedLessThan); |
| 565 return VisitWord32Compare(value, &cont); |
| 566 case IrOpcode::kUint32LessThanOrEqual: |
| 567 cont.OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual); |
| 568 return VisitWord32Compare(value, &cont); |
| 569 case IrOpcode::kFloat64Equal: |
| 570 cont.OverwriteAndNegateIfEqual(kUnorderedEqual); |
| 571 return VisitFloat64Compare(value, &cont); |
| 572 case IrOpcode::kFloat64LessThan: |
| 573 cont.OverwriteAndNegateIfEqual(kUnorderedLessThan); |
| 574 return VisitFloat64Compare(value, &cont); |
| 575 case IrOpcode::kFloat64LessThanOrEqual: |
| 576 cont.OverwriteAndNegateIfEqual(kUnorderedLessThanOrEqual); |
| 577 return VisitFloat64Compare(value, &cont); |
| 578 case IrOpcode::kProjection: |
| 579 // Check if this is the overflow output projection of an |
| 580 // <Operation>WithOverflow node. |
| 581 if (OpParameter<int32_t>(value) == 1) { |
| 582 // We cannot combine the <Operation>WithOverflow with this branch |
| 583 // unless the 0th projection (the use of the actual value of the |
| 584 // <Operation> is either NULL, which means there's no use of the |
| 585 // actual value, or was already defined, which means it is scheduled |
| 586 // *AFTER* this branch). |
| 587 Node* node = value->InputAt(0); |
| 588 Node* result = node->FindProjection(0); |
| 589 if (result == NULL || IsDefined(result)) { |
| 590 switch (node->opcode()) { |
| 591 case IrOpcode::kInt32AddWithOverflow: |
| 592 cont.OverwriteAndNegateIfEqual(kOverflow); |
| 593 return VisitBinop(this, node, kIA32Add, &cont); |
| 594 case IrOpcode::kUint32AddWithOverflow: |
| 595 cont.OverwriteAndNegateIfEqual(kUnsignedLessThan); |
| 596 return VisitBinop(this, node, kIA32Add, &cont); |
| 597 case IrOpcode::kInt32SubWithOverflow: |
| 598 cont.OverwriteAndNegateIfEqual(kOverflow); |
| 599 return VisitBinop(this, node, kIA32Sub, &cont); |
| 600 case IrOpcode::kUint32SubWithOverflow: |
| 601 cont.OverwriteAndNegateIfEqual(kUnsignedLessThan); |
| 602 return VisitBinop(this, node, kIA32Sub, &cont); |
| 603 default: |
| 604 break; |
| 605 } |
| 606 } |
| 607 } |
| 608 break; |
| 609 default: |
| 610 break; |
| 611 } |
| 612 } |
| 613 |
| 614 // Branch could not be combined with a compare, emit compare against 0. |
| 615 VisitWord32Test(value, &cont); |
| 616 } |
| 617 |
| 618 |
| 503 void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation, | 619 void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation, |
| 504 BasicBlock* deoptimization) { | 620 BasicBlock* deoptimization) { |
| 505 IA32OperandGenerator g(this); | 621 IA32OperandGenerator g(this); |
| 506 CallDescriptor* descriptor = OpParameter<CallDescriptor*>(call); | 622 CallDescriptor* descriptor = OpParameter<CallDescriptor*>(call); |
| 507 CallBuffer buffer(zone(), descriptor); | 623 CallBuffer buffer(zone(), descriptor); |
| 508 | 624 |
| 509 // Compute InstructionOperands for inputs and outputs. | 625 // Compute InstructionOperands for inputs and outputs. |
| 510 InitializeCallBuffer(call, &buffer, true, true, continuation, deoptimization); | 626 InitializeCallBuffer(call, &buffer, true, true, continuation, deoptimization); |
| 511 | 627 |
| 512 // Push any stack arguments. | 628 // Push any stack arguments. |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 551 if (descriptor->kind() == CallDescriptor::kCallAddress && | 667 if (descriptor->kind() == CallDescriptor::kCallAddress && |
| 552 buffer.pushed_count > 0) { | 668 buffer.pushed_count > 0) { |
| 553 DCHECK(deoptimization == NULL && continuation == NULL); | 669 DCHECK(deoptimization == NULL && continuation == NULL); |
| 554 Emit(kPopStack | MiscField::encode(buffer.pushed_count), NULL); | 670 Emit(kPopStack | MiscField::encode(buffer.pushed_count), NULL); |
| 555 } | 671 } |
| 556 } | 672 } |
| 557 | 673 |
| 558 } // namespace compiler | 674 } // namespace compiler |
| 559 } // namespace internal | 675 } // namespace internal |
| 560 } // namespace v8 | 676 } // namespace v8 |
| OLD | NEW |