| 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/base/adapters.h" | 5 #include "src/base/adapters.h" |
| 6 #include "src/compiler/instruction-selector-impl.h" | 6 #include "src/compiler/instruction-selector-impl.h" |
| 7 #include "src/compiler/node-matchers.h" | 7 #include "src/compiler/node-matchers.h" |
| 8 #include "src/compiler/node-properties.h" | 8 #include "src/compiler/node-properties.h" |
| 9 | 9 |
| 10 namespace v8 { | 10 namespace v8 { |
| 11 namespace internal { | 11 namespace internal { |
| 12 namespace compiler { | 12 namespace compiler { |
| 13 | 13 |
| 14 // Adds IA32-specific methods for generating operands. | 14 // Adds X87-specific methods for generating operands. |
| 15 class IA32OperandGenerator final : public OperandGenerator { | 15 class X87OperandGenerator final : public OperandGenerator { |
| 16 public: | 16 public: |
| 17 explicit IA32OperandGenerator(InstructionSelector* selector) | 17 explicit X87OperandGenerator(InstructionSelector* selector) |
| 18 : OperandGenerator(selector) {} | 18 : OperandGenerator(selector) {} |
| 19 | 19 |
| 20 InstructionOperand UseByteRegister(Node* node) { | 20 InstructionOperand UseByteRegister(Node* node) { |
| 21 // TODO(titzer): encode byte register use constraints. | 21 // TODO(titzer): encode byte register use constraints. |
| 22 return UseFixed(node, edx); | 22 return UseFixed(node, edx); |
| 23 } | 23 } |
| 24 | 24 |
| 25 InstructionOperand DefineAsByteRegister(Node* node) { | 25 InstructionOperand DefineAsByteRegister(Node* node) { |
| 26 // TODO(titzer): encode byte register def constraints. | 26 // TODO(titzer): encode byte register def constraints. |
| 27 return DefineAsRegister(node); | 27 return DefineAsRegister(node); |
| 28 } | 28 } |
| 29 | 29 |
| 30 InstructionOperand CreateImmediate(int imm) { |
| 31 return sequence()->AddImmediate(Constant(imm)); |
| 32 } |
| 33 |
| 30 bool CanBeImmediate(Node* node) { | 34 bool CanBeImmediate(Node* node) { |
| 31 switch (node->opcode()) { | 35 switch (node->opcode()) { |
| 32 case IrOpcode::kInt32Constant: | 36 case IrOpcode::kInt32Constant: |
| 33 case IrOpcode::kNumberConstant: | 37 case IrOpcode::kNumberConstant: |
| 34 case IrOpcode::kExternalConstant: | 38 case IrOpcode::kExternalConstant: |
| 35 return true; | 39 return true; |
| 36 case IrOpcode::kHeapConstant: { | 40 case IrOpcode::kHeapConstant: { |
| 37 // Constants in new space cannot be used as immediates in V8 because | 41 // Constants in new space cannot be used as immediates in V8 because |
| 38 // the GC does not scan code objects when collecting the new generation. | 42 // the GC does not scan code objects when collecting the new generation. |
| 39 Unique<HeapObject> value = OpParameter<Unique<HeapObject> >(node); | 43 Unique<HeapObject> value = OpParameter<Unique<HeapObject> >(node); |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 118 return kMode_MR1; | 122 return kMode_MR1; |
| 119 } | 123 } |
| 120 } | 124 } |
| 121 | 125 |
| 122 bool CanBeBetterLeftOperand(Node* node) const { | 126 bool CanBeBetterLeftOperand(Node* node) const { |
| 123 return !selector()->IsLive(node); | 127 return !selector()->IsLive(node); |
| 124 } | 128 } |
| 125 }; | 129 }; |
| 126 | 130 |
| 127 | 131 |
| 128 namespace { | |
| 129 | |
| 130 void VisitROFloat(InstructionSelector* selector, Node* node, | |
| 131 ArchOpcode opcode) { | |
| 132 IA32OperandGenerator g(selector); | |
| 133 selector->Emit(opcode, g.DefineAsRegister(node), g.Use(node->InputAt(0))); | |
| 134 } | |
| 135 | |
| 136 | |
| 137 void VisitRRFloat(InstructionSelector* selector, Node* node, | |
| 138 InstructionCode opcode) { | |
| 139 IA32OperandGenerator g(selector); | |
| 140 selector->Emit(opcode, g.DefineAsRegister(node), | |
| 141 g.UseRegister(node->InputAt(0))); | |
| 142 } | |
| 143 | |
| 144 | |
| 145 void VisitRROFloat(InstructionSelector* selector, Node* node, | |
| 146 ArchOpcode avx_opcode, ArchOpcode sse_opcode) { | |
| 147 IA32OperandGenerator g(selector); | |
| 148 InstructionOperand operand0 = g.UseRegister(node->InputAt(0)); | |
| 149 InstructionOperand operand1 = g.Use(node->InputAt(1)); | |
| 150 if (selector->IsSupported(AVX)) { | |
| 151 selector->Emit(avx_opcode, g.DefineAsRegister(node), operand0, operand1); | |
| 152 } else { | |
| 153 selector->Emit(sse_opcode, g.DefineSameAsFirst(node), operand0, operand1); | |
| 154 } | |
| 155 } | |
| 156 | |
| 157 | |
| 158 void VisitFloatUnop(InstructionSelector* selector, Node* node, Node* input, | |
| 159 ArchOpcode avx_opcode, ArchOpcode sse_opcode) { | |
| 160 IA32OperandGenerator g(selector); | |
| 161 if (selector->IsSupported(AVX)) { | |
| 162 selector->Emit(avx_opcode, g.DefineAsRegister(node), g.Use(input)); | |
| 163 } else { | |
| 164 selector->Emit(sse_opcode, g.DefineSameAsFirst(node), g.UseRegister(input)); | |
| 165 } | |
| 166 } | |
| 167 | |
| 168 | |
| 169 } // namespace | |
| 170 | |
| 171 | |
| 172 void InstructionSelector::VisitLoad(Node* node) { | 132 void InstructionSelector::VisitLoad(Node* node) { |
| 173 MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node)); | 133 MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node)); |
| 174 MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node)); | 134 MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node)); |
| 175 | 135 |
| 176 ArchOpcode opcode; | 136 ArchOpcode opcode; |
| 177 switch (rep) { | 137 switch (rep) { |
| 178 case kRepFloat32: | 138 case kRepFloat32: |
| 179 opcode = kIA32Movss; | 139 opcode = kX87Movss; |
| 180 break; | 140 break; |
| 181 case kRepFloat64: | 141 case kRepFloat64: |
| 182 opcode = kIA32Movsd; | 142 opcode = kX87Movsd; |
| 183 break; | 143 break; |
| 184 case kRepBit: // Fall through. | 144 case kRepBit: // Fall through. |
| 185 case kRepWord8: | 145 case kRepWord8: |
| 186 opcode = typ == kTypeInt32 ? kIA32Movsxbl : kIA32Movzxbl; | 146 opcode = typ == kTypeInt32 ? kX87Movsxbl : kX87Movzxbl; |
| 187 break; | 147 break; |
| 188 case kRepWord16: | 148 case kRepWord16: |
| 189 opcode = typ == kTypeInt32 ? kIA32Movsxwl : kIA32Movzxwl; | 149 opcode = typ == kTypeInt32 ? kX87Movsxwl : kX87Movzxwl; |
| 190 break; | 150 break; |
| 191 case kRepTagged: // Fall through. | 151 case kRepTagged: // Fall through. |
| 192 case kRepWord32: | 152 case kRepWord32: |
| 193 opcode = kIA32Movl; | 153 opcode = kX87Movl; |
| 194 break; | 154 break; |
| 195 default: | 155 default: |
| 196 UNREACHABLE(); | 156 UNREACHABLE(); |
| 197 return; | 157 return; |
| 198 } | 158 } |
| 199 | 159 |
| 200 IA32OperandGenerator g(this); | 160 X87OperandGenerator g(this); |
| 201 InstructionOperand outputs[1]; | 161 InstructionOperand outputs[1]; |
| 202 outputs[0] = g.DefineAsRegister(node); | 162 outputs[0] = g.DefineAsRegister(node); |
| 203 InstructionOperand inputs[3]; | 163 InstructionOperand inputs[3]; |
| 204 size_t input_count = 0; | 164 size_t input_count = 0; |
| 205 AddressingMode mode = | 165 AddressingMode mode = |
| 206 g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count); | 166 g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count); |
| 207 InstructionCode code = opcode | AddressingModeField::encode(mode); | 167 InstructionCode code = opcode | AddressingModeField::encode(mode); |
| 208 Emit(code, 1, outputs, input_count, inputs); | 168 Emit(code, 1, outputs, input_count, inputs); |
| 209 } | 169 } |
| 210 | 170 |
| 211 | 171 |
| 212 void InstructionSelector::VisitStore(Node* node) { | 172 void InstructionSelector::VisitStore(Node* node) { |
| 213 IA32OperandGenerator g(this); | 173 X87OperandGenerator g(this); |
| 214 Node* base = node->InputAt(0); | 174 Node* base = node->InputAt(0); |
| 215 Node* index = node->InputAt(1); | 175 Node* index = node->InputAt(1); |
| 216 Node* value = node->InputAt(2); | 176 Node* value = node->InputAt(2); |
| 217 | 177 |
| 218 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node); | 178 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node); |
| 219 MachineType rep = RepresentationOf(store_rep.machine_type()); | 179 MachineType rep = RepresentationOf(store_rep.machine_type()); |
| 220 if (store_rep.write_barrier_kind() == kFullWriteBarrier) { | 180 if (store_rep.write_barrier_kind() == kFullWriteBarrier) { |
| 221 DCHECK_EQ(kRepTagged, rep); | 181 DCHECK_EQ(kRepTagged, rep); |
| 222 // TODO(dcarney): refactor RecordWrite function to take temp registers | 182 // TODO(dcarney): refactor RecordWrite function to take temp registers |
| 223 // and pass them here instead of using fixed regs | 183 // and pass them here instead of using fixed regs |
| 224 if (g.CanBeImmediate(index)) { | 184 if (g.CanBeImmediate(index)) { |
| 225 InstructionOperand temps[] = {g.TempRegister(ecx), g.TempRegister()}; | 185 InstructionOperand temps[] = {g.TempRegister(ecx), g.TempRegister()}; |
| 226 Emit(kIA32StoreWriteBarrier, g.NoOutput(), g.UseFixed(base, ebx), | 186 Emit(kX87StoreWriteBarrier, g.NoOutput(), g.UseFixed(base, ebx), |
| 227 g.UseImmediate(index), g.UseFixed(value, ecx), arraysize(temps), | 187 g.UseImmediate(index), g.UseFixed(value, ecx), arraysize(temps), |
| 228 temps); | 188 temps); |
| 229 } else { | 189 } else { |
| 230 InstructionOperand temps[] = {g.TempRegister(ecx), g.TempRegister(edx)}; | 190 InstructionOperand temps[] = {g.TempRegister(ecx), g.TempRegister(edx)}; |
| 231 Emit(kIA32StoreWriteBarrier, g.NoOutput(), g.UseFixed(base, ebx), | 191 Emit(kX87StoreWriteBarrier, g.NoOutput(), g.UseFixed(base, ebx), |
| 232 g.UseFixed(index, ecx), g.UseFixed(value, edx), arraysize(temps), | 192 g.UseFixed(index, ecx), g.UseFixed(value, edx), arraysize(temps), |
| 233 temps); | 193 temps); |
| 234 } | 194 } |
| 235 return; | 195 return; |
| 236 } | 196 } |
| 237 DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind()); | 197 DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind()); |
| 238 | 198 |
| 239 ArchOpcode opcode; | 199 ArchOpcode opcode; |
| 240 switch (rep) { | 200 switch (rep) { |
| 241 case kRepFloat32: | 201 case kRepFloat32: |
| 242 opcode = kIA32Movss; | 202 opcode = kX87Movss; |
| 243 break; | 203 break; |
| 244 case kRepFloat64: | 204 case kRepFloat64: |
| 245 opcode = kIA32Movsd; | 205 opcode = kX87Movsd; |
| 246 break; | 206 break; |
| 247 case kRepBit: // Fall through. | 207 case kRepBit: // Fall through. |
| 248 case kRepWord8: | 208 case kRepWord8: |
| 249 opcode = kIA32Movb; | 209 opcode = kX87Movb; |
| 250 break; | 210 break; |
| 251 case kRepWord16: | 211 case kRepWord16: |
| 252 opcode = kIA32Movw; | 212 opcode = kX87Movw; |
| 253 break; | 213 break; |
| 254 case kRepTagged: // Fall through. | 214 case kRepTagged: // Fall through. |
| 255 case kRepWord32: | 215 case kRepWord32: |
| 256 opcode = kIA32Movl; | 216 opcode = kX87Movl; |
| 257 break; | 217 break; |
| 258 default: | 218 default: |
| 259 UNREACHABLE(); | 219 UNREACHABLE(); |
| 260 return; | 220 return; |
| 261 } | 221 } |
| 262 | 222 |
| 263 InstructionOperand val; | 223 InstructionOperand val; |
| 264 if (g.CanBeImmediate(value)) { | 224 if (g.CanBeImmediate(value)) { |
| 265 val = g.UseImmediate(value); | 225 val = g.UseImmediate(value); |
| 266 } else if (rep == kRepWord8 || rep == kRepBit) { | 226 } else if (rep == kRepWord8 || rep == kRepBit) { |
| 267 val = g.UseByteRegister(value); | 227 val = g.UseByteRegister(value); |
| 268 } else { | 228 } else { |
| 269 val = g.UseRegister(value); | 229 val = g.UseRegister(value); |
| 270 } | 230 } |
| 271 | 231 |
| 272 InstructionOperand inputs[4]; | 232 InstructionOperand inputs[4]; |
| 273 size_t input_count = 0; | 233 size_t input_count = 0; |
| 274 AddressingMode mode = | 234 AddressingMode mode = |
| 275 g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count); | 235 g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count); |
| 276 InstructionCode code = opcode | AddressingModeField::encode(mode); | 236 InstructionCode code = opcode | AddressingModeField::encode(mode); |
| 277 inputs[input_count++] = val; | 237 inputs[input_count++] = val; |
| 278 Emit(code, 0, static_cast<InstructionOperand*>(NULL), input_count, inputs); | 238 Emit(code, 0, static_cast<InstructionOperand*>(NULL), input_count, inputs); |
| 279 } | 239 } |
| 280 | 240 |
| 281 | 241 |
| 282 void InstructionSelector::VisitCheckedLoad(Node* node) { | 242 void InstructionSelector::VisitCheckedLoad(Node* node) { |
| 283 MachineType rep = RepresentationOf(OpParameter<MachineType>(node)); | 243 MachineType rep = RepresentationOf(OpParameter<MachineType>(node)); |
| 284 MachineType typ = TypeOf(OpParameter<MachineType>(node)); | 244 MachineType typ = TypeOf(OpParameter<MachineType>(node)); |
| 285 IA32OperandGenerator g(this); | 245 X87OperandGenerator g(this); |
| 286 Node* const buffer = node->InputAt(0); | 246 Node* const buffer = node->InputAt(0); |
| 287 Node* const offset = node->InputAt(1); | 247 Node* const offset = node->InputAt(1); |
| 288 Node* const length = node->InputAt(2); | 248 Node* const length = node->InputAt(2); |
| 289 ArchOpcode opcode; | 249 ArchOpcode opcode; |
| 290 switch (rep) { | 250 switch (rep) { |
| 291 case kRepWord8: | 251 case kRepWord8: |
| 292 opcode = typ == kTypeInt32 ? kCheckedLoadInt8 : kCheckedLoadUint8; | 252 opcode = typ == kTypeInt32 ? kCheckedLoadInt8 : kCheckedLoadUint8; |
| 293 break; | 253 break; |
| 294 case kRepWord16: | 254 case kRepWord16: |
| 295 opcode = typ == kTypeInt32 ? kCheckedLoadInt16 : kCheckedLoadUint16; | 255 opcode = typ == kTypeInt32 ? kCheckedLoadInt16 : kCheckedLoadUint16; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 317 } else { | 277 } else { |
| 318 Emit(opcode | AddressingModeField::encode(kMode_MR1), | 278 Emit(opcode | AddressingModeField::encode(kMode_MR1), |
| 319 g.DefineAsRegister(node), offset_operand, length_operand, | 279 g.DefineAsRegister(node), offset_operand, length_operand, |
| 320 g.UseRegister(buffer), offset_operand); | 280 g.UseRegister(buffer), offset_operand); |
| 321 } | 281 } |
| 322 } | 282 } |
| 323 | 283 |
| 324 | 284 |
| 325 void InstructionSelector::VisitCheckedStore(Node* node) { | 285 void InstructionSelector::VisitCheckedStore(Node* node) { |
| 326 MachineType rep = RepresentationOf(OpParameter<MachineType>(node)); | 286 MachineType rep = RepresentationOf(OpParameter<MachineType>(node)); |
| 327 IA32OperandGenerator g(this); | 287 X87OperandGenerator g(this); |
| 328 Node* const buffer = node->InputAt(0); | 288 Node* const buffer = node->InputAt(0); |
| 329 Node* const offset = node->InputAt(1); | 289 Node* const offset = node->InputAt(1); |
| 330 Node* const length = node->InputAt(2); | 290 Node* const length = node->InputAt(2); |
| 331 Node* const value = node->InputAt(3); | 291 Node* const value = node->InputAt(3); |
| 332 ArchOpcode opcode; | 292 ArchOpcode opcode; |
| 333 switch (rep) { | 293 switch (rep) { |
| 334 case kRepWord8: | 294 case kRepWord8: |
| 335 opcode = kCheckedStoreWord8; | 295 opcode = kCheckedStoreWord8; |
| 336 break; | 296 break; |
| 337 case kRepWord16: | 297 case kRepWord16: |
| (...skipping 28 matching lines...) Expand all Loading... |
| 366 Emit(opcode | AddressingModeField::encode(kMode_MR1), g.NoOutput(), | 326 Emit(opcode | AddressingModeField::encode(kMode_MR1), g.NoOutput(), |
| 367 offset_operand, length_operand, value_operand, g.UseRegister(buffer), | 327 offset_operand, length_operand, value_operand, g.UseRegister(buffer), |
| 368 offset_operand); | 328 offset_operand); |
| 369 } | 329 } |
| 370 } | 330 } |
| 371 | 331 |
| 372 | 332 |
| 373 // Shared routine for multiple binary operations. | 333 // Shared routine for multiple binary operations. |
| 374 static void VisitBinop(InstructionSelector* selector, Node* node, | 334 static void VisitBinop(InstructionSelector* selector, Node* node, |
| 375 InstructionCode opcode, FlagsContinuation* cont) { | 335 InstructionCode opcode, FlagsContinuation* cont) { |
| 376 IA32OperandGenerator g(selector); | 336 X87OperandGenerator g(selector); |
| 377 Int32BinopMatcher m(node); | 337 Int32BinopMatcher m(node); |
| 378 Node* left = m.left().node(); | 338 Node* left = m.left().node(); |
| 379 Node* right = m.right().node(); | 339 Node* right = m.right().node(); |
| 380 InstructionOperand inputs[4]; | 340 InstructionOperand inputs[4]; |
| 381 size_t input_count = 0; | 341 size_t input_count = 0; |
| 382 InstructionOperand outputs[2]; | 342 InstructionOperand outputs[2]; |
| 383 size_t output_count = 0; | 343 size_t output_count = 0; |
| 384 | 344 |
| 385 // TODO(turbofan): match complex addressing modes. | 345 // TODO(turbofan): match complex addressing modes. |
| 386 if (left == right) { | 346 if (left == right) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 406 inputs[input_count++] = g.Use(right); | 366 inputs[input_count++] = g.Use(right); |
| 407 } | 367 } |
| 408 | 368 |
| 409 if (cont->IsBranch()) { | 369 if (cont->IsBranch()) { |
| 410 inputs[input_count++] = g.Label(cont->true_block()); | 370 inputs[input_count++] = g.Label(cont->true_block()); |
| 411 inputs[input_count++] = g.Label(cont->false_block()); | 371 inputs[input_count++] = g.Label(cont->false_block()); |
| 412 } | 372 } |
| 413 | 373 |
| 414 outputs[output_count++] = g.DefineSameAsFirst(node); | 374 outputs[output_count++] = g.DefineSameAsFirst(node); |
| 415 if (cont->IsSet()) { | 375 if (cont->IsSet()) { |
| 416 outputs[output_count++] = g.DefineAsByteRegister(cont->result()); | 376 outputs[output_count++] = g.DefineAsRegister(cont->result()); |
| 417 } | 377 } |
| 418 | 378 |
| 419 DCHECK_NE(0u, input_count); | 379 DCHECK_NE(0u, input_count); |
| 420 DCHECK_NE(0u, output_count); | 380 DCHECK_NE(0u, output_count); |
| 421 DCHECK_GE(arraysize(inputs), input_count); | 381 DCHECK_GE(arraysize(inputs), input_count); |
| 422 DCHECK_GE(arraysize(outputs), output_count); | 382 DCHECK_GE(arraysize(outputs), output_count); |
| 423 | 383 |
| 424 selector->Emit(cont->Encode(opcode), output_count, outputs, input_count, | 384 selector->Emit(cont->Encode(opcode), output_count, outputs, input_count, |
| 425 inputs); | 385 inputs); |
| 426 } | 386 } |
| 427 | 387 |
| 428 | 388 |
| 429 // Shared routine for multiple binary operations. | 389 // Shared routine for multiple binary operations. |
| 430 static void VisitBinop(InstructionSelector* selector, Node* node, | 390 static void VisitBinop(InstructionSelector* selector, Node* node, |
| 431 InstructionCode opcode) { | 391 InstructionCode opcode) { |
| 432 FlagsContinuation cont; | 392 FlagsContinuation cont; |
| 433 VisitBinop(selector, node, opcode, &cont); | 393 VisitBinop(selector, node, opcode, &cont); |
| 434 } | 394 } |
| 435 | 395 |
| 436 | 396 |
| 437 void InstructionSelector::VisitWord32And(Node* node) { | 397 void InstructionSelector::VisitWord32And(Node* node) { |
| 438 VisitBinop(this, node, kIA32And); | 398 VisitBinop(this, node, kX87And); |
| 439 } | 399 } |
| 440 | 400 |
| 441 | 401 |
| 442 void InstructionSelector::VisitWord32Or(Node* node) { | 402 void InstructionSelector::VisitWord32Or(Node* node) { |
| 443 VisitBinop(this, node, kIA32Or); | 403 VisitBinop(this, node, kX87Or); |
| 444 } | 404 } |
| 445 | 405 |
| 446 | 406 |
| 447 void InstructionSelector::VisitWord32Xor(Node* node) { | 407 void InstructionSelector::VisitWord32Xor(Node* node) { |
| 448 IA32OperandGenerator g(this); | 408 X87OperandGenerator g(this); |
| 449 Int32BinopMatcher m(node); | 409 Int32BinopMatcher m(node); |
| 450 if (m.right().Is(-1)) { | 410 if (m.right().Is(-1)) { |
| 451 Emit(kIA32Not, g.DefineSameAsFirst(node), g.UseRegister(m.left().node())); | 411 Emit(kX87Not, g.DefineSameAsFirst(node), g.UseRegister(m.left().node())); |
| 452 } else { | 412 } else { |
| 453 VisitBinop(this, node, kIA32Xor); | 413 VisitBinop(this, node, kX87Xor); |
| 454 } | 414 } |
| 455 } | 415 } |
| 456 | 416 |
| 457 | 417 |
| 458 // Shared routine for multiple shift operations. | 418 // Shared routine for multiple shift operations. |
| 459 static inline void VisitShift(InstructionSelector* selector, Node* node, | 419 static inline void VisitShift(InstructionSelector* selector, Node* node, |
| 460 ArchOpcode opcode) { | 420 ArchOpcode opcode) { |
| 461 IA32OperandGenerator g(selector); | 421 X87OperandGenerator g(selector); |
| 462 Node* left = node->InputAt(0); | 422 Node* left = node->InputAt(0); |
| 463 Node* right = node->InputAt(1); | 423 Node* right = node->InputAt(1); |
| 464 | 424 |
| 465 if (g.CanBeImmediate(right)) { | 425 if (g.CanBeImmediate(right)) { |
| 466 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left), | 426 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left), |
| 467 g.UseImmediate(right)); | 427 g.UseImmediate(right)); |
| 468 } else { | 428 } else { |
| 469 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left), | 429 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left), |
| 470 g.UseFixed(right, ecx)); | 430 g.UseFixed(right, ecx)); |
| 471 } | 431 } |
| 472 } | 432 } |
| 473 | 433 |
| 474 | 434 |
| 475 namespace { | 435 namespace { |
| 476 | 436 |
| 477 void VisitMulHigh(InstructionSelector* selector, Node* node, | 437 void VisitMulHigh(InstructionSelector* selector, Node* node, |
| 478 ArchOpcode opcode) { | 438 ArchOpcode opcode) { |
| 479 IA32OperandGenerator g(selector); | 439 X87OperandGenerator g(selector); |
| 480 selector->Emit(opcode, g.DefineAsFixed(node, edx), | 440 selector->Emit(opcode, g.DefineAsFixed(node, edx), |
| 481 g.UseFixed(node->InputAt(0), eax), | 441 g.UseFixed(node->InputAt(0), eax), |
| 482 g.UseUniqueRegister(node->InputAt(1))); | 442 g.UseUniqueRegister(node->InputAt(1))); |
| 483 } | 443 } |
| 484 | 444 |
| 485 | 445 |
| 486 void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode opcode) { | 446 void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode opcode) { |
| 487 IA32OperandGenerator g(selector); | 447 X87OperandGenerator g(selector); |
| 488 InstructionOperand temps[] = {g.TempRegister(edx)}; | 448 InstructionOperand temps[] = {g.TempRegister(edx)}; |
| 489 selector->Emit(opcode, g.DefineAsFixed(node, eax), | 449 selector->Emit(opcode, g.DefineAsFixed(node, eax), |
| 490 g.UseFixed(node->InputAt(0), eax), | 450 g.UseFixed(node->InputAt(0), eax), |
| 491 g.UseUnique(node->InputAt(1)), arraysize(temps), temps); | 451 g.UseUnique(node->InputAt(1)), arraysize(temps), temps); |
| 492 } | 452 } |
| 493 | 453 |
| 494 | 454 |
| 495 void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode opcode) { | 455 void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode opcode) { |
| 496 IA32OperandGenerator g(selector); | 456 X87OperandGenerator g(selector); |
| 497 selector->Emit(opcode, g.DefineAsFixed(node, edx), | 457 selector->Emit(opcode, g.DefineAsFixed(node, edx), |
| 498 g.UseFixed(node->InputAt(0), eax), | 458 g.UseFixed(node->InputAt(0), eax), |
| 499 g.UseUnique(node->InputAt(1))); | 459 g.UseUnique(node->InputAt(1))); |
| 500 } | 460 } |
| 501 | 461 |
| 502 void EmitLea(InstructionSelector* selector, Node* result, Node* index, | 462 void EmitLea(InstructionSelector* selector, Node* result, Node* index, |
| 503 int scale, Node* base, Node* displacement) { | 463 int scale, Node* base, Node* displacement) { |
| 504 IA32OperandGenerator g(selector); | 464 X87OperandGenerator g(selector); |
| 505 InstructionOperand inputs[4]; | 465 InstructionOperand inputs[4]; |
| 506 size_t input_count = 0; | 466 size_t input_count = 0; |
| 507 AddressingMode mode = g.GenerateMemoryOperandInputs( | 467 AddressingMode mode = g.GenerateMemoryOperandInputs( |
| 508 index, scale, base, displacement, inputs, &input_count); | 468 index, scale, base, displacement, inputs, &input_count); |
| 509 | 469 |
| 510 DCHECK_NE(0u, input_count); | 470 DCHECK_NE(0u, input_count); |
| 511 DCHECK_GE(arraysize(inputs), input_count); | 471 DCHECK_GE(arraysize(inputs), input_count); |
| 512 | 472 |
| 513 InstructionOperand outputs[1]; | 473 InstructionOperand outputs[1]; |
| 514 outputs[0] = g.DefineAsRegister(result); | 474 outputs[0] = g.DefineAsRegister(result); |
| 515 | 475 |
| 516 InstructionCode opcode = AddressingModeField::encode(mode) | kIA32Lea; | 476 InstructionCode opcode = AddressingModeField::encode(mode) | kX87Lea; |
| 517 | 477 |
| 518 selector->Emit(opcode, 1, outputs, input_count, inputs); | 478 selector->Emit(opcode, 1, outputs, input_count, inputs); |
| 519 } | 479 } |
| 520 | 480 |
| 521 } // namespace | 481 } // namespace |
| 522 | 482 |
| 523 | 483 |
| 524 void InstructionSelector::VisitWord32Shl(Node* node) { | 484 void InstructionSelector::VisitWord32Shl(Node* node) { |
| 525 Int32ScaleMatcher m(node, true); | 485 Int32ScaleMatcher m(node, true); |
| 526 if (m.matches()) { | 486 if (m.matches()) { |
| 527 Node* index = node->InputAt(0); | 487 Node* index = node->InputAt(0); |
| 528 Node* base = m.power_of_two_plus_one() ? index : NULL; | 488 Node* base = m.power_of_two_plus_one() ? index : NULL; |
| 529 EmitLea(this, node, index, m.scale(), base, NULL); | 489 EmitLea(this, node, index, m.scale(), base, NULL); |
| 530 return; | 490 return; |
| 531 } | 491 } |
| 532 VisitShift(this, node, kIA32Shl); | 492 VisitShift(this, node, kX87Shl); |
| 533 } | 493 } |
| 534 | 494 |
| 535 | 495 |
| 536 void InstructionSelector::VisitWord32Shr(Node* node) { | 496 void InstructionSelector::VisitWord32Shr(Node* node) { |
| 537 VisitShift(this, node, kIA32Shr); | 497 VisitShift(this, node, kX87Shr); |
| 538 } | 498 } |
| 539 | 499 |
| 540 | 500 |
| 541 void InstructionSelector::VisitWord32Sar(Node* node) { | 501 void InstructionSelector::VisitWord32Sar(Node* node) { |
| 542 VisitShift(this, node, kIA32Sar); | 502 VisitShift(this, node, kX87Sar); |
| 543 } | 503 } |
| 544 | 504 |
| 545 | 505 |
| 546 void InstructionSelector::VisitWord32Ror(Node* node) { | 506 void InstructionSelector::VisitWord32Ror(Node* node) { |
| 547 VisitShift(this, node, kIA32Ror); | 507 VisitShift(this, node, kX87Ror); |
| 548 } | 508 } |
| 549 | 509 |
| 550 | 510 |
| 551 void InstructionSelector::VisitWord32Clz(Node* node) { | 511 void InstructionSelector::VisitWord32Clz(Node* node) { |
| 552 IA32OperandGenerator g(this); | 512 X87OperandGenerator g(this); |
| 553 Emit(kIA32Lzcnt, g.DefineAsRegister(node), g.Use(node->InputAt(0))); | 513 Emit(kX87Lzcnt, g.DefineAsRegister(node), g.Use(node->InputAt(0))); |
| 554 } | 514 } |
| 555 | 515 |
| 556 | 516 |
| 557 void InstructionSelector::VisitInt32Add(Node* node) { | 517 void InstructionSelector::VisitInt32Add(Node* node) { |
| 558 IA32OperandGenerator g(this); | 518 X87OperandGenerator g(this); |
| 559 | 519 |
| 560 // Try to match the Add to a lea pattern | 520 // Try to match the Add to a lea pattern |
| 561 BaseWithIndexAndDisplacement32Matcher m(node); | 521 BaseWithIndexAndDisplacement32Matcher m(node); |
| 562 if (m.matches() && | 522 if (m.matches() && |
| 563 (m.displacement() == NULL || g.CanBeImmediate(m.displacement()))) { | 523 (m.displacement() == NULL || g.CanBeImmediate(m.displacement()))) { |
| 564 InstructionOperand inputs[4]; | 524 InstructionOperand inputs[4]; |
| 565 size_t input_count = 0; | 525 size_t input_count = 0; |
| 566 AddressingMode mode = g.GenerateMemoryOperandInputs( | 526 AddressingMode mode = g.GenerateMemoryOperandInputs( |
| 567 m.index(), m.scale(), m.base(), m.displacement(), inputs, &input_count); | 527 m.index(), m.scale(), m.base(), m.displacement(), inputs, &input_count); |
| 568 | 528 |
| 569 DCHECK_NE(0u, input_count); | 529 DCHECK_NE(0u, input_count); |
| 570 DCHECK_GE(arraysize(inputs), input_count); | 530 DCHECK_GE(arraysize(inputs), input_count); |
| 571 | 531 |
| 572 InstructionOperand outputs[1]; | 532 InstructionOperand outputs[1]; |
| 573 outputs[0] = g.DefineAsRegister(node); | 533 outputs[0] = g.DefineAsRegister(node); |
| 574 | 534 |
| 575 InstructionCode opcode = AddressingModeField::encode(mode) | kIA32Lea; | 535 InstructionCode opcode = AddressingModeField::encode(mode) | kX87Lea; |
| 576 Emit(opcode, 1, outputs, input_count, inputs); | 536 Emit(opcode, 1, outputs, input_count, inputs); |
| 577 return; | 537 return; |
| 578 } | 538 } |
| 579 | 539 |
| 580 // No lea pattern match, use add | 540 // No lea pattern match, use add |
| 581 VisitBinop(this, node, kIA32Add); | 541 VisitBinop(this, node, kX87Add); |
| 582 } | 542 } |
| 583 | 543 |
| 584 | 544 |
| 585 void InstructionSelector::VisitInt32Sub(Node* node) { | 545 void InstructionSelector::VisitInt32Sub(Node* node) { |
| 586 IA32OperandGenerator g(this); | 546 X87OperandGenerator g(this); |
| 587 Int32BinopMatcher m(node); | 547 Int32BinopMatcher m(node); |
| 588 if (m.left().Is(0)) { | 548 if (m.left().Is(0)) { |
| 589 Emit(kIA32Neg, g.DefineSameAsFirst(node), g.Use(m.right().node())); | 549 Emit(kX87Neg, g.DefineSameAsFirst(node), g.Use(m.right().node())); |
| 590 } else { | 550 } else { |
| 591 VisitBinop(this, node, kIA32Sub); | 551 VisitBinop(this, node, kX87Sub); |
| 592 } | 552 } |
| 593 } | 553 } |
| 594 | 554 |
| 595 | 555 |
| 596 void InstructionSelector::VisitInt32Mul(Node* node) { | 556 void InstructionSelector::VisitInt32Mul(Node* node) { |
| 597 Int32ScaleMatcher m(node, true); | 557 Int32ScaleMatcher m(node, true); |
| 598 if (m.matches()) { | 558 if (m.matches()) { |
| 599 Node* index = node->InputAt(0); | 559 Node* index = node->InputAt(0); |
| 600 Node* base = m.power_of_two_plus_one() ? index : NULL; | 560 Node* base = m.power_of_two_plus_one() ? index : NULL; |
| 601 EmitLea(this, node, index, m.scale(), base, NULL); | 561 EmitLea(this, node, index, m.scale(), base, NULL); |
| 602 return; | 562 return; |
| 603 } | 563 } |
| 604 IA32OperandGenerator g(this); | 564 X87OperandGenerator g(this); |
| 605 Node* left = node->InputAt(0); | 565 Node* left = node->InputAt(0); |
| 606 Node* right = node->InputAt(1); | 566 Node* right = node->InputAt(1); |
| 607 if (g.CanBeImmediate(right)) { | 567 if (g.CanBeImmediate(right)) { |
| 608 Emit(kIA32Imul, g.DefineAsRegister(node), g.Use(left), | 568 Emit(kX87Imul, g.DefineAsRegister(node), g.Use(left), |
| 609 g.UseImmediate(right)); | 569 g.UseImmediate(right)); |
| 610 } else { | 570 } else { |
| 611 if (g.CanBeBetterLeftOperand(right)) { | 571 if (g.CanBeBetterLeftOperand(right)) { |
| 612 std::swap(left, right); | 572 std::swap(left, right); |
| 613 } | 573 } |
| 614 Emit(kIA32Imul, g.DefineSameAsFirst(node), g.UseRegister(left), | 574 Emit(kX87Imul, g.DefineSameAsFirst(node), g.UseRegister(left), |
| 615 g.Use(right)); | 575 g.Use(right)); |
| 616 } | 576 } |
| 617 } | 577 } |
| 618 | 578 |
| 619 | 579 |
| 620 void InstructionSelector::VisitInt32MulHigh(Node* node) { | 580 void InstructionSelector::VisitInt32MulHigh(Node* node) { |
| 621 VisitMulHigh(this, node, kIA32ImulHigh); | 581 VisitMulHigh(this, node, kX87ImulHigh); |
| 622 } | 582 } |
| 623 | 583 |
| 624 | 584 |
| 625 void InstructionSelector::VisitUint32MulHigh(Node* node) { | 585 void InstructionSelector::VisitUint32MulHigh(Node* node) { |
| 626 VisitMulHigh(this, node, kIA32UmulHigh); | 586 VisitMulHigh(this, node, kX87UmulHigh); |
| 627 } | 587 } |
| 628 | 588 |
| 629 | 589 |
| 630 void InstructionSelector::VisitInt32Div(Node* node) { | 590 void InstructionSelector::VisitInt32Div(Node* node) { |
| 631 VisitDiv(this, node, kIA32Idiv); | 591 VisitDiv(this, node, kX87Idiv); |
| 632 } | 592 } |
| 633 | 593 |
| 634 | 594 |
| 635 void InstructionSelector::VisitUint32Div(Node* node) { | 595 void InstructionSelector::VisitUint32Div(Node* node) { |
| 636 VisitDiv(this, node, kIA32Udiv); | 596 VisitDiv(this, node, kX87Udiv); |
| 637 } | 597 } |
| 638 | 598 |
| 639 | 599 |
| 640 void InstructionSelector::VisitInt32Mod(Node* node) { | 600 void InstructionSelector::VisitInt32Mod(Node* node) { |
| 641 VisitMod(this, node, kIA32Idiv); | 601 VisitMod(this, node, kX87Idiv); |
| 642 } | 602 } |
| 643 | 603 |
| 644 | 604 |
| 645 void InstructionSelector::VisitUint32Mod(Node* node) { | 605 void InstructionSelector::VisitUint32Mod(Node* node) { |
| 646 VisitMod(this, node, kIA32Udiv); | 606 VisitMod(this, node, kX87Udiv); |
| 647 } | 607 } |
| 648 | 608 |
| 649 | 609 |
| 650 void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) { | 610 void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) { |
| 651 IA32OperandGenerator g(this); | 611 X87OperandGenerator g(this); |
| 652 Emit(kSSEFloat32ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0))); | 612 Emit(kX87Float32ToFloat64, g.DefineAsFixed(node, stX_0), |
| 613 g.Use(node->InputAt(0))); |
| 653 } | 614 } |
| 654 | 615 |
| 655 | 616 |
| 656 void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) { | 617 void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) { |
| 657 IA32OperandGenerator g(this); | 618 X87OperandGenerator g(this); |
| 658 Emit(kSSEInt32ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0))); | 619 Emit(kX87Int32ToFloat64, g.DefineAsFixed(node, stX_0), |
| 620 g.Use(node->InputAt(0))); |
| 659 } | 621 } |
| 660 | 622 |
| 661 | 623 |
| 662 void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) { | 624 void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) { |
| 663 IA32OperandGenerator g(this); | 625 X87OperandGenerator g(this); |
| 664 Emit(kSSEUint32ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0))); | 626 Emit(kX87Uint32ToFloat64, g.DefineAsFixed(node, stX_0), |
| 627 g.UseRegister(node->InputAt(0))); |
| 665 } | 628 } |
| 666 | 629 |
| 667 | 630 |
| 668 void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) { | 631 void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) { |
| 669 IA32OperandGenerator g(this); | 632 X87OperandGenerator g(this); |
| 670 Emit(kSSEFloat64ToInt32, g.DefineAsRegister(node), g.Use(node->InputAt(0))); | 633 Emit(kX87Float64ToInt32, g.DefineAsRegister(node), g.Use(node->InputAt(0))); |
| 671 } | 634 } |
| 672 | 635 |
| 673 | 636 |
| 674 void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) { | 637 void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) { |
| 675 IA32OperandGenerator g(this); | 638 X87OperandGenerator g(this); |
| 676 Emit(kSSEFloat64ToUint32, g.DefineAsRegister(node), g.Use(node->InputAt(0))); | 639 Emit(kX87Float64ToUint32, g.DefineAsRegister(node), g.Use(node->InputAt(0))); |
| 677 } | 640 } |
| 678 | 641 |
| 679 | 642 |
| 680 void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) { | 643 void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) { |
| 681 IA32OperandGenerator g(this); | 644 X87OperandGenerator g(this); |
| 682 Emit(kSSEFloat64ToFloat32, g.DefineAsRegister(node), g.Use(node->InputAt(0))); | 645 Emit(kX87Float64ToFloat32, g.DefineAsFixed(node, stX_0), |
| 646 g.Use(node->InputAt(0))); |
| 683 } | 647 } |
| 684 | 648 |
| 685 | 649 |
| 686 void InstructionSelector::VisitFloat32Add(Node* node) { | 650 void InstructionSelector::VisitFloat32Add(Node* node) { |
| 687 VisitRROFloat(this, node, kAVXFloat32Add, kSSEFloat32Add); | 651 X87OperandGenerator g(this); |
| 652 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0))); |
| 653 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(1))); |
| 654 Emit(kX87Float32Add, g.DefineAsFixed(node, stX_0), 0, NULL); |
| 688 } | 655 } |
| 689 | 656 |
| 690 | 657 |
| 691 void InstructionSelector::VisitFloat64Add(Node* node) { | 658 void InstructionSelector::VisitFloat64Add(Node* node) { |
| 692 VisitRROFloat(this, node, kAVXFloat64Add, kSSEFloat64Add); | 659 X87OperandGenerator g(this); |
| 660 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0))); |
| 661 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(1))); |
| 662 Emit(kX87Float64Add, g.DefineAsFixed(node, stX_0), 0, NULL); |
| 693 } | 663 } |
| 694 | 664 |
| 695 | 665 |
| 696 void InstructionSelector::VisitFloat32Sub(Node* node) { | 666 void InstructionSelector::VisitFloat32Sub(Node* node) { |
| 697 IA32OperandGenerator g(this); | 667 X87OperandGenerator g(this); |
| 698 Float32BinopMatcher m(node); | 668 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0))); |
| 699 if (m.left().IsMinusZero()) { | 669 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(1))); |
| 700 VisitFloatUnop(this, node, m.right().node(), kAVXFloat32Neg, | 670 Emit(kX87Float32Sub, g.DefineAsFixed(node, stX_0), 0, NULL); |
| 701 kSSEFloat32Neg); | |
| 702 return; | |
| 703 } | |
| 704 VisitRROFloat(this, node, kAVXFloat32Sub, kSSEFloat32Sub); | |
| 705 } | 671 } |
| 706 | 672 |
| 707 | 673 |
| 708 void InstructionSelector::VisitFloat64Sub(Node* node) { | 674 void InstructionSelector::VisitFloat64Sub(Node* node) { |
| 709 IA32OperandGenerator g(this); | 675 X87OperandGenerator g(this); |
| 710 Float64BinopMatcher m(node); | 676 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0))); |
| 711 if (m.left().IsMinusZero()) { | 677 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(1))); |
| 712 if (m.right().IsFloat64RoundDown() && | 678 Emit(kX87Float64Sub, g.DefineAsFixed(node, stX_0), 0, NULL); |
| 713 CanCover(m.node(), m.right().node())) { | |
| 714 if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat64Sub && | |
| 715 CanCover(m.right().node(), m.right().InputAt(0))) { | |
| 716 Float64BinopMatcher mright0(m.right().InputAt(0)); | |
| 717 if (mright0.left().IsMinusZero()) { | |
| 718 Emit(kSSEFloat64Round | MiscField::encode(kRoundUp), | |
| 719 g.DefineAsRegister(node), g.UseRegister(mright0.right().node())); | |
| 720 return; | |
| 721 } | |
| 722 } | |
| 723 } | |
| 724 VisitFloatUnop(this, node, m.right().node(), kAVXFloat64Neg, | |
| 725 kSSEFloat64Neg); | |
| 726 return; | |
| 727 } | |
| 728 VisitRROFloat(this, node, kAVXFloat64Sub, kSSEFloat64Sub); | |
| 729 } | 679 } |
| 730 | 680 |
| 731 | 681 |
| 732 void InstructionSelector::VisitFloat32Mul(Node* node) { | 682 void InstructionSelector::VisitFloat32Mul(Node* node) { |
| 733 VisitRROFloat(this, node, kAVXFloat32Mul, kSSEFloat32Mul); | 683 X87OperandGenerator g(this); |
| 684 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0))); |
| 685 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(1))); |
| 686 Emit(kX87Float32Mul, g.DefineAsFixed(node, stX_0), 0, NULL); |
| 734 } | 687 } |
| 735 | 688 |
| 736 | 689 |
| 737 void InstructionSelector::VisitFloat64Mul(Node* node) { | 690 void InstructionSelector::VisitFloat64Mul(Node* node) { |
| 738 VisitRROFloat(this, node, kAVXFloat64Mul, kSSEFloat64Mul); | 691 X87OperandGenerator g(this); |
| 692 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0))); |
| 693 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(1))); |
| 694 Emit(kX87Float64Mul, g.DefineAsFixed(node, stX_0), 0, NULL); |
| 739 } | 695 } |
| 740 | 696 |
| 741 | 697 |
| 742 void InstructionSelector::VisitFloat32Div(Node* node) { | 698 void InstructionSelector::VisitFloat32Div(Node* node) { |
| 743 VisitRROFloat(this, node, kAVXFloat32Div, kSSEFloat32Div); | 699 X87OperandGenerator g(this); |
| 700 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0))); |
| 701 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(1))); |
| 702 Emit(kX87Float32Div, g.DefineAsFixed(node, stX_0), 0, NULL); |
| 744 } | 703 } |
| 745 | 704 |
| 746 | 705 |
| 747 void InstructionSelector::VisitFloat64Div(Node* node) { | 706 void InstructionSelector::VisitFloat64Div(Node* node) { |
| 748 VisitRROFloat(this, node, kAVXFloat64Div, kSSEFloat64Div); | 707 X87OperandGenerator g(this); |
| 708 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0))); |
| 709 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(1))); |
| 710 Emit(kX87Float64Div, g.DefineAsFixed(node, stX_0), 0, NULL); |
| 749 } | 711 } |
| 750 | 712 |
| 751 | 713 |
| 752 void InstructionSelector::VisitFloat64Mod(Node* node) { | 714 void InstructionSelector::VisitFloat64Mod(Node* node) { |
| 753 IA32OperandGenerator g(this); | 715 X87OperandGenerator g(this); |
| 754 InstructionOperand temps[] = {g.TempRegister(eax)}; | 716 InstructionOperand temps[] = {g.TempRegister(eax)}; |
| 755 Emit(kSSEFloat64Mod, g.DefineSameAsFirst(node), | 717 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0))); |
| 756 g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)), 1, | 718 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(1))); |
| 757 temps); | 719 Emit(kX87Float64Mod, g.DefineAsFixed(node, stX_0), 1, temps)->MarkAsCall(); |
| 758 } | 720 } |
| 759 | 721 |
| 760 | 722 |
| 761 void InstructionSelector::VisitFloat32Max(Node* node) { | 723 void InstructionSelector::VisitFloat32Max(Node* node) { |
| 762 VisitRROFloat(this, node, kAVXFloat32Max, kSSEFloat32Max); | 724 X87OperandGenerator g(this); |
| 725 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0))); |
| 726 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(1))); |
| 727 Emit(kX87Float32Max, g.DefineAsFixed(node, stX_0), 0, NULL); |
| 763 } | 728 } |
| 764 | 729 |
| 765 | 730 |
| 766 void InstructionSelector::VisitFloat64Max(Node* node) { | 731 void InstructionSelector::VisitFloat64Max(Node* node) { |
| 767 VisitRROFloat(this, node, kAVXFloat64Max, kSSEFloat64Max); | 732 X87OperandGenerator g(this); |
| 733 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0))); |
| 734 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(1))); |
| 735 Emit(kX87Float64Max, g.DefineAsFixed(node, stX_0), 0, NULL); |
| 768 } | 736 } |
| 769 | 737 |
| 770 | 738 |
| 771 void InstructionSelector::VisitFloat32Min(Node* node) { | 739 void InstructionSelector::VisitFloat32Min(Node* node) { |
| 772 VisitRROFloat(this, node, kAVXFloat32Min, kSSEFloat32Min); | 740 X87OperandGenerator g(this); |
| 741 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0))); |
| 742 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(1))); |
| 743 Emit(kX87Float32Min, g.DefineAsFixed(node, stX_0), 0, NULL); |
| 773 } | 744 } |
| 774 | 745 |
| 775 | 746 |
| 776 void InstructionSelector::VisitFloat64Min(Node* node) { | 747 void InstructionSelector::VisitFloat64Min(Node* node) { |
| 777 VisitRROFloat(this, node, kAVXFloat64Min, kSSEFloat64Min); | 748 X87OperandGenerator g(this); |
| 749 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0))); |
| 750 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(1))); |
| 751 Emit(kX87Float64Min, g.DefineAsFixed(node, stX_0), 0, NULL); |
| 778 } | 752 } |
| 779 | 753 |
| 780 | 754 |
| 781 void InstructionSelector::VisitFloat32Abs(Node* node) { | 755 void InstructionSelector::VisitFloat32Abs(Node* node) { |
| 782 IA32OperandGenerator g(this); | 756 X87OperandGenerator g(this); |
| 783 VisitFloatUnop(this, node, node->InputAt(0), kAVXFloat32Abs, kSSEFloat32Abs); | 757 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0))); |
| 758 Emit(kX87Float32Abs, g.DefineAsFixed(node, stX_0), 0, NULL); |
| 784 } | 759 } |
| 785 | 760 |
| 786 | 761 |
| 787 void InstructionSelector::VisitFloat64Abs(Node* node) { | 762 void InstructionSelector::VisitFloat64Abs(Node* node) { |
| 788 IA32OperandGenerator g(this); | 763 X87OperandGenerator g(this); |
| 789 VisitFloatUnop(this, node, node->InputAt(0), kAVXFloat64Abs, kSSEFloat64Abs); | 764 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0))); |
| 765 Emit(kX87Float64Abs, g.DefineAsFixed(node, stX_0), 0, NULL); |
| 790 } | 766 } |
| 791 | 767 |
| 792 | 768 |
| 793 void InstructionSelector::VisitFloat32Sqrt(Node* node) { | 769 void InstructionSelector::VisitFloat32Sqrt(Node* node) { |
| 794 VisitROFloat(this, node, kSSEFloat32Sqrt); | 770 X87OperandGenerator g(this); |
| 771 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0))); |
| 772 Emit(kX87Float32Sqrt, g.DefineAsFixed(node, stX_0), 0, NULL); |
| 795 } | 773 } |
| 796 | 774 |
| 797 | 775 |
| 798 void InstructionSelector::VisitFloat64Sqrt(Node* node) { | 776 void InstructionSelector::VisitFloat64Sqrt(Node* node) { |
| 799 VisitROFloat(this, node, kSSEFloat64Sqrt); | 777 X87OperandGenerator g(this); |
| 778 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0))); |
| 779 Emit(kX87Float64Sqrt, g.DefineAsFixed(node, stX_0), 0, NULL); |
| 800 } | 780 } |
| 801 | 781 |
| 802 | 782 |
| 803 void InstructionSelector::VisitFloat64RoundDown(Node* node) { | 783 void InstructionSelector::VisitFloat64RoundDown(Node* node) { |
| 804 VisitRRFloat(this, node, kSSEFloat64Round | MiscField::encode(kRoundDown)); | 784 X87OperandGenerator g(this); |
| 785 Emit(kX87Float64Round | MiscField::encode(kRoundDown), |
| 786 g.UseFixed(node, stX_0), g.Use(node->InputAt(0))); |
| 805 } | 787 } |
| 806 | 788 |
| 807 | 789 |
| 808 void InstructionSelector::VisitFloat64RoundTruncate(Node* node) { | 790 void InstructionSelector::VisitFloat64RoundTruncate(Node* node) { |
| 809 VisitRRFloat(this, node, kSSEFloat64Round | MiscField::encode(kRoundToZero)); | 791 X87OperandGenerator g(this); |
| 810 } | 792 Emit(kX87Float64Round | MiscField::encode(kRoundToZero), |
| 811 | 793 g.UseFixed(node, stX_0), g.Use(node->InputAt(0))); |
| 812 | 794 } |
| 795 |
| 796 |
| 813 void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) { | 797 void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) { |
| 814 UNREACHABLE(); | 798 UNREACHABLE(); |
| 815 } | 799 } |
| 816 | 800 |
| 817 | 801 |
| 818 void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) { | 802 void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) { |
| 819 IA32OperandGenerator g(this); | 803 X87OperandGenerator g(this); |
| 820 const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node); | 804 const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node); |
| 821 | 805 |
| 822 FrameStateDescriptor* frame_state_descriptor = nullptr; | 806 FrameStateDescriptor* frame_state_descriptor = nullptr; |
| 823 if (descriptor->NeedsFrameState()) { | 807 if (descriptor->NeedsFrameState()) { |
| 824 frame_state_descriptor = | 808 frame_state_descriptor = |
| 825 GetFrameStateDescriptor(node->InputAt(descriptor->InputCount())); | 809 GetFrameStateDescriptor(node->InputAt(descriptor->InputCount())); |
| 826 } | 810 } |
| 827 | 811 |
| 828 CallBuffer buffer(zone(), descriptor, frame_state_descriptor); | 812 CallBuffer buffer(zone(), descriptor, frame_state_descriptor); |
| 829 | 813 |
| 830 // Compute InstructionOperands for inputs and outputs. | 814 // Compute InstructionOperands for inputs and outputs. |
| 831 InitializeCallBuffer(node, &buffer, true, true); | 815 InitializeCallBuffer(node, &buffer, true, true); |
| 832 | 816 |
| 833 // Push any stack arguments. | 817 // Push any stack arguments. |
| 834 for (Node* node : base::Reversed(buffer.pushed_nodes)) { | 818 for (Node* node : base::Reversed(buffer.pushed_nodes)) { |
| 835 // TODO(titzer): handle pushing double parameters. | 819 // TODO(titzer): handle pushing double parameters. |
| 836 InstructionOperand value = | 820 InstructionOperand value = |
| 837 g.CanBeImmediate(node) | 821 g.CanBeImmediate(node) |
| 838 ? g.UseImmediate(node) | 822 ? g.UseImmediate(node) |
| 839 : IsSupported(ATOM) ? g.UseRegister(node) : g.Use(node); | 823 : IsSupported(ATOM) ? g.UseRegister(node) : g.Use(node); |
| 840 Emit(kIA32Push, g.NoOutput(), value); | 824 Emit(kX87Push, g.NoOutput(), value); |
| 841 } | 825 } |
| 842 | 826 |
| 843 // Pass label of exception handler block. | 827 // Pass label of exception handler block. |
| 844 CallDescriptor::Flags flags = descriptor->flags(); | 828 CallDescriptor::Flags flags = descriptor->flags(); |
| 845 if (handler) { | 829 if (handler) { |
| 846 DCHECK_EQ(IrOpcode::kIfException, handler->front()->opcode()); | 830 DCHECK_EQ(IrOpcode::kIfException, handler->front()->opcode()); |
| 847 IfExceptionHint hint = OpParameter<IfExceptionHint>(handler->front()); | 831 IfExceptionHint hint = OpParameter<IfExceptionHint>(handler->front()); |
| 848 if (hint == IfExceptionHint::kLocallyCaught) { | 832 if (hint == IfExceptionHint::kLocallyCaught) { |
| 849 flags |= CallDescriptor::kHasLocalCatchHandler; | 833 flags |= CallDescriptor::kHasLocalCatchHandler; |
| 850 } | 834 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 870 | 854 |
| 871 // Emit the call instruction. | 855 // Emit the call instruction. |
| 872 size_t const output_count = buffer.outputs.size(); | 856 size_t const output_count = buffer.outputs.size(); |
| 873 auto* outputs = output_count ? &buffer.outputs.front() : nullptr; | 857 auto* outputs = output_count ? &buffer.outputs.front() : nullptr; |
| 874 Emit(opcode, output_count, outputs, buffer.instruction_args.size(), | 858 Emit(opcode, output_count, outputs, buffer.instruction_args.size(), |
| 875 &buffer.instruction_args.front())->MarkAsCall(); | 859 &buffer.instruction_args.front())->MarkAsCall(); |
| 876 } | 860 } |
| 877 | 861 |
| 878 | 862 |
| 879 void InstructionSelector::VisitTailCall(Node* node) { | 863 void InstructionSelector::VisitTailCall(Node* node) { |
| 880 IA32OperandGenerator g(this); | 864 X87OperandGenerator g(this); |
| 881 CallDescriptor const* descriptor = OpParameter<CallDescriptor const*>(node); | 865 CallDescriptor const* descriptor = OpParameter<CallDescriptor const*>(node); |
| 882 DCHECK_NE(0, descriptor->flags() & CallDescriptor::kSupportsTailCalls); | 866 DCHECK_NE(0, descriptor->flags() & CallDescriptor::kSupportsTailCalls); |
| 883 DCHECK_EQ(0, descriptor->flags() & CallDescriptor::kPatchableCallSite); | 867 DCHECK_EQ(0, descriptor->flags() & CallDescriptor::kPatchableCallSite); |
| 884 DCHECK_EQ(0, descriptor->flags() & CallDescriptor::kNeedsNopAfterCall); | 868 DCHECK_EQ(0, descriptor->flags() & CallDescriptor::kNeedsNopAfterCall); |
| 885 | 869 |
| 886 // TODO(turbofan): Relax restriction for stack parameters. | 870 // TODO(turbofan): Relax restriction for stack parameters. |
| 887 if (descriptor->UsesOnlyRegisters() && | 871 if (descriptor->UsesOnlyRegisters() && |
| 888 descriptor->HasSameReturnLocationsAs( | 872 descriptor->HasSameReturnLocationsAs( |
| 889 linkage()->GetIncomingDescriptor())) { | 873 linkage()->GetIncomingDescriptor())) { |
| 890 CallBuffer buffer(zone(), descriptor, nullptr); | 874 CallBuffer buffer(zone(), descriptor, nullptr); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 924 // Compute InstructionOperands for inputs and outputs. | 908 // Compute InstructionOperands for inputs and outputs. |
| 925 InitializeCallBuffer(node, &buffer, true, true); | 909 InitializeCallBuffer(node, &buffer, true, true); |
| 926 | 910 |
| 927 // Push any stack arguments. | 911 // Push any stack arguments. |
| 928 for (Node* node : base::Reversed(buffer.pushed_nodes)) { | 912 for (Node* node : base::Reversed(buffer.pushed_nodes)) { |
| 929 // TODO(titzer): Handle pushing double parameters. | 913 // TODO(titzer): Handle pushing double parameters. |
| 930 InstructionOperand value = | 914 InstructionOperand value = |
| 931 g.CanBeImmediate(node) | 915 g.CanBeImmediate(node) |
| 932 ? g.UseImmediate(node) | 916 ? g.UseImmediate(node) |
| 933 : IsSupported(ATOM) ? g.UseRegister(node) : g.Use(node); | 917 : IsSupported(ATOM) ? g.UseRegister(node) : g.Use(node); |
| 934 Emit(kIA32Push, g.NoOutput(), value); | 918 Emit(kX87Push, g.NoOutput(), value); |
| 935 } | 919 } |
| 936 | 920 |
| 937 // Select the appropriate opcode based on the call type. | 921 // Select the appropriate opcode based on the call type. |
| 938 InstructionCode opcode; | 922 InstructionCode opcode; |
| 939 switch (descriptor->kind()) { | 923 switch (descriptor->kind()) { |
| 940 case CallDescriptor::kCallCodeObject: | 924 case CallDescriptor::kCallCodeObject: |
| 941 opcode = kArchCallCodeObject; | 925 opcode = kArchCallCodeObject; |
| 942 break; | 926 break; |
| 943 case CallDescriptor::kCallJSFunction: | 927 case CallDescriptor::kCallJSFunction: |
| 944 opcode = kArchCallJSFunction; | 928 opcode = kArchCallJSFunction; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 958 } | 942 } |
| 959 } | 943 } |
| 960 | 944 |
| 961 | 945 |
| 962 namespace { | 946 namespace { |
| 963 | 947 |
| 964 // Shared routine for multiple compare operations. | 948 // Shared routine for multiple compare operations. |
| 965 void VisitCompare(InstructionSelector* selector, InstructionCode opcode, | 949 void VisitCompare(InstructionSelector* selector, InstructionCode opcode, |
| 966 InstructionOperand left, InstructionOperand right, | 950 InstructionOperand left, InstructionOperand right, |
| 967 FlagsContinuation* cont) { | 951 FlagsContinuation* cont) { |
| 968 IA32OperandGenerator g(selector); | 952 X87OperandGenerator g(selector); |
| 969 if (cont->IsBranch()) { | 953 if (cont->IsBranch()) { |
| 970 selector->Emit(cont->Encode(opcode), g.NoOutput(), left, right, | 954 selector->Emit(cont->Encode(opcode), g.NoOutput(), left, right, |
| 971 g.Label(cont->true_block()), g.Label(cont->false_block())); | 955 g.Label(cont->true_block()), g.Label(cont->false_block())); |
| 972 } else { | 956 } else { |
| 973 DCHECK(cont->IsSet()); | 957 DCHECK(cont->IsSet()); |
| 974 selector->Emit(cont->Encode(opcode), g.DefineAsByteRegister(cont->result()), | 958 selector->Emit(cont->Encode(opcode), g.DefineAsByteRegister(cont->result()), |
| 975 left, right); | 959 left, right); |
| 976 } | 960 } |
| 977 } | 961 } |
| 978 | 962 |
| 979 | 963 |
| 980 // Shared routine for multiple compare operations. | 964 // Shared routine for multiple compare operations. |
| 981 void VisitCompare(InstructionSelector* selector, InstructionCode opcode, | 965 void VisitCompare(InstructionSelector* selector, InstructionCode opcode, |
| 982 Node* left, Node* right, FlagsContinuation* cont, | 966 Node* left, Node* right, FlagsContinuation* cont, |
| 983 bool commutative) { | 967 bool commutative) { |
| 984 IA32OperandGenerator g(selector); | 968 X87OperandGenerator g(selector); |
| 985 if (commutative && g.CanBeBetterLeftOperand(right)) { | 969 if (commutative && g.CanBeBetterLeftOperand(right)) { |
| 986 std::swap(left, right); | 970 std::swap(left, right); |
| 987 } | 971 } |
| 988 VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont); | 972 VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont); |
| 989 } | 973 } |
| 990 | 974 |
| 991 | 975 |
| 992 // Shared routine for multiple float32 compare operations (inputs commuted). | 976 // Shared routine for multiple float32 compare operations (inputs commuted). |
| 993 void VisitFloat32Compare(InstructionSelector* selector, Node* node, | 977 void VisitFloat32Compare(InstructionSelector* selector, Node* node, |
| 994 FlagsContinuation* cont) { | 978 FlagsContinuation* cont) { |
| 995 Node* const left = node->InputAt(0); | 979 X87OperandGenerator g(selector); |
| 996 Node* const right = node->InputAt(1); | 980 selector->Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0))); |
| 997 VisitCompare(selector, kSSEFloat32Cmp, right, left, cont, false); | 981 selector->Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(1))); |
| 982 if (cont->IsBranch()) { |
| 983 selector->Emit(cont->Encode(kX87Float32Cmp), g.NoOutput(), |
| 984 g.Label(cont->true_block()), g.Label(cont->false_block())); |
| 985 } else { |
| 986 DCHECK(cont->IsSet()); |
| 987 selector->Emit(cont->Encode(kX87Float32Cmp), |
| 988 g.DefineAsByteRegister(cont->result())); |
| 989 } |
| 998 } | 990 } |
| 999 | 991 |
| 1000 | 992 |
| 1001 // Shared routine for multiple float64 compare operations (inputs commuted). | 993 // Shared routine for multiple float64 compare operations (inputs commuted). |
| 1002 void VisitFloat64Compare(InstructionSelector* selector, Node* node, | 994 void VisitFloat64Compare(InstructionSelector* selector, Node* node, |
| 1003 FlagsContinuation* cont) { | 995 FlagsContinuation* cont) { |
| 1004 Node* const left = node->InputAt(0); | 996 X87OperandGenerator g(selector); |
| 1005 Node* const right = node->InputAt(1); | 997 selector->Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0))); |
| 1006 VisitCompare(selector, kSSEFloat64Cmp, right, left, cont, false); | 998 selector->Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(1))); |
| 999 if (cont->IsBranch()) { |
| 1000 selector->Emit(cont->Encode(kX87Float64Cmp), g.NoOutput(), |
| 1001 g.Label(cont->true_block()), g.Label(cont->false_block())); |
| 1002 } else { |
| 1003 DCHECK(cont->IsSet()); |
| 1004 selector->Emit(cont->Encode(kX87Float64Cmp), |
| 1005 g.DefineAsByteRegister(cont->result())); |
| 1006 } |
| 1007 } | 1007 } |
| 1008 | 1008 |
| 1009 | 1009 |
| 1010 // Shared routine for multiple word compare operations. | 1010 // Shared routine for multiple word compare operations. |
| 1011 void VisitWordCompare(InstructionSelector* selector, Node* node, | 1011 void VisitWordCompare(InstructionSelector* selector, Node* node, |
| 1012 InstructionCode opcode, FlagsContinuation* cont) { | 1012 InstructionCode opcode, FlagsContinuation* cont) { |
| 1013 IA32OperandGenerator g(selector); | 1013 X87OperandGenerator g(selector); |
| 1014 Node* const left = node->InputAt(0); | 1014 Node* const left = node->InputAt(0); |
| 1015 Node* const right = node->InputAt(1); | 1015 Node* const right = node->InputAt(1); |
| 1016 | 1016 |
| 1017 // Match immediates on left or right side of comparison. | 1017 // Match immediates on left or right side of comparison. |
| 1018 if (g.CanBeImmediate(right)) { | 1018 if (g.CanBeImmediate(right)) { |
| 1019 VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right), cont); | 1019 VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right), cont); |
| 1020 } else if (g.CanBeImmediate(left)) { | 1020 } else if (g.CanBeImmediate(left)) { |
| 1021 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute(); | 1021 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute(); |
| 1022 VisitCompare(selector, opcode, g.Use(right), g.UseImmediate(left), cont); | 1022 VisitCompare(selector, opcode, g.Use(right), g.UseImmediate(left), cont); |
| 1023 } else { | 1023 } else { |
| 1024 VisitCompare(selector, opcode, left, right, cont, | 1024 VisitCompare(selector, opcode, left, right, cont, |
| 1025 node->op()->HasProperty(Operator::kCommutative)); | 1025 node->op()->HasProperty(Operator::kCommutative)); |
| 1026 } | 1026 } |
| 1027 } | 1027 } |
| 1028 | 1028 |
| 1029 | 1029 |
| 1030 void VisitWordCompare(InstructionSelector* selector, Node* node, | 1030 void VisitWordCompare(InstructionSelector* selector, Node* node, |
| 1031 FlagsContinuation* cont) { | 1031 FlagsContinuation* cont) { |
| 1032 IA32OperandGenerator g(selector); | 1032 X87OperandGenerator g(selector); |
| 1033 Int32BinopMatcher m(node); | 1033 Int32BinopMatcher m(node); |
| 1034 if (m.left().IsLoad() && m.right().IsLoadStackPointer()) { | 1034 if (m.left().IsLoad() && m.right().IsLoadStackPointer()) { |
| 1035 LoadMatcher<ExternalReferenceMatcher> mleft(m.left().node()); | 1035 LoadMatcher<ExternalReferenceMatcher> mleft(m.left().node()); |
| 1036 ExternalReference js_stack_limit = | 1036 ExternalReference js_stack_limit = |
| 1037 ExternalReference::address_of_stack_limit(selector->isolate()); | 1037 ExternalReference::address_of_stack_limit(selector->isolate()); |
| 1038 if (mleft.object().Is(js_stack_limit) && mleft.index().Is(0)) { | 1038 if (mleft.object().Is(js_stack_limit) && mleft.index().Is(0)) { |
| 1039 // Compare(Load(js_stack_limit), LoadStackPointer) | 1039 // Compare(Load(js_stack_limit), LoadStackPointer) |
| 1040 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute(); | 1040 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute(); |
| 1041 InstructionCode opcode = cont->Encode(kIA32StackCheck); | 1041 InstructionCode opcode = cont->Encode(kX87StackCheck); |
| 1042 if (cont->IsBranch()) { | 1042 if (cont->IsBranch()) { |
| 1043 selector->Emit(opcode, g.NoOutput(), g.Label(cont->true_block()), | 1043 selector->Emit(opcode, g.NoOutput(), g.Label(cont->true_block()), |
| 1044 g.Label(cont->false_block())); | 1044 g.Label(cont->false_block())); |
| 1045 } else { | 1045 } else { |
| 1046 DCHECK(cont->IsSet()); | 1046 DCHECK(cont->IsSet()); |
| 1047 selector->Emit(opcode, g.DefineAsRegister(cont->result())); | 1047 selector->Emit(opcode, g.DefineAsRegister(cont->result())); |
| 1048 } | 1048 } |
| 1049 return; | 1049 return; |
| 1050 } | 1050 } |
| 1051 } | 1051 } |
| 1052 VisitWordCompare(selector, node, kIA32Cmp, cont); | 1052 VisitWordCompare(selector, node, kX87Cmp, cont); |
| 1053 } | 1053 } |
| 1054 | 1054 |
| 1055 | 1055 |
| 1056 // Shared routine for word comparison with zero. | 1056 // Shared routine for word comparison with zero. |
| 1057 void VisitWordCompareZero(InstructionSelector* selector, Node* user, | 1057 void VisitWordCompareZero(InstructionSelector* selector, Node* user, |
| 1058 Node* value, FlagsContinuation* cont) { | 1058 Node* value, FlagsContinuation* cont) { |
| 1059 // Try to combine the branch with a comparison. | 1059 // Try to combine the branch with a comparison. |
| 1060 while (selector->CanCover(user, value)) { | 1060 while (selector->CanCover(user, value)) { |
| 1061 switch (value->opcode()) { | 1061 switch (value->opcode()) { |
| 1062 case IrOpcode::kWord32Equal: { | 1062 case IrOpcode::kWord32Equal: { |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1110 // unless the 0th projection (the use of the actual value of the | 1110 // unless the 0th projection (the use of the actual value of the |
| 1111 // <Operation> is either NULL, which means there's no use of the | 1111 // <Operation> is either NULL, which means there's no use of the |
| 1112 // actual value, or was already defined, which means it is scheduled | 1112 // actual value, or was already defined, which means it is scheduled |
| 1113 // *AFTER* this branch). | 1113 // *AFTER* this branch). |
| 1114 Node* const node = value->InputAt(0); | 1114 Node* const node = value->InputAt(0); |
| 1115 Node* const result = NodeProperties::FindProjection(node, 0); | 1115 Node* const result = NodeProperties::FindProjection(node, 0); |
| 1116 if (result == NULL || selector->IsDefined(result)) { | 1116 if (result == NULL || selector->IsDefined(result)) { |
| 1117 switch (node->opcode()) { | 1117 switch (node->opcode()) { |
| 1118 case IrOpcode::kInt32AddWithOverflow: | 1118 case IrOpcode::kInt32AddWithOverflow: |
| 1119 cont->OverwriteAndNegateIfEqual(kOverflow); | 1119 cont->OverwriteAndNegateIfEqual(kOverflow); |
| 1120 return VisitBinop(selector, node, kIA32Add, cont); | 1120 return VisitBinop(selector, node, kX87Add, cont); |
| 1121 case IrOpcode::kInt32SubWithOverflow: | 1121 case IrOpcode::kInt32SubWithOverflow: |
| 1122 cont->OverwriteAndNegateIfEqual(kOverflow); | 1122 cont->OverwriteAndNegateIfEqual(kOverflow); |
| 1123 return VisitBinop(selector, node, kIA32Sub, cont); | 1123 return VisitBinop(selector, node, kX87Sub, cont); |
| 1124 default: | 1124 default: |
| 1125 break; | 1125 break; |
| 1126 } | 1126 } |
| 1127 } | 1127 } |
| 1128 } | 1128 } |
| 1129 break; | 1129 break; |
| 1130 case IrOpcode::kInt32Sub: | 1130 case IrOpcode::kInt32Sub: |
| 1131 return VisitWordCompare(selector, value, cont); | 1131 return VisitWordCompare(selector, value, cont); |
| 1132 case IrOpcode::kWord32And: | 1132 case IrOpcode::kWord32And: |
| 1133 return VisitWordCompare(selector, value, kIA32Test, cont); | 1133 return VisitWordCompare(selector, value, kX87Test, cont); |
| 1134 default: | 1134 default: |
| 1135 break; | 1135 break; |
| 1136 } | 1136 } |
| 1137 break; | 1137 break; |
| 1138 } | 1138 } |
| 1139 | 1139 |
| 1140 // Continuation could not be combined with a compare, emit compare against 0. | 1140 // Continuation could not be combined with a compare, emit compare against 0. |
| 1141 IA32OperandGenerator g(selector); | 1141 X87OperandGenerator g(selector); |
| 1142 VisitCompare(selector, kIA32Cmp, g.Use(value), g.TempImmediate(0), cont); | 1142 VisitCompare(selector, kX87Cmp, g.Use(value), g.TempImmediate(0), cont); |
| 1143 } | 1143 } |
| 1144 | 1144 |
| 1145 } // namespace | 1145 } // namespace |
| 1146 | 1146 |
| 1147 | 1147 |
| 1148 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, | 1148 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, |
| 1149 BasicBlock* fbranch) { | 1149 BasicBlock* fbranch) { |
| 1150 FlagsContinuation cont(kNotEqual, tbranch, fbranch); | 1150 FlagsContinuation cont(kNotEqual, tbranch, fbranch); |
| 1151 VisitWordCompareZero(this, branch, branch->InputAt(0), &cont); | 1151 VisitWordCompareZero(this, branch, branch->InputAt(0), &cont); |
| 1152 } | 1152 } |
| 1153 | 1153 |
| 1154 | 1154 |
| 1155 void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { | 1155 void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { |
| 1156 IA32OperandGenerator g(this); | 1156 X87OperandGenerator g(this); |
| 1157 InstructionOperand value_operand = g.UseRegister(node->InputAt(0)); | 1157 InstructionOperand value_operand = g.UseRegister(node->InputAt(0)); |
| 1158 | 1158 |
| 1159 // Emit either ArchTableSwitch or ArchLookupSwitch. | 1159 // Emit either ArchTableSwitch or ArchLookupSwitch. |
| 1160 size_t table_space_cost = 4 + sw.value_range; | 1160 size_t table_space_cost = 4 + sw.value_range; |
| 1161 size_t table_time_cost = 3; | 1161 size_t table_time_cost = 3; |
| 1162 size_t lookup_space_cost = 3 + 2 * sw.case_count; | 1162 size_t lookup_space_cost = 3 + 2 * sw.case_count; |
| 1163 size_t lookup_time_cost = sw.case_count; | 1163 size_t lookup_time_cost = sw.case_count; |
| 1164 if (sw.case_count > 4 && | 1164 if (sw.case_count > 4 && |
| 1165 table_space_cost + 3 * table_time_cost <= | 1165 table_space_cost + 3 * table_time_cost <= |
| 1166 lookup_space_cost + 3 * lookup_time_cost && | 1166 lookup_space_cost + 3 * lookup_time_cost && |
| 1167 sw.min_value > std::numeric_limits<int32_t>::min()) { | 1167 sw.min_value > std::numeric_limits<int32_t>::min()) { |
| 1168 InstructionOperand index_operand = value_operand; | 1168 InstructionOperand index_operand = value_operand; |
| 1169 if (sw.min_value) { | 1169 if (sw.min_value) { |
| 1170 index_operand = g.TempRegister(); | 1170 index_operand = g.TempRegister(); |
| 1171 Emit(kIA32Lea | AddressingModeField::encode(kMode_MRI), index_operand, | 1171 Emit(kX87Lea | AddressingModeField::encode(kMode_MRI), index_operand, |
| 1172 value_operand, g.TempImmediate(-sw.min_value)); | 1172 value_operand, g.TempImmediate(-sw.min_value)); |
| 1173 } | 1173 } |
| 1174 // Generate a table lookup. | 1174 // Generate a table lookup. |
| 1175 return EmitTableSwitch(sw, index_operand); | 1175 return EmitTableSwitch(sw, index_operand); |
| 1176 } | 1176 } |
| 1177 | 1177 |
| 1178 // Generate a sequence of conditional jumps. | 1178 // Generate a sequence of conditional jumps. |
| 1179 return EmitLookupSwitch(sw, value_operand); | 1179 return EmitLookupSwitch(sw, value_operand); |
| 1180 } | 1180 } |
| 1181 | 1181 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1210 | 1210 |
| 1211 void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) { | 1211 void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) { |
| 1212 FlagsContinuation cont(kUnsignedLessThanOrEqual, node); | 1212 FlagsContinuation cont(kUnsignedLessThanOrEqual, node); |
| 1213 VisitWordCompare(this, node, &cont); | 1213 VisitWordCompare(this, node, &cont); |
| 1214 } | 1214 } |
| 1215 | 1215 |
| 1216 | 1216 |
| 1217 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) { | 1217 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) { |
| 1218 if (Node* ovf = NodeProperties::FindProjection(node, 1)) { | 1218 if (Node* ovf = NodeProperties::FindProjection(node, 1)) { |
| 1219 FlagsContinuation cont(kOverflow, ovf); | 1219 FlagsContinuation cont(kOverflow, ovf); |
| 1220 return VisitBinop(this, node, kIA32Add, &cont); | 1220 return VisitBinop(this, node, kX87Add, &cont); |
| 1221 } | 1221 } |
| 1222 FlagsContinuation cont; | 1222 FlagsContinuation cont; |
| 1223 VisitBinop(this, node, kIA32Add, &cont); | 1223 VisitBinop(this, node, kX87Add, &cont); |
| 1224 } | 1224 } |
| 1225 | 1225 |
| 1226 | 1226 |
| 1227 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { | 1227 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { |
| 1228 if (Node* ovf = NodeProperties::FindProjection(node, 1)) { | 1228 if (Node* ovf = NodeProperties::FindProjection(node, 1)) { |
| 1229 FlagsContinuation cont(kOverflow, ovf); | 1229 FlagsContinuation cont(kOverflow, ovf); |
| 1230 return VisitBinop(this, node, kIA32Sub, &cont); | 1230 return VisitBinop(this, node, kX87Sub, &cont); |
| 1231 } | 1231 } |
| 1232 FlagsContinuation cont; | 1232 FlagsContinuation cont; |
| 1233 VisitBinop(this, node, kIA32Sub, &cont); | 1233 VisitBinop(this, node, kX87Sub, &cont); |
| 1234 } | 1234 } |
| 1235 | 1235 |
| 1236 | 1236 |
| 1237 void InstructionSelector::VisitFloat32Equal(Node* node) { | 1237 void InstructionSelector::VisitFloat32Equal(Node* node) { |
| 1238 FlagsContinuation cont(kUnorderedEqual, node); | 1238 FlagsContinuation cont(kUnorderedEqual, node); |
| 1239 VisitFloat32Compare(this, node, &cont); | 1239 VisitFloat32Compare(this, node, &cont); |
| 1240 } | 1240 } |
| 1241 | 1241 |
| 1242 | 1242 |
| 1243 void InstructionSelector::VisitFloat32LessThan(Node* node) { | 1243 void InstructionSelector::VisitFloat32LessThan(Node* node) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1264 } | 1264 } |
| 1265 | 1265 |
| 1266 | 1266 |
| 1267 void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { | 1267 void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { |
| 1268 FlagsContinuation cont(kUnsignedGreaterThanOrEqual, node); | 1268 FlagsContinuation cont(kUnsignedGreaterThanOrEqual, node); |
| 1269 VisitFloat64Compare(this, node, &cont); | 1269 VisitFloat64Compare(this, node, &cont); |
| 1270 } | 1270 } |
| 1271 | 1271 |
| 1272 | 1272 |
| 1273 void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) { | 1273 void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) { |
| 1274 IA32OperandGenerator g(this); | 1274 X87OperandGenerator g(this); |
| 1275 Emit(kSSEFloat64ExtractLowWord32, g.DefineAsRegister(node), | 1275 Emit(kX87Float64ExtractLowWord32, g.DefineAsRegister(node), |
| 1276 g.Use(node->InputAt(0))); | 1276 g.Use(node->InputAt(0))); |
| 1277 } | 1277 } |
| 1278 | 1278 |
| 1279 | 1279 |
| 1280 void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) { | 1280 void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) { |
| 1281 IA32OperandGenerator g(this); | 1281 X87OperandGenerator g(this); |
| 1282 Emit(kSSEFloat64ExtractHighWord32, g.DefineAsRegister(node), | 1282 Emit(kX87Float64ExtractHighWord32, g.DefineAsRegister(node), |
| 1283 g.Use(node->InputAt(0))); | 1283 g.Use(node->InputAt(0))); |
| 1284 } | 1284 } |
| 1285 | 1285 |
| 1286 | 1286 |
| 1287 void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) { | 1287 void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) { |
| 1288 IA32OperandGenerator g(this); | 1288 X87OperandGenerator g(this); |
| 1289 Node* left = node->InputAt(0); | 1289 Node* left = node->InputAt(0); |
| 1290 Node* right = node->InputAt(1); | 1290 Node* right = node->InputAt(1); |
| 1291 Float64Matcher mleft(left); | 1291 Emit(kX87Float64InsertLowWord32, g.UseFixed(node, stX_0), g.UseRegister(left), |
| 1292 if (mleft.HasValue() && (bit_cast<uint64_t>(mleft.Value()) >> 32) == 0u) { | 1292 g.UseRegister(right)); |
| 1293 Emit(kSSEFloat64LoadLowWord32, g.DefineAsRegister(node), g.Use(right)); | |
| 1294 return; | |
| 1295 } | |
| 1296 Emit(kSSEFloat64InsertLowWord32, g.DefineSameAsFirst(node), | |
| 1297 g.UseRegister(left), g.Use(right)); | |
| 1298 } | 1293 } |
| 1299 | 1294 |
| 1300 | 1295 |
| 1301 void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) { | 1296 void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) { |
| 1302 IA32OperandGenerator g(this); | 1297 X87OperandGenerator g(this); |
| 1303 Node* left = node->InputAt(0); | 1298 Node* left = node->InputAt(0); |
| 1304 Node* right = node->InputAt(1); | 1299 Node* right = node->InputAt(1); |
| 1305 Emit(kSSEFloat64InsertHighWord32, g.DefineSameAsFirst(node), | 1300 Emit(kX87Float64InsertHighWord32, g.UseFixed(node, stX_0), |
| 1306 g.UseRegister(left), g.Use(right)); | 1301 g.UseRegister(left), g.UseRegister(right)); |
| 1307 } | 1302 } |
| 1308 | 1303 |
| 1309 | 1304 |
| 1310 // static | 1305 // static |
| 1311 MachineOperatorBuilder::Flags | 1306 MachineOperatorBuilder::Flags |
| 1312 InstructionSelector::SupportedMachineOperatorFlags() { | 1307 InstructionSelector::SupportedMachineOperatorFlags() { |
| 1313 MachineOperatorBuilder::Flags flags = | 1308 MachineOperatorBuilder::Flags flags = |
| 1314 MachineOperatorBuilder::kFloat32Max | | 1309 MachineOperatorBuilder::kFloat32Max | |
| 1315 MachineOperatorBuilder::kFloat32Min | | 1310 MachineOperatorBuilder::kFloat32Min | |
| 1316 MachineOperatorBuilder::kFloat64Max | | 1311 MachineOperatorBuilder::kFloat64Max | |
| 1317 MachineOperatorBuilder::kFloat64Min | | 1312 MachineOperatorBuilder::kFloat64Min | |
| 1318 MachineOperatorBuilder::kWord32ShiftIsSafe; | 1313 MachineOperatorBuilder::kWord32ShiftIsSafe; |
| 1319 if (CpuFeatures::IsSupported(SSE4_1)) { | |
| 1320 flags |= MachineOperatorBuilder::kFloat64RoundDown | | |
| 1321 MachineOperatorBuilder::kFloat64RoundTruncate; | |
| 1322 } | |
| 1323 return flags; | 1314 return flags; |
| 1324 } | 1315 } |
| 1325 | 1316 |
| 1326 } // namespace compiler | 1317 } // namespace compiler |
| 1327 } // namespace internal | 1318 } // namespace internal |
| 1328 } // namespace v8 | 1319 } // namespace v8 |
| OLD | NEW |