OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/globals.h" // NOLINT | 5 #include "vm/globals.h" // NOLINT |
6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
7 | 7 |
8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
9 #include "vm/cpu.h" | 9 #include "vm/cpu.h" |
10 #include "vm/longjump.h" | 10 #include "vm/longjump.h" |
(...skipping 417 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
428 EmitMulOp(cond, B22 | B21, ra, rd, rn, rm); | 428 EmitMulOp(cond, B22 | B21, ra, rd, rn, rm); |
429 } else { | 429 } else { |
430 mul(IP, rn, rm, cond); | 430 mul(IP, rn, rm, cond); |
431 sub(rd, ra, Operand(IP), cond); | 431 sub(rd, ra, Operand(IP), cond); |
432 } | 432 } |
433 } | 433 } |
434 | 434 |
435 | 435 |
436 void Assembler::smull(Register rd_lo, Register rd_hi, | 436 void Assembler::smull(Register rd_lo, Register rd_hi, |
437 Register rn, Register rm, Condition cond) { | 437 Register rn, Register rm, Condition cond) { |
438 ASSERT(TargetCPUFeatures::arm_version() == ARMv7); | |
439 // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. | 438 // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. |
440 EmitMulOp(cond, B23 | B22, rd_lo, rd_hi, rn, rm); | 439 EmitMulOp(cond, B23 | B22, rd_lo, rd_hi, rn, rm); |
441 } | 440 } |
442 | 441 |
443 | 442 |
444 void Assembler::umull(Register rd_lo, Register rd_hi, | 443 void Assembler::umull(Register rd_lo, Register rd_hi, |
445 Register rn, Register rm, Condition cond) { | 444 Register rn, Register rm, Condition cond) { |
446 ASSERT(TargetCPUFeatures::arm_version() == ARMv7); | 445 ASSERT(TargetCPUFeatures::arm_version() == ARMv7); |
447 // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. | 446 // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. |
448 EmitMulOp(cond, B23, rd_lo, rd_hi, rn, rm); | 447 EmitMulOp(cond, B23, rd_lo, rd_hi, rn, rm); |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
533 void Assembler::ldrsb(Register rd, Address ad, Condition cond) { | 532 void Assembler::ldrsb(Register rd, Address ad, Condition cond) { |
534 EmitMemOpAddressMode3(cond, L | B7 | B6 | B4, rd, ad); | 533 EmitMemOpAddressMode3(cond, L | B7 | B6 | B4, rd, ad); |
535 } | 534 } |
536 | 535 |
537 | 536 |
538 void Assembler::ldrsh(Register rd, Address ad, Condition cond) { | 537 void Assembler::ldrsh(Register rd, Address ad, Condition cond) { |
539 EmitMemOpAddressMode3(cond, L | B7 | B6 | H | B4, rd, ad); | 538 EmitMemOpAddressMode3(cond, L | B7 | B6 | H | B4, rd, ad); |
540 } | 539 } |
541 | 540 |
542 | 541 |
543 void Assembler::ldrd(Register rd, Address ad, Condition cond) { | 542 void Assembler::ldrd(Register rd, Register rn, int32_t offset, Condition cond) { |
544 ASSERT((rd % 2) == 0); | 543 ASSERT((rd % 2) == 0); |
545 EmitMemOpAddressMode3(cond, B7 | B6 | B4, rd, ad); | 544 if (TargetCPUFeatures::arm_version() == ARMv5TE) { |
| 545 const Register rd2 = static_cast<Register>(static_cast<int32_t>(rd) + 1); |
| 546 ldr(rd, Address(rn, offset), cond); |
| 547 ldr(rd2, Address(rn, offset + kWordSize), cond); |
| 548 } else { |
| 549 EmitMemOpAddressMode3(cond, B7 | B6 | B4, rd, Address(rn, offset)); |
| 550 } |
546 } | 551 } |
547 | 552 |
548 | 553 |
549 void Assembler::strd(Register rd, Address ad, Condition cond) { | 554 void Assembler::strd(Register rd, Register rn, int32_t offset, Condition cond) { |
550 ASSERT((rd % 2) == 0); | 555 ASSERT((rd % 2) == 0); |
551 EmitMemOpAddressMode3(cond, B7 | B6 | B5 | B4, rd, ad); | 556 if (TargetCPUFeatures::arm_version() == ARMv5TE) { |
| 557 const Register rd2 = static_cast<Register>(static_cast<int32_t>(rd) + 1); |
| 558 str(rd, Address(rn, offset), cond); |
| 559 str(rd2, Address(rn, offset + kWordSize), cond); |
| 560 } else { |
| 561 EmitMemOpAddressMode3(cond, B7 | B6 | B5 | B4, rd, Address(rn, offset)); |
| 562 } |
552 } | 563 } |
553 | 564 |
554 | 565 |
555 void Assembler::ldm(BlockAddressMode am, Register base, RegList regs, | 566 void Assembler::ldm(BlockAddressMode am, Register base, RegList regs, |
556 Condition cond) { | 567 Condition cond) { |
557 ASSERT(regs != 0); | 568 ASSERT(regs != 0); |
558 EmitMultiMemOp(cond, am, true, base, regs); | 569 EmitMultiMemOp(cond, am, true, base, regs); |
559 if (TargetCPUFeatures::arm_version() == ARMv5TE) { | |
560 // On ARMv5, touching a "banked" register after an ldm gives undefined | |
561 // behavior, so we just add a nop here to make that case easy to avoid. | |
562 nop(); | |
563 } | |
564 } | 570 } |
565 | 571 |
566 | 572 |
567 void Assembler::stm(BlockAddressMode am, Register base, RegList regs, | 573 void Assembler::stm(BlockAddressMode am, Register base, RegList regs, |
568 Condition cond) { | 574 Condition cond) { |
569 ASSERT(regs != 0); | 575 ASSERT(regs != 0); |
570 EmitMultiMemOp(cond, am, false, base, regs); | 576 EmitMultiMemOp(cond, am, false, base, regs); |
571 if (TargetCPUFeatures::arm_version() == ARMv5TE) { | |
572 // On ARMv5, touching a "banked" register after an stm gives undefined | |
573 // behavior, so we just add a nop here to make that case easy to avoid. | |
574 nop(); | |
575 } | |
576 } | 577 } |
577 | 578 |
578 | 579 |
579 void Assembler::ldrex(Register rt, Register rn, Condition cond) { | 580 void Assembler::ldrex(Register rt, Register rn, Condition cond) { |
580 ASSERT(TargetCPUFeatures::arm_version() != ARMv5TE); | 581 ASSERT(TargetCPUFeatures::arm_version() != ARMv5TE); |
581 ASSERT(rn != kNoRegister); | 582 ASSERT(rn != kNoRegister); |
582 ASSERT(rt != kNoRegister); | 583 ASSERT(rt != kNoRegister); |
583 ASSERT(cond != kNoCondition); | 584 ASSERT(cond != kNoCondition); |
584 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | | 585 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | |
585 B24 | | 586 B24 | |
(...skipping 1083 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1669 intptr_t offset, | 1670 intptr_t offset, |
1670 Register value_even, | 1671 Register value_even, |
1671 Register value_odd, | 1672 Register value_odd, |
1672 Condition cond) { | 1673 Condition cond) { |
1673 ASSERT(value_odd == value_even + 1); | 1674 ASSERT(value_odd == value_even + 1); |
1674 if (VerifiedMemory::enabled()) { | 1675 if (VerifiedMemory::enabled()) { |
1675 ASSERT(base != value_even); | 1676 ASSERT(base != value_even); |
1676 ASSERT(base != value_odd); | 1677 ASSERT(base != value_odd); |
1677 Operand shadow(GetVerifiedMemoryShadow()); | 1678 Operand shadow(GetVerifiedMemoryShadow()); |
1678 add(base, base, shadow, cond); | 1679 add(base, base, shadow, cond); |
1679 strd(value_even, Address(base, offset), cond); | 1680 strd(value_even, base, offset, cond); |
1680 sub(base, base, shadow, cond); | 1681 sub(base, base, shadow, cond); |
1681 } | 1682 } |
1682 strd(value_even, Address(base, offset), cond); | 1683 strd(value_even, base, offset, cond); |
1683 } | 1684 } |
1684 | 1685 |
1685 | 1686 |
1686 Register UseRegister(Register reg, RegList* used) { | 1687 Register UseRegister(Register reg, RegList* used) { |
1687 ASSERT(reg != SP); | 1688 ASSERT(reg != SP); |
1688 ASSERT(reg != PC); | 1689 ASSERT(reg != PC); |
1689 ASSERT((*used & (1 << reg)) == 0); | 1690 ASSERT((*used & (1 << reg)) == 0); |
1690 *used |= (1 << reg); | 1691 *used |= (1 << reg); |
1691 return reg; | 1692 return reg; |
1692 } | 1693 } |
(...skipping 1094 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2787 case kHalfword: | 2788 case kHalfword: |
2788 ldrsh(reg, Address(base, offset), cond); | 2789 ldrsh(reg, Address(base, offset), cond); |
2789 break; | 2790 break; |
2790 case kUnsignedHalfword: | 2791 case kUnsignedHalfword: |
2791 ldrh(reg, Address(base, offset), cond); | 2792 ldrh(reg, Address(base, offset), cond); |
2792 break; | 2793 break; |
2793 case kWord: | 2794 case kWord: |
2794 ldr(reg, Address(base, offset), cond); | 2795 ldr(reg, Address(base, offset), cond); |
2795 break; | 2796 break; |
2796 case kWordPair: | 2797 case kWordPair: |
2797 ldrd(reg, Address(base, offset), cond); | 2798 ldrd(reg, base, offset, cond); |
2798 break; | 2799 break; |
2799 default: | 2800 default: |
2800 UNREACHABLE(); | 2801 UNREACHABLE(); |
2801 } | 2802 } |
2802 } | 2803 } |
2803 | 2804 |
2804 | 2805 |
2805 void Assembler::StoreToOffset(OperandSize size, | 2806 void Assembler::StoreToOffset(OperandSize size, |
2806 Register reg, | 2807 Register reg, |
2807 Register base, | 2808 Register base, |
(...skipping 11 matching lines...) Expand all Loading... |
2819 case kByte: | 2820 case kByte: |
2820 strb(reg, Address(base, offset), cond); | 2821 strb(reg, Address(base, offset), cond); |
2821 break; | 2822 break; |
2822 case kHalfword: | 2823 case kHalfword: |
2823 strh(reg, Address(base, offset), cond); | 2824 strh(reg, Address(base, offset), cond); |
2824 break; | 2825 break; |
2825 case kWord: | 2826 case kWord: |
2826 str(reg, Address(base, offset), cond); | 2827 str(reg, Address(base, offset), cond); |
2827 break; | 2828 break; |
2828 case kWordPair: | 2829 case kWordPair: |
2829 strd(reg, Address(base, offset), cond); | 2830 strd(reg, base, offset, cond); |
2830 break; | 2831 break; |
2831 default: | 2832 default: |
2832 UNREACHABLE(); | 2833 UNREACHABLE(); |
2833 } | 2834 } |
2834 } | 2835 } |
2835 | 2836 |
2836 | 2837 |
2837 void Assembler::LoadSFromOffset(SRegister reg, | 2838 void Assembler::LoadSFromOffset(SRegister reg, |
2838 Register base, | 2839 Register base, |
2839 int32_t offset, | 2840 int32_t offset, |
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3125 vcvtdi(tmpl, stmpl); // left is in tmpl. | 3126 vcvtdi(tmpl, stmpl); // left is in tmpl. |
3126 vmovsr(stmpr, right); | 3127 vmovsr(stmpr, right); |
3127 vcvtdi(tmpr, stmpr); // right is in tmpr. | 3128 vcvtdi(tmpr, stmpr); // right is in tmpr. |
3128 vdivd(tmpr, tmpl, tmpr); | 3129 vdivd(tmpr, tmpl, tmpr); |
3129 vcvtid(stmpr, tmpr); | 3130 vcvtid(stmpr, tmpr); |
3130 vmovrs(result, stmpr); | 3131 vmovrs(result, stmpr); |
3131 } | 3132 } |
3132 } | 3133 } |
3133 | 3134 |
3134 | 3135 |
3135 // If we aren't on ARMv7, there is no smull, and we have to check for overflow | |
3136 // manually. | |
3137 void Assembler::CheckMultSignedOverflow(Register left, | |
3138 Register right, | |
3139 Register tmp, | |
3140 DRegister dtmp0, DRegister dtmp1, | |
3141 Label* overflow) { | |
3142 Label done, left_neg, left_pos_right_neg, left_neg_right_pos; | |
3143 | |
3144 CompareImmediate(left, 0); | |
3145 b(&left_neg, LT); | |
3146 b(&done, EQ); | |
3147 CompareImmediate(right, 0); | |
3148 b(&left_pos_right_neg, LT); | |
3149 b(&done, EQ); | |
3150 | |
3151 // Both positive. | |
3152 LoadImmediate(tmp, INT_MAX); | |
3153 IntegerDivide(tmp, tmp, left, dtmp0, dtmp1); | |
3154 cmp(tmp, Operand(right)); | |
3155 b(overflow, LT); | |
3156 b(&done); | |
3157 | |
3158 // left positive, right non-positive. | |
3159 Bind(&left_pos_right_neg); | |
3160 LoadImmediate(tmp, INT_MIN); | |
3161 IntegerDivide(tmp, tmp, left, dtmp0, dtmp1); | |
3162 cmp(tmp, Operand(right)); | |
3163 b(overflow, GT); | |
3164 b(&done); | |
3165 | |
3166 Bind(&left_neg); | |
3167 CompareImmediate(right, 0); | |
3168 b(&left_neg_right_pos, GT); | |
3169 b(&done, EQ); | |
3170 | |
3171 // both negative. | |
3172 LoadImmediate(tmp, INT_MAX); | |
3173 IntegerDivide(tmp, tmp, left, dtmp0, dtmp1); | |
3174 cmp(tmp, Operand(right)); | |
3175 b(overflow, GT); | |
3176 b(&done); | |
3177 | |
3178 // left non-positive, right positive. | |
3179 Bind(&left_neg_right_pos); | |
3180 LoadImmediate(tmp, INT_MIN); | |
3181 IntegerDivide(tmp, tmp, right, dtmp0, dtmp1); | |
3182 cmp(tmp, Operand(left)); | |
3183 b(overflow, GT); | |
3184 | |
3185 Bind(&done); | |
3186 } | |
3187 | |
3188 | |
3189 static int NumRegsBelowFP(RegList regs) { | 3136 static int NumRegsBelowFP(RegList regs) { |
3190 int count = 0; | 3137 int count = 0; |
3191 for (int i = 0; i < FP; i++) { | 3138 for (int i = 0; i < FP; i++) { |
3192 if ((regs & (1 << i)) != 0) { | 3139 if ((regs & (1 << i)) != 0) { |
3193 count++; | 3140 count++; |
3194 } | 3141 } |
3195 } | 3142 } |
3196 return count; | 3143 return count; |
3197 } | 3144 } |
3198 | 3145 |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3316 AddImmediate(SP, -frame_size); | 3263 AddImmediate(SP, -frame_size); |
3317 } | 3264 } |
3318 | 3265 |
3319 | 3266 |
3320 // On entry to a function compiled for OSR, the caller's frame pointer, the | 3267 // On entry to a function compiled for OSR, the caller's frame pointer, the |
3321 // stack locals, and any copied parameters are already in place. The frame | 3268 // stack locals, and any copied parameters are already in place. The frame |
3322 // pointer is already set up. The PC marker is not correct for the | 3269 // pointer is already set up. The PC marker is not correct for the |
3323 // optimized function and there may be extra space for spill slots to | 3270 // optimized function and there may be extra space for spill slots to |
3324 // allocate. We must also set up the pool pointer for the function. | 3271 // allocate. We must also set up the pool pointer for the function. |
3325 void Assembler::EnterOsrFrame(intptr_t extra_size) { | 3272 void Assembler::EnterOsrFrame(intptr_t extra_size) { |
3326 const intptr_t offset = CodeSize(); | 3273 // The offset for the PC marker is adjusted by the difference in PC offset |
| 3274 // between stores and other instructions. In particular, on some ARMv5's the |
| 3275 // PC offset for stores is 12 and the offset in other instructions is 8. |
| 3276 const intptr_t offset = CodeSize() - |
| 3277 (TargetCPUFeatures::store_pc_read_offset() - Instr::kPCReadOffset); |
3327 | 3278 |
3328 Comment("EnterOsrFrame"); | 3279 Comment("EnterOsrFrame"); |
3329 mov(IP, Operand(PC)); | 3280 mov(IP, Operand(PC)); |
3330 | 3281 |
3331 AddImmediate(IP, -offset); | 3282 AddImmediate(IP, -offset); |
3332 str(IP, Address(FP, kPcMarkerSlotFromFp * kWordSize)); | 3283 str(IP, Address(FP, kPcMarkerSlotFromFp * kWordSize)); |
3333 | 3284 |
3334 // Setup pool pointer for this dart function. | 3285 // Setup pool pointer for this dart function. |
3335 LoadPoolPointer(); | 3286 LoadPoolPointer(); |
3336 | 3287 |
(...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3631 | 3582 |
3632 | 3583 |
3633 const char* Assembler::FpuRegisterName(FpuRegister reg) { | 3584 const char* Assembler::FpuRegisterName(FpuRegister reg) { |
3634 ASSERT((0 <= reg) && (reg < kNumberOfFpuRegisters)); | 3585 ASSERT((0 <= reg) && (reg < kNumberOfFpuRegisters)); |
3635 return fpu_reg_names[reg]; | 3586 return fpu_reg_names[reg]; |
3636 } | 3587 } |
3637 | 3588 |
3638 } // namespace dart | 3589 } // namespace dart |
3639 | 3590 |
3640 #endif // defined TARGET_ARCH_ARM | 3591 #endif // defined TARGET_ARCH_ARM |
OLD | NEW |