OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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/code-generator.h" | 5 #include "src/compiler/code-generator.h" |
6 | 6 |
7 #include "src/compiler/code-generator-impl.h" | 7 #include "src/compiler/code-generator-impl.h" |
8 #include "src/compiler/gap-resolver.h" | 8 #include "src/compiler/gap-resolver.h" |
9 #include "src/compiler/node-matchers.h" | 9 #include "src/compiler/node-matchers.h" |
10 #include "src/ia32/assembler-ia32.h" | |
11 #include "src/ia32/macro-assembler-ia32.h" | |
12 #include "src/scopes.h" | 10 #include "src/scopes.h" |
| 11 #include "src/x87/assembler-x87.h" |
| 12 #include "src/x87/macro-assembler-x87.h" |
13 | 13 |
14 namespace v8 { | 14 namespace v8 { |
15 namespace internal { | 15 namespace internal { |
16 namespace compiler { | 16 namespace compiler { |
17 | 17 |
18 #define __ masm()-> | 18 #define __ masm()-> |
19 | 19 |
20 | 20 |
21 #define kScratchDoubleReg xmm0 | 21 // Adds X87 specific methods for decoding operands. |
22 | 22 class X87OperandConverter : public InstructionOperandConverter { |
23 | |
24 // Adds IA-32 specific methods for decoding operands. | |
25 class IA32OperandConverter : public InstructionOperandConverter { | |
26 public: | 23 public: |
27 IA32OperandConverter(CodeGenerator* gen, Instruction* instr) | 24 X87OperandConverter(CodeGenerator* gen, Instruction* instr) |
28 : InstructionOperandConverter(gen, instr) {} | 25 : InstructionOperandConverter(gen, instr) {} |
29 | 26 |
30 Operand InputOperand(size_t index, int extra = 0) { | 27 Operand InputOperand(size_t index, int extra = 0) { |
31 return ToOperand(instr_->InputAt(index), extra); | 28 return ToOperand(instr_->InputAt(index), extra); |
32 } | 29 } |
33 | 30 |
34 Immediate InputImmediate(size_t index) { | 31 Immediate InputImmediate(size_t index) { |
35 return ToImmediate(instr_->InputAt(index)); | 32 return ToImmediate(instr_->InputAt(index)); |
36 } | 33 } |
37 | 34 |
38 Operand OutputOperand() { return ToOperand(instr_->Output()); } | 35 Operand OutputOperand() { return ToOperand(instr_->Output()); } |
39 | 36 |
40 Operand ToOperand(InstructionOperand* op, int extra = 0) { | 37 Operand ToOperand(InstructionOperand* op, int extra = 0) { |
41 if (op->IsRegister()) { | 38 if (op->IsRegister()) { |
42 DCHECK(extra == 0); | 39 DCHECK(extra == 0); |
43 return Operand(ToRegister(op)); | 40 return Operand(ToRegister(op)); |
44 } else if (op->IsDoubleRegister()) { | 41 } else if (op->IsDoubleRegister()) { |
45 DCHECK(extra == 0); | 42 DCHECK(extra == 0); |
46 return Operand(ToDoubleRegister(op)); | 43 UNIMPLEMENTED(); |
47 } | 44 } |
48 DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot()); | 45 DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot()); |
49 // The linkage computes where all spill slots are located. | 46 // The linkage computes where all spill slots are located. |
50 FrameOffset offset = linkage()->GetFrameOffset( | 47 FrameOffset offset = linkage()->GetFrameOffset( |
51 AllocatedOperand::cast(op)->index(), frame(), extra); | 48 AllocatedOperand::cast(op)->index(), frame(), extra); |
52 return Operand(offset.from_stack_pointer() ? esp : ebp, offset.offset()); | 49 return Operand(offset.from_stack_pointer() ? esp : ebp, offset.offset()); |
53 } | 50 } |
54 | 51 |
55 Operand HighOperand(InstructionOperand* op) { | 52 Operand HighOperand(InstructionOperand* op) { |
56 DCHECK(op->IsDoubleStackSlot()); | 53 DCHECK(op->IsDoubleStackSlot()); |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
180 | 177 |
181 void Generate() final { __ xor_(result_, result_); } | 178 void Generate() final { __ xor_(result_, result_); } |
182 | 179 |
183 private: | 180 private: |
184 Register const result_; | 181 Register const result_; |
185 }; | 182 }; |
186 | 183 |
187 | 184 |
188 class OutOfLineLoadFloat final : public OutOfLineCode { | 185 class OutOfLineLoadFloat final : public OutOfLineCode { |
189 public: | 186 public: |
190 OutOfLineLoadFloat(CodeGenerator* gen, XMMRegister result) | 187 OutOfLineLoadFloat(CodeGenerator* gen, X87Register result) |
191 : OutOfLineCode(gen), result_(result) {} | 188 : OutOfLineCode(gen), result_(result) {} |
192 | 189 |
193 void Generate() final { __ pcmpeqd(result_, result_); } | 190 void Generate() final { |
| 191 DCHECK(result_.code() == 0); |
| 192 USE(result_); |
| 193 __ fstp(0); |
| 194 __ push(Immediate(0xffffffff)); |
| 195 __ push(Immediate(0x7fffffff)); |
| 196 __ fld_d(MemOperand(esp, 0)); |
| 197 __ lea(esp, Operand(esp, kDoubleSize)); |
| 198 } |
194 | 199 |
195 private: | 200 private: |
196 XMMRegister const result_; | 201 X87Register const result_; |
197 }; | 202 }; |
198 | 203 |
199 | 204 |
200 class OutOfLineTruncateDoubleToI final : public OutOfLineCode { | 205 class OutOfLineTruncateDoubleToI final : public OutOfLineCode { |
201 public: | 206 public: |
202 OutOfLineTruncateDoubleToI(CodeGenerator* gen, Register result, | 207 OutOfLineTruncateDoubleToI(CodeGenerator* gen, Register result, |
203 XMMRegister input) | 208 X87Register input) |
204 : OutOfLineCode(gen), result_(result), input_(input) {} | 209 : OutOfLineCode(gen), result_(result), input_(input) {} |
205 | 210 |
206 void Generate() final { | 211 void Generate() final { |
207 __ sub(esp, Immediate(kDoubleSize)); | 212 UNIMPLEMENTED(); |
208 __ movsd(MemOperand(esp, 0), input_); | 213 USE(result_); |
209 __ SlowTruncateToI(result_, esp, 0); | 214 USE(input_); |
210 __ add(esp, Immediate(kDoubleSize)); | |
211 } | 215 } |
212 | 216 |
213 private: | 217 private: |
214 Register const result_; | 218 Register const result_; |
215 XMMRegister const input_; | 219 X87Register const input_; |
216 }; | 220 }; |
217 | 221 |
218 } // namespace | 222 } // namespace |
219 | 223 |
220 | 224 |
221 #define ASSEMBLE_CHECKED_LOAD_FLOAT(asm_instr) \ | 225 #define ASSEMBLE_CHECKED_LOAD_FLOAT(asm_instr) \ |
222 do { \ | 226 do { \ |
223 auto result = i.OutputDoubleRegister(); \ | 227 auto result = i.OutputDoubleRegister(); \ |
224 auto offset = i.InputRegister(0); \ | 228 auto offset = i.InputRegister(0); \ |
| 229 DCHECK(result.code() == 0); \ |
225 if (instr->InputAt(1)->IsRegister()) { \ | 230 if (instr->InputAt(1)->IsRegister()) { \ |
226 __ cmp(offset, i.InputRegister(1)); \ | 231 __ cmp(offset, i.InputRegister(1)); \ |
227 } else { \ | 232 } else { \ |
228 __ cmp(offset, i.InputImmediate(1)); \ | 233 __ cmp(offset, i.InputImmediate(1)); \ |
229 } \ | 234 } \ |
230 OutOfLineCode* ool = new (zone()) OutOfLineLoadFloat(this, result); \ | 235 OutOfLineCode* ool = new (zone()) OutOfLineLoadFloat(this, result); \ |
231 __ j(above_equal, ool->entry()); \ | 236 __ j(above_equal, ool->entry()); \ |
232 __ asm_instr(result, i.MemoryOperand(2)); \ | 237 __ fstp(0); \ |
| 238 __ asm_instr(i.MemoryOperand(2)); \ |
233 __ bind(ool->exit()); \ | 239 __ bind(ool->exit()); \ |
234 } while (false) | 240 } while (false) |
235 | 241 |
236 | 242 |
237 #define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \ | 243 #define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \ |
238 do { \ | 244 do { \ |
239 auto result = i.OutputRegister(); \ | 245 auto result = i.OutputRegister(); \ |
240 auto offset = i.InputRegister(0); \ | 246 auto offset = i.InputRegister(0); \ |
241 if (instr->InputAt(1)->IsRegister()) { \ | 247 if (instr->InputAt(1)->IsRegister()) { \ |
242 __ cmp(offset, i.InputRegister(1)); \ | 248 __ cmp(offset, i.InputRegister(1)); \ |
243 } else { \ | 249 } else { \ |
244 __ cmp(offset, i.InputImmediate(1)); \ | 250 __ cmp(offset, i.InputImmediate(1)); \ |
245 } \ | 251 } \ |
246 OutOfLineCode* ool = new (zone()) OutOfLineLoadInteger(this, result); \ | 252 OutOfLineCode* ool = new (zone()) OutOfLineLoadInteger(this, result); \ |
247 __ j(above_equal, ool->entry()); \ | 253 __ j(above_equal, ool->entry()); \ |
248 __ asm_instr(result, i.MemoryOperand(2)); \ | 254 __ asm_instr(result, i.MemoryOperand(2)); \ |
249 __ bind(ool->exit()); \ | 255 __ bind(ool->exit()); \ |
250 } while (false) | 256 } while (false) |
251 | 257 |
252 | 258 |
253 #define ASSEMBLE_CHECKED_STORE_FLOAT(asm_instr) \ | 259 #define ASSEMBLE_CHECKED_STORE_FLOAT(asm_instr) \ |
254 do { \ | 260 do { \ |
255 auto offset = i.InputRegister(0); \ | 261 auto offset = i.InputRegister(0); \ |
256 if (instr->InputAt(1)->IsRegister()) { \ | 262 if (instr->InputAt(1)->IsRegister()) { \ |
257 __ cmp(offset, i.InputRegister(1)); \ | 263 __ cmp(offset, i.InputRegister(1)); \ |
258 } else { \ | 264 } else { \ |
259 __ cmp(offset, i.InputImmediate(1)); \ | 265 __ cmp(offset, i.InputImmediate(1)); \ |
260 } \ | 266 } \ |
261 Label done; \ | 267 Label done; \ |
| 268 DCHECK(i.InputDoubleRegister(2).code() == 0); \ |
262 __ j(above_equal, &done, Label::kNear); \ | 269 __ j(above_equal, &done, Label::kNear); \ |
263 __ asm_instr(i.MemoryOperand(3), i.InputDoubleRegister(2)); \ | 270 __ asm_instr(i.MemoryOperand(3)); \ |
264 __ bind(&done); \ | 271 __ bind(&done); \ |
265 } while (false) | 272 } while (false) |
266 | 273 |
267 | 274 |
268 #define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \ | 275 #define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \ |
269 do { \ | 276 do { \ |
270 auto offset = i.InputRegister(0); \ | 277 auto offset = i.InputRegister(0); \ |
271 if (instr->InputAt(1)->IsRegister()) { \ | 278 if (instr->InputAt(1)->IsRegister()) { \ |
272 __ cmp(offset, i.InputRegister(1)); \ | 279 __ cmp(offset, i.InputRegister(1)); \ |
273 } else { \ | 280 } else { \ |
(...skipping 22 matching lines...) Expand all Loading... |
296 kPointerSize) | 303 kPointerSize) |
297 : 0; | 304 : 0; |
298 __ pop(Operand(esp, bytes_to_pop)); | 305 __ pop(Operand(esp, bytes_to_pop)); |
299 __ add(esp, Immediate(bytes_to_pop)); | 306 __ add(esp, Immediate(bytes_to_pop)); |
300 } | 307 } |
301 } | 308 } |
302 | 309 |
303 | 310 |
304 // Assembles an instruction after register allocation, producing machine code. | 311 // Assembles an instruction after register allocation, producing machine code. |
305 void CodeGenerator::AssembleArchInstruction(Instruction* instr) { | 312 void CodeGenerator::AssembleArchInstruction(Instruction* instr) { |
306 IA32OperandConverter i(this, instr); | 313 X87OperandConverter i(this, instr); |
307 | 314 |
308 switch (ArchOpcodeField::decode(instr->opcode())) { | 315 switch (ArchOpcodeField::decode(instr->opcode())) { |
309 case kArchCallCodeObject: { | 316 case kArchCallCodeObject: { |
310 EnsureSpaceForLazyDeopt(); | 317 EnsureSpaceForLazyDeopt(); |
311 if (HasImmediateInput(instr, 0)) { | 318 if (HasImmediateInput(instr, 0)) { |
312 Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0)); | 319 Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0)); |
313 __ call(code, RelocInfo::CODE_TARGET); | 320 __ call(code, RelocInfo::CODE_TARGET); |
314 } else { | 321 } else { |
315 Register reg = i.InputRegister(0); | 322 Register reg = i.InputRegister(0); |
316 __ call(Operand(reg, Code::kHeaderSize - kHeapObjectTag)); | 323 __ call(Operand(reg, Code::kHeaderSize - kHeapObjectTag)); |
317 } | 324 } |
318 RecordCallPosition(instr); | 325 RecordCallPosition(instr); |
| 326 bool double_result = |
| 327 instr->HasOutput() && instr->Output()->IsDoubleRegister(); |
| 328 if (double_result) { |
| 329 __ lea(esp, Operand(esp, -kDoubleSize)); |
| 330 __ fstp_d(Operand(esp, 0)); |
| 331 } |
| 332 __ fninit(); |
| 333 if (double_result) { |
| 334 __ fld_d(Operand(esp, 0)); |
| 335 __ lea(esp, Operand(esp, kDoubleSize)); |
| 336 } else { |
| 337 __ fld1(); |
| 338 } |
319 break; | 339 break; |
320 } | 340 } |
321 case kArchTailCallCodeObject: { | 341 case kArchTailCallCodeObject: { |
322 AssembleDeconstructActivationRecord(); | 342 AssembleDeconstructActivationRecord(); |
323 if (HasImmediateInput(instr, 0)) { | 343 if (HasImmediateInput(instr, 0)) { |
324 Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0)); | 344 Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0)); |
325 __ jmp(code, RelocInfo::CODE_TARGET); | 345 __ jmp(code, RelocInfo::CODE_TARGET); |
326 } else { | 346 } else { |
327 Register reg = i.InputRegister(0); | 347 Register reg = i.InputRegister(0); |
328 __ jmp(Operand(reg, Code::kHeaderSize - kHeapObjectTag)); | 348 __ jmp(Operand(reg, Code::kHeaderSize - kHeapObjectTag)); |
329 } | 349 } |
330 break; | 350 break; |
331 } | 351 } |
332 case kArchCallJSFunction: { | 352 case kArchCallJSFunction: { |
333 EnsureSpaceForLazyDeopt(); | 353 EnsureSpaceForLazyDeopt(); |
334 Register func = i.InputRegister(0); | 354 Register func = i.InputRegister(0); |
335 if (FLAG_debug_code) { | 355 if (FLAG_debug_code) { |
336 // Check the function's context matches the context argument. | 356 // Check the function's context matches the context argument. |
337 __ cmp(esi, FieldOperand(func, JSFunction::kContextOffset)); | 357 __ cmp(esi, FieldOperand(func, JSFunction::kContextOffset)); |
338 __ Assert(equal, kWrongFunctionContext); | 358 __ Assert(equal, kWrongFunctionContext); |
339 } | 359 } |
340 __ call(FieldOperand(func, JSFunction::kCodeEntryOffset)); | 360 __ call(FieldOperand(func, JSFunction::kCodeEntryOffset)); |
341 RecordCallPosition(instr); | 361 RecordCallPosition(instr); |
| 362 bool double_result = |
| 363 instr->HasOutput() && instr->Output()->IsDoubleRegister(); |
| 364 if (double_result) { |
| 365 __ lea(esp, Operand(esp, -kDoubleSize)); |
| 366 __ fstp_d(Operand(esp, 0)); |
| 367 } |
| 368 __ fninit(); |
| 369 if (double_result) { |
| 370 __ fld_d(Operand(esp, 0)); |
| 371 __ lea(esp, Operand(esp, kDoubleSize)); |
| 372 } else { |
| 373 __ fld1(); |
| 374 } |
342 break; | 375 break; |
343 } | 376 } |
344 case kArchTailCallJSFunction: { | 377 case kArchTailCallJSFunction: { |
345 Register func = i.InputRegister(0); | 378 Register func = i.InputRegister(0); |
346 if (FLAG_debug_code) { | 379 if (FLAG_debug_code) { |
347 // Check the function's context matches the context argument. | 380 // Check the function's context matches the context argument. |
348 __ cmp(esi, FieldOperand(func, JSFunction::kContextOffset)); | 381 __ cmp(esi, FieldOperand(func, JSFunction::kContextOffset)); |
349 __ Assert(equal, kWrongFunctionContext); | 382 __ Assert(equal, kWrongFunctionContext); |
350 } | 383 } |
351 AssembleDeconstructActivationRecord(); | 384 AssembleDeconstructActivationRecord(); |
(...skipping 14 matching lines...) Expand all Loading... |
366 break; | 399 break; |
367 case kArchDeoptimize: { | 400 case kArchDeoptimize: { |
368 int deopt_state_id = | 401 int deopt_state_id = |
369 BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore()); | 402 BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore()); |
370 AssembleDeoptimizerCall(deopt_state_id, Deoptimizer::EAGER); | 403 AssembleDeoptimizerCall(deopt_state_id, Deoptimizer::EAGER); |
371 break; | 404 break; |
372 } | 405 } |
373 case kArchRet: | 406 case kArchRet: |
374 AssembleReturn(); | 407 AssembleReturn(); |
375 break; | 408 break; |
| 409 case kArchFramePointer: |
| 410 __ mov(i.OutputRegister(), ebp); |
| 411 break; |
376 case kArchStackPointer: | 412 case kArchStackPointer: |
377 __ mov(i.OutputRegister(), esp); | 413 __ mov(i.OutputRegister(), esp); |
378 break; | 414 break; |
379 case kArchFramePointer: | |
380 __ mov(i.OutputRegister(), ebp); | |
381 break; | |
382 case kArchTruncateDoubleToI: { | 415 case kArchTruncateDoubleToI: { |
383 auto result = i.OutputRegister(); | |
384 auto input = i.InputDoubleRegister(0); | 416 auto input = i.InputDoubleRegister(0); |
385 auto ool = new (zone()) OutOfLineTruncateDoubleToI(this, result, input); | 417 USE(input); |
386 __ cvttsd2si(result, Operand(input)); | 418 DCHECK(input.code() == 0); |
387 __ cmp(result, 1); | 419 auto result_reg = i.OutputRegister(); |
388 __ j(overflow, ool->entry()); | 420 __ TruncateX87TOSToI(result_reg); |
389 __ bind(ool->exit()); | 421 break; |
390 break; | 422 } |
391 } | 423 case kX87Add: |
392 case kIA32Add: | |
393 if (HasImmediateInput(instr, 1)) { | 424 if (HasImmediateInput(instr, 1)) { |
394 __ add(i.InputOperand(0), i.InputImmediate(1)); | 425 __ add(i.InputOperand(0), i.InputImmediate(1)); |
395 } else { | 426 } else { |
396 __ add(i.InputRegister(0), i.InputOperand(1)); | 427 __ add(i.InputRegister(0), i.InputOperand(1)); |
397 } | 428 } |
398 break; | 429 break; |
399 case kIA32And: | 430 case kX87And: |
400 if (HasImmediateInput(instr, 1)) { | 431 if (HasImmediateInput(instr, 1)) { |
401 __ and_(i.InputOperand(0), i.InputImmediate(1)); | 432 __ and_(i.InputOperand(0), i.InputImmediate(1)); |
402 } else { | 433 } else { |
403 __ and_(i.InputRegister(0), i.InputOperand(1)); | 434 __ and_(i.InputRegister(0), i.InputOperand(1)); |
404 } | 435 } |
405 break; | 436 break; |
406 case kIA32Cmp: | 437 case kX87Cmp: |
407 if (HasImmediateInput(instr, 1)) { | 438 if (HasImmediateInput(instr, 1)) { |
408 __ cmp(i.InputOperand(0), i.InputImmediate(1)); | 439 __ cmp(i.InputOperand(0), i.InputImmediate(1)); |
409 } else { | 440 } else { |
410 __ cmp(i.InputRegister(0), i.InputOperand(1)); | 441 __ cmp(i.InputRegister(0), i.InputOperand(1)); |
411 } | 442 } |
412 break; | 443 break; |
413 case kIA32Test: | 444 case kX87Test: |
414 if (HasImmediateInput(instr, 1)) { | 445 if (HasImmediateInput(instr, 1)) { |
415 __ test(i.InputOperand(0), i.InputImmediate(1)); | 446 __ test(i.InputOperand(0), i.InputImmediate(1)); |
416 } else { | 447 } else { |
417 __ test(i.InputRegister(0), i.InputOperand(1)); | 448 __ test(i.InputRegister(0), i.InputOperand(1)); |
418 } | 449 } |
419 break; | 450 break; |
420 case kIA32Imul: | 451 case kX87Imul: |
421 if (HasImmediateInput(instr, 1)) { | 452 if (HasImmediateInput(instr, 1)) { |
422 __ imul(i.OutputRegister(), i.InputOperand(0), i.InputInt32(1)); | 453 __ imul(i.OutputRegister(), i.InputOperand(0), i.InputInt32(1)); |
423 } else { | 454 } else { |
424 __ imul(i.OutputRegister(), i.InputOperand(1)); | 455 __ imul(i.OutputRegister(), i.InputOperand(1)); |
425 } | 456 } |
426 break; | 457 break; |
427 case kIA32ImulHigh: | 458 case kX87ImulHigh: |
428 __ imul(i.InputRegister(1)); | 459 __ imul(i.InputRegister(1)); |
429 break; | 460 break; |
430 case kIA32UmulHigh: | 461 case kX87UmulHigh: |
431 __ mul(i.InputRegister(1)); | 462 __ mul(i.InputRegister(1)); |
432 break; | 463 break; |
433 case kIA32Idiv: | 464 case kX87Idiv: |
434 __ cdq(); | 465 __ cdq(); |
435 __ idiv(i.InputOperand(1)); | 466 __ idiv(i.InputOperand(1)); |
436 break; | 467 break; |
437 case kIA32Udiv: | 468 case kX87Udiv: |
438 __ Move(edx, Immediate(0)); | 469 __ Move(edx, Immediate(0)); |
439 __ div(i.InputOperand(1)); | 470 __ div(i.InputOperand(1)); |
440 break; | 471 break; |
441 case kIA32Not: | 472 case kX87Not: |
442 __ not_(i.OutputOperand()); | 473 __ not_(i.OutputOperand()); |
443 break; | 474 break; |
444 case kIA32Neg: | 475 case kX87Neg: |
445 __ neg(i.OutputOperand()); | 476 __ neg(i.OutputOperand()); |
446 break; | 477 break; |
447 case kIA32Or: | 478 case kX87Or: |
448 if (HasImmediateInput(instr, 1)) { | 479 if (HasImmediateInput(instr, 1)) { |
449 __ or_(i.InputOperand(0), i.InputImmediate(1)); | 480 __ or_(i.InputOperand(0), i.InputImmediate(1)); |
450 } else { | 481 } else { |
451 __ or_(i.InputRegister(0), i.InputOperand(1)); | 482 __ or_(i.InputRegister(0), i.InputOperand(1)); |
452 } | 483 } |
453 break; | 484 break; |
454 case kIA32Xor: | 485 case kX87Xor: |
455 if (HasImmediateInput(instr, 1)) { | 486 if (HasImmediateInput(instr, 1)) { |
456 __ xor_(i.InputOperand(0), i.InputImmediate(1)); | 487 __ xor_(i.InputOperand(0), i.InputImmediate(1)); |
457 } else { | 488 } else { |
458 __ xor_(i.InputRegister(0), i.InputOperand(1)); | 489 __ xor_(i.InputRegister(0), i.InputOperand(1)); |
459 } | 490 } |
460 break; | 491 break; |
461 case kIA32Sub: | 492 case kX87Sub: |
462 if (HasImmediateInput(instr, 1)) { | 493 if (HasImmediateInput(instr, 1)) { |
463 __ sub(i.InputOperand(0), i.InputImmediate(1)); | 494 __ sub(i.InputOperand(0), i.InputImmediate(1)); |
464 } else { | 495 } else { |
465 __ sub(i.InputRegister(0), i.InputOperand(1)); | 496 __ sub(i.InputRegister(0), i.InputOperand(1)); |
466 } | 497 } |
467 break; | 498 break; |
468 case kIA32Shl: | 499 case kX87Shl: |
469 if (HasImmediateInput(instr, 1)) { | 500 if (HasImmediateInput(instr, 1)) { |
470 __ shl(i.OutputOperand(), i.InputInt5(1)); | 501 __ shl(i.OutputOperand(), i.InputInt5(1)); |
471 } else { | 502 } else { |
472 __ shl_cl(i.OutputOperand()); | 503 __ shl_cl(i.OutputOperand()); |
473 } | 504 } |
474 break; | 505 break; |
475 case kIA32Shr: | 506 case kX87Shr: |
476 if (HasImmediateInput(instr, 1)) { | 507 if (HasImmediateInput(instr, 1)) { |
477 __ shr(i.OutputOperand(), i.InputInt5(1)); | 508 __ shr(i.OutputOperand(), i.InputInt5(1)); |
478 } else { | 509 } else { |
479 __ shr_cl(i.OutputOperand()); | 510 __ shr_cl(i.OutputOperand()); |
480 } | 511 } |
481 break; | 512 break; |
482 case kIA32Sar: | 513 case kX87Sar: |
483 if (HasImmediateInput(instr, 1)) { | 514 if (HasImmediateInput(instr, 1)) { |
484 __ sar(i.OutputOperand(), i.InputInt5(1)); | 515 __ sar(i.OutputOperand(), i.InputInt5(1)); |
485 } else { | 516 } else { |
486 __ sar_cl(i.OutputOperand()); | 517 __ sar_cl(i.OutputOperand()); |
487 } | 518 } |
488 break; | 519 break; |
489 case kIA32Ror: | 520 case kX87Ror: |
490 if (HasImmediateInput(instr, 1)) { | 521 if (HasImmediateInput(instr, 1)) { |
491 __ ror(i.OutputOperand(), i.InputInt5(1)); | 522 __ ror(i.OutputOperand(), i.InputInt5(1)); |
492 } else { | 523 } else { |
493 __ ror_cl(i.OutputOperand()); | 524 __ ror_cl(i.OutputOperand()); |
494 } | 525 } |
495 break; | 526 break; |
496 case kIA32Lzcnt: | 527 case kX87Lzcnt: |
497 __ Lzcnt(i.OutputRegister(), i.InputOperand(0)); | 528 __ Lzcnt(i.OutputRegister(), i.InputOperand(0)); |
498 break; | 529 break; |
499 case kSSEFloat32Cmp: | 530 case kX87LoadFloat64Constant: { |
500 __ ucomiss(i.InputDoubleRegister(0), i.InputOperand(1)); | 531 InstructionOperand* source = instr->InputAt(0); |
501 break; | 532 InstructionOperand* destination = instr->Output(); |
502 case kSSEFloat32Add: | 533 DCHECK(source->IsConstant()); |
503 __ addss(i.InputDoubleRegister(0), i.InputOperand(1)); | 534 X87OperandConverter g(this, NULL); |
504 break; | 535 Constant src_constant = g.ToConstant(source); |
505 case kSSEFloat32Sub: | 536 |
506 __ subss(i.InputDoubleRegister(0), i.InputOperand(1)); | 537 DCHECK_EQ(Constant::kFloat64, src_constant.type()); |
507 break; | 538 uint64_t src = bit_cast<uint64_t>(src_constant.ToFloat64()); |
508 case kSSEFloat32Mul: | 539 uint32_t lower = static_cast<uint32_t>(src); |
509 __ mulss(i.InputDoubleRegister(0), i.InputOperand(1)); | 540 uint32_t upper = static_cast<uint32_t>(src >> 32); |
510 break; | 541 if (destination->IsDoubleRegister()) { |
511 case kSSEFloat32Div: | 542 __ sub(esp, Immediate(kDoubleSize)); |
512 __ divss(i.InputDoubleRegister(0), i.InputOperand(1)); | 543 __ mov(MemOperand(esp, 0), Immediate(lower)); |
513 // Don't delete this mov. It may improve performance on some CPUs, | 544 __ mov(MemOperand(esp, kInt32Size), Immediate(upper)); |
514 // when there is a (v)mulss depending on the result. | 545 __ fstp(0); |
515 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister()); | 546 __ fld_d(MemOperand(esp, 0)); |
516 break; | 547 __ add(esp, Immediate(kDoubleSize)); |
517 case kSSEFloat32Max: | 548 } else { |
518 __ maxss(i.InputDoubleRegister(0), i.InputOperand(1)); | 549 UNREACHABLE(); |
519 break; | 550 } |
520 case kSSEFloat32Min: | 551 break; |
521 __ minss(i.InputDoubleRegister(0), i.InputOperand(1)); | 552 } |
522 break; | 553 case kX87Float32Cmp: { |
523 case kSSEFloat32Sqrt: | 554 __ fld_s(MemOperand(esp, kFloatSize)); |
524 __ sqrtss(i.OutputDoubleRegister(), i.InputOperand(0)); | 555 __ fld_s(MemOperand(esp, 0)); |
525 break; | 556 __ FCmp(); |
526 case kSSEFloat32Abs: { | 557 __ lea(esp, Operand(esp, 2 * kFloatSize)); |
527 // TODO(bmeurer): Use 128-bit constants. | 558 break; |
528 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); | 559 } |
529 __ psrlq(kScratchDoubleReg, 33); | 560 case kX87Float32Add: { |
530 __ andps(i.OutputDoubleRegister(), kScratchDoubleReg); | 561 __ X87SetFPUCW(0x027F); |
531 break; | 562 __ fstp(0); |
532 } | 563 __ fld_s(MemOperand(esp, 0)); |
533 case kSSEFloat32Neg: { | 564 __ fld_s(MemOperand(esp, kFloatSize)); |
534 // TODO(bmeurer): Use 128-bit constants. | 565 __ faddp(); |
535 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); | 566 // Clear stack. |
536 __ psllq(kScratchDoubleReg, 31); | 567 __ lea(esp, Operand(esp, 2 * kFloatSize)); |
537 __ xorps(i.OutputDoubleRegister(), kScratchDoubleReg); | 568 // Restore the default value of control word. |
538 break; | 569 __ X87SetFPUCW(0x037F); |
539 } | 570 break; |
540 case kSSEFloat64Cmp: | 571 } |
541 __ ucomisd(i.InputDoubleRegister(0), i.InputOperand(1)); | 572 case kX87Float32Sub: { |
542 break; | 573 __ X87SetFPUCW(0x027F); |
543 case kSSEFloat64Add: | 574 __ fstp(0); |
544 __ addsd(i.InputDoubleRegister(0), i.InputOperand(1)); | 575 __ fld_s(MemOperand(esp, kFloatSize)); |
545 break; | 576 __ fld_s(MemOperand(esp, 0)); |
546 case kSSEFloat64Sub: | 577 __ fsubp(); |
547 __ subsd(i.InputDoubleRegister(0), i.InputOperand(1)); | 578 // Clear stack. |
548 break; | 579 __ lea(esp, Operand(esp, 2 * kFloatSize)); |
549 case kSSEFloat64Mul: | 580 // Restore the default value of control word. |
550 __ mulsd(i.InputDoubleRegister(0), i.InputOperand(1)); | 581 __ X87SetFPUCW(0x037F); |
551 break; | 582 break; |
552 case kSSEFloat64Div: | 583 } |
553 __ divsd(i.InputDoubleRegister(0), i.InputOperand(1)); | 584 case kX87Float32Mul: { |
554 // Don't delete this mov. It may improve performance on some CPUs, | 585 __ X87SetFPUCW(0x027F); |
555 // when there is a (v)mulsd depending on the result. | 586 __ fstp(0); |
556 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister()); | 587 __ fld_s(MemOperand(esp, kFloatSize)); |
557 break; | 588 __ fld_s(MemOperand(esp, 0)); |
558 case kSSEFloat64Max: | 589 __ fmulp(); |
559 __ maxsd(i.InputDoubleRegister(0), i.InputOperand(1)); | 590 // Clear stack. |
560 break; | 591 __ lea(esp, Operand(esp, 2 * kFloatSize)); |
561 case kSSEFloat64Min: | 592 // Restore the default value of control word. |
562 __ minsd(i.InputDoubleRegister(0), i.InputOperand(1)); | 593 __ X87SetFPUCW(0x037F); |
563 break; | 594 break; |
564 case kSSEFloat64Mod: { | 595 } |
565 // TODO(dcarney): alignment is wrong. | 596 case kX87Float32Div: { |
| 597 __ X87SetFPUCW(0x027F); |
| 598 __ fstp(0); |
| 599 __ fld_s(MemOperand(esp, kFloatSize)); |
| 600 __ fld_s(MemOperand(esp, 0)); |
| 601 __ fdivp(); |
| 602 // Clear stack. |
| 603 __ lea(esp, Operand(esp, 2 * kFloatSize)); |
| 604 // Restore the default value of control word. |
| 605 __ X87SetFPUCW(0x037F); |
| 606 break; |
| 607 } |
| 608 case kX87Float32Max: { |
| 609 Label check_nan_left, check_zero, return_left, return_right; |
| 610 Condition condition = below; |
| 611 __ fstp(0); |
| 612 __ fld_s(MemOperand(esp, kFloatSize)); |
| 613 __ fld_s(MemOperand(esp, 0)); |
| 614 __ fld(1); |
| 615 __ fld(1); |
| 616 __ FCmp(); |
| 617 __ j(parity_even, &check_nan_left, Label::kNear); // At least one NaN. |
| 618 __ j(equal, &check_zero, Label::kNear); // left == right. |
| 619 __ j(condition, &return_left, Label::kNear); |
| 620 __ jmp(&return_right, Label::kNear); |
| 621 |
| 622 __ bind(&check_zero); |
| 623 __ fld(0); |
| 624 __ fldz(); |
| 625 __ FCmp(); |
| 626 __ j(not_equal, &return_left, Label::kNear); // left == right != 0. |
| 627 |
| 628 __ fadd(1); |
| 629 __ jmp(&return_left, Label::kNear); |
| 630 |
| 631 __ bind(&check_nan_left); |
| 632 __ fld(0); |
| 633 __ fld(0); |
| 634 __ FCmp(); // NaN check. |
| 635 __ j(parity_even, &return_left, Label::kNear); // left == NaN. |
| 636 |
| 637 __ bind(&return_right); |
| 638 __ fxch(); |
| 639 |
| 640 __ bind(&return_left); |
| 641 __ fstp(0); |
| 642 __ lea(esp, Operand(esp, 2 * kFloatSize)); |
| 643 break; |
| 644 } |
| 645 case kX87Float32Min: { |
| 646 Label check_nan_left, check_zero, return_left, return_right; |
| 647 Condition condition = above; |
| 648 __ fstp(0); |
| 649 __ fld_s(MemOperand(esp, kFloatSize)); |
| 650 __ fld_s(MemOperand(esp, 0)); |
| 651 __ fld(1); |
| 652 __ fld(1); |
| 653 __ FCmp(); |
| 654 __ j(parity_even, &check_nan_left, Label::kNear); // At least one NaN. |
| 655 __ j(equal, &check_zero, Label::kNear); // left == right. |
| 656 __ j(condition, &return_left, Label::kNear); |
| 657 __ jmp(&return_right, Label::kNear); |
| 658 |
| 659 __ bind(&check_zero); |
| 660 __ fld(0); |
| 661 __ fldz(); |
| 662 __ FCmp(); |
| 663 __ j(not_equal, &return_left, Label::kNear); // left == right != 0. |
| 664 // At this point, both left and right are either 0 or -0. |
| 665 // Push st0 and st1 to stack, then pop them to temp registers and OR them, |
| 666 // load it to left. |
| 667 __ push(eax); |
| 668 __ fld(1); |
| 669 __ fld(1); |
| 670 __ sub(esp, Immediate(2 * kPointerSize)); |
| 671 __ fstp_s(MemOperand(esp, 0)); |
| 672 __ fstp_s(MemOperand(esp, kPointerSize)); |
| 673 __ pop(eax); |
| 674 __ xor_(MemOperand(esp, 0), eax); |
| 675 __ fstp(0); |
| 676 __ fld_s(MemOperand(esp, 0)); |
| 677 __ pop(eax); // restore esp |
| 678 __ pop(eax); // restore esp |
| 679 __ jmp(&return_left, Label::kNear); |
| 680 |
| 681 __ bind(&check_nan_left); |
| 682 __ fld(0); |
| 683 __ fld(0); |
| 684 __ FCmp(); // NaN check. |
| 685 __ j(parity_even, &return_left, Label::kNear); // left == NaN. |
| 686 |
| 687 __ bind(&return_right); |
| 688 __ fxch(); |
| 689 |
| 690 __ bind(&return_left); |
| 691 __ fstp(0); |
| 692 __ lea(esp, Operand(esp, 2 * kFloatSize)); |
| 693 break; |
| 694 } |
| 695 case kX87Float32Sqrt: { |
| 696 __ fstp(0); |
| 697 __ fld_s(MemOperand(esp, 0)); |
| 698 __ fsqrt(); |
| 699 __ lea(esp, Operand(esp, kFloatSize)); |
| 700 break; |
| 701 } |
| 702 case kX87Float32Abs: { |
| 703 __ fstp(0); |
| 704 __ fld_s(MemOperand(esp, 0)); |
| 705 __ fabs(); |
| 706 __ lea(esp, Operand(esp, kFloatSize)); |
| 707 break; |
| 708 } |
| 709 case kX87Float64Add: { |
| 710 __ X87SetFPUCW(0x027F); |
| 711 __ fstp(0); |
| 712 __ fld_d(MemOperand(esp, 0)); |
| 713 __ fld_d(MemOperand(esp, kDoubleSize)); |
| 714 __ faddp(); |
| 715 // Clear stack. |
| 716 __ lea(esp, Operand(esp, 2 * kDoubleSize)); |
| 717 // Restore the default value of control word. |
| 718 __ X87SetFPUCW(0x037F); |
| 719 break; |
| 720 } |
| 721 case kX87Float64Sub: { |
| 722 __ X87SetFPUCW(0x027F); |
| 723 __ fstp(0); |
| 724 __ fld_d(MemOperand(esp, kDoubleSize)); |
| 725 __ fsub_d(MemOperand(esp, 0)); |
| 726 // Clear stack. |
| 727 __ lea(esp, Operand(esp, 2 * kDoubleSize)); |
| 728 // Restore the default value of control word. |
| 729 __ X87SetFPUCW(0x037F); |
| 730 break; |
| 731 } |
| 732 case kX87Float64Mul: { |
| 733 __ X87SetFPUCW(0x027F); |
| 734 __ fstp(0); |
| 735 __ fld_d(MemOperand(esp, kDoubleSize)); |
| 736 __ fmul_d(MemOperand(esp, 0)); |
| 737 // Clear stack. |
| 738 __ lea(esp, Operand(esp, 2 * kDoubleSize)); |
| 739 // Restore the default value of control word. |
| 740 __ X87SetFPUCW(0x037F); |
| 741 break; |
| 742 } |
| 743 case kX87Float64Div: { |
| 744 __ X87SetFPUCW(0x027F); |
| 745 __ fstp(0); |
| 746 __ fld_d(MemOperand(esp, kDoubleSize)); |
| 747 __ fdiv_d(MemOperand(esp, 0)); |
| 748 // Clear stack. |
| 749 __ lea(esp, Operand(esp, 2 * kDoubleSize)); |
| 750 // Restore the default value of control word. |
| 751 __ X87SetFPUCW(0x037F); |
| 752 break; |
| 753 } |
| 754 case kX87Float64Mod: { |
| 755 FrameScope frame_scope(&masm_, StackFrame::MANUAL); |
| 756 __ mov(eax, esp); |
| 757 __ PrepareCallCFunction(4, eax); |
| 758 __ fstp(0); |
| 759 __ fld_d(MemOperand(eax, 0)); |
| 760 __ fstp_d(Operand(esp, 1 * kDoubleSize)); |
| 761 __ fld_d(MemOperand(eax, kDoubleSize)); |
| 762 __ fstp_d(Operand(esp, 0)); |
| 763 __ CallCFunction( |
| 764 ExternalReference::mod_two_doubles_operation(isolate()), 4); |
| 765 __ lea(esp, Operand(esp, 2 * kDoubleSize)); |
| 766 break; |
| 767 } |
| 768 case kX87Float64Max: { |
| 769 Label check_nan_left, check_zero, return_left, return_right; |
| 770 Condition condition = below; |
| 771 __ fstp(0); |
| 772 __ fld_d(MemOperand(esp, kDoubleSize)); |
| 773 __ fld_d(MemOperand(esp, 0)); |
| 774 __ fld(1); |
| 775 __ fld(1); |
| 776 __ FCmp(); |
| 777 __ j(parity_even, &check_nan_left, Label::kNear); // At least one NaN. |
| 778 __ j(equal, &check_zero, Label::kNear); // left == right. |
| 779 __ j(condition, &return_left, Label::kNear); |
| 780 __ jmp(&return_right, Label::kNear); |
| 781 |
| 782 __ bind(&check_zero); |
| 783 __ fld(0); |
| 784 __ fldz(); |
| 785 __ FCmp(); |
| 786 __ j(not_equal, &return_left, Label::kNear); // left == right != 0. |
| 787 |
| 788 __ fadd(1); |
| 789 __ jmp(&return_left, Label::kNear); |
| 790 |
| 791 __ bind(&check_nan_left); |
| 792 __ fld(0); |
| 793 __ fld(0); |
| 794 __ FCmp(); // NaN check. |
| 795 __ j(parity_even, &return_left, Label::kNear); // left == NaN. |
| 796 |
| 797 __ bind(&return_right); |
| 798 __ fxch(); |
| 799 |
| 800 __ bind(&return_left); |
| 801 __ fstp(0); |
| 802 __ lea(esp, Operand(esp, 2 * kDoubleSize)); |
| 803 break; |
| 804 } |
| 805 case kX87Float64Min: { |
| 806 Label check_nan_left, check_zero, return_left, return_right; |
| 807 Condition condition = above; |
| 808 __ fstp(0); |
| 809 __ fld_d(MemOperand(esp, kDoubleSize)); |
| 810 __ fld_d(MemOperand(esp, 0)); |
| 811 __ fld(1); |
| 812 __ fld(1); |
| 813 __ FCmp(); |
| 814 __ j(parity_even, &check_nan_left, Label::kNear); // At least one NaN. |
| 815 __ j(equal, &check_zero, Label::kNear); // left == right. |
| 816 __ j(condition, &return_left, Label::kNear); |
| 817 __ jmp(&return_right, Label::kNear); |
| 818 |
| 819 __ bind(&check_zero); |
| 820 __ fld(0); |
| 821 __ fldz(); |
| 822 __ FCmp(); |
| 823 __ j(not_equal, &return_left, Label::kNear); // left == right != 0. |
| 824 // At this point, both left and right are either 0 or -0. |
| 825 // Push st0 and st1 to stack, then pop them to temp registers and OR them, |
| 826 // load it to left. |
| 827 __ push(eax); |
| 828 __ fld(1); |
| 829 __ fld(1); |
| 830 __ sub(esp, Immediate(2 * kPointerSize)); |
| 831 __ fstp_s(MemOperand(esp, 0)); |
| 832 __ fstp_s(MemOperand(esp, kPointerSize)); |
| 833 __ pop(eax); |
| 834 __ xor_(MemOperand(esp, 0), eax); |
| 835 __ fstp(0); |
| 836 __ fld_s(MemOperand(esp, 0)); |
| 837 __ pop(eax); // restore esp |
| 838 __ pop(eax); // restore esp |
| 839 __ jmp(&return_left, Label::kNear); |
| 840 |
| 841 __ bind(&check_nan_left); |
| 842 __ fld(0); |
| 843 __ fld(0); |
| 844 __ FCmp(); // NaN check. |
| 845 __ j(parity_even, &return_left, Label::kNear); // left == NaN. |
| 846 |
| 847 __ bind(&return_right); |
| 848 __ fxch(); |
| 849 |
| 850 __ bind(&return_left); |
| 851 __ fstp(0); |
| 852 __ lea(esp, Operand(esp, 2 * kDoubleSize)); |
| 853 break; |
| 854 } |
| 855 case kX87Float64Abs: { |
| 856 __ fstp(0); |
| 857 __ fld_d(MemOperand(esp, 0)); |
| 858 __ fabs(); |
| 859 __ lea(esp, Operand(esp, kDoubleSize)); |
| 860 break; |
| 861 } |
| 862 case kX87Int32ToFloat64: { |
| 863 InstructionOperand* input = instr->InputAt(0); |
| 864 DCHECK(input->IsRegister() || input->IsStackSlot()); |
| 865 __ fstp(0); |
| 866 if (input->IsRegister()) { |
| 867 Register input_reg = i.InputRegister(0); |
| 868 __ push(input_reg); |
| 869 __ fild_s(Operand(esp, 0)); |
| 870 __ pop(input_reg); |
| 871 } else { |
| 872 __ fild_s(i.InputOperand(0)); |
| 873 } |
| 874 break; |
| 875 } |
| 876 case kX87Float32ToFloat64: { |
| 877 InstructionOperand* input = instr->InputAt(0); |
| 878 if (input->IsDoubleRegister()) { |
| 879 __ sub(esp, Immediate(kDoubleSize)); |
| 880 __ fstp_d(MemOperand(esp, 0)); |
| 881 __ fld_d(MemOperand(esp, 0)); |
| 882 __ add(esp, Immediate(kDoubleSize)); |
| 883 } else { |
| 884 DCHECK(input->IsDoubleStackSlot()); |
| 885 __ fstp(0); |
| 886 __ fld_s(i.InputOperand(0)); |
| 887 } |
| 888 break; |
| 889 } |
| 890 case kX87Uint32ToFloat64: { |
| 891 __ fstp(0); |
| 892 __ LoadUint32NoSSE2(i.InputRegister(0)); |
| 893 break; |
| 894 } |
| 895 case kX87Float64ToInt32: { |
| 896 if (!instr->InputAt(0)->IsDoubleRegister()) { |
| 897 __ fld_d(i.InputOperand(0)); |
| 898 } |
| 899 __ TruncateX87TOSToI(i.OutputRegister(0)); |
| 900 if (!instr->InputAt(0)->IsDoubleRegister()) { |
| 901 __ fstp(0); |
| 902 } |
| 903 break; |
| 904 } |
| 905 case kX87Float64ToFloat32: { |
| 906 InstructionOperand* input = instr->InputAt(0); |
| 907 if (input->IsDoubleRegister()) { |
| 908 __ sub(esp, Immediate(kDoubleSize)); |
| 909 __ fstp_s(MemOperand(esp, 0)); |
| 910 __ fld_s(MemOperand(esp, 0)); |
| 911 __ add(esp, Immediate(kDoubleSize)); |
| 912 } else { |
| 913 DCHECK(input->IsDoubleStackSlot()); |
| 914 __ fstp(0); |
| 915 __ fld_d(i.InputOperand(0)); |
| 916 __ sub(esp, Immediate(kDoubleSize)); |
| 917 __ fstp_s(MemOperand(esp, 0)); |
| 918 __ fld_s(MemOperand(esp, 0)); |
| 919 __ add(esp, Immediate(kDoubleSize)); |
| 920 } |
| 921 break; |
| 922 } |
| 923 case kX87Float64ToUint32: { |
| 924 __ push_imm32(-2147483648); |
| 925 if (!instr->InputAt(0)->IsDoubleRegister()) { |
| 926 __ fld_d(i.InputOperand(0)); |
| 927 } |
| 928 __ fild_s(Operand(esp, 0)); |
| 929 __ fadd(1); |
| 930 __ fstp(0); |
| 931 __ TruncateX87TOSToI(i.OutputRegister(0)); |
| 932 __ add(esp, Immediate(kInt32Size)); |
| 933 __ add(i.OutputRegister(), Immediate(0x80000000)); |
| 934 if (!instr->InputAt(0)->IsDoubleRegister()) { |
| 935 __ fstp(0); |
| 936 } |
| 937 break; |
| 938 } |
| 939 case kX87Float64ExtractHighWord32: { |
| 940 if (instr->InputAt(0)->IsDoubleRegister()) { |
| 941 __ sub(esp, Immediate(kDoubleSize)); |
| 942 __ fst_d(MemOperand(esp, 0)); |
| 943 __ mov(i.OutputRegister(), MemOperand(esp, kDoubleSize / 2)); |
| 944 __ add(esp, Immediate(kDoubleSize)); |
| 945 } else { |
| 946 InstructionOperand* input = instr->InputAt(0); |
| 947 USE(input); |
| 948 DCHECK(input->IsDoubleStackSlot()); |
| 949 __ mov(i.OutputRegister(), i.InputOperand(0, kDoubleSize / 2)); |
| 950 } |
| 951 break; |
| 952 } |
| 953 case kX87Float64ExtractLowWord32: { |
| 954 if (instr->InputAt(0)->IsDoubleRegister()) { |
| 955 __ sub(esp, Immediate(kDoubleSize)); |
| 956 __ fst_d(MemOperand(esp, 0)); |
| 957 __ mov(i.OutputRegister(), MemOperand(esp, 0)); |
| 958 __ add(esp, Immediate(kDoubleSize)); |
| 959 } else { |
| 960 InstructionOperand* input = instr->InputAt(0); |
| 961 USE(input); |
| 962 DCHECK(input->IsDoubleStackSlot()); |
| 963 __ mov(i.OutputRegister(), i.InputOperand(0)); |
| 964 } |
| 965 break; |
| 966 } |
| 967 case kX87Float64InsertHighWord32: { |
566 __ sub(esp, Immediate(kDoubleSize)); | 968 __ sub(esp, Immediate(kDoubleSize)); |
567 // Move values to st(0) and st(1). | 969 __ fstp_d(MemOperand(esp, 0)); |
568 __ movsd(Operand(esp, 0), i.InputDoubleRegister(1)); | 970 __ mov(MemOperand(esp, kDoubleSize / 2), i.InputRegister(1)); |
569 __ fld_d(Operand(esp, 0)); | 971 __ fld_d(MemOperand(esp, 0)); |
570 __ movsd(Operand(esp, 0), i.InputDoubleRegister(0)); | |
571 __ fld_d(Operand(esp, 0)); | |
572 // Loop while fprem isn't done. | |
573 Label mod_loop; | |
574 __ bind(&mod_loop); | |
575 // This instructions traps on all kinds inputs, but we are assuming the | |
576 // floating point control word is set to ignore them all. | |
577 __ fprem(); | |
578 // The following 2 instruction implicitly use eax. | |
579 __ fnstsw_ax(); | |
580 __ sahf(); | |
581 __ j(parity_even, &mod_loop); | |
582 // Move output to stack and clean up. | |
583 __ fstp(1); | |
584 __ fstp_d(Operand(esp, 0)); | |
585 __ movsd(i.OutputDoubleRegister(), Operand(esp, 0)); | |
586 __ add(esp, Immediate(kDoubleSize)); | 972 __ add(esp, Immediate(kDoubleSize)); |
587 break; | 973 break; |
588 } | 974 } |
589 case kSSEFloat64Abs: { | 975 case kX87Float64InsertLowWord32: { |
590 // TODO(bmeurer): Use 128-bit constants. | 976 __ sub(esp, Immediate(kDoubleSize)); |
591 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); | 977 __ fstp_d(MemOperand(esp, 0)); |
592 __ psrlq(kScratchDoubleReg, 1); | 978 __ mov(MemOperand(esp, 0), i.InputRegister(1)); |
593 __ andpd(i.OutputDoubleRegister(), kScratchDoubleReg); | 979 __ fld_d(MemOperand(esp, 0)); |
594 break; | 980 __ add(esp, Immediate(kDoubleSize)); |
595 } | 981 break; |
596 case kSSEFloat64Neg: { | 982 } |
597 // TODO(bmeurer): Use 128-bit constants. | 983 case kX87Float64Sqrt: { |
598 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); | 984 __ fstp(0); |
599 __ psllq(kScratchDoubleReg, 63); | 985 __ fld_d(MemOperand(esp, 0)); |
600 __ xorpd(i.OutputDoubleRegister(), kScratchDoubleReg); | 986 __ fsqrt(); |
601 break; | 987 __ lea(esp, Operand(esp, kDoubleSize)); |
602 } | 988 break; |
603 case kSSEFloat64Sqrt: | 989 } |
604 __ sqrtsd(i.OutputDoubleRegister(), i.InputOperand(0)); | 990 case kX87Float64Round: { |
605 break; | 991 RoundingMode mode = |
606 case kSSEFloat64Round: { | |
607 CpuFeatureScope sse_scope(masm(), SSE4_1); | |
608 RoundingMode const mode = | |
609 static_cast<RoundingMode>(MiscField::decode(instr->opcode())); | 992 static_cast<RoundingMode>(MiscField::decode(instr->opcode())); |
610 __ roundsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), mode); | 993 if (mode == MiscField::encode(kRoundDown)) { |
611 break; | 994 __ X87SetRC(0x0400); |
612 } | 995 } else { |
613 case kSSEFloat32ToFloat64: | 996 __ X87SetRC(0x0c00); |
614 __ cvtss2sd(i.OutputDoubleRegister(), i.InputOperand(0)); | 997 } |
615 break; | 998 |
616 case kSSEFloat64ToFloat32: | 999 if (!instr->InputAt(0)->IsDoubleRegister()) { |
617 __ cvtsd2ss(i.OutputDoubleRegister(), i.InputOperand(0)); | 1000 InstructionOperand* input = instr->InputAt(0); |
618 break; | 1001 USE(input); |
619 case kSSEFloat64ToInt32: | 1002 DCHECK(input->IsDoubleStackSlot()); |
620 __ cvttsd2si(i.OutputRegister(), i.InputOperand(0)); | 1003 __ fstp(0); |
621 break; | 1004 __ fld_d(i.InputOperand(0)); |
622 case kSSEFloat64ToUint32: { | 1005 } |
623 __ Move(kScratchDoubleReg, -2147483648.0); | 1006 __ frndint(); |
624 __ addsd(kScratchDoubleReg, i.InputOperand(0)); | 1007 __ X87SetRC(0x0000); |
625 __ cvttsd2si(i.OutputRegister(), kScratchDoubleReg); | 1008 break; |
626 __ add(i.OutputRegister(), Immediate(0x80000000)); | 1009 } |
627 break; | 1010 case kX87Float64Cmp: { |
628 } | 1011 __ fld_d(MemOperand(esp, kDoubleSize)); |
629 case kSSEInt32ToFloat64: | 1012 __ fld_d(MemOperand(esp, 0)); |
630 __ cvtsi2sd(i.OutputDoubleRegister(), i.InputOperand(0)); | 1013 __ FCmp(); |
631 break; | 1014 __ lea(esp, Operand(esp, 2 * kDoubleSize)); |
632 case kSSEUint32ToFloat64: | 1015 break; |
633 __ LoadUint32(i.OutputDoubleRegister(), i.InputOperand(0)); | 1016 } |
634 break; | 1017 case kX87Movsxbl: |
635 case kSSEFloat64ExtractLowWord32: | |
636 if (instr->InputAt(0)->IsDoubleStackSlot()) { | |
637 __ mov(i.OutputRegister(), i.InputOperand(0)); | |
638 } else { | |
639 __ movd(i.OutputRegister(), i.InputDoubleRegister(0)); | |
640 } | |
641 break; | |
642 case kSSEFloat64ExtractHighWord32: | |
643 if (instr->InputAt(0)->IsDoubleStackSlot()) { | |
644 __ mov(i.OutputRegister(), i.InputOperand(0, kDoubleSize / 2)); | |
645 } else { | |
646 __ Pextrd(i.OutputRegister(), i.InputDoubleRegister(0), 1); | |
647 } | |
648 break; | |
649 case kSSEFloat64InsertLowWord32: | |
650 __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 0); | |
651 break; | |
652 case kSSEFloat64InsertHighWord32: | |
653 __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 1); | |
654 break; | |
655 case kSSEFloat64LoadLowWord32: | |
656 __ movd(i.OutputDoubleRegister(), i.InputOperand(0)); | |
657 break; | |
658 case kAVXFloat32Add: { | |
659 CpuFeatureScope avx_scope(masm(), AVX); | |
660 __ vaddss(i.OutputDoubleRegister(), i.InputDoubleRegister(0), | |
661 i.InputOperand(1)); | |
662 break; | |
663 } | |
664 case kAVXFloat32Sub: { | |
665 CpuFeatureScope avx_scope(masm(), AVX); | |
666 __ vsubss(i.OutputDoubleRegister(), i.InputDoubleRegister(0), | |
667 i.InputOperand(1)); | |
668 break; | |
669 } | |
670 case kAVXFloat32Mul: { | |
671 CpuFeatureScope avx_scope(masm(), AVX); | |
672 __ vmulss(i.OutputDoubleRegister(), i.InputDoubleRegister(0), | |
673 i.InputOperand(1)); | |
674 break; | |
675 } | |
676 case kAVXFloat32Div: { | |
677 CpuFeatureScope avx_scope(masm(), AVX); | |
678 __ vdivss(i.OutputDoubleRegister(), i.InputDoubleRegister(0), | |
679 i.InputOperand(1)); | |
680 // Don't delete this mov. It may improve performance on some CPUs, | |
681 // when there is a (v)mulss depending on the result. | |
682 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister()); | |
683 break; | |
684 } | |
685 case kAVXFloat32Max: { | |
686 CpuFeatureScope avx_scope(masm(), AVX); | |
687 __ vmaxss(i.OutputDoubleRegister(), i.InputDoubleRegister(0), | |
688 i.InputOperand(1)); | |
689 break; | |
690 } | |
691 case kAVXFloat32Min: { | |
692 CpuFeatureScope avx_scope(masm(), AVX); | |
693 __ vminss(i.OutputDoubleRegister(), i.InputDoubleRegister(0), | |
694 i.InputOperand(1)); | |
695 break; | |
696 } | |
697 case kAVXFloat64Add: { | |
698 CpuFeatureScope avx_scope(masm(), AVX); | |
699 __ vaddsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), | |
700 i.InputOperand(1)); | |
701 break; | |
702 } | |
703 case kAVXFloat64Sub: { | |
704 CpuFeatureScope avx_scope(masm(), AVX); | |
705 __ vsubsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), | |
706 i.InputOperand(1)); | |
707 break; | |
708 } | |
709 case kAVXFloat64Mul: { | |
710 CpuFeatureScope avx_scope(masm(), AVX); | |
711 __ vmulsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), | |
712 i.InputOperand(1)); | |
713 break; | |
714 } | |
715 case kAVXFloat64Div: { | |
716 CpuFeatureScope avx_scope(masm(), AVX); | |
717 __ vdivsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), | |
718 i.InputOperand(1)); | |
719 // Don't delete this mov. It may improve performance on some CPUs, | |
720 // when there is a (v)mulsd depending on the result. | |
721 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister()); | |
722 break; | |
723 } | |
724 case kAVXFloat64Max: { | |
725 CpuFeatureScope avx_scope(masm(), AVX); | |
726 __ vmaxsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), | |
727 i.InputOperand(1)); | |
728 break; | |
729 } | |
730 case kAVXFloat64Min: { | |
731 CpuFeatureScope avx_scope(masm(), AVX); | |
732 __ vminsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), | |
733 i.InputOperand(1)); | |
734 break; | |
735 } | |
736 case kAVXFloat32Abs: { | |
737 // TODO(bmeurer): Use RIP relative 128-bit constants. | |
738 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); | |
739 __ psrlq(kScratchDoubleReg, 33); | |
740 CpuFeatureScope avx_scope(masm(), AVX); | |
741 __ vandps(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0)); | |
742 break; | |
743 } | |
744 case kAVXFloat32Neg: { | |
745 // TODO(bmeurer): Use RIP relative 128-bit constants. | |
746 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); | |
747 __ psllq(kScratchDoubleReg, 31); | |
748 CpuFeatureScope avx_scope(masm(), AVX); | |
749 __ vxorps(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0)); | |
750 break; | |
751 } | |
752 case kAVXFloat64Abs: { | |
753 // TODO(bmeurer): Use RIP relative 128-bit constants. | |
754 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); | |
755 __ psrlq(kScratchDoubleReg, 1); | |
756 CpuFeatureScope avx_scope(masm(), AVX); | |
757 __ vandpd(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0)); | |
758 break; | |
759 } | |
760 case kAVXFloat64Neg: { | |
761 // TODO(bmeurer): Use RIP relative 128-bit constants. | |
762 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); | |
763 __ psllq(kScratchDoubleReg, 63); | |
764 CpuFeatureScope avx_scope(masm(), AVX); | |
765 __ vxorpd(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0)); | |
766 break; | |
767 } | |
768 case kIA32Movsxbl: | |
769 __ movsx_b(i.OutputRegister(), i.MemoryOperand()); | 1018 __ movsx_b(i.OutputRegister(), i.MemoryOperand()); |
770 break; | 1019 break; |
771 case kIA32Movzxbl: | 1020 case kX87Movzxbl: |
772 __ movzx_b(i.OutputRegister(), i.MemoryOperand()); | 1021 __ movzx_b(i.OutputRegister(), i.MemoryOperand()); |
773 break; | 1022 break; |
774 case kIA32Movb: { | 1023 case kX87Movb: { |
775 size_t index = 0; | 1024 size_t index = 0; |
776 Operand operand = i.MemoryOperand(&index); | 1025 Operand operand = i.MemoryOperand(&index); |
777 if (HasImmediateInput(instr, index)) { | 1026 if (HasImmediateInput(instr, index)) { |
778 __ mov_b(operand, i.InputInt8(index)); | 1027 __ mov_b(operand, i.InputInt8(index)); |
779 } else { | 1028 } else { |
780 __ mov_b(operand, i.InputRegister(index)); | 1029 __ mov_b(operand, i.InputRegister(index)); |
781 } | 1030 } |
782 break; | 1031 break; |
783 } | 1032 } |
784 case kIA32Movsxwl: | 1033 case kX87Movsxwl: |
785 __ movsx_w(i.OutputRegister(), i.MemoryOperand()); | 1034 __ movsx_w(i.OutputRegister(), i.MemoryOperand()); |
786 break; | 1035 break; |
787 case kIA32Movzxwl: | 1036 case kX87Movzxwl: |
788 __ movzx_w(i.OutputRegister(), i.MemoryOperand()); | 1037 __ movzx_w(i.OutputRegister(), i.MemoryOperand()); |
789 break; | 1038 break; |
790 case kIA32Movw: { | 1039 case kX87Movw: { |
791 size_t index = 0; | 1040 size_t index = 0; |
792 Operand operand = i.MemoryOperand(&index); | 1041 Operand operand = i.MemoryOperand(&index); |
793 if (HasImmediateInput(instr, index)) { | 1042 if (HasImmediateInput(instr, index)) { |
794 __ mov_w(operand, i.InputInt16(index)); | 1043 __ mov_w(operand, i.InputInt16(index)); |
795 } else { | 1044 } else { |
796 __ mov_w(operand, i.InputRegister(index)); | 1045 __ mov_w(operand, i.InputRegister(index)); |
797 } | 1046 } |
798 break; | 1047 break; |
799 } | 1048 } |
800 case kIA32Movl: | 1049 case kX87Movl: |
801 if (instr->HasOutput()) { | 1050 if (instr->HasOutput()) { |
802 __ mov(i.OutputRegister(), i.MemoryOperand()); | 1051 __ mov(i.OutputRegister(), i.MemoryOperand()); |
803 } else { | 1052 } else { |
804 size_t index = 0; | 1053 size_t index = 0; |
805 Operand operand = i.MemoryOperand(&index); | 1054 Operand operand = i.MemoryOperand(&index); |
806 if (HasImmediateInput(instr, index)) { | 1055 if (HasImmediateInput(instr, index)) { |
807 __ mov(operand, i.InputImmediate(index)); | 1056 __ mov(operand, i.InputImmediate(index)); |
808 } else { | 1057 } else { |
809 __ mov(operand, i.InputRegister(index)); | 1058 __ mov(operand, i.InputRegister(index)); |
810 } | 1059 } |
811 } | 1060 } |
812 break; | 1061 break; |
813 case kIA32Movsd: | 1062 case kX87Movsd: { |
814 if (instr->HasOutput()) { | 1063 if (instr->HasOutput()) { |
815 __ movsd(i.OutputDoubleRegister(), i.MemoryOperand()); | 1064 X87Register output = i.OutputDoubleRegister(); |
| 1065 USE(output); |
| 1066 DCHECK(output.code() == 0); |
| 1067 __ fstp(0); |
| 1068 __ fld_d(i.MemoryOperand()); |
816 } else { | 1069 } else { |
817 size_t index = 0; | 1070 size_t index = 0; |
818 Operand operand = i.MemoryOperand(&index); | 1071 Operand operand = i.MemoryOperand(&index); |
819 __ movsd(operand, i.InputDoubleRegister(index)); | 1072 __ fst_d(operand); |
820 } | 1073 } |
821 break; | 1074 break; |
822 case kIA32Movss: | 1075 } |
| 1076 case kX87Movss: { |
823 if (instr->HasOutput()) { | 1077 if (instr->HasOutput()) { |
824 __ movss(i.OutputDoubleRegister(), i.MemoryOperand()); | 1078 X87Register output = i.OutputDoubleRegister(); |
| 1079 USE(output); |
| 1080 DCHECK(output.code() == 0); |
| 1081 __ fstp(0); |
| 1082 __ fld_s(i.MemoryOperand()); |
825 } else { | 1083 } else { |
826 size_t index = 0; | 1084 size_t index = 0; |
827 Operand operand = i.MemoryOperand(&index); | 1085 Operand operand = i.MemoryOperand(&index); |
828 __ movss(operand, i.InputDoubleRegister(index)); | 1086 __ fst_s(operand); |
829 } | 1087 } |
830 break; | 1088 break; |
831 case kIA32Lea: { | 1089 } |
| 1090 case kX87Lea: { |
832 AddressingMode mode = AddressingModeField::decode(instr->opcode()); | 1091 AddressingMode mode = AddressingModeField::decode(instr->opcode()); |
833 // Shorten "leal" to "addl", "subl" or "shll" if the register allocation | 1092 // Shorten "leal" to "addl", "subl" or "shll" if the register allocation |
834 // and addressing mode just happens to work out. The "addl"/"subl" forms | 1093 // and addressing mode just happens to work out. The "addl"/"subl" forms |
835 // in these cases are faster based on measurements. | 1094 // in these cases are faster based on measurements. |
836 if (mode == kMode_MI) { | 1095 if (mode == kMode_MI) { |
837 __ Move(i.OutputRegister(), Immediate(i.InputInt32(0))); | 1096 __ Move(i.OutputRegister(), Immediate(i.InputInt32(0))); |
838 } else if (i.InputRegister(0).is(i.OutputRegister())) { | 1097 } else if (i.InputRegister(0).is(i.OutputRegister())) { |
839 if (mode == kMode_MRI) { | 1098 if (mode == kMode_MRI) { |
840 int32_t constant_summand = i.InputInt32(1); | 1099 int32_t constant_summand = i.InputInt32(1); |
841 if (constant_summand > 0) { | 1100 if (constant_summand > 0) { |
(...skipping 14 matching lines...) Expand all Loading... |
856 } else if (mode == kMode_M8) { | 1115 } else if (mode == kMode_M8) { |
857 __ shl(i.OutputRegister(), 3); | 1116 __ shl(i.OutputRegister(), 3); |
858 } else { | 1117 } else { |
859 __ lea(i.OutputRegister(), i.MemoryOperand()); | 1118 __ lea(i.OutputRegister(), i.MemoryOperand()); |
860 } | 1119 } |
861 } else { | 1120 } else { |
862 __ lea(i.OutputRegister(), i.MemoryOperand()); | 1121 __ lea(i.OutputRegister(), i.MemoryOperand()); |
863 } | 1122 } |
864 break; | 1123 break; |
865 } | 1124 } |
866 case kIA32Push: | 1125 case kX87Push: |
867 if (HasImmediateInput(instr, 0)) { | 1126 if (HasImmediateInput(instr, 0)) { |
868 __ push(i.InputImmediate(0)); | 1127 __ push(i.InputImmediate(0)); |
869 } else { | 1128 } else { |
870 __ push(i.InputOperand(0)); | 1129 __ push(i.InputOperand(0)); |
871 } | 1130 } |
872 break; | 1131 break; |
873 case kIA32StoreWriteBarrier: { | 1132 case kX87PushFloat32: |
| 1133 __ lea(esp, Operand(esp, -kFloatSize)); |
| 1134 if (instr->InputAt(0)->IsDoubleStackSlot()) { |
| 1135 __ fld_s(i.InputOperand(0)); |
| 1136 __ fstp_s(MemOperand(esp, 0)); |
| 1137 } else if (instr->InputAt(0)->IsDoubleRegister()) { |
| 1138 __ fst_s(MemOperand(esp, 0)); |
| 1139 } else { |
| 1140 UNREACHABLE(); |
| 1141 } |
| 1142 break; |
| 1143 case kX87PushFloat64: |
| 1144 __ lea(esp, Operand(esp, -kDoubleSize)); |
| 1145 if (instr->InputAt(0)->IsDoubleStackSlot()) { |
| 1146 __ fld_d(i.InputOperand(0)); |
| 1147 __ fstp_d(MemOperand(esp, 0)); |
| 1148 } else if (instr->InputAt(0)->IsDoubleRegister()) { |
| 1149 __ fst_d(MemOperand(esp, 0)); |
| 1150 } else { |
| 1151 UNREACHABLE(); |
| 1152 } |
| 1153 break; |
| 1154 case kX87StoreWriteBarrier: { |
874 Register object = i.InputRegister(0); | 1155 Register object = i.InputRegister(0); |
875 Register value = i.InputRegister(2); | 1156 Register value = i.InputRegister(2); |
876 SaveFPRegsMode mode = | 1157 SaveFPRegsMode mode = |
877 frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs; | 1158 frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs; |
878 if (HasImmediateInput(instr, 1)) { | 1159 if (HasImmediateInput(instr, 1)) { |
879 int index = i.InputInt32(1); | 1160 int index = i.InputInt32(1); |
880 Register scratch = i.TempRegister(1); | 1161 Register scratch = i.TempRegister(1); |
881 __ mov(Operand(object, index), value); | 1162 __ mov(Operand(object, index), value); |
882 __ RecordWriteContextSlot(object, index, value, scratch, mode); | 1163 __ RecordWriteContextSlot(object, index, value, scratch, mode); |
883 } else { | 1164 } else { |
(...skipping 13 matching lines...) Expand all Loading... |
897 case kCheckedLoadInt16: | 1178 case kCheckedLoadInt16: |
898 ASSEMBLE_CHECKED_LOAD_INTEGER(movsx_w); | 1179 ASSEMBLE_CHECKED_LOAD_INTEGER(movsx_w); |
899 break; | 1180 break; |
900 case kCheckedLoadUint16: | 1181 case kCheckedLoadUint16: |
901 ASSEMBLE_CHECKED_LOAD_INTEGER(movzx_w); | 1182 ASSEMBLE_CHECKED_LOAD_INTEGER(movzx_w); |
902 break; | 1183 break; |
903 case kCheckedLoadWord32: | 1184 case kCheckedLoadWord32: |
904 ASSEMBLE_CHECKED_LOAD_INTEGER(mov); | 1185 ASSEMBLE_CHECKED_LOAD_INTEGER(mov); |
905 break; | 1186 break; |
906 case kCheckedLoadFloat32: | 1187 case kCheckedLoadFloat32: |
907 ASSEMBLE_CHECKED_LOAD_FLOAT(movss); | 1188 ASSEMBLE_CHECKED_LOAD_FLOAT(fld_s); |
908 break; | 1189 break; |
909 case kCheckedLoadFloat64: | 1190 case kCheckedLoadFloat64: |
910 ASSEMBLE_CHECKED_LOAD_FLOAT(movsd); | 1191 ASSEMBLE_CHECKED_LOAD_FLOAT(fld_d); |
911 break; | 1192 break; |
912 case kCheckedStoreWord8: | 1193 case kCheckedStoreWord8: |
913 ASSEMBLE_CHECKED_STORE_INTEGER(mov_b); | 1194 ASSEMBLE_CHECKED_STORE_INTEGER(mov_b); |
914 break; | 1195 break; |
915 case kCheckedStoreWord16: | 1196 case kCheckedStoreWord16: |
916 ASSEMBLE_CHECKED_STORE_INTEGER(mov_w); | 1197 ASSEMBLE_CHECKED_STORE_INTEGER(mov_w); |
917 break; | 1198 break; |
918 case kCheckedStoreWord32: | 1199 case kCheckedStoreWord32: |
919 ASSEMBLE_CHECKED_STORE_INTEGER(mov); | 1200 ASSEMBLE_CHECKED_STORE_INTEGER(mov); |
920 break; | 1201 break; |
921 case kCheckedStoreFloat32: | 1202 case kCheckedStoreFloat32: |
922 ASSEMBLE_CHECKED_STORE_FLOAT(movss); | 1203 ASSEMBLE_CHECKED_STORE_FLOAT(fst_s); |
923 break; | 1204 break; |
924 case kCheckedStoreFloat64: | 1205 case kCheckedStoreFloat64: |
925 ASSEMBLE_CHECKED_STORE_FLOAT(movsd); | 1206 ASSEMBLE_CHECKED_STORE_FLOAT(fst_d); |
926 break; | 1207 break; |
927 case kIA32StackCheck: { | 1208 case kX87StackCheck: { |
928 ExternalReference const stack_limit = | 1209 ExternalReference const stack_limit = |
929 ExternalReference::address_of_stack_limit(isolate()); | 1210 ExternalReference::address_of_stack_limit(isolate()); |
930 __ cmp(esp, Operand::StaticVariable(stack_limit)); | 1211 __ cmp(esp, Operand::StaticVariable(stack_limit)); |
931 break; | 1212 break; |
932 } | 1213 } |
933 } | 1214 } |
934 } // NOLINT(readability/fn_size) | 1215 } // NOLINT(readability/fn_size) |
935 | 1216 |
936 | 1217 |
937 // Assembles a branch after an instruction. | 1218 // Assembles a branch after an instruction. |
938 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) { | 1219 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) { |
939 IA32OperandConverter i(this, instr); | 1220 X87OperandConverter i(this, instr); |
940 Label::Distance flabel_distance = | 1221 Label::Distance flabel_distance = |
941 branch->fallthru ? Label::kNear : Label::kFar; | 1222 branch->fallthru ? Label::kNear : Label::kFar; |
942 Label* tlabel = branch->true_label; | 1223 Label* tlabel = branch->true_label; |
943 Label* flabel = branch->false_label; | 1224 Label* flabel = branch->false_label; |
944 switch (branch->condition) { | 1225 switch (branch->condition) { |
945 case kUnorderedEqual: | 1226 case kUnorderedEqual: |
946 __ j(parity_even, flabel, flabel_distance); | 1227 __ j(parity_even, flabel, flabel_distance); |
947 // Fall through. | 1228 // Fall through. |
948 case kEqual: | 1229 case kEqual: |
949 __ j(equal, tlabel); | 1230 __ j(equal, tlabel); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
991 | 1272 |
992 | 1273 |
993 void CodeGenerator::AssembleArchJump(RpoNumber target) { | 1274 void CodeGenerator::AssembleArchJump(RpoNumber target) { |
994 if (!IsNextInAssemblyOrder(target)) __ jmp(GetLabel(target)); | 1275 if (!IsNextInAssemblyOrder(target)) __ jmp(GetLabel(target)); |
995 } | 1276 } |
996 | 1277 |
997 | 1278 |
998 // Assembles boolean materializations after an instruction. | 1279 // Assembles boolean materializations after an instruction. |
999 void CodeGenerator::AssembleArchBoolean(Instruction* instr, | 1280 void CodeGenerator::AssembleArchBoolean(Instruction* instr, |
1000 FlagsCondition condition) { | 1281 FlagsCondition condition) { |
1001 IA32OperandConverter i(this, instr); | 1282 X87OperandConverter i(this, instr); |
1002 Label done; | 1283 Label done; |
1003 | 1284 |
1004 // Materialize a full 32-bit 1 or 0 value. The result register is always the | 1285 // Materialize a full 32-bit 1 or 0 value. The result register is always the |
1005 // last output of the instruction. | 1286 // last output of the instruction. |
1006 Label check; | 1287 Label check; |
1007 DCHECK_NE(0u, instr->OutputCount()); | 1288 DCHECK_NE(0u, instr->OutputCount()); |
1008 Register reg = i.OutputRegister(instr->OutputCount() - 1); | 1289 Register reg = i.OutputRegister(instr->OutputCount() - 1); |
1009 Condition cc = no_condition; | 1290 Condition cc = no_condition; |
1010 switch (condition) { | 1291 switch (condition) { |
1011 case kUnorderedEqual: | 1292 case kUnorderedEqual: |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1067 __ Move(reg, Immediate(0)); | 1348 __ Move(reg, Immediate(0)); |
1068 __ jmp(&done, Label::kNear); | 1349 __ jmp(&done, Label::kNear); |
1069 __ bind(&set); | 1350 __ bind(&set); |
1070 __ mov(reg, Immediate(1)); | 1351 __ mov(reg, Immediate(1)); |
1071 } | 1352 } |
1072 __ bind(&done); | 1353 __ bind(&done); |
1073 } | 1354 } |
1074 | 1355 |
1075 | 1356 |
1076 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) { | 1357 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) { |
1077 IA32OperandConverter i(this, instr); | 1358 X87OperandConverter i(this, instr); |
1078 Register input = i.InputRegister(0); | 1359 Register input = i.InputRegister(0); |
1079 for (size_t index = 2; index < instr->InputCount(); index += 2) { | 1360 for (size_t index = 2; index < instr->InputCount(); index += 2) { |
1080 __ cmp(input, Immediate(i.InputInt32(index + 0))); | 1361 __ cmp(input, Immediate(i.InputInt32(index + 0))); |
1081 __ j(equal, GetLabel(i.InputRpo(index + 1))); | 1362 __ j(equal, GetLabel(i.InputRpo(index + 1))); |
1082 } | 1363 } |
1083 AssembleArchJump(i.InputRpo(1)); | 1364 AssembleArchJump(i.InputRpo(1)); |
1084 } | 1365 } |
1085 | 1366 |
1086 | 1367 |
1087 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) { | 1368 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) { |
1088 IA32OperandConverter i(this, instr); | 1369 X87OperandConverter i(this, instr); |
1089 Register input = i.InputRegister(0); | 1370 Register input = i.InputRegister(0); |
1090 size_t const case_count = instr->InputCount() - 2; | 1371 size_t const case_count = instr->InputCount() - 2; |
1091 Label** cases = zone()->NewArray<Label*>(case_count); | 1372 Label** cases = zone()->NewArray<Label*>(case_count); |
1092 for (size_t index = 0; index < case_count; ++index) { | 1373 for (size_t index = 0; index < case_count; ++index) { |
1093 cases[index] = GetLabel(i.InputRpo(index + 2)); | 1374 cases[index] = GetLabel(i.InputRpo(index + 2)); |
1094 } | 1375 } |
1095 Label* const table = AddJumpTable(cases, case_count); | 1376 Label* const table = AddJumpTable(cases, case_count); |
1096 __ cmp(input, Immediate(case_count)); | 1377 __ cmp(input, Immediate(case_count)); |
1097 __ j(above_equal, GetLabel(i.InputRpo(1))); | 1378 __ j(above_equal, GetLabel(i.InputRpo(1))); |
1098 __ jmp(Operand::JumpTable(input, times_4, table)); | 1379 __ jmp(Operand::JumpTable(input, times_4, table)); |
1099 } | 1380 } |
1100 | 1381 |
1101 | 1382 |
1102 void CodeGenerator::AssembleDeoptimizerCall( | 1383 void CodeGenerator::AssembleDeoptimizerCall( |
1103 int deoptimization_id, Deoptimizer::BailoutType bailout_type) { | 1384 int deoptimization_id, Deoptimizer::BailoutType bailout_type) { |
1104 Address deopt_entry = Deoptimizer::GetDeoptimizationEntry( | 1385 Address deopt_entry = Deoptimizer::GetDeoptimizationEntry( |
1105 isolate(), deoptimization_id, bailout_type); | 1386 isolate(), deoptimization_id, bailout_type); |
1106 __ call(deopt_entry, RelocInfo::RUNTIME_ENTRY); | 1387 __ call(deopt_entry, RelocInfo::RUNTIME_ENTRY); |
1107 } | 1388 } |
1108 | 1389 |
1109 | 1390 |
1110 // The calling convention for JSFunctions on IA32 passes arguments on the | 1391 // The calling convention for JSFunctions on X87 passes arguments on the |
1111 // stack and the JSFunction and context in EDI and ESI, respectively, thus | 1392 // stack and the JSFunction and context in EDI and ESI, respectively, thus |
1112 // the steps of the call look as follows: | 1393 // the steps of the call look as follows: |
1113 | 1394 |
1114 // --{ before the call instruction }-------------------------------------------- | 1395 // --{ before the call instruction }-------------------------------------------- |
1115 // | caller frame | | 1396 // | caller frame | |
1116 // ^ esp ^ ebp | 1397 // ^ esp ^ ebp |
1117 | 1398 |
1118 // --{ push arguments and setup ESI, EDI }-------------------------------------- | 1399 // --{ push arguments and setup ESI, EDI }-------------------------------------- |
1119 // | args + receiver | caller frame | | 1400 // | args + receiver | caller frame | |
1120 // ^ esp ^ ebp | 1401 // ^ esp ^ ebp |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1155 // --{ pop ebp }----------------------------------------------------------- | 1436 // --{ pop ebp }----------------------------------------------------------- |
1156 // | | RET | args + receiver | caller frame | | 1437 // | | RET | args + receiver | caller frame | |
1157 // ^ esp ^ ebp | 1438 // ^ esp ^ ebp |
1158 | 1439 |
1159 // --{ ret #A+1 }----------------------------------------------------------- | 1440 // --{ ret #A+1 }----------------------------------------------------------- |
1160 // | | caller frame | | 1441 // | | caller frame | |
1161 // ^ esp ^ ebp | 1442 // ^ esp ^ ebp |
1162 | 1443 |
1163 | 1444 |
1164 // Runtime function calls are accomplished by doing a stub call to the | 1445 // Runtime function calls are accomplished by doing a stub call to the |
1165 // CEntryStub (a real code object). On IA32 passes arguments on the | 1446 // CEntryStub (a real code object). On X87 passes arguments on the |
1166 // stack, the number of arguments in EAX, the address of the runtime function | 1447 // stack, the number of arguments in EAX, the address of the runtime function |
1167 // in EBX, and the context in ESI. | 1448 // in EBX, and the context in ESI. |
1168 | 1449 |
1169 // --{ before the call instruction }-------------------------------------------- | 1450 // --{ before the call instruction }-------------------------------------------- |
1170 // | caller frame | | 1451 // | caller frame | |
1171 // ^ esp ^ ebp | 1452 // ^ esp ^ ebp |
1172 | 1453 |
1173 // --{ push arguments and setup EAX, EBX, and ESI }----------------------------- | 1454 // --{ push arguments and setup EAX, EBX, and ESI }----------------------------- |
1174 // | args + receiver | caller frame | | 1455 // | args + receiver | caller frame | |
1175 // ^ esp ^ ebp | 1456 // ^ esp ^ ebp |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1278 // TODO(titzer): cannot address target function == local #-1 | 1559 // TODO(titzer): cannot address target function == local #-1 |
1279 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 1560 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
1280 DCHECK(stack_slots >= frame()->GetOsrStackSlotCount()); | 1561 DCHECK(stack_slots >= frame()->GetOsrStackSlotCount()); |
1281 stack_slots -= frame()->GetOsrStackSlotCount(); | 1562 stack_slots -= frame()->GetOsrStackSlotCount(); |
1282 } | 1563 } |
1283 | 1564 |
1284 if (stack_slots > 0) { | 1565 if (stack_slots > 0) { |
1285 // Allocate the stack slots used by this frame. | 1566 // Allocate the stack slots used by this frame. |
1286 __ sub(esp, Immediate(stack_slots * kPointerSize)); | 1567 __ sub(esp, Immediate(stack_slots * kPointerSize)); |
1287 } | 1568 } |
| 1569 |
| 1570 // Initailize FPU state. |
| 1571 __ fninit(); |
| 1572 __ fld1(); |
1288 } | 1573 } |
1289 | 1574 |
1290 | 1575 |
1291 void CodeGenerator::AssembleReturn() { | 1576 void CodeGenerator::AssembleReturn() { |
1292 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); | 1577 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); |
1293 int stack_slots = frame()->GetSpillSlotCount(); | 1578 int stack_slots = frame()->GetSpillSlotCount(); |
1294 if (descriptor->kind() == CallDescriptor::kCallAddress) { | 1579 if (descriptor->kind() == CallDescriptor::kCallAddress) { |
1295 const RegList saves = descriptor->CalleeSavedRegisters(); | 1580 const RegList saves = descriptor->CalleeSavedRegisters(); |
1296 if (frame()->GetRegisterSaveAreaSize() > 0) { | 1581 if (frame()->GetRegisterSaveAreaSize() > 0) { |
1297 // Remove this frame's spill slots first. | 1582 // Remove this frame's spill slots first. |
(...skipping 23 matching lines...) Expand all Loading... |
1321 : 0; | 1606 : 0; |
1322 __ Ret(pop_count * kPointerSize, ebx); | 1607 __ Ret(pop_count * kPointerSize, ebx); |
1323 } else { | 1608 } else { |
1324 __ ret(0); | 1609 __ ret(0); |
1325 } | 1610 } |
1326 } | 1611 } |
1327 | 1612 |
1328 | 1613 |
1329 void CodeGenerator::AssembleMove(InstructionOperand* source, | 1614 void CodeGenerator::AssembleMove(InstructionOperand* source, |
1330 InstructionOperand* destination) { | 1615 InstructionOperand* destination) { |
1331 IA32OperandConverter g(this, NULL); | 1616 X87OperandConverter g(this, NULL); |
1332 // Dispatch on the source and destination operand kinds. Not all | 1617 // Dispatch on the source and destination operand kinds. Not all |
1333 // combinations are possible. | 1618 // combinations are possible. |
1334 if (source->IsRegister()) { | 1619 if (source->IsRegister()) { |
1335 DCHECK(destination->IsRegister() || destination->IsStackSlot()); | 1620 DCHECK(destination->IsRegister() || destination->IsStackSlot()); |
1336 Register src = g.ToRegister(source); | 1621 Register src = g.ToRegister(source); |
1337 Operand dst = g.ToOperand(destination); | 1622 Operand dst = g.ToOperand(destination); |
1338 __ mov(dst, src); | 1623 __ mov(dst, src); |
1339 } else if (source->IsStackSlot()) { | 1624 } else if (source->IsStackSlot()) { |
1340 DCHECK(destination->IsRegister() || destination->IsStackSlot()); | 1625 DCHECK(destination->IsRegister() || destination->IsStackSlot()); |
1341 Operand src = g.ToOperand(source); | 1626 Operand src = g.ToOperand(source); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1379 } else if (destination->IsRegister()) { | 1664 } else if (destination->IsRegister()) { |
1380 Register dst = g.ToRegister(destination); | 1665 Register dst = g.ToRegister(destination); |
1381 __ Move(dst, g.ToImmediate(source)); | 1666 __ Move(dst, g.ToImmediate(source)); |
1382 } else if (destination->IsStackSlot()) { | 1667 } else if (destination->IsStackSlot()) { |
1383 Operand dst = g.ToOperand(destination); | 1668 Operand dst = g.ToOperand(destination); |
1384 __ Move(dst, g.ToImmediate(source)); | 1669 __ Move(dst, g.ToImmediate(source)); |
1385 } else if (src_constant.type() == Constant::kFloat32) { | 1670 } else if (src_constant.type() == Constant::kFloat32) { |
1386 // TODO(turbofan): Can we do better here? | 1671 // TODO(turbofan): Can we do better here? |
1387 uint32_t src = bit_cast<uint32_t>(src_constant.ToFloat32()); | 1672 uint32_t src = bit_cast<uint32_t>(src_constant.ToFloat32()); |
1388 if (destination->IsDoubleRegister()) { | 1673 if (destination->IsDoubleRegister()) { |
1389 XMMRegister dst = g.ToDoubleRegister(destination); | 1674 __ sub(esp, Immediate(kInt32Size)); |
1390 __ Move(dst, src); | 1675 __ mov(MemOperand(esp, 0), Immediate(src)); |
| 1676 // always only push one value into the x87 stack. |
| 1677 __ fstp(0); |
| 1678 __ fld_s(MemOperand(esp, 0)); |
| 1679 __ add(esp, Immediate(kInt32Size)); |
1391 } else { | 1680 } else { |
1392 DCHECK(destination->IsDoubleStackSlot()); | 1681 DCHECK(destination->IsDoubleStackSlot()); |
1393 Operand dst = g.ToOperand(destination); | 1682 Operand dst = g.ToOperand(destination); |
1394 __ Move(dst, Immediate(src)); | 1683 __ Move(dst, Immediate(src)); |
1395 } | 1684 } |
1396 } else { | 1685 } else { |
1397 DCHECK_EQ(Constant::kFloat64, src_constant.type()); | 1686 DCHECK_EQ(Constant::kFloat64, src_constant.type()); |
1398 uint64_t src = bit_cast<uint64_t>(src_constant.ToFloat64()); | 1687 uint64_t src = bit_cast<uint64_t>(src_constant.ToFloat64()); |
1399 uint32_t lower = static_cast<uint32_t>(src); | 1688 uint32_t lower = static_cast<uint32_t>(src); |
1400 uint32_t upper = static_cast<uint32_t>(src >> 32); | 1689 uint32_t upper = static_cast<uint32_t>(src >> 32); |
1401 if (destination->IsDoubleRegister()) { | 1690 if (destination->IsDoubleRegister()) { |
1402 XMMRegister dst = g.ToDoubleRegister(destination); | 1691 __ sub(esp, Immediate(kDoubleSize)); |
1403 __ Move(dst, src); | 1692 __ mov(MemOperand(esp, 0), Immediate(lower)); |
| 1693 __ mov(MemOperand(esp, kInt32Size), Immediate(upper)); |
| 1694 // always only push one value into the x87 stack. |
| 1695 __ fstp(0); |
| 1696 __ fld_d(MemOperand(esp, 0)); |
| 1697 __ add(esp, Immediate(kDoubleSize)); |
1404 } else { | 1698 } else { |
1405 DCHECK(destination->IsDoubleStackSlot()); | 1699 DCHECK(destination->IsDoubleStackSlot()); |
1406 Operand dst0 = g.ToOperand(destination); | 1700 Operand dst0 = g.ToOperand(destination); |
1407 Operand dst1 = g.HighOperand(destination); | 1701 Operand dst1 = g.HighOperand(destination); |
1408 __ Move(dst0, Immediate(lower)); | 1702 __ Move(dst0, Immediate(lower)); |
1409 __ Move(dst1, Immediate(upper)); | 1703 __ Move(dst1, Immediate(upper)); |
1410 } | 1704 } |
1411 } | 1705 } |
1412 } else if (source->IsDoubleRegister()) { | 1706 } else if (source->IsDoubleRegister()) { |
1413 XMMRegister src = g.ToDoubleRegister(source); | 1707 DCHECK(destination->IsDoubleStackSlot()); |
1414 if (destination->IsDoubleRegister()) { | 1708 Operand dst = g.ToOperand(destination); |
1415 XMMRegister dst = g.ToDoubleRegister(destination); | 1709 auto allocated = AllocatedOperand::cast(*source); |
1416 __ movaps(dst, src); | 1710 switch (allocated.machine_type()) { |
1417 } else { | 1711 case kRepFloat32: |
1418 DCHECK(destination->IsDoubleStackSlot()); | 1712 __ fst_s(dst); |
1419 Operand dst = g.ToOperand(destination); | 1713 break; |
1420 __ movsd(dst, src); | 1714 case kRepFloat64: |
| 1715 __ fst_d(dst); |
| 1716 break; |
| 1717 default: |
| 1718 UNREACHABLE(); |
1421 } | 1719 } |
1422 } else if (source->IsDoubleStackSlot()) { | 1720 } else if (source->IsDoubleStackSlot()) { |
1423 DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot()); | 1721 DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot()); |
1424 Operand src = g.ToOperand(source); | 1722 Operand src = g.ToOperand(source); |
| 1723 auto allocated = AllocatedOperand::cast(*source); |
1425 if (destination->IsDoubleRegister()) { | 1724 if (destination->IsDoubleRegister()) { |
1426 XMMRegister dst = g.ToDoubleRegister(destination); | 1725 // always only push one value into the x87 stack. |
1427 __ movsd(dst, src); | 1726 __ fstp(0); |
| 1727 switch (allocated.machine_type()) { |
| 1728 case kRepFloat32: |
| 1729 __ fld_s(src); |
| 1730 break; |
| 1731 case kRepFloat64: |
| 1732 __ fld_d(src); |
| 1733 break; |
| 1734 default: |
| 1735 UNREACHABLE(); |
| 1736 } |
1428 } else { | 1737 } else { |
1429 Operand dst = g.ToOperand(destination); | 1738 Operand dst = g.ToOperand(destination); |
1430 __ movsd(kScratchDoubleReg, src); | 1739 switch (allocated.machine_type()) { |
1431 __ movsd(dst, kScratchDoubleReg); | 1740 case kRepFloat32: |
| 1741 __ fld_s(src); |
| 1742 __ fstp_s(dst); |
| 1743 break; |
| 1744 case kRepFloat64: |
| 1745 __ fld_d(src); |
| 1746 __ fstp_d(dst); |
| 1747 break; |
| 1748 default: |
| 1749 UNREACHABLE(); |
| 1750 } |
1432 } | 1751 } |
1433 } else { | 1752 } else { |
1434 UNREACHABLE(); | 1753 UNREACHABLE(); |
1435 } | 1754 } |
1436 } | 1755 } |
1437 | 1756 |
1438 | 1757 |
1439 void CodeGenerator::AssembleSwap(InstructionOperand* source, | 1758 void CodeGenerator::AssembleSwap(InstructionOperand* source, |
1440 InstructionOperand* destination) { | 1759 InstructionOperand* destination) { |
1441 IA32OperandConverter g(this, NULL); | 1760 X87OperandConverter g(this, NULL); |
1442 // Dispatch on the source and destination operand kinds. Not all | 1761 // Dispatch on the source and destination operand kinds. Not all |
1443 // combinations are possible. | 1762 // combinations are possible. |
1444 if (source->IsRegister() && destination->IsRegister()) { | 1763 if (source->IsRegister() && destination->IsRegister()) { |
1445 // Register-register. | 1764 // Register-register. |
1446 Register src = g.ToRegister(source); | 1765 Register src = g.ToRegister(source); |
1447 Register dst = g.ToRegister(destination); | 1766 Register dst = g.ToRegister(destination); |
1448 __ xchg(dst, src); | 1767 __ xchg(dst, src); |
1449 } else if (source->IsRegister() && destination->IsStackSlot()) { | 1768 } else if (source->IsRegister() && destination->IsStackSlot()) { |
1450 // Register-memory. | 1769 // Register-memory. |
1451 __ xchg(g.ToRegister(source), g.ToOperand(destination)); | 1770 __ xchg(g.ToRegister(source), g.ToOperand(destination)); |
1452 } else if (source->IsStackSlot() && destination->IsStackSlot()) { | 1771 } else if (source->IsStackSlot() && destination->IsStackSlot()) { |
1453 // Memory-memory. | 1772 // Memory-memory. |
1454 Operand src = g.ToOperand(source); | 1773 Operand src = g.ToOperand(source); |
1455 Operand dst = g.ToOperand(destination); | 1774 Operand dst = g.ToOperand(destination); |
1456 __ push(dst); | 1775 __ push(dst); |
1457 __ push(src); | 1776 __ push(src); |
1458 __ pop(dst); | 1777 __ pop(dst); |
1459 __ pop(src); | 1778 __ pop(src); |
1460 } else if (source->IsDoubleRegister() && destination->IsDoubleRegister()) { | 1779 } else if (source->IsDoubleRegister() && destination->IsDoubleRegister()) { |
1461 // XMM register-register swap. | 1780 UNREACHABLE(); |
1462 XMMRegister src = g.ToDoubleRegister(source); | |
1463 XMMRegister dst = g.ToDoubleRegister(destination); | |
1464 __ movaps(kScratchDoubleReg, src); | |
1465 __ movaps(src, dst); | |
1466 __ movaps(dst, kScratchDoubleReg); | |
1467 } else if (source->IsDoubleRegister() && destination->IsDoubleStackSlot()) { | 1781 } else if (source->IsDoubleRegister() && destination->IsDoubleStackSlot()) { |
1468 // XMM register-memory swap. | 1782 auto allocated = AllocatedOperand::cast(*source); |
1469 XMMRegister reg = g.ToDoubleRegister(source); | 1783 switch (allocated.machine_type()) { |
1470 Operand other = g.ToOperand(destination); | 1784 case kRepFloat32: |
1471 __ movsd(kScratchDoubleReg, other); | 1785 __ fld_s(g.ToOperand(destination)); |
1472 __ movsd(other, reg); | 1786 __ fxch(); |
1473 __ movaps(reg, kScratchDoubleReg); | 1787 __ fstp_s(g.ToOperand(destination)); |
| 1788 break; |
| 1789 case kRepFloat64: |
| 1790 __ fld_d(g.ToOperand(destination)); |
| 1791 __ fxch(); |
| 1792 __ fstp_d(g.ToOperand(destination)); |
| 1793 break; |
| 1794 default: |
| 1795 UNREACHABLE(); |
| 1796 } |
1474 } else if (source->IsDoubleStackSlot() && destination->IsDoubleStackSlot()) { | 1797 } else if (source->IsDoubleStackSlot() && destination->IsDoubleStackSlot()) { |
1475 // Double-width memory-to-memory. | 1798 auto allocated = AllocatedOperand::cast(*source); |
1476 Operand src0 = g.ToOperand(source); | 1799 switch (allocated.machine_type()) { |
1477 Operand src1 = g.HighOperand(source); | 1800 case kRepFloat32: |
1478 Operand dst0 = g.ToOperand(destination); | 1801 __ fld_s(g.ToOperand(source)); |
1479 Operand dst1 = g.HighOperand(destination); | 1802 __ fld_s(g.ToOperand(destination)); |
1480 __ movsd(kScratchDoubleReg, dst0); // Save destination in scratch register. | 1803 __ fstp_s(g.ToOperand(source)); |
1481 __ push(src0); // Then use stack to copy source to destination. | 1804 __ fstp_s(g.ToOperand(destination)); |
1482 __ pop(dst0); | 1805 break; |
1483 __ push(src1); | 1806 case kRepFloat64: |
1484 __ pop(dst1); | 1807 __ fld_d(g.ToOperand(source)); |
1485 __ movsd(src0, kScratchDoubleReg); | 1808 __ fld_d(g.ToOperand(destination)); |
| 1809 __ fstp_d(g.ToOperand(source)); |
| 1810 __ fstp_d(g.ToOperand(destination)); |
| 1811 break; |
| 1812 default: |
| 1813 UNREACHABLE(); |
| 1814 } |
1486 } else { | 1815 } else { |
1487 // No other combinations are possible. | 1816 // No other combinations are possible. |
1488 UNREACHABLE(); | 1817 UNREACHABLE(); |
1489 } | 1818 } |
1490 } | 1819 } |
1491 | 1820 |
1492 | 1821 |
1493 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) { | 1822 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) { |
1494 for (size_t index = 0; index < target_count; ++index) { | 1823 for (size_t index = 0; index < target_count; ++index) { |
1495 __ dd(targets[index]); | 1824 __ dd(targets[index]); |
(...skipping 16 matching lines...) Expand all Loading... |
1512 } | 1841 } |
1513 } | 1842 } |
1514 MarkLazyDeoptSite(); | 1843 MarkLazyDeoptSite(); |
1515 } | 1844 } |
1516 | 1845 |
1517 #undef __ | 1846 #undef __ |
1518 | 1847 |
1519 } // namespace compiler | 1848 } // namespace compiler |
1520 } // namespace internal | 1849 } // namespace internal |
1521 } // namespace v8 | 1850 } // namespace v8 |
OLD | NEW |