| 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 |