| 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 26 matching lines...) Expand all Loading... |
| 37 return false; | 37 return false; |
| 38 } | 38 } |
| 39 } | 39 } |
| 40 | 40 |
| 41 bool CanBeBetterLeftOperand(Node* node) const { | 41 bool CanBeBetterLeftOperand(Node* node) const { |
| 42 return !selector()->IsLive(node); | 42 return !selector()->IsLive(node); |
| 43 } | 43 } |
| 44 }; | 44 }; |
| 45 | 45 |
| 46 | 46 |
| 47 class AddressingModeMatcher { |
| 48 public: |
| 49 AddressingModeMatcher(IA32OperandGenerator* g, Node* base, Node* index) |
| 50 : base_operand_(NULL), |
| 51 index_operand_(NULL), |
| 52 displacement_operand_(NULL), |
| 53 mode_(kMode_None) { |
| 54 Int32Matcher index_imm(index); |
| 55 if (index_imm.HasValue()) { |
| 56 int32_t displacement = index_imm.Value(); |
| 57 // Compute base operand and fold base immediate into displacement. |
| 58 Int32Matcher base_imm(base); |
| 59 if (!base_imm.HasValue()) { |
| 60 base_operand_ = g->UseRegister(base); |
| 61 } else { |
| 62 displacement += base_imm.Value(); |
| 63 } |
| 64 if (displacement != 0 || base_operand_ == NULL) { |
| 65 displacement_operand_ = g->TempImmediate(displacement); |
| 66 } |
| 67 if (base_operand_ == NULL) { |
| 68 mode_ = kMode_MI; |
| 69 } else { |
| 70 if (displacement == 0) { |
| 71 mode_ = kMode_MR; |
| 72 } else { |
| 73 mode_ = kMode_MRI; |
| 74 } |
| 75 } |
| 76 } else { |
| 77 // Compute index and displacement. |
| 78 IndexAndDisplacementMatcher matcher(index); |
| 79 index_operand_ = g->UseRegister(matcher.index_node()); |
| 80 int32_t displacement = matcher.displacement(); |
| 81 // Compute base operand and fold base immediate into displacement. |
| 82 Int32Matcher base_imm(base); |
| 83 if (!base_imm.HasValue()) { |
| 84 base_operand_ = g->UseRegister(base); |
| 85 } else { |
| 86 displacement += base_imm.Value(); |
| 87 } |
| 88 // Compute displacement operand. |
| 89 if (displacement != 0) { |
| 90 displacement_operand_ = g->TempImmediate(displacement); |
| 91 } |
| 92 // Compute mode with scale factor one. |
| 93 if (base_operand_ == NULL) { |
| 94 if (displacement_operand_ == NULL) { |
| 95 mode_ = kMode_M1; |
| 96 } else { |
| 97 mode_ = kMode_M1I; |
| 98 } |
| 99 } else { |
| 100 if (displacement_operand_ == NULL) { |
| 101 mode_ = kMode_MR1; |
| 102 } else { |
| 103 mode_ = kMode_MR1I; |
| 104 } |
| 105 } |
| 106 // Adjust mode to actual scale factor. |
| 107 mode_ = GetMode(mode_, matcher.power()); |
| 108 // Don't emit instructions with scale factor 1 if there's no base. |
| 109 if (mode_ == kMode_M1) { |
| 110 mode_ = kMode_MR; |
| 111 } else if (mode_ == kMode_M1I) { |
| 112 mode_ = kMode_MRI; |
| 113 } |
| 114 } |
| 115 DCHECK_NE(kMode_None, mode_); |
| 116 } |
| 117 |
| 118 AddressingMode GetMode(AddressingMode one, int power) { |
| 119 return static_cast<AddressingMode>(static_cast<int>(one) + power); |
| 120 } |
| 121 |
| 122 size_t SetInputs(InstructionOperand** inputs) { |
| 123 size_t input_count = 0; |
| 124 // Compute inputs_ and input_count. |
| 125 if (base_operand_ != NULL) { |
| 126 inputs[input_count++] = base_operand_; |
| 127 } |
| 128 if (index_operand_ != NULL) { |
| 129 inputs[input_count++] = index_operand_; |
| 130 } |
| 131 if (displacement_operand_ != NULL) { |
| 132 inputs[input_count++] = displacement_operand_; |
| 133 } |
| 134 DCHECK_NE(input_count, 0); |
| 135 return input_count; |
| 136 } |
| 137 |
| 138 static const int kMaxInputCount = 3; |
| 139 InstructionOperand* base_operand_; |
| 140 InstructionOperand* index_operand_; |
| 141 InstructionOperand* displacement_operand_; |
| 142 AddressingMode mode_; |
| 143 }; |
| 144 |
| 145 |
| 47 void InstructionSelector::VisitLoad(Node* node) { | 146 void InstructionSelector::VisitLoad(Node* node) { |
| 48 MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node)); | 147 MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node)); |
| 49 MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node)); | 148 MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node)); |
| 50 IA32OperandGenerator g(this); | |
| 51 Node* base = node->InputAt(0); | 149 Node* base = node->InputAt(0); |
| 52 Node* index = node->InputAt(1); | 150 Node* index = node->InputAt(1); |
| 53 | 151 |
| 54 ArchOpcode opcode; | 152 ArchOpcode opcode; |
| 55 // TODO(titzer): signed/unsigned small loads | 153 // TODO(titzer): signed/unsigned small loads |
| 56 switch (rep) { | 154 switch (rep) { |
| 57 case kRepFloat32: | 155 case kRepFloat32: |
| 58 opcode = kIA32Movss; | 156 opcode = kIA32Movss; |
| 59 break; | 157 break; |
| 60 case kRepFloat64: | 158 case kRepFloat64: |
| 61 opcode = kIA32Movsd; | 159 opcode = kIA32Movsd; |
| 62 break; | 160 break; |
| 63 case kRepBit: // Fall through. | 161 case kRepBit: // Fall through. |
| 64 case kRepWord8: | 162 case kRepWord8: |
| 65 opcode = typ == kTypeInt32 ? kIA32Movsxbl : kIA32Movzxbl; | 163 opcode = typ == kTypeInt32 ? kIA32Movsxbl : kIA32Movzxbl; |
| 66 break; | 164 break; |
| 67 case kRepWord16: | 165 case kRepWord16: |
| 68 opcode = typ == kTypeInt32 ? kIA32Movsxwl : kIA32Movzxwl; | 166 opcode = typ == kTypeInt32 ? kIA32Movsxwl : kIA32Movzxwl; |
| 69 break; | 167 break; |
| 70 case kRepTagged: // Fall through. | 168 case kRepTagged: // Fall through. |
| 71 case kRepWord32: | 169 case kRepWord32: |
| 72 opcode = kIA32Movl; | 170 opcode = kIA32Movl; |
| 73 break; | 171 break; |
| 74 default: | 172 default: |
| 75 UNREACHABLE(); | 173 UNREACHABLE(); |
| 76 return; | 174 return; |
| 77 } | 175 } |
| 78 if (g.CanBeImmediate(base)) { | 176 |
| 79 if (Int32Matcher(index).Is(0)) { // load [#base + #0] | 177 IA32OperandGenerator g(this); |
| 80 Emit(opcode | AddressingModeField::encode(kMode_MI), | 178 AddressingModeMatcher matcher(&g, base, index); |
| 81 g.DefineAsRegister(node), g.UseImmediate(base)); | 179 InstructionCode code = opcode | AddressingModeField::encode(matcher.mode_); |
| 82 } else { // load [#base + %index] | 180 InstructionOperand* outputs[] = {g.DefineAsRegister(node)}; |
| 83 Emit(opcode | AddressingModeField::encode(kMode_MRI), | 181 InstructionOperand* inputs[AddressingModeMatcher::kMaxInputCount]; |
| 84 g.DefineAsRegister(node), g.UseRegister(index), | 182 size_t input_count = matcher.SetInputs(inputs); |
| 85 g.UseImmediate(base)); | 183 Emit(code, 1, outputs, input_count, inputs); |
| 86 } | |
| 87 } else if (g.CanBeImmediate(index)) { // load [%base + #index] | |
| 88 Emit(opcode | AddressingModeField::encode(kMode_MRI), | |
| 89 g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index)); | |
| 90 } else { // load [%base + %index + K] | |
| 91 Emit(opcode | AddressingModeField::encode(kMode_MR1I), | |
| 92 g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index)); | |
| 93 } | |
| 94 // TODO(turbofan): addressing modes [r+r*{2,4,8}+K] | |
| 95 } | 184 } |
| 96 | 185 |
| 97 | 186 |
| 98 void InstructionSelector::VisitStore(Node* node) { | 187 void InstructionSelector::VisitStore(Node* node) { |
| 99 IA32OperandGenerator g(this); | 188 IA32OperandGenerator g(this); |
| 100 Node* base = node->InputAt(0); | 189 Node* base = node->InputAt(0); |
| 101 Node* index = node->InputAt(1); | 190 Node* index = node->InputAt(1); |
| 102 Node* value = node->InputAt(2); | 191 Node* value = node->InputAt(2); |
| 103 | 192 |
| 104 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node); | 193 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node); |
| 105 MachineType rep = RepresentationOf(store_rep.machine_type()); | 194 MachineType rep = RepresentationOf(store_rep.machine_type()); |
| 106 if (store_rep.write_barrier_kind() == kFullWriteBarrier) { | 195 if (store_rep.write_barrier_kind() == kFullWriteBarrier) { |
| 107 DCHECK_EQ(kRepTagged, rep); | 196 DCHECK_EQ(kRepTagged, rep); |
| 108 // TODO(dcarney): refactor RecordWrite function to take temp registers | 197 // TODO(dcarney): refactor RecordWrite function to take temp registers |
| 109 // and pass them here instead of using fixed regs | 198 // and pass them here instead of using fixed regs |
| 110 // TODO(dcarney): handle immediate indices. | 199 // TODO(dcarney): handle immediate indices. |
| 111 InstructionOperand* temps[] = {g.TempRegister(ecx), g.TempRegister(edx)}; | 200 InstructionOperand* temps[] = {g.TempRegister(ecx), g.TempRegister(edx)}; |
| 112 Emit(kIA32StoreWriteBarrier, NULL, g.UseFixed(base, ebx), | 201 Emit(kIA32StoreWriteBarrier, NULL, g.UseFixed(base, ebx), |
| 113 g.UseFixed(index, ecx), g.UseFixed(value, edx), arraysize(temps), | 202 g.UseFixed(index, ecx), g.UseFixed(value, edx), arraysize(temps), |
| 114 temps); | 203 temps); |
| 115 return; | 204 return; |
| 116 } | 205 } |
| 117 DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind()); | 206 DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind()); |
| 118 InstructionOperand* val; | 207 |
| 119 if (g.CanBeImmediate(value)) { | |
| 120 val = g.UseImmediate(value); | |
| 121 } else if (rep == kRepWord8 || rep == kRepBit) { | |
| 122 val = g.UseByteRegister(value); | |
| 123 } else { | |
| 124 val = g.UseRegister(value); | |
| 125 } | |
| 126 ArchOpcode opcode; | 208 ArchOpcode opcode; |
| 127 switch (rep) { | 209 switch (rep) { |
| 128 case kRepFloat32: | 210 case kRepFloat32: |
| 129 opcode = kIA32Movss; | 211 opcode = kIA32Movss; |
| 130 break; | 212 break; |
| 131 case kRepFloat64: | 213 case kRepFloat64: |
| 132 opcode = kIA32Movsd; | 214 opcode = kIA32Movsd; |
| 133 break; | 215 break; |
| 134 case kRepBit: // Fall through. | 216 case kRepBit: // Fall through. |
| 135 case kRepWord8: | 217 case kRepWord8: |
| 136 opcode = kIA32Movb; | 218 opcode = kIA32Movb; |
| 137 break; | 219 break; |
| 138 case kRepWord16: | 220 case kRepWord16: |
| 139 opcode = kIA32Movw; | 221 opcode = kIA32Movw; |
| 140 break; | 222 break; |
| 141 case kRepTagged: // Fall through. | 223 case kRepTagged: // Fall through. |
| 142 case kRepWord32: | 224 case kRepWord32: |
| 143 opcode = kIA32Movl; | 225 opcode = kIA32Movl; |
| 144 break; | 226 break; |
| 145 default: | 227 default: |
| 146 UNREACHABLE(); | 228 UNREACHABLE(); |
| 147 return; | 229 return; |
| 148 } | 230 } |
| 149 if (g.CanBeImmediate(base)) { | 231 |
| 150 if (Int32Matcher(index).Is(0)) { // store [#base], %|#value | 232 InstructionOperand* val; |
| 151 Emit(opcode | AddressingModeField::encode(kMode_MI), NULL, | 233 if (g.CanBeImmediate(value)) { |
| 152 g.UseImmediate(base), val); | 234 val = g.UseImmediate(value); |
| 153 } else { // store [#base + %index], %|#value | 235 } else if (rep == kRepWord8 || rep == kRepBit) { |
| 154 Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL, | 236 val = g.UseByteRegister(value); |
| 155 g.UseRegister(index), g.UseImmediate(base), val); | 237 } else { |
| 156 } | 238 val = g.UseRegister(value); |
| 157 } else if (g.CanBeImmediate(index)) { // store [%base + #index], %|#value | |
| 158 Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL, | |
| 159 g.UseRegister(base), g.UseImmediate(index), val); | |
| 160 } else { // store [%base + %index], %|#value | |
| 161 Emit(opcode | AddressingModeField::encode(kMode_MR1I), NULL, | |
| 162 g.UseRegister(base), g.UseRegister(index), val); | |
| 163 } | 239 } |
| 164 // TODO(turbofan): addressing modes [r+r*{2,4,8}+K] | 240 |
| 241 AddressingModeMatcher matcher(&g, base, index); |
| 242 InstructionCode code = opcode | AddressingModeField::encode(matcher.mode_); |
| 243 InstructionOperand* inputs[AddressingModeMatcher::kMaxInputCount + 1]; |
| 244 size_t input_count = matcher.SetInputs(inputs); |
| 245 inputs[input_count++] = val; |
| 246 Emit(code, 0, static_cast<InstructionOperand**>(NULL), input_count, inputs); |
| 165 } | 247 } |
| 166 | 248 |
| 167 | 249 |
| 168 // Shared routine for multiple binary operations. | 250 // Shared routine for multiple binary operations. |
| 169 static void VisitBinop(InstructionSelector* selector, Node* node, | 251 static void VisitBinop(InstructionSelector* selector, Node* node, |
| 170 InstructionCode opcode, FlagsContinuation* cont) { | 252 InstructionCode opcode, FlagsContinuation* cont) { |
| 171 IA32OperandGenerator g(selector); | 253 IA32OperandGenerator g(selector); |
| 172 Int32BinopMatcher m(node); | 254 Int32BinopMatcher m(node); |
| 173 Node* left = m.left().node(); | 255 Node* left = m.left().node(); |
| 174 Node* right = m.right().node(); | 256 Node* right = m.right().node(); |
| (...skipping 401 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 576 call_instr->MarkAsCall(); | 658 call_instr->MarkAsCall(); |
| 577 if (deoptimization != NULL) { | 659 if (deoptimization != NULL) { |
| 578 DCHECK(continuation != NULL); | 660 DCHECK(continuation != NULL); |
| 579 call_instr->MarkAsControl(); | 661 call_instr->MarkAsControl(); |
| 580 } | 662 } |
| 581 } | 663 } |
| 582 | 664 |
| 583 } // namespace compiler | 665 } // namespace compiler |
| 584 } // namespace internal | 666 } // namespace internal |
| 585 } // namespace v8 | 667 } // namespace v8 |
| OLD | NEW |