| 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 { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 const int64_t value = OpParameter<int64_t>(node); | 24 const int64_t value = OpParameter<int64_t>(node); |
| 25 return value == static_cast<int64_t>(static_cast<int32_t>(value)); | 25 return value == static_cast<int64_t>(static_cast<int32_t>(value)); |
| 26 } | 26 } |
| 27 default: | 27 default: |
| 28 return false; | 28 return false; |
| 29 } | 29 } |
| 30 } | 30 } |
| 31 | 31 |
| 32 AddressingMode GenerateMemoryOperandInputs(Node* index, int scale_exponent, | 32 AddressingMode GenerateMemoryOperandInputs(Node* index, int scale_exponent, |
| 33 Node* base, Node* displacement, | 33 Node* base, Node* displacement, |
| 34 InstructionOperand* inputs[], | 34 InstructionOperand inputs[], |
| 35 size_t* input_count) { | 35 size_t* input_count) { |
| 36 AddressingMode mode = kMode_MRI; | 36 AddressingMode mode = kMode_MRI; |
| 37 if (base != NULL) { | 37 if (base != NULL) { |
| 38 inputs[(*input_count)++] = UseRegister(base); | 38 inputs[(*input_count)++] = UseRegister(base); |
| 39 if (index != NULL) { | 39 if (index != NULL) { |
| 40 DCHECK(scale_exponent >= 0 && scale_exponent <= 3); | 40 DCHECK(scale_exponent >= 0 && scale_exponent <= 3); |
| 41 inputs[(*input_count)++] = UseRegister(index); | 41 inputs[(*input_count)++] = UseRegister(index); |
| 42 if (displacement != NULL) { | 42 if (displacement != NULL) { |
| 43 inputs[(*input_count)++] = UseImmediate(displacement); | 43 inputs[(*input_count)++] = UseImmediate(displacement); |
| 44 static const AddressingMode kMRnI_modes[] = {kMode_MR1I, kMode_MR2I, | 44 static const AddressingMode kMRnI_modes[] = {kMode_MR1I, kMode_MR2I, |
| (...skipping 28 matching lines...) Expand all Loading... |
| 73 if (mode == kMode_MR1) { | 73 if (mode == kMode_MR1) { |
| 74 // [%r1 + %r1*1] has a smaller encoding than [%r1*2+0] | 74 // [%r1 + %r1*1] has a smaller encoding than [%r1*2+0] |
| 75 inputs[(*input_count)++] = UseRegister(index); | 75 inputs[(*input_count)++] = UseRegister(index); |
| 76 } | 76 } |
| 77 } | 77 } |
| 78 } | 78 } |
| 79 return mode; | 79 return mode; |
| 80 } | 80 } |
| 81 | 81 |
| 82 AddressingMode GetEffectiveAddressMemoryOperand(Node* operand, | 82 AddressingMode GetEffectiveAddressMemoryOperand(Node* operand, |
| 83 InstructionOperand* inputs[], | 83 InstructionOperand inputs[], |
| 84 size_t* input_count) { | 84 size_t* input_count) { |
| 85 BaseWithIndexAndDisplacement64Matcher m(operand, true); | 85 BaseWithIndexAndDisplacement64Matcher m(operand, true); |
| 86 DCHECK(m.matches()); | 86 DCHECK(m.matches()); |
| 87 if ((m.displacement() == NULL || CanBeImmediate(m.displacement()))) { | 87 if ((m.displacement() == NULL || CanBeImmediate(m.displacement()))) { |
| 88 return GenerateMemoryOperandInputs(m.index(), m.scale(), m.base(), | 88 return GenerateMemoryOperandInputs(m.index(), m.scale(), m.base(), |
| 89 m.displacement(), inputs, input_count); | 89 m.displacement(), inputs, input_count); |
| 90 } else { | 90 } else { |
| 91 inputs[(*input_count)++] = UseRegister(operand->InputAt(0)); | 91 inputs[(*input_count)++] = UseRegister(operand->InputAt(0)); |
| 92 inputs[(*input_count)++] = UseRegister(operand->InputAt(1)); | 92 inputs[(*input_count)++] = UseRegister(operand->InputAt(1)); |
| 93 return kMode_MR1; | 93 return kMode_MR1; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 125 break; | 125 break; |
| 126 case kRepTagged: // Fall through. | 126 case kRepTagged: // Fall through. |
| 127 case kRepWord64: | 127 case kRepWord64: |
| 128 opcode = kX64Movq; | 128 opcode = kX64Movq; |
| 129 break; | 129 break; |
| 130 default: | 130 default: |
| 131 UNREACHABLE(); | 131 UNREACHABLE(); |
| 132 return; | 132 return; |
| 133 } | 133 } |
| 134 | 134 |
| 135 InstructionOperand* outputs[1]; | 135 InstructionOperand outputs[1]; |
| 136 outputs[0] = g.DefineAsRegister(node); | 136 outputs[0] = g.DefineAsRegister(node); |
| 137 InstructionOperand* inputs[3]; | 137 InstructionOperand inputs[3]; |
| 138 size_t input_count = 0; | 138 size_t input_count = 0; |
| 139 AddressingMode mode = | 139 AddressingMode mode = |
| 140 g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count); | 140 g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count); |
| 141 InstructionCode code = opcode | AddressingModeField::encode(mode); | 141 InstructionCode code = opcode | AddressingModeField::encode(mode); |
| 142 Emit(code, 1, outputs, input_count, inputs); | 142 Emit(code, 1, outputs, input_count, inputs); |
| 143 } | 143 } |
| 144 | 144 |
| 145 | 145 |
| 146 void InstructionSelector::VisitStore(Node* node) { | 146 void InstructionSelector::VisitStore(Node* node) { |
| 147 X64OperandGenerator g(this); | 147 X64OperandGenerator g(this); |
| 148 Node* base = node->InputAt(0); | 148 Node* base = node->InputAt(0); |
| 149 Node* index = node->InputAt(1); | 149 Node* index = node->InputAt(1); |
| 150 Node* value = node->InputAt(2); | 150 Node* value = node->InputAt(2); |
| 151 | 151 |
| 152 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node); | 152 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node); |
| 153 MachineType rep = RepresentationOf(store_rep.machine_type()); | 153 MachineType rep = RepresentationOf(store_rep.machine_type()); |
| 154 if (store_rep.write_barrier_kind() == kFullWriteBarrier) { | 154 if (store_rep.write_barrier_kind() == kFullWriteBarrier) { |
| 155 DCHECK(rep == kRepTagged); | 155 DCHECK(rep == kRepTagged); |
| 156 // TODO(dcarney): refactor RecordWrite function to take temp registers | 156 // TODO(dcarney): refactor RecordWrite function to take temp registers |
| 157 // and pass them here instead of using fixed regs | 157 // and pass them here instead of using fixed regs |
| 158 // TODO(dcarney): handle immediate indices. | 158 // TODO(dcarney): handle immediate indices. |
| 159 InstructionOperand* temps[] = {g.TempRegister(rcx), g.TempRegister(rdx)}; | 159 InstructionOperand temps[] = {g.TempRegister(rcx), g.TempRegister(rdx)}; |
| 160 Emit(kX64StoreWriteBarrier, NULL, g.UseFixed(base, rbx), | 160 Emit(kX64StoreWriteBarrier, g.NoOutput(), g.UseFixed(base, rbx), |
| 161 g.UseFixed(index, rcx), g.UseFixed(value, rdx), arraysize(temps), | 161 g.UseFixed(index, rcx), g.UseFixed(value, rdx), arraysize(temps), |
| 162 temps); | 162 temps); |
| 163 return; | 163 return; |
| 164 } | 164 } |
| 165 DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind()); | 165 DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind()); |
| 166 ArchOpcode opcode; | 166 ArchOpcode opcode; |
| 167 switch (rep) { | 167 switch (rep) { |
| 168 case kRepFloat32: | 168 case kRepFloat32: |
| 169 opcode = kX64Movss; | 169 opcode = kX64Movss; |
| 170 break; | 170 break; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 182 opcode = kX64Movl; | 182 opcode = kX64Movl; |
| 183 break; | 183 break; |
| 184 case kRepTagged: // Fall through. | 184 case kRepTagged: // Fall through. |
| 185 case kRepWord64: | 185 case kRepWord64: |
| 186 opcode = kX64Movq; | 186 opcode = kX64Movq; |
| 187 break; | 187 break; |
| 188 default: | 188 default: |
| 189 UNREACHABLE(); | 189 UNREACHABLE(); |
| 190 return; | 190 return; |
| 191 } | 191 } |
| 192 InstructionOperand* inputs[4]; | 192 InstructionOperand inputs[4]; |
| 193 size_t input_count = 0; | 193 size_t input_count = 0; |
| 194 AddressingMode mode = | 194 AddressingMode mode = |
| 195 g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count); | 195 g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count); |
| 196 InstructionCode code = opcode | AddressingModeField::encode(mode); | 196 InstructionCode code = opcode | AddressingModeField::encode(mode); |
| 197 InstructionOperand* value_operand = | 197 InstructionOperand value_operand = |
| 198 g.CanBeImmediate(value) ? g.UseImmediate(value) : g.UseRegister(value); | 198 g.CanBeImmediate(value) ? g.UseImmediate(value) : g.UseRegister(value); |
| 199 inputs[input_count++] = value_operand; | 199 inputs[input_count++] = value_operand; |
| 200 Emit(code, 0, static_cast<InstructionOperand**>(NULL), input_count, inputs); | 200 Emit(code, 0, static_cast<InstructionOperand*>(NULL), input_count, inputs); |
| 201 } | 201 } |
| 202 | 202 |
| 203 | 203 |
| 204 void InstructionSelector::VisitCheckedLoad(Node* node) { | 204 void InstructionSelector::VisitCheckedLoad(Node* node) { |
| 205 MachineType rep = RepresentationOf(OpParameter<MachineType>(node)); | 205 MachineType rep = RepresentationOf(OpParameter<MachineType>(node)); |
| 206 MachineType typ = TypeOf(OpParameter<MachineType>(node)); | 206 MachineType typ = TypeOf(OpParameter<MachineType>(node)); |
| 207 X64OperandGenerator g(this); | 207 X64OperandGenerator g(this); |
| 208 Node* const buffer = node->InputAt(0); | 208 Node* const buffer = node->InputAt(0); |
| 209 Node* const offset = node->InputAt(1); | 209 Node* const offset = node->InputAt(1); |
| 210 Node* const length = node->InputAt(2); | 210 Node* const length = node->InputAt(2); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 234 Int32BinopMatcher moffset(offset); | 234 Int32BinopMatcher moffset(offset); |
| 235 if (mlength.HasValue() && moffset.right().HasValue() && | 235 if (mlength.HasValue() && moffset.right().HasValue() && |
| 236 moffset.right().Value() >= 0 && | 236 moffset.right().Value() >= 0 && |
| 237 mlength.Value() >= moffset.right().Value()) { | 237 mlength.Value() >= moffset.right().Value()) { |
| 238 Emit(opcode, g.DefineAsRegister(node), g.UseRegister(buffer), | 238 Emit(opcode, g.DefineAsRegister(node), g.UseRegister(buffer), |
| 239 g.UseRegister(moffset.left().node()), | 239 g.UseRegister(moffset.left().node()), |
| 240 g.UseImmediate(moffset.right().node()), g.UseImmediate(length)); | 240 g.UseImmediate(moffset.right().node()), g.UseImmediate(length)); |
| 241 return; | 241 return; |
| 242 } | 242 } |
| 243 } | 243 } |
| 244 InstructionOperand* length_operand = | 244 InstructionOperand length_operand = |
| 245 g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length); | 245 g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length); |
| 246 Emit(opcode, g.DefineAsRegister(node), g.UseRegister(buffer), | 246 Emit(opcode, g.DefineAsRegister(node), g.UseRegister(buffer), |
| 247 g.UseRegister(offset), g.TempImmediate(0), length_operand); | 247 g.UseRegister(offset), g.TempImmediate(0), length_operand); |
| 248 } | 248 } |
| 249 | 249 |
| 250 | 250 |
| 251 void InstructionSelector::VisitCheckedStore(Node* node) { | 251 void InstructionSelector::VisitCheckedStore(Node* node) { |
| 252 MachineType rep = RepresentationOf(OpParameter<MachineType>(node)); | 252 MachineType rep = RepresentationOf(OpParameter<MachineType>(node)); |
| 253 X64OperandGenerator g(this); | 253 X64OperandGenerator g(this); |
| 254 Node* const buffer = node->InputAt(0); | 254 Node* const buffer = node->InputAt(0); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 269 case kRepFloat32: | 269 case kRepFloat32: |
| 270 opcode = kCheckedStoreFloat32; | 270 opcode = kCheckedStoreFloat32; |
| 271 break; | 271 break; |
| 272 case kRepFloat64: | 272 case kRepFloat64: |
| 273 opcode = kCheckedStoreFloat64; | 273 opcode = kCheckedStoreFloat64; |
| 274 break; | 274 break; |
| 275 default: | 275 default: |
| 276 UNREACHABLE(); | 276 UNREACHABLE(); |
| 277 return; | 277 return; |
| 278 } | 278 } |
| 279 InstructionOperand* value_operand = | 279 InstructionOperand value_operand = |
| 280 g.CanBeImmediate(value) ? g.UseImmediate(value) : g.UseRegister(value); | 280 g.CanBeImmediate(value) ? g.UseImmediate(value) : g.UseRegister(value); |
| 281 if (offset->opcode() == IrOpcode::kInt32Add && CanCover(node, offset)) { | 281 if (offset->opcode() == IrOpcode::kInt32Add && CanCover(node, offset)) { |
| 282 Int32Matcher mlength(length); | 282 Int32Matcher mlength(length); |
| 283 Int32BinopMatcher moffset(offset); | 283 Int32BinopMatcher moffset(offset); |
| 284 if (mlength.HasValue() && moffset.right().HasValue() && | 284 if (mlength.HasValue() && moffset.right().HasValue() && |
| 285 moffset.right().Value() >= 0 && | 285 moffset.right().Value() >= 0 && |
| 286 mlength.Value() >= moffset.right().Value()) { | 286 mlength.Value() >= moffset.right().Value()) { |
| 287 Emit(opcode, nullptr, g.UseRegister(buffer), | 287 Emit(opcode, g.NoOutput(), g.UseRegister(buffer), |
| 288 g.UseRegister(moffset.left().node()), | 288 g.UseRegister(moffset.left().node()), |
| 289 g.UseImmediate(moffset.right().node()), g.UseImmediate(length), | 289 g.UseImmediate(moffset.right().node()), g.UseImmediate(length), |
| 290 value_operand); | 290 value_operand); |
| 291 return; | 291 return; |
| 292 } | 292 } |
| 293 } | 293 } |
| 294 InstructionOperand* length_operand = | 294 InstructionOperand length_operand = |
| 295 g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length); | 295 g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length); |
| 296 Emit(opcode, nullptr, g.UseRegister(buffer), g.UseRegister(offset), | 296 Emit(opcode, g.NoOutput(), g.UseRegister(buffer), g.UseRegister(offset), |
| 297 g.TempImmediate(0), length_operand, value_operand); | 297 g.TempImmediate(0), length_operand, value_operand); |
| 298 } | 298 } |
| 299 | 299 |
| 300 | 300 |
| 301 // Shared routine for multiple binary operations. | 301 // Shared routine for multiple binary operations. |
| 302 static void VisitBinop(InstructionSelector* selector, Node* node, | 302 static void VisitBinop(InstructionSelector* selector, Node* node, |
| 303 InstructionCode opcode, FlagsContinuation* cont) { | 303 InstructionCode opcode, FlagsContinuation* cont) { |
| 304 X64OperandGenerator g(selector); | 304 X64OperandGenerator g(selector); |
| 305 Int32BinopMatcher m(node); | 305 Int32BinopMatcher m(node); |
| 306 Node* left = m.left().node(); | 306 Node* left = m.left().node(); |
| 307 Node* right = m.right().node(); | 307 Node* right = m.right().node(); |
| 308 InstructionOperand* inputs[4]; | 308 InstructionOperand inputs[4]; |
| 309 size_t input_count = 0; | 309 size_t input_count = 0; |
| 310 InstructionOperand* outputs[2]; | 310 InstructionOperand outputs[2]; |
| 311 size_t output_count = 0; | 311 size_t output_count = 0; |
| 312 | 312 |
| 313 // TODO(turbofan): match complex addressing modes. | 313 // TODO(turbofan): match complex addressing modes. |
| 314 if (left == right) { | 314 if (left == right) { |
| 315 // If both inputs refer to the same operand, enforce allocating a register | 315 // If both inputs refer to the same operand, enforce allocating a register |
| 316 // for both of them to ensure that we don't end up generating code like | 316 // for both of them to ensure that we don't end up generating code like |
| 317 // this: | 317 // this: |
| 318 // | 318 // |
| 319 // mov rax, [rbp-0x10] | 319 // mov rax, [rbp-0x10] |
| 320 // add rax, [rbp-0x10] | 320 // add rax, [rbp-0x10] |
| 321 // jo label | 321 // jo label |
| 322 InstructionOperand* const input = g.UseRegister(left); | 322 InstructionOperand const input = g.UseRegister(left); |
| 323 inputs[input_count++] = input; | 323 inputs[input_count++] = input; |
| 324 inputs[input_count++] = input; | 324 inputs[input_count++] = input; |
| 325 } else if (g.CanBeImmediate(right)) { | 325 } else if (g.CanBeImmediate(right)) { |
| 326 inputs[input_count++] = g.UseRegister(left); | 326 inputs[input_count++] = g.UseRegister(left); |
| 327 inputs[input_count++] = g.UseImmediate(right); | 327 inputs[input_count++] = g.UseImmediate(right); |
| 328 } else { | 328 } else { |
| 329 if (node->op()->HasProperty(Operator::kCommutative) && | 329 if (node->op()->HasProperty(Operator::kCommutative) && |
| 330 g.CanBeBetterLeftOperand(right)) { | 330 g.CanBeBetterLeftOperand(right)) { |
| 331 std::swap(left, right); | 331 std::swap(left, right); |
| 332 } | 332 } |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 449 g.UseFixed(right, rcx)); | 449 g.UseFixed(right, rcx)); |
| 450 } | 450 } |
| 451 } | 451 } |
| 452 | 452 |
| 453 | 453 |
| 454 void EmitLea(InstructionSelector* selector, InstructionCode opcode, | 454 void EmitLea(InstructionSelector* selector, InstructionCode opcode, |
| 455 Node* result, Node* index, int scale, Node* base, | 455 Node* result, Node* index, int scale, Node* base, |
| 456 Node* displacement) { | 456 Node* displacement) { |
| 457 X64OperandGenerator g(selector); | 457 X64OperandGenerator g(selector); |
| 458 | 458 |
| 459 InstructionOperand* inputs[4]; | 459 InstructionOperand inputs[4]; |
| 460 size_t input_count = 0; | 460 size_t input_count = 0; |
| 461 AddressingMode mode = g.GenerateMemoryOperandInputs( | 461 AddressingMode mode = g.GenerateMemoryOperandInputs( |
| 462 index, scale, base, displacement, inputs, &input_count); | 462 index, scale, base, displacement, inputs, &input_count); |
| 463 | 463 |
| 464 DCHECK_NE(0, static_cast<int>(input_count)); | 464 DCHECK_NE(0, static_cast<int>(input_count)); |
| 465 DCHECK_GE(arraysize(inputs), input_count); | 465 DCHECK_GE(arraysize(inputs), input_count); |
| 466 | 466 |
| 467 InstructionOperand* outputs[1]; | 467 InstructionOperand outputs[1]; |
| 468 outputs[0] = g.DefineAsRegister(result); | 468 outputs[0] = g.DefineAsRegister(result); |
| 469 | 469 |
| 470 opcode = AddressingModeField::encode(mode) | opcode; | 470 opcode = AddressingModeField::encode(mode) | opcode; |
| 471 | 471 |
| 472 selector->Emit(opcode, 1, outputs, input_count, inputs); | 472 selector->Emit(opcode, 1, outputs, input_count, inputs); |
| 473 } | 473 } |
| 474 | 474 |
| 475 } // namespace | 475 } // namespace |
| 476 | 476 |
| 477 | 477 |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 627 } | 627 } |
| 628 // TODO(turbofan): We use UseUniqueRegister here to improve register | 628 // TODO(turbofan): We use UseUniqueRegister here to improve register |
| 629 // allocation. | 629 // allocation. |
| 630 selector->Emit(opcode, g.DefineAsFixed(node, rdx), g.UseFixed(left, rax), | 630 selector->Emit(opcode, g.DefineAsFixed(node, rdx), g.UseFixed(left, rax), |
| 631 g.UseUniqueRegister(right)); | 631 g.UseUniqueRegister(right)); |
| 632 } | 632 } |
| 633 | 633 |
| 634 | 634 |
| 635 void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode opcode) { | 635 void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode opcode) { |
| 636 X64OperandGenerator g(selector); | 636 X64OperandGenerator g(selector); |
| 637 InstructionOperand* temps[] = {g.TempRegister(rdx)}; | 637 InstructionOperand temps[] = {g.TempRegister(rdx)}; |
| 638 selector->Emit( | 638 selector->Emit( |
| 639 opcode, g.DefineAsFixed(node, rax), g.UseFixed(node->InputAt(0), rax), | 639 opcode, g.DefineAsFixed(node, rax), g.UseFixed(node->InputAt(0), rax), |
| 640 g.UseUniqueRegister(node->InputAt(1)), arraysize(temps), temps); | 640 g.UseUniqueRegister(node->InputAt(1)), arraysize(temps), temps); |
| 641 } | 641 } |
| 642 | 642 |
| 643 | 643 |
| 644 void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode opcode) { | 644 void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode opcode) { |
| 645 X64OperandGenerator g(selector); | 645 X64OperandGenerator g(selector); |
| 646 selector->Emit(opcode, g.DefineAsFixed(node, rdx), | 646 selector->Emit(opcode, g.DefineAsFixed(node, rdx), |
| 647 g.UseFixed(node->InputAt(0), rax), | 647 g.UseFixed(node->InputAt(0), rax), |
| (...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 863 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1))); | 863 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1))); |
| 864 } else { | 864 } else { |
| 865 Emit(kSSEFloat64Div, g.DefineSameAsFirst(node), | 865 Emit(kSSEFloat64Div, g.DefineSameAsFirst(node), |
| 866 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1))); | 866 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1))); |
| 867 } | 867 } |
| 868 } | 868 } |
| 869 | 869 |
| 870 | 870 |
| 871 void InstructionSelector::VisitFloat64Mod(Node* node) { | 871 void InstructionSelector::VisitFloat64Mod(Node* node) { |
| 872 X64OperandGenerator g(this); | 872 X64OperandGenerator g(this); |
| 873 InstructionOperand* temps[] = {g.TempRegister(rax)}; | 873 InstructionOperand temps[] = {g.TempRegister(rax)}; |
| 874 Emit(kSSEFloat64Mod, g.DefineSameAsFirst(node), | 874 Emit(kSSEFloat64Mod, g.DefineSameAsFirst(node), |
| 875 g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)), 1, | 875 g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)), 1, |
| 876 temps); | 876 temps); |
| 877 } | 877 } |
| 878 | 878 |
| 879 | 879 |
| 880 void InstructionSelector::VisitFloat64Sqrt(Node* node) { | 880 void InstructionSelector::VisitFloat64Sqrt(Node* node) { |
| 881 X64OperandGenerator g(this); | 881 X64OperandGenerator g(this); |
| 882 Emit(kSSEFloat64Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0))); | 882 Emit(kSSEFloat64Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0))); |
| 883 } | 883 } |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 930 | 930 |
| 931 CallBuffer buffer(zone(), descriptor, frame_state_descriptor); | 931 CallBuffer buffer(zone(), descriptor, frame_state_descriptor); |
| 932 | 932 |
| 933 // Compute InstructionOperands for inputs and outputs. | 933 // Compute InstructionOperands for inputs and outputs. |
| 934 InitializeCallBuffer(node, &buffer, true, true); | 934 InitializeCallBuffer(node, &buffer, true, true); |
| 935 | 935 |
| 936 // Push any stack arguments. | 936 // Push any stack arguments. |
| 937 for (auto i = buffer.pushed_nodes.rbegin(); i != buffer.pushed_nodes.rend(); | 937 for (auto i = buffer.pushed_nodes.rbegin(); i != buffer.pushed_nodes.rend(); |
| 938 ++i) { | 938 ++i) { |
| 939 // TODO(titzer): handle pushing double parameters. | 939 // TODO(titzer): handle pushing double parameters. |
| 940 InstructionOperand* value = | 940 InstructionOperand value = |
| 941 g.CanBeImmediate(*i) ? g.UseImmediate(*i) : IsSupported(ATOM) | 941 g.CanBeImmediate(*i) ? g.UseImmediate(*i) : IsSupported(ATOM) |
| 942 ? g.UseRegister(*i) | 942 ? g.UseRegister(*i) |
| 943 : g.Use(*i); | 943 : g.Use(*i); |
| 944 Emit(kX64Push, nullptr, value); | 944 Emit(kX64Push, g.NoOutput(), value); |
| 945 } | 945 } |
| 946 | 946 |
| 947 // Select the appropriate opcode based on the call type. | 947 // Select the appropriate opcode based on the call type. |
| 948 InstructionCode opcode; | 948 InstructionCode opcode; |
| 949 switch (descriptor->kind()) { | 949 switch (descriptor->kind()) { |
| 950 case CallDescriptor::kCallCodeObject: { | 950 case CallDescriptor::kCallCodeObject: { |
| 951 opcode = kArchCallCodeObject; | 951 opcode = kArchCallCodeObject; |
| 952 break; | 952 break; |
| 953 } | 953 } |
| 954 case CallDescriptor::kCallJSFunction: | 954 case CallDescriptor::kCallJSFunction: |
| 955 opcode = kArchCallJSFunction; | 955 opcode = kArchCallJSFunction; |
| 956 break; | 956 break; |
| 957 default: | 957 default: |
| 958 UNREACHABLE(); | 958 UNREACHABLE(); |
| 959 return; | 959 return; |
| 960 } | 960 } |
| 961 opcode |= MiscField::encode(descriptor->flags()); | 961 opcode |= MiscField::encode(descriptor->flags()); |
| 962 | 962 |
| 963 // Emit the call instruction. | 963 // Emit the call instruction. |
| 964 InstructionOperand** first_output = | 964 InstructionOperand* first_output = |
| 965 buffer.outputs.size() > 0 ? &buffer.outputs.front() : NULL; | 965 buffer.outputs.size() > 0 ? &buffer.outputs.front() : NULL; |
| 966 Instruction* call_instr = | 966 Instruction* call_instr = |
| 967 Emit(opcode, buffer.outputs.size(), first_output, | 967 Emit(opcode, buffer.outputs.size(), first_output, |
| 968 buffer.instruction_args.size(), &buffer.instruction_args.front()); | 968 buffer.instruction_args.size(), &buffer.instruction_args.front()); |
| 969 call_instr->MarkAsCall(); | 969 call_instr->MarkAsCall(); |
| 970 } | 970 } |
| 971 | 971 |
| 972 | 972 |
| 973 // Shared routine for multiple compare operations. | 973 // Shared routine for multiple compare operations. |
| 974 static void VisitCompare(InstructionSelector* selector, InstructionCode opcode, | 974 static void VisitCompare(InstructionSelector* selector, InstructionCode opcode, |
| 975 InstructionOperand* left, InstructionOperand* right, | 975 InstructionOperand left, InstructionOperand right, |
| 976 FlagsContinuation* cont) { | 976 FlagsContinuation* cont) { |
| 977 X64OperandGenerator g(selector); | 977 X64OperandGenerator g(selector); |
| 978 opcode = cont->Encode(opcode); | 978 opcode = cont->Encode(opcode); |
| 979 if (cont->IsBranch()) { | 979 if (cont->IsBranch()) { |
| 980 selector->Emit(opcode, NULL, left, right, g.Label(cont->true_block()), | 980 selector->Emit(opcode, g.NoOutput(), left, right, |
| 981 g.Label(cont->true_block()), |
| 981 g.Label(cont->false_block()))->MarkAsControl(); | 982 g.Label(cont->false_block()))->MarkAsControl(); |
| 982 } else { | 983 } else { |
| 983 DCHECK(cont->IsSet()); | 984 DCHECK(cont->IsSet()); |
| 984 selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right); | 985 selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right); |
| 985 } | 986 } |
| 986 } | 987 } |
| 987 | 988 |
| 988 | 989 |
| 989 // Shared routine for multiple compare operations. | 990 // Shared routine for multiple compare operations. |
| 990 static void VisitCompare(InstructionSelector* selector, InstructionCode opcode, | 991 static void VisitCompare(InstructionSelector* selector, InstructionCode opcode, |
| (...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1310 MachineOperatorBuilder::kFloat64Ceil | | 1311 MachineOperatorBuilder::kFloat64Ceil | |
| 1311 MachineOperatorBuilder::kFloat64RoundTruncate | | 1312 MachineOperatorBuilder::kFloat64RoundTruncate | |
| 1312 MachineOperatorBuilder::kWord32ShiftIsSafe; | 1313 MachineOperatorBuilder::kWord32ShiftIsSafe; |
| 1313 } | 1314 } |
| 1314 return MachineOperatorBuilder::kNoFlags; | 1315 return MachineOperatorBuilder::kNoFlags; |
| 1315 } | 1316 } |
| 1316 | 1317 |
| 1317 } // namespace compiler | 1318 } // namespace compiler |
| 1318 } // namespace internal | 1319 } // namespace internal |
| 1319 } // namespace v8 | 1320 } // namespace v8 |
| OLD | NEW |