Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(46)

Side by Side Diff: src/arm/code-stubs-arm.cc

Issue 6312059: ARM: Add multiplication and modulus to the type recording binary operation st... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | src/arm/full-codegen-arm.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after
382 Destination destination, 382 Destination destination,
383 Register scratch1, 383 Register scratch1,
384 Register scratch2); 384 Register scratch2);
385 385
386 // Loads objects from r0 and r1 (right and left in binary operations) into 386 // Loads objects from r0 and r1 (right and left in binary operations) into
387 // floating point registers. Depending on the destination the values ends up 387 // floating point registers. Depending on the destination the values ends up
388 // either d7 and d6 or in r2/r3 and r0/r1 respectively. If the destination is 388 // either d7 and d6 or in r2/r3 and r0/r1 respectively. If the destination is
389 // floating point registers VFP3 must be supported. If core registers are 389 // floating point registers VFP3 must be supported. If core registers are
390 // requested when VFP3 is supported d6 and d7 will still be scratched. If 390 // requested when VFP3 is supported d6 and d7 will still be scratched. If
391 // either r0 or r1 is not a number (not smi and not heap number object) the 391 // either r0 or r1 is not a number (not smi and not heap number object) the
392 // not_number label is jumped to. 392 // not_number label is jumped to with r0 and r1 intact.
393 static void LoadOperands(MacroAssembler* masm, 393 static void LoadOperands(MacroAssembler* masm,
394 FloatingPointHelper::Destination destination, 394 FloatingPointHelper::Destination destination,
395 Register heap_number_map, 395 Register heap_number_map,
396 Register scratch1, 396 Register scratch1,
397 Register scratch2, 397 Register scratch2,
398 Label* not_number); 398 Label* not_number);
399 private: 399 private:
400 static void LoadNumber(MacroAssembler* masm, 400 static void LoadNumber(MacroAssembler* masm,
401 FloatingPointHelper::Destination destination, 401 FloatingPointHelper::Destination destination,
402 Register object, 402 Register object,
403 DwVfpRegister dst, 403 DwVfpRegister dst,
404 Register dst1, 404 Register dst1,
405 Register dst2, 405 Register dst2,
406 Register heap_number_map, 406 Register heap_number_map,
407 Register scratch1, 407 Register scratch1,
408 Register scratch2, 408 Register scratch2,
409 Label* not_number); 409 Label* not_number);
410 }; 410 };
411 411
412 412
413 void FloatingPointHelper::LoadSmis(MacroAssembler* masm, 413 void FloatingPointHelper::LoadSmis(MacroAssembler* masm,
414 FloatingPointHelper::Destination destination, 414 FloatingPointHelper::Destination destination,
415 Register scratch1, 415 Register scratch1,
416 Register scratch2) { 416 Register scratch2) {
417 if (CpuFeatures::IsSupported(VFP3)) { 417 if (CpuFeatures::IsSupported(VFP3)) {
418 CpuFeatures::Scope scope(VFP3); 418 CpuFeatures::Scope scope(VFP3);
419 __ mov(scratch1, Operand(r0, ASR, kSmiTagSize)); 419 __ mov(scratch1, Operand(r0, ASR, kSmiTagSize));
420 __ vmov(s15, scratch1); 420 __ vmov(d7.high(), scratch1);
421 __ vcvt_f64_s32(d7, s15); 421 __ vcvt_f64_s32(d7, d7.high());
422 __ mov(scratch1, Operand(r1, ASR, kSmiTagSize)); 422 __ mov(scratch1, Operand(r1, ASR, kSmiTagSize));
423 __ vmov(s13, scratch1); 423 __ vmov(d6.high(), scratch1);
424 __ vcvt_f64_s32(d6, s13); 424 __ vcvt_f64_s32(d6, d6.high());
425 if (destination == kCoreRegisters) { 425 if (destination == kCoreRegisters) {
426 __ vmov(r2, r3, d7); 426 __ vmov(r2, r3, d7);
427 __ vmov(r0, r1, d6); 427 __ vmov(r0, r1, d6);
428 } 428 }
429 } else { 429 } else {
430 ASSERT(destination == kCoreRegisters); 430 ASSERT(destination == kCoreRegisters);
431 // Write Smi from r0 to r3 and r2 in double format. 431 // Write Smi from r0 to r3 and r2 in double format.
432 __ mov(scratch1, Operand(r0)); 432 __ mov(scratch1, Operand(r0));
433 ConvertToDoubleStub stub1(r3, r2, scratch1, scratch2); 433 ConvertToDoubleStub stub1(r3, r2, scratch1, scratch2);
434 __ push(lr); 434 __ push(lr);
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
469 Register heap_number_map, 469 Register heap_number_map,
470 Register scratch1, 470 Register scratch1,
471 Register scratch2, 471 Register scratch2,
472 Label* not_number) { 472 Label* not_number) {
473 Label is_smi, done; 473 Label is_smi, done;
474 474
475 __ JumpIfSmi(object, &is_smi); 475 __ JumpIfSmi(object, &is_smi);
476 __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number); 476 __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number);
477 477
478 // Handle loading a double from a heap number. 478 // Handle loading a double from a heap number.
479 if (CpuFeatures::IsSupported(VFP3)) { 479 if (CpuFeatures::IsSupported(VFP3) && destination == kVFPRegisters) {
480 CpuFeatures::Scope scope(VFP3); 480 CpuFeatures::Scope scope(VFP3);
481 // Load the double from tagged HeapNumber to double register. 481 // Load the double from tagged HeapNumber to double register.
482 __ sub(scratch1, object, Operand(kHeapObjectTag)); 482 __ sub(scratch1, object, Operand(kHeapObjectTag));
483 __ vldr(dst, scratch1, HeapNumber::kValueOffset); 483 __ vldr(dst, scratch1, HeapNumber::kValueOffset);
484 } else { 484 } else {
485 ASSERT(destination == kCoreRegisters); 485 ASSERT(destination == kCoreRegisters);
486 // Load the double from heap number to dst1 and dst2 in double format. 486 // Load the double from heap number to dst1 and dst2 in double format.
487 __ Ldrd(dst1, dst2, FieldMemOperand(object, HeapNumber::kValueOffset)); 487 __ Ldrd(dst1, dst2, FieldMemOperand(object, HeapNumber::kValueOffset));
488 } 488 }
489 __ jmp(&done); 489 __ jmp(&done);
490 490
491 // Handle loading a double from a smi. 491 // Handle loading a double from a smi.
492 __ bind(&is_smi); 492 __ bind(&is_smi);
493 if (CpuFeatures::IsSupported(VFP3)) { 493 if (CpuFeatures::IsSupported(VFP3)) {
494 CpuFeatures::Scope scope(VFP3); 494 CpuFeatures::Scope scope(VFP3);
495 // Convert smi to double. 495 // Convert smi to double using VFP instructions.
496 __ SmiUntag(scratch1, object); 496 __ SmiUntag(scratch1, object);
497 __ vmov(dst.high(), scratch1); 497 __ vmov(dst.high(), scratch1);
498 __ vcvt_f64_s32(dst, dst.high()); 498 __ vcvt_f64_s32(dst, dst.high());
499 if (destination == kCoreRegisters) { 499 if (destination == kCoreRegisters) {
500 // Load the converted smi to dst1 and dst2 in double format.
500 __ vmov(dst1, dst2, dst); 501 __ vmov(dst1, dst2, dst);
501 } 502 }
502 } else { 503 } else {
503 ASSERT(destination == kCoreRegisters); 504 ASSERT(destination == kCoreRegisters);
504 // Write Smi to dst1 and dst2 double format. 505 // Write smi to dst1 and dst2 double format.
505 __ mov(scratch1, Operand(object)); 506 __ mov(scratch1, Operand(object));
506 ConvertToDoubleStub stub(dst2, dst1, scratch1, scratch2); 507 ConvertToDoubleStub stub(dst2, dst1, scratch1, scratch2);
507 __ push(lr); 508 __ push(lr);
508 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET); 509 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET);
509 __ pop(lr); 510 __ pop(lr);
510 } 511 }
511 512
512 __ bind(&done); 513 __ bind(&done);
513 } 514 }
514 515
(...skipping 1979 matching lines...) Expand 10 before | Expand all | Expand 10 after
2494 __ mov(right, Operand(scratch1), LeaveCC, ne); 2495 __ mov(right, Operand(scratch1), LeaveCC, ne);
2495 __ Ret(ne); 2496 __ Ret(ne);
2496 // We need -0 if we were multiplying a negative number with 0 to get 0. 2497 // We need -0 if we were multiplying a negative number with 0 to get 0.
2497 // We know one of them was zero. 2498 // We know one of them was zero.
2498 __ add(scratch2, right, Operand(left), SetCC); 2499 __ add(scratch2, right, Operand(left), SetCC);
2499 __ mov(right, Operand(Smi::FromInt(0)), LeaveCC, pl); 2500 __ mov(right, Operand(Smi::FromInt(0)), LeaveCC, pl);
2500 __ Ret(pl); // Return smi 0 if the non-zero one was positive. 2501 __ Ret(pl); // Return smi 0 if the non-zero one was positive.
2501 // We fall through here if we multiplied a negative number with 0, because 2502 // We fall through here if we multiplied a negative number with 0, because
2502 // that would mean we should produce -0. 2503 // that would mean we should produce -0.
2503 break; 2504 break;
2505 case Token::DIV:
2506 // Check for power of two on the right hand side.
2507 __ JumpIfNotPowerOfTwoOrZero(right, scratch1, &not_smi_result);
2508 // Check for positive and no remainder (scratch1 contains right - 1).
2509 __ orr(scratch2, scratch1, Operand(0x80000000u));
2510 __ tst(left, scratch2);
2511 __ b(ne, &not_smi_result);
2512
2513 // Perform division by shifting.
2514 __ CountLeadingZeros(scratch1, scratch1, scratch2);
2515 __ rsb(scratch1, scratch1, Operand(31));
2516 __ mov(right, Operand(left, LSR, scratch1));
2517 __ Ret();
2518 break;
2519 case Token::MOD:
2520 // Check for two positive smis.
2521 __ orr(scratch1, left, Operand(right));
2522 __ tst(scratch1, Operand(0x80000000u | kSmiTagMask));
2523 __ b(ne, &not_smi_result);
2524
2525 // Check for power of two on the right hand side.
2526 __ JumpIfNotPowerOfTwoOrZero(right, scratch1, &not_smi_result);
2527
2528 // Perform modulus by masking.
2529 __ and_(right, left, Operand(scratch1));
2530 __ Ret();
2531 break;
2504 default: 2532 default:
2505 UNREACHABLE(); 2533 UNREACHABLE();
2506 } 2534 }
2507 __ bind(&not_smi_result); 2535 __ bind(&not_smi_result);
2508 } 2536 }
2509 2537
2510 2538
2511 void TypeRecordingBinaryOpStub::GenerateVFPOperation( 2539 void TypeRecordingBinaryOpStub::GenerateVFPOperation(
2512 MacroAssembler* masm) { 2540 MacroAssembler* masm) {
2513 switch (op_) { 2541 switch (op_) {
2514 case Token::ADD: 2542 case Token::ADD:
2515 __ vadd(d5, d6, d7); 2543 __ vadd(d5, d6, d7);
2516 break; 2544 break;
2517 case Token::SUB: 2545 case Token::SUB:
2518 __ vsub(d5, d6, d7); 2546 __ vsub(d5, d6, d7);
2519 break; 2547 break;
2520 case Token::MUL: 2548 case Token::MUL:
2521 __ vmul(d5, d6, d7); 2549 __ vmul(d5, d6, d7);
2522 break; 2550 break;
2551 case Token::DIV:
2552 __ vdiv(d5, d6, d7);
2553 break;
2523 default: 2554 default:
2524 UNREACHABLE(); 2555 UNREACHABLE();
2525 } 2556 }
2526 } 2557 }
2527 2558
2528 2559
2529 // Generate the smi code. If the operation on smis are successful this return is 2560 // Generate the smi code. If the operation on smis are successful this return is
2530 // generated. If the result is not a smi and heap number allocation is not 2561 // generated. If the result is not a smi and heap number allocation is not
2531 // requested the code falls through. If number allocation is requested but a 2562 // requested the code falls through. If number allocation is requested but a
2532 // heap number cannot be allocated the code jumps to the lable gc_required. 2563 // heap number cannot be allocated the code jumps to the lable gc_required.
2533 void TypeRecordingBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, 2564 void TypeRecordingBinaryOpStub::GenerateSmiCode(MacroAssembler* masm,
2534 Label* gc_required, 2565 Label* gc_required,
2535 SmiCodeGenerateHeapNumberResults allow_heapnumber_results) { 2566 SmiCodeGenerateHeapNumberResults allow_heapnumber_results) {
2536 Label not_smis; 2567 Label not_smis;
2537 2568
2538 ASSERT(op_ == Token::ADD || op_ == Token::SUB || op_ == Token::MUL); 2569 ASSERT(op_ == Token::ADD ||
2570 op_ == Token::SUB ||
2571 op_ == Token::MUL ||
2572 op_ == Token::DIV ||
2573 op_ == Token::MOD);
2539 2574
2540 Register left = r1; 2575 Register left = r1;
2541 Register right = r0; 2576 Register right = r0;
2542 Register scratch1 = r7; 2577 Register scratch1 = r7;
2543 Register scratch2 = r9; 2578 Register scratch2 = r9;
2544 2579
2545 // Perform combined smi check on both operands. 2580 // Perform combined smi check on both operands.
2546 __ orr(scratch1, left, Operand(right)); 2581 __ orr(scratch1, left, Operand(right));
2547 STATIC_ASSERT(kSmiTag == 0); 2582 STATIC_ASSERT(kSmiTag == 0);
2548 __ tst(scratch1, Operand(kSmiTagMask)); 2583 __ tst(scratch1, Operand(kSmiTagMask));
2549 __ b(ne, &not_smis); 2584 __ b(ne, &not_smis);
2550 2585
2586 // If the smi-smi operation results in a smi return is generated.
2551 GenerateSmiSmiOperation(masm); 2587 GenerateSmiSmiOperation(masm);
2552 2588
2553 // If heap number results are possible generate the result in an allocated 2589 // If heap number results are possible generate the result in an allocated
2554 // heap number. 2590 // heap number.
2555 if (allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS) { 2591 if (allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS) {
2556 FloatingPointHelper::Destination destination = 2592 FloatingPointHelper::Destination destination =
2557 CpuFeatures::IsSupported(VFP3) && Token::MOD != op_ ? 2593 CpuFeatures::IsSupported(VFP3) && op_ != Token::MOD ?
2558 FloatingPointHelper::kVFPRegisters : 2594 FloatingPointHelper::kVFPRegisters :
2559 FloatingPointHelper::kCoreRegisters; 2595 FloatingPointHelper::kCoreRegisters;
2560 2596
2561 Register heap_number_map = r6; 2597 Register heap_number_map = r6;
2562 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); 2598 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
2563 2599
2564 // Allocate new heap number for result. 2600 // Allocate new heap number for result.
2565 Register heap_number = r5; 2601 Register result = r5;
2566 __ AllocateHeapNumber( 2602 __ AllocateHeapNumber(
2567 heap_number, scratch1, scratch2, heap_number_map, gc_required); 2603 result, scratch1, scratch2, heap_number_map, gc_required);
2568 2604
2569 // Load the smis. 2605 // Load the smis.
2570 FloatingPointHelper::LoadSmis(masm, destination, scratch1, scratch2); 2606 FloatingPointHelper::LoadSmis(masm, destination, scratch1, scratch2);
2571 2607
2572 // Calculate the result. 2608 // Calculate the result.
2573 if (destination == FloatingPointHelper::kVFPRegisters) { 2609 if (destination == FloatingPointHelper::kVFPRegisters) {
2574 // Using VFP registers: 2610 // Using VFP registers:
2575 // d6: Left value 2611 // d6: Left value
2576 // d7: Right value 2612 // d7: Right value
2577 CpuFeatures::Scope scope(VFP3); 2613 CpuFeatures::Scope scope(VFP3);
2578 GenerateVFPOperation(masm); 2614 GenerateVFPOperation(masm);
2579 2615
2580 __ sub(r0, heap_number, Operand(kHeapObjectTag)); 2616 __ sub(r0, result, Operand(kHeapObjectTag));
2581 __ vstr(d5, r0, HeapNumber::kValueOffset); 2617 __ vstr(d5, r0, HeapNumber::kValueOffset);
2582 __ add(r0, r0, Operand(kHeapObjectTag)); 2618 __ add(r0, r0, Operand(kHeapObjectTag));
2583 __ Ret(); 2619 __ Ret();
2584 } else { 2620 } else {
2585 // Using core registers: 2621 // Using core registers:
2586 // r0: Left value (least significant part of mantissa). 2622 // r0: Left value (least significant part of mantissa).
2587 // r1: Left value (sign, exponent, top of mantissa). 2623 // r1: Left value (sign, exponent, top of mantissa).
2588 // r2: Right value (least significant part of mantissa). 2624 // r2: Right value (least significant part of mantissa).
2589 // r3: Right value (sign, exponent, top of mantissa). 2625 // r3: Right value (sign, exponent, top of mantissa).
2590 2626
2591 __ push(lr); // For later. 2627 __ push(lr); // For later.
2592 __ PrepareCallCFunction(4, scratch1); // Two doubles are 4 arguments. 2628 __ PrepareCallCFunction(4, scratch1); // Two doubles are 4 arguments.
2593 // Call C routine that may not cause GC or other trouble. r5 is callee 2629 // Call C routine that may not cause GC or other trouble. r5 is callee
2594 // save. 2630 // save.
2595 __ CallCFunction(ExternalReference::double_fp_operation(op_), 4); 2631 __ CallCFunction(ExternalReference::double_fp_operation(op_), 4);
2596 // Store answer in the overwritable heap number. 2632 // Store answer in the overwritable heap number.
2597 #if !defined(USE_ARM_EABI) 2633 #if !defined(USE_ARM_EABI)
2598 // Double returned in fp coprocessor register 0 and 1, encoded as 2634 // Double returned in fp coprocessor register 0 and 1, encoded as
2599 // register cr8. Offsets must be divisible by 4 for coprocessor so we 2635 // register cr8. Offsets must be divisible by 4 for coprocessor so we
2600 // need to substract the tag from r5. 2636 // need to substract the tag from r5.
2601 __ sub(scratch1, heap_number, Operand(kHeapObjectTag)); 2637 __ sub(scratch1, result, Operand(kHeapObjectTag));
2602 __ stc(p1, cr8, MemOperand(scratch1, HeapNumber::kValueOffset)); 2638 __ stc(p1, cr8, MemOperand(scratch1, HeapNumber::kValueOffset));
2603 #else 2639 #else
2604 // Double returned in registers 0 and 1. 2640 // Double returned in registers 0 and 1.
2605 __ Strd(r0, r1, FieldMemOperand(heap_number, HeapNumber::kValueOffset)); 2641 __ Strd(r0, r1, FieldMemOperand(result, HeapNumber::kValueOffset));
2606 #endif 2642 #endif
2607 __ mov(r0, Operand(heap_number)); 2643 __ mov(r0, Operand(result));
2608 // And we are done. 2644 // And we are done.
2609 __ pop(pc); 2645 __ pop(pc);
2610 } 2646 }
2611 } 2647 }
2612 __ bind(&not_smis); 2648 __ bind(&not_smis);
2613 } 2649 }
2614 2650
2615 2651
2616 void TypeRecordingBinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { 2652 void TypeRecordingBinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
2617 Label not_smis, call_runtime; 2653 Label not_smis, call_runtime;
2618 2654
2619 ASSERT(op_ == Token::ADD || op_ == Token::SUB || op_ == Token::MUL); 2655 ASSERT(op_ == Token::ADD ||
2656 op_ == Token::SUB ||
2657 op_ == Token::MUL ||
2658 op_ == Token::DIV ||
2659 op_ == Token::MOD);
2620 2660
2621 if (result_type_ == TRBinaryOpIC::UNINITIALIZED || 2661 if (result_type_ == TRBinaryOpIC::UNINITIALIZED ||
2622 result_type_ == TRBinaryOpIC::SMI) { 2662 result_type_ == TRBinaryOpIC::SMI) {
2623 // Only allow smi results. 2663 // Only allow smi results.
2624 GenerateSmiCode(masm, NULL, NO_HEAPNUMBER_RESULTS); 2664 GenerateSmiCode(masm, NULL, NO_HEAPNUMBER_RESULTS);
2625 } else { 2665 } else {
2626 // Allow heap number result and don't make a transition if a heap number 2666 // Allow heap number result and don't make a transition if a heap number
2627 // cannot be allocated. 2667 // cannot be allocated.
2628 GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); 2668 GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS);
2629 } 2669 }
(...skipping 11 matching lines...) Expand all
2641 ASSERT(operands_type_ == TRBinaryOpIC::STRING); 2681 ASSERT(operands_type_ == TRBinaryOpIC::STRING);
2642 ASSERT(op_ == Token::ADD); 2682 ASSERT(op_ == Token::ADD);
2643 // Try to add arguments as strings, otherwise, transition to the generic 2683 // Try to add arguments as strings, otherwise, transition to the generic
2644 // TRBinaryOpIC type. 2684 // TRBinaryOpIC type.
2645 GenerateAddStrings(masm); 2685 GenerateAddStrings(masm);
2646 GenerateTypeTransition(masm); 2686 GenerateTypeTransition(masm);
2647 } 2687 }
2648 2688
2649 2689
2650 void TypeRecordingBinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { 2690 void TypeRecordingBinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
2651 ASSERT(op_ == Token::ADD || op_ == Token::SUB || op_ == Token::MUL); 2691 ASSERT(op_ == Token::ADD ||
2692 op_ == Token::SUB ||
2693 op_ == Token::MUL ||
2694 op_ == Token::DIV ||
2695 op_ == Token::MOD);
2652 2696
2653 ASSERT(operands_type_ == TRBinaryOpIC::INT32); 2697 ASSERT(operands_type_ == TRBinaryOpIC::INT32);
2654 2698
2655 GenerateTypeTransition(masm); 2699 GenerateTypeTransition(masm);
2656 } 2700 }
2657 2701
2658 2702
2659 void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { 2703 void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
2660 ASSERT(op_ == Token::ADD || op_ == Token::SUB || op_ == Token::MUL); 2704 ASSERT(op_ == Token::ADD ||
2705 op_ == Token::SUB ||
2706 op_ == Token::MUL ||
2707 op_ == Token::DIV ||
2708 op_ == Token::MOD);
2661 2709
2662 Register scratch1 = r7; 2710 Register scratch1 = r7;
2663 Register scratch2 = r9; 2711 Register scratch2 = r9;
2664 2712
2665 Label not_number, call_runtime; 2713 Label not_number, call_runtime;
2666 ASSERT(operands_type_ == TRBinaryOpIC::HEAP_NUMBER); 2714 ASSERT(operands_type_ == TRBinaryOpIC::HEAP_NUMBER);
2667 2715
2668 Register heap_number_map = r6; 2716 Register heap_number_map = r6;
2669 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); 2717 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
2670 2718
2719 // Get a heap number object for the result - might be left or right if one
2720 // of these are overwritable. Uses a callee-save register to keep the value
2721 // across the C call which we might use below.
2722 Register result = r5;
2723 GenerateHeapResultAllocation(
2724 masm, result, heap_number_map, scratch1, scratch2, &call_runtime);
2725
2671 // Load left and right operands into d6 and d7 or r0/r1 and r2/r3 depending on 2726 // Load left and right operands into d6 and d7 or r0/r1 and r2/r3 depending on
2672 // whether VFP3 is available. 2727 // whether VFP3 is available.
2673 FloatingPointHelper::Destination destination = 2728 FloatingPointHelper::Destination destination =
2674 CpuFeatures::IsSupported(VFP3) ? 2729 CpuFeatures::IsSupported(VFP3) && op_ != Token::MOD ?
2675 FloatingPointHelper::kVFPRegisters : 2730 FloatingPointHelper::kVFPRegisters :
2676 FloatingPointHelper::kCoreRegisters; 2731 FloatingPointHelper::kCoreRegisters;
2677 FloatingPointHelper::LoadOperands(masm, 2732 FloatingPointHelper::LoadOperands(masm,
2678 destination, 2733 destination,
2679 heap_number_map, 2734 heap_number_map,
2680 scratch1, 2735 scratch1,
2681 scratch2, 2736 scratch2,
2682 &not_number); 2737 &not_number);
2683 if (destination == FloatingPointHelper::kVFPRegisters) { 2738 if (destination == FloatingPointHelper::kVFPRegisters) {
2684 // Use floating point instructions for the binary operation. 2739 // Use floating point instructions for the binary operation.
2685 CpuFeatures::Scope scope(VFP3); 2740 CpuFeatures::Scope scope(VFP3);
2686 GenerateVFPOperation(masm); 2741 GenerateVFPOperation(masm);
2687 2742
2688 // Get a heap number object for the result - might be left or right if one
2689 // of these are overwritable.
2690 GenerateHeapResultAllocation(
2691 masm, r4, heap_number_map, scratch1, scratch2, &call_runtime);
2692
2693 // Fill the result into the allocated heap number and return. 2743 // Fill the result into the allocated heap number and return.
2694 __ sub(r0, r4, Operand(kHeapObjectTag)); 2744 __ sub(r0, result, Operand(kHeapObjectTag));
2695 __ vstr(d5, r0, HeapNumber::kValueOffset); 2745 __ vstr(d5, r0, HeapNumber::kValueOffset);
2696 __ add(r0, r0, Operand(kHeapObjectTag)); 2746 __ add(r0, r0, Operand(kHeapObjectTag));
2697 __ Ret(); 2747 __ Ret();
2698 2748
2699 } else { 2749 } else {
2700 // Call a C function for the binary operation. 2750 // Call a C function for the binary operation.
2701 // r0/r1: Left operand 2751 // r0/r1: Left operand
2702 // r2/r3: Right operand 2752 // r2/r3: Right operand
2703 2753
2704 // Get a heap number object for the result - might be left or right if one
2705 // of these are overwritable. Uses a callee-save register to keep the value
2706 // across the c call.
2707 GenerateHeapResultAllocation(
2708 masm, r4, heap_number_map, scratch1, scratch2, &call_runtime);
2709
2710 __ push(lr); // For returning later (no GC after this point). 2754 __ push(lr); // For returning later (no GC after this point).
2711 __ PrepareCallCFunction(4, scratch1); // Two doubles count as 4 arguments. 2755 __ PrepareCallCFunction(4, scratch1); // Two doubles count as 4 arguments.
2712 // Call C routine that may not cause GC or other trouble. r4 is callee 2756 // Call C routine that may not cause GC or other trouble. result (r5) is
2713 // saved. 2757 // callee saved.
2714 __ CallCFunction(ExternalReference::double_fp_operation(op_), 4); 2758 __ CallCFunction(ExternalReference::double_fp_operation(op_), 4);
2715
2716 // Fill the result into the allocated heap number. 2759 // Fill the result into the allocated heap number.
2717 #if !defined(USE_ARM_EABI) 2760 #if !defined(USE_ARM_EABI)
2718 // Double returned in fp coprocessor register 0 and 1, encoded as 2761 // Double returned in fp coprocessor register 0 and 1, encoded as
2719 // register cr8. Offsets must be divisible by 4 for coprocessor so we 2762 // register cr8. Offsets must be divisible by 4 for coprocessor so we
2720 // need to substract the tag from r5. 2763 // need to substract the tag from r5.
2721 __ sub(scratch1, r4, Operand(kHeapObjectTag)); 2764 __ sub(scratch1, result, Operand(kHeapObjectTag));
2722 __ stc(p1, cr8, MemOperand(scratch1, HeapNumber::kValueOffset)); 2765 __ stc(p1, cr8, MemOperand(scratch1, HeapNumber::kValueOffset));
2723 #else 2766 #else
2724 // Double returned in registers 0 and 1. 2767 // Double returned in registers 0 and 1.
2725 __ Strd(r0, r1, FieldMemOperand(r4, HeapNumber::kValueOffset)); 2768 __ Strd(r0, r1, FieldMemOperand(result, HeapNumber::kValueOffset));
2726 #endif 2769 #endif
2727 __ mov(r0, Operand(r4)); 2770 __ mov(r0, Operand(result));
2728 __ pop(pc); // Return to the pushed lr. 2771 __ pop(pc); // Return to the pushed lr.
2729 } 2772 }
2730 2773
2731 __ bind(&not_number); 2774 __ bind(&not_number);
2732 GenerateTypeTransition(masm); 2775 GenerateTypeTransition(masm);
2733 2776
2734 __ bind(&call_runtime); 2777 __ bind(&call_runtime);
2735 GenerateCallRuntime(masm); 2778 GenerateCallRuntime(masm);
2736 } 2779 }
2737 2780
2738 2781
2739 void TypeRecordingBinaryOpStub::GenerateGeneric(MacroAssembler* masm) { 2782 void TypeRecordingBinaryOpStub::GenerateGeneric(MacroAssembler* masm) {
2740 ASSERT(op_ == Token::ADD || op_ == Token::SUB || op_ == Token::MUL); 2783 ASSERT(op_ == Token::ADD ||
2784 op_ == Token::SUB ||
2785 op_ == Token::MUL ||
2786 op_ == Token::DIV ||
2787 op_ == Token::MOD);
2741 2788
2742 Label call_runtime; 2789 Label call_runtime;
2743 2790
2744 GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); 2791 GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS);
2745 2792
2746 // If all else fails, use the runtime system to get the correct 2793 // If all else fails, use the runtime system to get the correct
2747 // result. 2794 // result.
2748 __ bind(&call_runtime); 2795 __ bind(&call_runtime);
2749 2796
2750 // Try to add strings before calling runtime. 2797 // Try to add strings before calling runtime.
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
2789 switch (op_) { 2836 switch (op_) {
2790 case Token::ADD: 2837 case Token::ADD:
2791 __ InvokeBuiltin(Builtins::ADD, JUMP_JS); 2838 __ InvokeBuiltin(Builtins::ADD, JUMP_JS);
2792 break; 2839 break;
2793 case Token::SUB: 2840 case Token::SUB:
2794 __ InvokeBuiltin(Builtins::SUB, JUMP_JS); 2841 __ InvokeBuiltin(Builtins::SUB, JUMP_JS);
2795 break; 2842 break;
2796 case Token::MUL: 2843 case Token::MUL:
2797 __ InvokeBuiltin(Builtins::MUL, JUMP_JS); 2844 __ InvokeBuiltin(Builtins::MUL, JUMP_JS);
2798 break; 2845 break;
2846 case Token::DIV:
2847 __ InvokeBuiltin(Builtins::DIV, JUMP_JS);
2848 break;
2849 case Token::MOD:
2850 __ InvokeBuiltin(Builtins::MOD, JUMP_JS);
2851 break;
2799 default: 2852 default:
2800 UNREACHABLE(); 2853 UNREACHABLE();
2801 } 2854 }
2802 } 2855 }
2803 2856
2804 2857
2805 void TypeRecordingBinaryOpStub::GenerateHeapResultAllocation( 2858 void TypeRecordingBinaryOpStub::GenerateHeapResultAllocation(
2806 MacroAssembler* masm, 2859 MacroAssembler* masm,
2807 Register result, 2860 Register result,
2808 Register heap_number_map, 2861 Register heap_number_map,
(...skipping 2907 matching lines...) Expand 10 before | Expand all | Expand 10 after
5716 __ pop(r1); 5769 __ pop(r1);
5717 __ Jump(r2); 5770 __ Jump(r2);
5718 } 5771 }
5719 5772
5720 5773
5721 #undef __ 5774 #undef __
5722 5775
5723 } } // namespace v8::internal 5776 } } // namespace v8::internal
5724 5777
5725 #endif // V8_TARGET_ARCH_ARM 5778 #endif // V8_TARGET_ARCH_ARM
OLDNEW
« no previous file with comments | « no previous file | src/arm/full-codegen-arm.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698