| 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.h" | 5 #include "src/compiler/instruction-selector.h" |
| 6 | 6 |
| 7 #include <limits> | 7 #include <limits> |
| 8 | 8 |
| 9 #include "src/base/adapters.h" | 9 #include "src/base/adapters.h" |
| 10 #include "src/compiler/instruction-selector-impl.h" | 10 #include "src/compiler/instruction-selector-impl.h" |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 current_block_(nullptr), | 34 current_block_(nullptr), |
| 35 instructions_(zone), | 35 instructions_(zone), |
| 36 defined_(node_count, false, zone), | 36 defined_(node_count, false, zone), |
| 37 used_(node_count, false, zone), | 37 used_(node_count, false, zone), |
| 38 effect_level_(node_count, 0, zone), | 38 effect_level_(node_count, 0, zone), |
| 39 virtual_registers_(node_count, | 39 virtual_registers_(node_count, |
| 40 InstructionOperand::kInvalidVirtualRegister, zone), | 40 InstructionOperand::kInvalidVirtualRegister, zone), |
| 41 virtual_register_rename_(zone), | 41 virtual_register_rename_(zone), |
| 42 scheduler_(nullptr), | 42 scheduler_(nullptr), |
| 43 enable_scheduling_(enable_scheduling), | 43 enable_scheduling_(enable_scheduling), |
| 44 frame_(frame) { | 44 frame_(frame), |
| 45 instruction_selection_failed_(false) { |
| 45 instructions_.reserve(node_count); | 46 instructions_.reserve(node_count); |
| 46 } | 47 } |
| 47 | 48 |
| 48 void InstructionSelector::SelectInstructions() { | 49 bool InstructionSelector::SelectInstructions() { |
| 49 // Mark the inputs of all phis in loop headers as used. | 50 // Mark the inputs of all phis in loop headers as used. |
| 50 BasicBlockVector* blocks = schedule()->rpo_order(); | 51 BasicBlockVector* blocks = schedule()->rpo_order(); |
| 51 for (auto const block : *blocks) { | 52 for (auto const block : *blocks) { |
| 52 if (!block->IsLoopHeader()) continue; | 53 if (!block->IsLoopHeader()) continue; |
| 53 DCHECK_LE(2u, block->PredecessorCount()); | 54 DCHECK_LE(2u, block->PredecessorCount()); |
| 54 for (Node* const phi : *block) { | 55 for (Node* const phi : *block) { |
| 55 if (phi->opcode() != IrOpcode::kPhi) continue; | 56 if (phi->opcode() != IrOpcode::kPhi) continue; |
| 56 | 57 |
| 57 // Mark all inputs as used. | 58 // Mark all inputs as used. |
| 58 for (Node* const input : phi->inputs()) { | 59 for (Node* const input : phi->inputs()) { |
| 59 MarkAsUsed(input); | 60 MarkAsUsed(input); |
| 60 } | 61 } |
| 61 } | 62 } |
| 62 } | 63 } |
| 63 | 64 |
| 64 // Visit each basic block in post order. | 65 // Visit each basic block in post order. |
| 65 for (auto i = blocks->rbegin(); i != blocks->rend(); ++i) { | 66 for (auto i = blocks->rbegin(); i != blocks->rend(); ++i) { |
| 66 VisitBlock(*i); | 67 VisitBlock(*i); |
| 68 if (instruction_selection_failed()) return false; |
| 67 } | 69 } |
| 68 | 70 |
| 69 // Schedule the selected instructions. | 71 // Schedule the selected instructions. |
| 70 if (UseInstructionScheduling()) { | 72 if (UseInstructionScheduling()) { |
| 71 scheduler_ = new (zone()) InstructionScheduler(zone(), sequence()); | 73 scheduler_ = new (zone()) InstructionScheduler(zone(), sequence()); |
| 72 } | 74 } |
| 73 | 75 |
| 74 for (auto const block : *blocks) { | 76 for (auto const block : *blocks) { |
| 75 InstructionBlock* instruction_block = | 77 InstructionBlock* instruction_block = |
| 76 sequence()->InstructionBlockAt(RpoNumber::FromInt(block->rpo_number())); | 78 sequence()->InstructionBlockAt(RpoNumber::FromInt(block->rpo_number())); |
| 77 for (size_t i = 0; i < instruction_block->phis().size(); i++) { | 79 for (size_t i = 0; i < instruction_block->phis().size(); i++) { |
| 78 UpdateRenamesInPhi(instruction_block->PhiAt(i)); | 80 UpdateRenamesInPhi(instruction_block->PhiAt(i)); |
| 79 } | 81 } |
| 80 size_t end = instruction_block->code_end(); | 82 size_t end = instruction_block->code_end(); |
| 81 size_t start = instruction_block->code_start(); | 83 size_t start = instruction_block->code_start(); |
| 82 DCHECK_LE(end, start); | 84 DCHECK_LE(end, start); |
| 83 StartBlock(RpoNumber::FromInt(block->rpo_number())); | 85 StartBlock(RpoNumber::FromInt(block->rpo_number())); |
| 84 while (start-- > end) { | 86 while (start-- > end) { |
| 85 UpdateRenames(instructions_[start]); | 87 UpdateRenames(instructions_[start]); |
| 86 AddInstruction(instructions_[start]); | 88 AddInstruction(instructions_[start]); |
| 87 } | 89 } |
| 88 EndBlock(RpoNumber::FromInt(block->rpo_number())); | 90 EndBlock(RpoNumber::FromInt(block->rpo_number())); |
| 89 } | 91 } |
| 90 #if DEBUG | 92 #if DEBUG |
| 91 sequence()->ValidateSSA(); | 93 sequence()->ValidateSSA(); |
| 92 #endif | 94 #endif |
| 95 return true; |
| 93 } | 96 } |
| 94 | 97 |
| 95 void InstructionSelector::StartBlock(RpoNumber rpo) { | 98 void InstructionSelector::StartBlock(RpoNumber rpo) { |
| 96 if (UseInstructionScheduling()) { | 99 if (UseInstructionScheduling()) { |
| 97 DCHECK_NOT_NULL(scheduler_); | 100 DCHECK_NOT_NULL(scheduler_); |
| 98 scheduler_->StartBlock(rpo); | 101 scheduler_->StartBlock(rpo); |
| 99 } else { | 102 } else { |
| 100 sequence()->StartBlock(rpo); | 103 sequence()->StartBlock(rpo); |
| 101 } | 104 } |
| 102 } | 105 } |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 201 size_t input_count = arraysize(inputs); | 204 size_t input_count = arraysize(inputs); |
| 202 return Emit(opcode, output_count, &output, input_count, inputs, temp_count, | 205 return Emit(opcode, output_count, &output, input_count, inputs, temp_count, |
| 203 temps); | 206 temps); |
| 204 } | 207 } |
| 205 | 208 |
| 206 | 209 |
| 207 Instruction* InstructionSelector::Emit( | 210 Instruction* InstructionSelector::Emit( |
| 208 InstructionCode opcode, size_t output_count, InstructionOperand* outputs, | 211 InstructionCode opcode, size_t output_count, InstructionOperand* outputs, |
| 209 size_t input_count, InstructionOperand* inputs, size_t temp_count, | 212 size_t input_count, InstructionOperand* inputs, size_t temp_count, |
| 210 InstructionOperand* temps) { | 213 InstructionOperand* temps) { |
| 214 if (output_count >= Instruction::kMaxOutputCount || |
| 215 input_count >= Instruction::kMaxInputCount || |
| 216 temp_count >= Instruction::kMaxTempCount) { |
| 217 set_instruction_selection_failed(); |
| 218 return nullptr; |
| 219 } |
| 220 |
| 211 Instruction* instr = | 221 Instruction* instr = |
| 212 Instruction::New(instruction_zone(), opcode, output_count, outputs, | 222 Instruction::New(instruction_zone(), opcode, output_count, outputs, |
| 213 input_count, inputs, temp_count, temps); | 223 input_count, inputs, temp_count, temps); |
| 214 return Emit(instr); | 224 return Emit(instr); |
| 215 } | 225 } |
| 216 | 226 |
| 217 | 227 |
| 218 Instruction* InstructionSelector::Emit(Instruction* instr) { | 228 Instruction* InstructionSelector::Emit(Instruction* instr) { |
| 219 instructions_.push_back(instr); | 229 instructions_.push_back(instr); |
| 220 return instr; | 230 return instr; |
| (...skipping 539 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 760 LinkageLocation saved_return_location = | 770 LinkageLocation saved_return_location = |
| 761 LinkageLocation::ForSavedCallerReturnAddress(); | 771 LinkageLocation::ForSavedCallerReturnAddress(); |
| 762 InstructionOperand return_address = | 772 InstructionOperand return_address = |
| 763 g.UsePointerLocation(LinkageLocation::ConvertToTailCallerLocation( | 773 g.UsePointerLocation(LinkageLocation::ConvertToTailCallerLocation( |
| 764 saved_return_location, stack_param_delta), | 774 saved_return_location, stack_param_delta), |
| 765 saved_return_location); | 775 saved_return_location); |
| 766 buffer->instruction_args.push_back(return_address); | 776 buffer->instruction_args.push_back(return_address); |
| 767 } | 777 } |
| 768 } | 778 } |
| 769 | 779 |
| 770 | |
| 771 void InstructionSelector::VisitBlock(BasicBlock* block) { | 780 void InstructionSelector::VisitBlock(BasicBlock* block) { |
| 772 DCHECK(!current_block_); | 781 DCHECK(!current_block_); |
| 773 current_block_ = block; | 782 current_block_ = block; |
| 774 int current_block_end = static_cast<int>(instructions_.size()); | 783 int current_block_end = static_cast<int>(instructions_.size()); |
| 775 | 784 |
| 776 int effect_level = 0; | 785 int effect_level = 0; |
| 777 for (Node* const node : *block) { | 786 for (Node* const node : *block) { |
| 778 if (node->opcode() == IrOpcode::kStore || | 787 if (node->opcode() == IrOpcode::kStore || |
| 779 node->opcode() == IrOpcode::kUnalignedStore || | 788 node->opcode() == IrOpcode::kUnalignedStore || |
| 780 node->opcode() == IrOpcode::kCheckedStore || | 789 node->opcode() == IrOpcode::kCheckedStore || |
| (...skipping 16 matching lines...) Expand all Loading... |
| 797 | 806 |
| 798 // Visit code in reverse control flow order, because architecture-specific | 807 // Visit code in reverse control flow order, because architecture-specific |
| 799 // matching may cover more than one node at a time. | 808 // matching may cover more than one node at a time. |
| 800 for (auto node : base::Reversed(*block)) { | 809 for (auto node : base::Reversed(*block)) { |
| 801 // Skip nodes that are unused or already defined. | 810 // Skip nodes that are unused or already defined. |
| 802 if (!IsUsed(node) || IsDefined(node)) continue; | 811 if (!IsUsed(node) || IsDefined(node)) continue; |
| 803 // Generate code for this node "top down", but schedule the code "bottom | 812 // Generate code for this node "top down", but schedule the code "bottom |
| 804 // up". | 813 // up". |
| 805 size_t current_node_end = instructions_.size(); | 814 size_t current_node_end = instructions_.size(); |
| 806 VisitNode(node); | 815 VisitNode(node); |
| 816 if (instruction_selection_failed()) return; |
| 807 std::reverse(instructions_.begin() + current_node_end, instructions_.end()); | 817 std::reverse(instructions_.begin() + current_node_end, instructions_.end()); |
| 808 if (instructions_.size() == current_node_end) continue; | 818 if (instructions_.size() == current_node_end) continue; |
| 809 // Mark source position on first instruction emitted. | 819 // Mark source position on first instruction emitted. |
| 810 SourcePosition source_position = source_positions_->GetSourcePosition(node); | 820 SourcePosition source_position = source_positions_->GetSourcePosition(node); |
| 811 if (source_position.IsKnown() && | 821 if (source_position.IsKnown() && |
| 812 (source_position_mode_ == kAllSourcePositions || | 822 (source_position_mode_ == kAllSourcePositions || |
| 813 node->opcode() == IrOpcode::kCall)) { | 823 node->opcode() == IrOpcode::kCall)) { |
| 814 sequence()->SetSourcePosition(instructions_[current_node_end], | 824 sequence()->SetSourcePosition(instructions_[current_node_end], |
| 815 source_position); | 825 source_position); |
| 816 } | 826 } |
| (...skipping 1019 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1836 opcode = kArchCallCodeObject | MiscField::encode(flags); | 1846 opcode = kArchCallCodeObject | MiscField::encode(flags); |
| 1837 break; | 1847 break; |
| 1838 case CallDescriptor::kCallJSFunction: | 1848 case CallDescriptor::kCallJSFunction: |
| 1839 opcode = kArchCallJSFunction | MiscField::encode(flags); | 1849 opcode = kArchCallJSFunction | MiscField::encode(flags); |
| 1840 break; | 1850 break; |
| 1841 } | 1851 } |
| 1842 | 1852 |
| 1843 // Emit the call instruction. | 1853 // Emit the call instruction. |
| 1844 size_t const output_count = buffer.outputs.size(); | 1854 size_t const output_count = buffer.outputs.size(); |
| 1845 auto* outputs = output_count ? &buffer.outputs.front() : nullptr; | 1855 auto* outputs = output_count ? &buffer.outputs.front() : nullptr; |
| 1846 Emit(opcode, output_count, outputs, buffer.instruction_args.size(), | 1856 Instruction* call_instr = |
| 1847 &buffer.instruction_args.front()) | 1857 Emit(opcode, output_count, outputs, buffer.instruction_args.size(), |
| 1848 ->MarkAsCall(); | 1858 &buffer.instruction_args.front()); |
| 1859 if (instruction_selection_failed()) return; |
| 1860 call_instr->MarkAsCall(); |
| 1849 } | 1861 } |
| 1850 | 1862 |
| 1851 | 1863 |
| 1852 void InstructionSelector::VisitTailCall(Node* node) { | 1864 void InstructionSelector::VisitTailCall(Node* node) { |
| 1853 OperandGenerator g(this); | 1865 OperandGenerator g(this); |
| 1854 CallDescriptor const* descriptor = CallDescriptorOf(node->op()); | 1866 CallDescriptor const* descriptor = CallDescriptorOf(node->op()); |
| 1855 DCHECK_NE(0, descriptor->flags() & CallDescriptor::kSupportsTailCalls); | 1867 DCHECK_NE(0, descriptor->flags() & CallDescriptor::kSupportsTailCalls); |
| 1856 | 1868 |
| 1857 CallDescriptor* caller = linkage()->GetIncomingDescriptor(); | 1869 CallDescriptor* caller = linkage()->GetIncomingDescriptor(); |
| 1858 if (caller->CanTailCall(node)) { | 1870 if (caller->CanTailCall(node)) { |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1944 break; | 1956 break; |
| 1945 default: | 1957 default: |
| 1946 UNREACHABLE(); | 1958 UNREACHABLE(); |
| 1947 return; | 1959 return; |
| 1948 } | 1960 } |
| 1949 opcode |= MiscField::encode(descriptor->flags()); | 1961 opcode |= MiscField::encode(descriptor->flags()); |
| 1950 | 1962 |
| 1951 // Emit the call instruction. | 1963 // Emit the call instruction. |
| 1952 size_t output_count = buffer.outputs.size(); | 1964 size_t output_count = buffer.outputs.size(); |
| 1953 auto* outputs = &buffer.outputs.front(); | 1965 auto* outputs = &buffer.outputs.front(); |
| 1954 Emit(opcode, output_count, outputs, buffer.instruction_args.size(), | 1966 Instruction* call_instr = |
| 1955 &buffer.instruction_args.front()) | 1967 Emit(opcode, output_count, outputs, buffer.instruction_args.size(), |
| 1956 ->MarkAsCall(); | 1968 &buffer.instruction_args.front()); |
| 1969 if (instruction_selection_failed()) return; |
| 1970 call_instr->MarkAsCall(); |
| 1957 Emit(kArchRet, 0, nullptr, output_count, outputs); | 1971 Emit(kArchRet, 0, nullptr, output_count, outputs); |
| 1958 } | 1972 } |
| 1959 } | 1973 } |
| 1960 | 1974 |
| 1961 | 1975 |
| 1962 void InstructionSelector::VisitGoto(BasicBlock* target) { | 1976 void InstructionSelector::VisitGoto(BasicBlock* target) { |
| 1963 // jump to the next block. | 1977 // jump to the next block. |
| 1964 OperandGenerator g(this); | 1978 OperandGenerator g(this); |
| 1965 Emit(kArchJmp, g.NoOutput(), g.Label(target)); | 1979 Emit(kArchJmp, g.NoOutput(), g.Label(target)); |
| 1966 } | 1980 } |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2099 return new (instruction_zone()) FrameStateDescriptor( | 2113 return new (instruction_zone()) FrameStateDescriptor( |
| 2100 instruction_zone(), state_info.type(), state_info.bailout_id(), | 2114 instruction_zone(), state_info.type(), state_info.bailout_id(), |
| 2101 state_info.state_combine(), parameters, locals, stack, | 2115 state_info.state_combine(), parameters, locals, stack, |
| 2102 state_info.shared_info(), outer_state); | 2116 state_info.shared_info(), outer_state); |
| 2103 } | 2117 } |
| 2104 | 2118 |
| 2105 | 2119 |
| 2106 } // namespace compiler | 2120 } // namespace compiler |
| 2107 } // namespace internal | 2121 } // namespace internal |
| 2108 } // namespace v8 | 2122 } // namespace v8 |
| OLD | NEW |