| 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.h" | 7 #include "src/compiler/node-properties.h" |
| 8 | 8 |
| 9 namespace v8 { | 9 namespace v8 { |
| 10 namespace internal { | 10 namespace internal { |
| 11 namespace compiler { | 11 namespace compiler { |
| 12 | 12 |
| 13 // Adds IA32-specific methods for generating operands. | 13 // Adds IA32-specific methods for generating operands. |
| 14 class IA32OperandGenerator FINAL : public OperandGenerator { | 14 class IA32OperandGenerator FINAL : public OperandGenerator { |
| 15 public: | 15 public: |
| 16 explicit IA32OperandGenerator(InstructionSelector* selector) | 16 explicit IA32OperandGenerator(InstructionSelector* selector) |
| 17 : OperandGenerator(selector) {} | 17 : OperandGenerator(selector) {} |
| 18 | 18 |
| 19 InstructionOperand* UseByteRegister(Node* node) { | 19 InstructionOperand UseByteRegister(Node* node) { |
| 20 // TODO(dcarney): relax constraint. | 20 // TODO(dcarney): relax constraint. |
| 21 return UseFixed(node, edx); | 21 return UseFixed(node, edx); |
| 22 } | 22 } |
| 23 | 23 |
| 24 bool CanBeImmediate(Node* node) { | 24 bool CanBeImmediate(Node* node) { |
| 25 switch (node->opcode()) { | 25 switch (node->opcode()) { |
| 26 case IrOpcode::kInt32Constant: | 26 case IrOpcode::kInt32Constant: |
| 27 case IrOpcode::kNumberConstant: | 27 case IrOpcode::kNumberConstant: |
| 28 case IrOpcode::kExternalConstant: | 28 case IrOpcode::kExternalConstant: |
| 29 return true; | 29 return true; |
| 30 case IrOpcode::kHeapConstant: { | 30 case IrOpcode::kHeapConstant: { |
| 31 // Constants in new space cannot be used as immediates in V8 because | 31 // Constants in new space cannot be used as immediates in V8 because |
| 32 // the GC does not scan code objects when collecting the new generation. | 32 // the GC does not scan code objects when collecting the new generation. |
| 33 Unique<HeapObject> value = OpParameter<Unique<HeapObject> >(node); | 33 Unique<HeapObject> value = OpParameter<Unique<HeapObject> >(node); |
| 34 Isolate* isolate = value.handle()->GetIsolate(); | 34 Isolate* isolate = value.handle()->GetIsolate(); |
| 35 return !isolate->heap()->InNewSpace(*value.handle()); | 35 return !isolate->heap()->InNewSpace(*value.handle()); |
| 36 } | 36 } |
| 37 default: | 37 default: |
| 38 return false; | 38 return false; |
| 39 } | 39 } |
| 40 } | 40 } |
| 41 | 41 |
| 42 AddressingMode GenerateMemoryOperandInputs(Node* index, int scale, Node* base, | 42 AddressingMode GenerateMemoryOperandInputs(Node* index, int scale, Node* base, |
| 43 Node* displacement_node, | 43 Node* displacement_node, |
| 44 InstructionOperand* inputs[], | 44 InstructionOperand inputs[], |
| 45 size_t* input_count) { | 45 size_t* input_count) { |
| 46 AddressingMode mode = kMode_MRI; | 46 AddressingMode mode = kMode_MRI; |
| 47 int32_t displacement = (displacement_node == NULL) | 47 int32_t displacement = (displacement_node == NULL) |
| 48 ? 0 | 48 ? 0 |
| 49 : OpParameter<int32_t>(displacement_node); | 49 : OpParameter<int32_t>(displacement_node); |
| 50 if (base != NULL) { | 50 if (base != NULL) { |
| 51 if (base->opcode() == IrOpcode::kInt32Constant) { | 51 if (base->opcode() == IrOpcode::kInt32Constant) { |
| 52 displacement += OpParameter<int32_t>(base); | 52 displacement += OpParameter<int32_t>(base); |
| 53 base = NULL; | 53 base = NULL; |
| 54 } | 54 } |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 92 } | 92 } |
| 93 } else { | 93 } else { |
| 94 inputs[(*input_count)++] = TempImmediate(displacement); | 94 inputs[(*input_count)++] = TempImmediate(displacement); |
| 95 return kMode_MI; | 95 return kMode_MI; |
| 96 } | 96 } |
| 97 } | 97 } |
| 98 return mode; | 98 return mode; |
| 99 } | 99 } |
| 100 | 100 |
| 101 AddressingMode GetEffectiveAddressMemoryOperand(Node* node, | 101 AddressingMode GetEffectiveAddressMemoryOperand(Node* node, |
| 102 InstructionOperand* inputs[], | 102 InstructionOperand inputs[], |
| 103 size_t* input_count) { | 103 size_t* input_count) { |
| 104 BaseWithIndexAndDisplacement32Matcher m(node, true); | 104 BaseWithIndexAndDisplacement32Matcher m(node, true); |
| 105 DCHECK(m.matches()); | 105 DCHECK(m.matches()); |
| 106 if ((m.displacement() == NULL || CanBeImmediate(m.displacement()))) { | 106 if ((m.displacement() == NULL || CanBeImmediate(m.displacement()))) { |
| 107 return GenerateMemoryOperandInputs(m.index(), m.scale(), m.base(), | 107 return GenerateMemoryOperandInputs(m.index(), m.scale(), m.base(), |
| 108 m.displacement(), inputs, input_count); | 108 m.displacement(), inputs, input_count); |
| 109 } else { | 109 } else { |
| 110 inputs[(*input_count)++] = UseRegister(node->InputAt(0)); | 110 inputs[(*input_count)++] = UseRegister(node->InputAt(0)); |
| 111 inputs[(*input_count)++] = UseRegister(node->InputAt(1)); | 111 inputs[(*input_count)++] = UseRegister(node->InputAt(1)); |
| 112 return kMode_MR1; | 112 return kMode_MR1; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 150 case kRepTagged: // Fall through. | 150 case kRepTagged: // Fall through. |
| 151 case kRepWord32: | 151 case kRepWord32: |
| 152 opcode = kIA32Movl; | 152 opcode = kIA32Movl; |
| 153 break; | 153 break; |
| 154 default: | 154 default: |
| 155 UNREACHABLE(); | 155 UNREACHABLE(); |
| 156 return; | 156 return; |
| 157 } | 157 } |
| 158 | 158 |
| 159 IA32OperandGenerator g(this); | 159 IA32OperandGenerator g(this); |
| 160 InstructionOperand* outputs[1]; | 160 InstructionOperand outputs[1]; |
| 161 outputs[0] = g.DefineAsRegister(node); | 161 outputs[0] = g.DefineAsRegister(node); |
| 162 InstructionOperand* inputs[3]; | 162 InstructionOperand inputs[3]; |
| 163 size_t input_count = 0; | 163 size_t input_count = 0; |
| 164 AddressingMode mode = | 164 AddressingMode mode = |
| 165 g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count); | 165 g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count); |
| 166 InstructionCode code = opcode | AddressingModeField::encode(mode); | 166 InstructionCode code = opcode | AddressingModeField::encode(mode); |
| 167 Emit(code, 1, outputs, input_count, inputs); | 167 Emit(code, 1, outputs, input_count, inputs); |
| 168 } | 168 } |
| 169 | 169 |
| 170 | 170 |
| 171 void InstructionSelector::VisitStore(Node* node) { | 171 void InstructionSelector::VisitStore(Node* node) { |
| 172 IA32OperandGenerator g(this); | 172 IA32OperandGenerator g(this); |
| 173 Node* base = node->InputAt(0); | 173 Node* base = node->InputAt(0); |
| 174 Node* index = node->InputAt(1); | 174 Node* index = node->InputAt(1); |
| 175 Node* value = node->InputAt(2); | 175 Node* value = node->InputAt(2); |
| 176 | 176 |
| 177 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node); | 177 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node); |
| 178 MachineType rep = RepresentationOf(store_rep.machine_type()); | 178 MachineType rep = RepresentationOf(store_rep.machine_type()); |
| 179 if (store_rep.write_barrier_kind() == kFullWriteBarrier) { | 179 if (store_rep.write_barrier_kind() == kFullWriteBarrier) { |
| 180 DCHECK_EQ(kRepTagged, rep); | 180 DCHECK_EQ(kRepTagged, rep); |
| 181 // TODO(dcarney): refactor RecordWrite function to take temp registers | 181 // TODO(dcarney): refactor RecordWrite function to take temp registers |
| 182 // and pass them here instead of using fixed regs | 182 // and pass them here instead of using fixed regs |
| 183 // TODO(dcarney): handle immediate indices. | 183 // TODO(dcarney): handle immediate indices. |
| 184 InstructionOperand* temps[] = {g.TempRegister(ecx), g.TempRegister(edx)}; | 184 InstructionOperand temps[] = {g.TempRegister(ecx), g.TempRegister(edx)}; |
| 185 Emit(kIA32StoreWriteBarrier, NULL, g.UseFixed(base, ebx), | 185 Emit(kIA32StoreWriteBarrier, g.NoOutput(), g.UseFixed(base, ebx), |
| 186 g.UseFixed(index, ecx), g.UseFixed(value, edx), arraysize(temps), | 186 g.UseFixed(index, ecx), g.UseFixed(value, edx), arraysize(temps), |
| 187 temps); | 187 temps); |
| 188 return; | 188 return; |
| 189 } | 189 } |
| 190 DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind()); | 190 DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind()); |
| 191 | 191 |
| 192 ArchOpcode opcode; | 192 ArchOpcode opcode; |
| 193 switch (rep) { | 193 switch (rep) { |
| 194 case kRepFloat32: | 194 case kRepFloat32: |
| 195 opcode = kIA32Movss; | 195 opcode = kIA32Movss; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 206 break; | 206 break; |
| 207 case kRepTagged: // Fall through. | 207 case kRepTagged: // Fall through. |
| 208 case kRepWord32: | 208 case kRepWord32: |
| 209 opcode = kIA32Movl; | 209 opcode = kIA32Movl; |
| 210 break; | 210 break; |
| 211 default: | 211 default: |
| 212 UNREACHABLE(); | 212 UNREACHABLE(); |
| 213 return; | 213 return; |
| 214 } | 214 } |
| 215 | 215 |
| 216 InstructionOperand* val; | 216 InstructionOperand val; |
| 217 if (g.CanBeImmediate(value)) { | 217 if (g.CanBeImmediate(value)) { |
| 218 val = g.UseImmediate(value); | 218 val = g.UseImmediate(value); |
| 219 } else if (rep == kRepWord8 || rep == kRepBit) { | 219 } else if (rep == kRepWord8 || rep == kRepBit) { |
| 220 val = g.UseByteRegister(value); | 220 val = g.UseByteRegister(value); |
| 221 } else { | 221 } else { |
| 222 val = g.UseRegister(value); | 222 val = g.UseRegister(value); |
| 223 } | 223 } |
| 224 | 224 |
| 225 InstructionOperand* inputs[4]; | 225 InstructionOperand inputs[4]; |
| 226 size_t input_count = 0; | 226 size_t input_count = 0; |
| 227 AddressingMode mode = | 227 AddressingMode mode = |
| 228 g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count); | 228 g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count); |
| 229 InstructionCode code = opcode | AddressingModeField::encode(mode); | 229 InstructionCode code = opcode | AddressingModeField::encode(mode); |
| 230 inputs[input_count++] = val; | 230 inputs[input_count++] = val; |
| 231 Emit(code, 0, static_cast<InstructionOperand**>(NULL), input_count, inputs); | 231 Emit(code, 0, static_cast<InstructionOperand*>(NULL), input_count, inputs); |
| 232 } | 232 } |
| 233 | 233 |
| 234 | 234 |
| 235 void InstructionSelector::VisitCheckedLoad(Node* node) { | 235 void InstructionSelector::VisitCheckedLoad(Node* node) { |
| 236 MachineType rep = RepresentationOf(OpParameter<MachineType>(node)); | 236 MachineType rep = RepresentationOf(OpParameter<MachineType>(node)); |
| 237 MachineType typ = TypeOf(OpParameter<MachineType>(node)); | 237 MachineType typ = TypeOf(OpParameter<MachineType>(node)); |
| 238 IA32OperandGenerator g(this); | 238 IA32OperandGenerator g(this); |
| 239 Node* const buffer = node->InputAt(0); | 239 Node* const buffer = node->InputAt(0); |
| 240 Node* const offset = node->InputAt(1); | 240 Node* const offset = node->InputAt(1); |
| 241 Node* const length = node->InputAt(2); | 241 Node* const length = node->InputAt(2); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 253 case kRepFloat32: | 253 case kRepFloat32: |
| 254 opcode = kCheckedLoadFloat32; | 254 opcode = kCheckedLoadFloat32; |
| 255 break; | 255 break; |
| 256 case kRepFloat64: | 256 case kRepFloat64: |
| 257 opcode = kCheckedLoadFloat64; | 257 opcode = kCheckedLoadFloat64; |
| 258 break; | 258 break; |
| 259 default: | 259 default: |
| 260 UNREACHABLE(); | 260 UNREACHABLE(); |
| 261 return; | 261 return; |
| 262 } | 262 } |
| 263 InstructionOperand* offset_operand = g.UseRegister(offset); | 263 InstructionOperand offset_operand = g.UseRegister(offset); |
| 264 InstructionOperand* length_operand = | 264 InstructionOperand length_operand = |
| 265 g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length); | 265 g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length); |
| 266 if (g.CanBeImmediate(buffer)) { | 266 if (g.CanBeImmediate(buffer)) { |
| 267 Emit(opcode | AddressingModeField::encode(kMode_MRI), | 267 Emit(opcode | AddressingModeField::encode(kMode_MRI), |
| 268 g.DefineAsRegister(node), offset_operand, length_operand, | 268 g.DefineAsRegister(node), offset_operand, length_operand, |
| 269 offset_operand, g.UseImmediate(buffer)); | 269 offset_operand, g.UseImmediate(buffer)); |
| 270 } else { | 270 } else { |
| 271 Emit(opcode | AddressingModeField::encode(kMode_MR1), | 271 Emit(opcode | AddressingModeField::encode(kMode_MR1), |
| 272 g.DefineAsRegister(node), offset_operand, length_operand, | 272 g.DefineAsRegister(node), offset_operand, length_operand, |
| 273 g.UseRegister(buffer), offset_operand); | 273 g.UseRegister(buffer), offset_operand); |
| 274 } | 274 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 296 case kRepFloat32: | 296 case kRepFloat32: |
| 297 opcode = kCheckedStoreFloat32; | 297 opcode = kCheckedStoreFloat32; |
| 298 break; | 298 break; |
| 299 case kRepFloat64: | 299 case kRepFloat64: |
| 300 opcode = kCheckedStoreFloat64; | 300 opcode = kCheckedStoreFloat64; |
| 301 break; | 301 break; |
| 302 default: | 302 default: |
| 303 UNREACHABLE(); | 303 UNREACHABLE(); |
| 304 return; | 304 return; |
| 305 } | 305 } |
| 306 InstructionOperand* value_operand = | 306 InstructionOperand value_operand = |
| 307 g.CanBeImmediate(value) | 307 g.CanBeImmediate(value) |
| 308 ? g.UseImmediate(value) | 308 ? g.UseImmediate(value) |
| 309 : ((rep == kRepWord8 || rep == kRepBit) ? g.UseByteRegister(value) | 309 : ((rep == kRepWord8 || rep == kRepBit) ? g.UseByteRegister(value) |
| 310 : g.UseRegister(value)); | 310 : g.UseRegister(value)); |
| 311 InstructionOperand* offset_operand = g.UseRegister(offset); | 311 InstructionOperand offset_operand = g.UseRegister(offset); |
| 312 InstructionOperand* length_operand = | 312 InstructionOperand length_operand = |
| 313 g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length); | 313 g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length); |
| 314 if (g.CanBeImmediate(buffer)) { | 314 if (g.CanBeImmediate(buffer)) { |
| 315 Emit(opcode | AddressingModeField::encode(kMode_MRI), nullptr, | 315 Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(), |
| 316 offset_operand, length_operand, value_operand, offset_operand, | 316 offset_operand, length_operand, value_operand, offset_operand, |
| 317 g.UseImmediate(buffer)); | 317 g.UseImmediate(buffer)); |
| 318 } else { | 318 } else { |
| 319 Emit(opcode | AddressingModeField::encode(kMode_MR1), nullptr, | 319 Emit(opcode | AddressingModeField::encode(kMode_MR1), g.NoOutput(), |
| 320 offset_operand, length_operand, value_operand, g.UseRegister(buffer), | 320 offset_operand, length_operand, value_operand, g.UseRegister(buffer), |
| 321 offset_operand); | 321 offset_operand); |
| 322 } | 322 } |
| 323 } | 323 } |
| 324 | 324 |
| 325 | 325 |
| 326 // Shared routine for multiple binary operations. | 326 // Shared routine for multiple binary operations. |
| 327 static void VisitBinop(InstructionSelector* selector, Node* node, | 327 static void VisitBinop(InstructionSelector* selector, Node* node, |
| 328 InstructionCode opcode, FlagsContinuation* cont) { | 328 InstructionCode opcode, FlagsContinuation* cont) { |
| 329 IA32OperandGenerator g(selector); | 329 IA32OperandGenerator g(selector); |
| 330 Int32BinopMatcher m(node); | 330 Int32BinopMatcher m(node); |
| 331 Node* left = m.left().node(); | 331 Node* left = m.left().node(); |
| 332 Node* right = m.right().node(); | 332 Node* right = m.right().node(); |
| 333 InstructionOperand* inputs[4]; | 333 InstructionOperand inputs[4]; |
| 334 size_t input_count = 0; | 334 size_t input_count = 0; |
| 335 InstructionOperand* outputs[2]; | 335 InstructionOperand outputs[2]; |
| 336 size_t output_count = 0; | 336 size_t output_count = 0; |
| 337 | 337 |
| 338 // TODO(turbofan): match complex addressing modes. | 338 // TODO(turbofan): match complex addressing modes. |
| 339 if (left == right) { | 339 if (left == right) { |
| 340 // If both inputs refer to the same operand, enforce allocating a register | 340 // If both inputs refer to the same operand, enforce allocating a register |
| 341 // for both of them to ensure that we don't end up generating code like | 341 // for both of them to ensure that we don't end up generating code like |
| 342 // this: | 342 // this: |
| 343 // | 343 // |
| 344 // mov eax, [ebp-0x10] | 344 // mov eax, [ebp-0x10] |
| 345 // add eax, [ebp-0x10] | 345 // add eax, [ebp-0x10] |
| 346 // jo label | 346 // jo label |
| 347 InstructionOperand* const input = g.UseRegister(left); | 347 InstructionOperand const input = g.UseRegister(left); |
| 348 inputs[input_count++] = input; | 348 inputs[input_count++] = input; |
| 349 inputs[input_count++] = input; | 349 inputs[input_count++] = input; |
| 350 } else if (g.CanBeImmediate(right)) { | 350 } else if (g.CanBeImmediate(right)) { |
| 351 inputs[input_count++] = g.UseRegister(left); | 351 inputs[input_count++] = g.UseRegister(left); |
| 352 inputs[input_count++] = g.UseImmediate(right); | 352 inputs[input_count++] = g.UseImmediate(right); |
| 353 } else { | 353 } else { |
| 354 if (node->op()->HasProperty(Operator::kCommutative) && | 354 if (node->op()->HasProperty(Operator::kCommutative) && |
| 355 g.CanBeBetterLeftOperand(right)) { | 355 g.CanBeBetterLeftOperand(right)) { |
| 356 std::swap(left, right); | 356 std::swap(left, right); |
| 357 } | 357 } |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 433 ArchOpcode opcode) { | 433 ArchOpcode opcode) { |
| 434 IA32OperandGenerator g(selector); | 434 IA32OperandGenerator g(selector); |
| 435 selector->Emit(opcode, g.DefineAsFixed(node, edx), | 435 selector->Emit(opcode, g.DefineAsFixed(node, edx), |
| 436 g.UseFixed(node->InputAt(0), eax), | 436 g.UseFixed(node->InputAt(0), eax), |
| 437 g.UseUniqueRegister(node->InputAt(1))); | 437 g.UseUniqueRegister(node->InputAt(1))); |
| 438 } | 438 } |
| 439 | 439 |
| 440 | 440 |
| 441 void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode opcode) { | 441 void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode opcode) { |
| 442 IA32OperandGenerator g(selector); | 442 IA32OperandGenerator g(selector); |
| 443 InstructionOperand* temps[] = {g.TempRegister(edx)}; | 443 InstructionOperand temps[] = {g.TempRegister(edx)}; |
| 444 selector->Emit(opcode, g.DefineAsFixed(node, eax), | 444 selector->Emit(opcode, g.DefineAsFixed(node, eax), |
| 445 g.UseFixed(node->InputAt(0), eax), | 445 g.UseFixed(node->InputAt(0), eax), |
| 446 g.UseUnique(node->InputAt(1)), arraysize(temps), temps); | 446 g.UseUnique(node->InputAt(1)), arraysize(temps), temps); |
| 447 } | 447 } |
| 448 | 448 |
| 449 | 449 |
| 450 void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode opcode) { | 450 void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode opcode) { |
| 451 IA32OperandGenerator g(selector); | 451 IA32OperandGenerator g(selector); |
| 452 selector->Emit(opcode, g.DefineAsFixed(node, edx), | 452 selector->Emit(opcode, g.DefineAsFixed(node, edx), |
| 453 g.UseFixed(node->InputAt(0), eax), | 453 g.UseFixed(node->InputAt(0), eax), |
| 454 g.UseUnique(node->InputAt(1))); | 454 g.UseUnique(node->InputAt(1))); |
| 455 } | 455 } |
| 456 | 456 |
| 457 void EmitLea(InstructionSelector* selector, Node* result, Node* index, | 457 void EmitLea(InstructionSelector* selector, Node* result, Node* index, |
| 458 int scale, Node* base, Node* displacement) { | 458 int scale, Node* base, Node* displacement) { |
| 459 IA32OperandGenerator g(selector); | 459 IA32OperandGenerator g(selector); |
| 460 InstructionOperand* inputs[4]; | 460 InstructionOperand inputs[4]; |
| 461 size_t input_count = 0; | 461 size_t input_count = 0; |
| 462 AddressingMode mode = g.GenerateMemoryOperandInputs( | 462 AddressingMode mode = g.GenerateMemoryOperandInputs( |
| 463 index, scale, base, displacement, inputs, &input_count); | 463 index, scale, base, displacement, inputs, &input_count); |
| 464 | 464 |
| 465 DCHECK_NE(0, static_cast<int>(input_count)); | 465 DCHECK_NE(0, static_cast<int>(input_count)); |
| 466 DCHECK_GE(arraysize(inputs), input_count); | 466 DCHECK_GE(arraysize(inputs), input_count); |
| 467 | 467 |
| 468 InstructionOperand* outputs[1]; | 468 InstructionOperand outputs[1]; |
| 469 outputs[0] = g.DefineAsRegister(result); | 469 outputs[0] = g.DefineAsRegister(result); |
| 470 | 470 |
| 471 InstructionCode opcode = AddressingModeField::encode(mode) | kIA32Lea; | 471 InstructionCode opcode = AddressingModeField::encode(mode) | kIA32Lea; |
| 472 | 472 |
| 473 selector->Emit(opcode, 1, outputs, input_count, inputs); | 473 selector->Emit(opcode, 1, outputs, input_count, inputs); |
| 474 } | 474 } |
| 475 | 475 |
| 476 } // namespace | 476 } // namespace |
| 477 | 477 |
| 478 | 478 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 503 } | 503 } |
| 504 | 504 |
| 505 | 505 |
| 506 void InstructionSelector::VisitInt32Add(Node* node) { | 506 void InstructionSelector::VisitInt32Add(Node* node) { |
| 507 IA32OperandGenerator g(this); | 507 IA32OperandGenerator g(this); |
| 508 | 508 |
| 509 // Try to match the Add to a lea pattern | 509 // Try to match the Add to a lea pattern |
| 510 BaseWithIndexAndDisplacement32Matcher m(node); | 510 BaseWithIndexAndDisplacement32Matcher m(node); |
| 511 if (m.matches() && | 511 if (m.matches() && |
| 512 (m.displacement() == NULL || g.CanBeImmediate(m.displacement()))) { | 512 (m.displacement() == NULL || g.CanBeImmediate(m.displacement()))) { |
| 513 InstructionOperand* inputs[4]; | 513 InstructionOperand inputs[4]; |
| 514 size_t input_count = 0; | 514 size_t input_count = 0; |
| 515 AddressingMode mode = g.GenerateMemoryOperandInputs( | 515 AddressingMode mode = g.GenerateMemoryOperandInputs( |
| 516 m.index(), m.scale(), m.base(), m.displacement(), inputs, &input_count); | 516 m.index(), m.scale(), m.base(), m.displacement(), inputs, &input_count); |
| 517 | 517 |
| 518 DCHECK_NE(0, static_cast<int>(input_count)); | 518 DCHECK_NE(0, static_cast<int>(input_count)); |
| 519 DCHECK_GE(arraysize(inputs), input_count); | 519 DCHECK_GE(arraysize(inputs), input_count); |
| 520 | 520 |
| 521 InstructionOperand* outputs[1]; | 521 InstructionOperand outputs[1]; |
| 522 outputs[0] = g.DefineAsRegister(node); | 522 outputs[0] = g.DefineAsRegister(node); |
| 523 | 523 |
| 524 InstructionCode opcode = AddressingModeField::encode(mode) | kIA32Lea; | 524 InstructionCode opcode = AddressingModeField::encode(mode) | kIA32Lea; |
| 525 Emit(opcode, 1, outputs, input_count, inputs); | 525 Emit(opcode, 1, outputs, input_count, inputs); |
| 526 return; | 526 return; |
| 527 } | 527 } |
| 528 | 528 |
| 529 // No lea pattern match, use add | 529 // No lea pattern match, use add |
| 530 VisitBinop(this, node, kIA32Add); | 530 VisitBinop(this, node, kIA32Add); |
| 531 } | 531 } |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 675 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1))); | 675 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1))); |
| 676 } else { | 676 } else { |
| 677 Emit(kSSEFloat64Div, g.DefineSameAsFirst(node), | 677 Emit(kSSEFloat64Div, g.DefineSameAsFirst(node), |
| 678 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1))); | 678 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1))); |
| 679 } | 679 } |
| 680 } | 680 } |
| 681 | 681 |
| 682 | 682 |
| 683 void InstructionSelector::VisitFloat64Mod(Node* node) { | 683 void InstructionSelector::VisitFloat64Mod(Node* node) { |
| 684 IA32OperandGenerator g(this); | 684 IA32OperandGenerator g(this); |
| 685 InstructionOperand* temps[] = {g.TempRegister(eax)}; | 685 InstructionOperand temps[] = {g.TempRegister(eax)}; |
| 686 Emit(kSSEFloat64Mod, g.DefineSameAsFirst(node), | 686 Emit(kSSEFloat64Mod, g.DefineSameAsFirst(node), |
| 687 g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)), 1, | 687 g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)), 1, |
| 688 temps); | 688 temps); |
| 689 } | 689 } |
| 690 | 690 |
| 691 | 691 |
| 692 void InstructionSelector::VisitFloat64Sqrt(Node* node) { | 692 void InstructionSelector::VisitFloat64Sqrt(Node* node) { |
| 693 IA32OperandGenerator g(this); | 693 IA32OperandGenerator g(this); |
| 694 Emit(kSSEFloat64Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0))); | 694 Emit(kSSEFloat64Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0))); |
| 695 } | 695 } |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 731 | 731 |
| 732 CallBuffer buffer(zone(), descriptor, frame_state_descriptor); | 732 CallBuffer buffer(zone(), descriptor, frame_state_descriptor); |
| 733 | 733 |
| 734 // Compute InstructionOperands for inputs and outputs. | 734 // Compute InstructionOperands for inputs and outputs. |
| 735 InitializeCallBuffer(node, &buffer, true, true); | 735 InitializeCallBuffer(node, &buffer, true, true); |
| 736 | 736 |
| 737 // Push any stack arguments. | 737 // Push any stack arguments. |
| 738 for (auto i = buffer.pushed_nodes.rbegin(); i != buffer.pushed_nodes.rend(); | 738 for (auto i = buffer.pushed_nodes.rbegin(); i != buffer.pushed_nodes.rend(); |
| 739 ++i) { | 739 ++i) { |
| 740 // TODO(titzer): handle pushing double parameters. | 740 // TODO(titzer): handle pushing double parameters. |
| 741 InstructionOperand* value = | 741 InstructionOperand value = |
| 742 g.CanBeImmediate(*i) ? g.UseImmediate(*i) : IsSupported(ATOM) | 742 g.CanBeImmediate(*i) ? g.UseImmediate(*i) : IsSupported(ATOM) |
| 743 ? g.UseRegister(*i) | 743 ? g.UseRegister(*i) |
| 744 : g.Use(*i); | 744 : g.Use(*i); |
| 745 Emit(kIA32Push, nullptr, value); | 745 Emit(kIA32Push, g.NoOutput(), value); |
| 746 } | 746 } |
| 747 | 747 |
| 748 // Select the appropriate opcode based on the call type. | 748 // Select the appropriate opcode based on the call type. |
| 749 InstructionCode opcode; | 749 InstructionCode opcode; |
| 750 switch (descriptor->kind()) { | 750 switch (descriptor->kind()) { |
| 751 case CallDescriptor::kCallCodeObject: { | 751 case CallDescriptor::kCallCodeObject: { |
| 752 opcode = kArchCallCodeObject; | 752 opcode = kArchCallCodeObject; |
| 753 break; | 753 break; |
| 754 } | 754 } |
| 755 case CallDescriptor::kCallJSFunction: | 755 case CallDescriptor::kCallJSFunction: |
| 756 opcode = kArchCallJSFunction; | 756 opcode = kArchCallJSFunction; |
| 757 break; | 757 break; |
| 758 default: | 758 default: |
| 759 UNREACHABLE(); | 759 UNREACHABLE(); |
| 760 return; | 760 return; |
| 761 } | 761 } |
| 762 opcode |= MiscField::encode(descriptor->flags()); | 762 opcode |= MiscField::encode(descriptor->flags()); |
| 763 | 763 |
| 764 // Emit the call instruction. | 764 // Emit the call instruction. |
| 765 InstructionOperand** first_output = | 765 InstructionOperand* first_output = |
| 766 buffer.outputs.size() > 0 ? &buffer.outputs.front() : NULL; | 766 buffer.outputs.size() > 0 ? &buffer.outputs.front() : NULL; |
| 767 Instruction* call_instr = | 767 Instruction* call_instr = |
| 768 Emit(opcode, buffer.outputs.size(), first_output, | 768 Emit(opcode, buffer.outputs.size(), first_output, |
| 769 buffer.instruction_args.size(), &buffer.instruction_args.front()); | 769 buffer.instruction_args.size(), &buffer.instruction_args.front()); |
| 770 call_instr->MarkAsCall(); | 770 call_instr->MarkAsCall(); |
| 771 } | 771 } |
| 772 | 772 |
| 773 | 773 |
| 774 namespace { | 774 namespace { |
| 775 | 775 |
| 776 // Shared routine for multiple compare operations. | 776 // Shared routine for multiple compare operations. |
| 777 void VisitCompare(InstructionSelector* selector, InstructionCode opcode, | 777 void VisitCompare(InstructionSelector* selector, InstructionCode opcode, |
| 778 InstructionOperand* left, InstructionOperand* right, | 778 InstructionOperand left, InstructionOperand right, |
| 779 FlagsContinuation* cont) { | 779 FlagsContinuation* cont) { |
| 780 IA32OperandGenerator g(selector); | 780 IA32OperandGenerator g(selector); |
| 781 if (cont->IsBranch()) { | 781 if (cont->IsBranch()) { |
| 782 selector->Emit(cont->Encode(opcode), NULL, left, right, | 782 selector->Emit(cont->Encode(opcode), g.NoOutput(), left, right, |
| 783 g.Label(cont->true_block()), | 783 g.Label(cont->true_block()), |
| 784 g.Label(cont->false_block()))->MarkAsControl(); | 784 g.Label(cont->false_block()))->MarkAsControl(); |
| 785 } else { | 785 } else { |
| 786 DCHECK(cont->IsSet()); | 786 DCHECK(cont->IsSet()); |
| 787 // TODO(titzer): Needs byte register. | 787 // TODO(titzer): Needs byte register. |
| 788 selector->Emit(cont->Encode(opcode), g.DefineAsRegister(cont->result()), | 788 selector->Emit(cont->Encode(opcode), g.DefineAsRegister(cont->result()), |
| 789 left, right); | 789 left, right); |
| 790 } | 790 } |
| 791 } | 791 } |
| 792 | 792 |
| (...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1008 MachineOperatorBuilder::kFloat64Ceil | | 1008 MachineOperatorBuilder::kFloat64Ceil | |
| 1009 MachineOperatorBuilder::kFloat64RoundTruncate | | 1009 MachineOperatorBuilder::kFloat64RoundTruncate | |
| 1010 MachineOperatorBuilder::kWord32ShiftIsSafe; | 1010 MachineOperatorBuilder::kWord32ShiftIsSafe; |
| 1011 } | 1011 } |
| 1012 return MachineOperatorBuilder::Flag::kNoFlags; | 1012 return MachineOperatorBuilder::Flag::kNoFlags; |
| 1013 } | 1013 } |
| 1014 | 1014 |
| 1015 } // namespace compiler | 1015 } // namespace compiler |
| 1016 } // namespace internal | 1016 } // namespace internal |
| 1017 } // namespace v8 | 1017 } // namespace v8 |
| OLD | NEW |